diff options
Diffstat (limited to 'src/server/scripts')
20 files changed, 3036 insertions, 54 deletions
diff --git a/src/server/scripts/Commands/cs_battlenet_account.cpp b/src/server/scripts/Commands/cs_battlenet_account.cpp index 06bd131150a..79b57cb94ff 100644 --- a/src/server/scripts/Commands/cs_battlenet_account.cpp +++ b/src/server/scripts/Commands/cs_battlenet_account.cpp @@ -44,17 +44,20 @@ public: static ChatCommand accountCommandTable[] = { - { "create", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE, true, &HandleAccountCreateCommand, "", NULL }, - { "lock", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, false, NULL, "", accountLockCommandTable }, - { "set", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_SET, true, NULL, "", accountSetCommandTable }, - { "password", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD, false, &HandleAccountPasswordCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } + { "create", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE, true, &HandleAccountCreateCommand, "", NULL }, + { "gameaccountcreate", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE_GAME, true, &HandleGameAccountCreateCommand, "", NULL }, + { "lock", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, false, NULL, "", accountLockCommandTable }, + { "set", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_SET, true, NULL, "", accountSetCommandTable }, + { "password", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD, false, &HandleAccountPasswordCommand, "", NULL }, + { "link", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_LINK, true, &HandleAccountLinkCommand, "", NULL }, + { "unlink", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_UNLINK, true, &HandleAccountUnlinkCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } }; static ChatCommand commandTable[] = { - { "battlenetaccount", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, true, NULL, "", accountCommandTable }, - { NULL, 0, false, NULL, "", NULL } + { "bnetaccount", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, true, NULL, "", accountCommandTable }, + { NULL, 0, false, NULL, "", NULL } }; return commandTable; @@ -328,6 +331,124 @@ public: } return true; } + + static bool HandleAccountLinkCommand(ChatHandler* handler, char const* args) + { + Tokenizer tokens(args, ' ', 2); + if (tokens.size() != 2) + { + handler->SendSysMessage(LANG_CMD_SYNTAX); + handler->SetSentErrorMessage(true); + return false; + } + + std::string bnetAccountName = tokens[0]; + std::string gameAccountName = tokens[1]; + + switch (Battlenet::AccountMgr::LinkWithGameAccount(bnetAccountName, gameAccountName)) + { + case AccountOpResult::AOR_OK: + handler->PSendSysMessage(LANG_ACCOUNT_BNET_LINKED, bnetAccountName.c_str(), gameAccountName.c_str()); + break; + case AccountOpResult::AOR_NAME_NOT_EXIST: + handler->PSendSysMessage(LANG_ACCOUNT_OR_BNET_DOES_NOT_EXIST, bnetAccountName.c_str(), gameAccountName.c_str()); + handler->SetSentErrorMessage(true); + break; + case AccountOpResult::AOR_ACCOUNT_BAD_LINK: + handler->PSendSysMessage(LANG_ACCOUNT_ALREADY_LINKED, gameAccountName.c_str()); + handler->SetSentErrorMessage(true); + break; + default: + break; + } + + return true; + } + + static bool HandleAccountUnlinkCommand(ChatHandler* handler, char const* args) + { + if (!*args) + { + handler->SendSysMessage(LANG_CMD_SYNTAX); + handler->SetSentErrorMessage(true); + return false; + } + + std::string gameAccountName = args; + + switch (Battlenet::AccountMgr::UnlinkGameAccount(gameAccountName)) + { + case AccountOpResult::AOR_OK: + handler->PSendSysMessage(LANG_ACCOUNT_BNET_UNLINKED, gameAccountName.c_str()); + break; + case AccountOpResult::AOR_NAME_NOT_EXIST: + handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, gameAccountName.c_str()); + handler->SetSentErrorMessage(true); + break; + case AccountOpResult::AOR_ACCOUNT_BAD_LINK: + handler->PSendSysMessage(LANG_ACCOUNT_BNET_NOT_LINKED, gameAccountName.c_str()); + handler->SetSentErrorMessage(true); + break; + default: + break; + } + + return true; + } + + static bool HandleGameAccountCreateCommand(ChatHandler* handler, char const* args) + { + if (!*args) + { + handler->SendSysMessage(LANG_CMD_SYNTAX); + handler->SetSentErrorMessage(true); + return false; + } + + std::string bnetAccountName = args; + uint32 accountId = Battlenet::AccountMgr::GetId(bnetAccountName); + if (!accountId) + { + handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, bnetAccountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + uint8 index = Battlenet::AccountMgr::GetMaxIndex(accountId) + 1; + std::string accountName = std::to_string(accountId) + '#' + std::to_string(uint32(index)); + + switch (sAccountMgr->CreateAccount(accountName, "DUMMY", bnetAccountName, accountId, index)) + { + case AccountOpResult::AOR_OK: + handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName.c_str()); + if (handler->GetSession()) + { + TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (%s) created Account %s (Email: '%s')", + handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().ToString().c_str(), + accountName.c_str(), bnetAccountName.c_str()); + } + break; + case AccountOpResult::AOR_NAME_TOO_LONG: + handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_NAME_ALREADY_EXIST: + handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_DB_INTERNAL_ERROR: + handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + default: + handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, accountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + return true; + } }; void AddSC_battlenet_account_commandscript() diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index 74a947e42e4..a5b2ed045c6 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -129,7 +129,10 @@ public: // Display the 'Message of the day' for the realm static bool HandleServerMotdCommand(ChatHandler* handler, char const* /*args*/) { - handler->PSendSysMessage(LANG_MOTD_CURRENT, sWorld->GetMotd()); + std::string motd; + for (std::string const& line : sWorld->GetMotd()) + motd += line; + handler->PSendSysMessage(LANG_MOTD_CURRENT, motd.c_str()); return true; } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp index 4b40660fafc..f736aa6ffbc 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp @@ -108,7 +108,7 @@ public: npc_twilight_flame_caller() : CreatureScript("npc_twilight_flame_caller" struct npc_twilight_flame_callerAI : public ScriptedAI { - npc_twilight_flame_callerAI(Creature* creature) : ScriptedAI(creature), _summons(me), _instance(creature->GetInstanceScript()) + npc_twilight_flame_callerAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _summons(me) { Initialize(); } diff --git a/src/server/scripts/Maelstrom/CMakeLists.txt b/src/server/scripts/Maelstrom/CMakeLists.txt index 79f0789fd3f..8d3f1ee1c69 100644 --- a/src/server/scripts/Maelstrom/CMakeLists.txt +++ b/src/server/scripts/Maelstrom/CMakeLists.txt @@ -9,6 +9,13 @@ set(scripts_STAT_SRCS ${scripts_STAT_SRCS} Maelstrom/kezan.cpp + Maelstrom/Stonecore/instance_stonecore.cpp + Maelstrom/Stonecore/stonecore.cpp + Maelstrom/Stonecore/stonecore.h + Maelstrom/Stonecore/boss_corborus.cpp + Maelstrom/Stonecore/boss_slabhide.cpp + Maelstrom/Stonecore/boss_ozruk.cpp + Maelstrom/Stonecore/boss_high_priestess_azil.cpp ) message(" -> Prepared: The Maelstrom") diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp new file mode 100644 index 00000000000..2d522928fce --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "CreatureGroups.h" +#include "stonecore.h" + +// TO-DO: +// Find heroic sniffs and script spawning Crystal Shards on heroic mode. + +enum Spells +{ + // Corborus intro + SPELL_TWILIGHT_DOCUMENTS = 93167, + SPELL_RING_WYRM_CHARGE = 81237, + SPELL_DOOR_BREAK = 81232, // cast by World Trigger 22515 + + // Corborus boss + SPELL_DAMPENING_WAVE = 82415, + SPELL_CRYSTAL_BARRAGE = 86881, // 81638 triggers 81637 +// SPELL_CRYSTAL_BARRAGE_SHARD = 92012, // heroic only, summons Crystal Shard (TO-DO!) + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_SUBMERGE = 81629, + SPELL_TRASHING_CHARGE_TELEPORT = 81839, // triggers 81864 +// SPELL_TRASHING_CHARGE_TELEPORT_2= 81838, // dummy, targets all players, threat update packet follows + SPELL_SUMMON_TRASHING_CHARGE = 81816, + SPELL_TRASHING_CHARGE_VISUAL = 81801, // cast time 3.5 sec + SPELL_TRASHING_CHARGE_EFFECT = 81828, // 40 yard radius + SPELL_EMERGE = 81948, + + // Rock Borer npc (43917) + SPELL_ROCK_BORER_EMERGE = 82185, + SPELL_ROCK_BORE = 80028, +}; + +enum NPCs +{ + NPC_TRASHING_CHARGE = 43743, +// NPC_CRYSTAL_SHARD = 49267, // 49473 +}; + +enum Events +{ + EVENT_NONE, + + // Corborus intro + EVENT_CORBORUS_CHARGE, + EVENT_CORBORUS_KNOCKBACK, + EVENT_CORBORUS_FACEPLAYERS, + + // Corborus boss + EVENT_DAMPENING_WAVE, + EVENT_CRYSTAL_BARRAGE, + EVENT_SUBMERGE, + EVENT_TELEPORT, + EVENT_TRASHING_CHARGE, + EVENT_SUMMON_BEETLE, + EVENT_EMERGE, + EVENT_ATTACK, + + // Rock Borer + EVENT_EMERGED, + EVENT_ROCK_BORE, +}; + +class boss_corborus : public CreatureScript +{ + public: + boss_corborus() : CreatureScript("boss_corborus") { } + + struct boss_corborusAI : public BossAI + { + boss_corborusAI(Creature* creature) : BossAI(creature, DATA_CORBORUS) + { + stateIntro = NOT_STARTED; + } + + void Reset() override + { + _Reset(); + countTrashingCharge = 0; + events.ScheduleEvent(EVENT_DAMPENING_WAVE, 10000); + events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 15000); + events.ScheduleEvent(EVENT_SUBMERGE, 36000); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_CORBORUS_INTRO: // Executes Corborus intro event + { + if (stateIntro != NOT_STARTED) + return; + + stateIntro = IN_PROGRESS; + + if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM))) + { + Millhouse->InterruptNonMeleeSpells(true); + Millhouse->RemoveAllAuras(); + Millhouse->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN); + } + + events.ScheduleEvent(EVENT_CORBORUS_CHARGE, 1000); + break; + } + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && stateIntro != IN_PROGRESS) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CORBORUS_CHARGE: + // Face Millhouse and other mobs + instance->SetData(DATA_MILLHOUSE_EVENT_FACE, 0); + + // Open rock gate and cast visual from nearby worldtrigger + instance->HandleGameObject(instance->GetGuidData(GAMEOBJECT_CORBORUS_ROCKDOOR), true); + if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 60.0f)) + worldtrigger->CastSpell(worldtrigger, SPELL_DOOR_BREAK, true); + + // Make Corborus charge + me->CastSpell(me, SPELL_RING_WYRM_CHARGE, true); + + events.ScheduleEvent(EVENT_CORBORUS_KNOCKBACK, 1000); + break; + case EVENT_CORBORUS_KNOCKBACK: + // Spawn Twilight Documents (quest gameobject) + if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM))) + Millhouse->CastSpell(Millhouse, SPELL_TWILIGHT_DOCUMENTS, true); + + // Knockback Millhouse and other mobs + instance->SetData(DATA_MILLHOUSE_EVENT_KNOCKBACK, 0); + + events.ScheduleEvent(EVENT_CORBORUS_FACEPLAYERS, 2000); + break; + case EVENT_CORBORUS_FACEPLAYERS: + // Face Corborus to players and set new home position + me->SetFacingTo(3.176499f); + me->SetHomePosition(1154.55f, 878.843f, 284.963f, 3.176499f); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + + // Despawn Millhouse and all trash + instance->SetData(DATA_MILLHOUSE_EVENT_DESPAWN, 0); + + stateIntro = DONE; + break; + case EVENT_DAMPENING_WAVE: + DoCastVictim(SPELL_DAMPENING_WAVE); + events.ScheduleEvent(EVENT_DAMPENING_WAVE, 15000); + break; + case EVENT_CRYSTAL_BARRAGE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_CRYSTAL_BARRAGE); + events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 10000); + break; + case EVENT_SUBMERGE: + events.RescheduleEvent(EVENT_DAMPENING_WAVE, 35000); + events.RescheduleEvent(EVENT_CRYSTAL_BARRAGE, 30000); + events.RescheduleEvent(EVENT_SUBMERGE, 100000); + + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + me->AttackStop(); + + DoCast(me, SPELL_SUBMERGE); + + countTrashingCharge = 0; + events.ScheduleEvent(EVENT_TELEPORT, 500); + break; + case EVENT_TELEPORT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_TRASHING_CHARGE_TELEPORT); + countTrashingCharge += 1; + if (countTrashingCharge <= 4) + events.ScheduleEvent(EVENT_TRASHING_CHARGE, 1000); + else + events.ScheduleEvent(EVENT_EMERGE, 2500); + break; + case EVENT_TRASHING_CHARGE: + DoCast(me, SPELL_SUMMON_TRASHING_CHARGE); + DoCast(me, SPELL_TRASHING_CHARGE_VISUAL); + events.ScheduleEvent(EVENT_TELEPORT, 5000); + break; + case EVENT_EMERGE: + me->RemoveAllAuras(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_EMERGE); + events.ScheduleEvent(EVENT_ATTACK, 2500); + break; + case EVENT_ATTACK: + me->SetReactState(REACT_AGGRESSIVE); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_TRASHING_CHARGE) + return; + + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_TRASHING_CHARGE_EFFECT); + summon->DespawnOrUnsummon(6000); + } + + private: + EncounterState stateIntro; + uint32 countTrashingCharge; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_corborusAI>(creature); + } +}; + +// 43391 - Rock Borer +class npc_rock_borer : public CreatureScript +{ + public: + npc_rock_borer() : CreatureScript("npc_rock_borer") { } + + struct npc_rock_borerAI : public ScriptedAI + { + npc_rock_borerAI(Creature* creature) : ScriptedAI(creature) + { + me->SetDisableGravity(true); + me->SetReactState(REACT_PASSIVE); + events.ScheduleEvent(EVENT_EMERGED, 1200); + events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer + } + + void IsSummonedBy(Unit* summoner) override + { + me->SetInCombatState(false, summoner); + DoCast(SPELL_ROCK_BORER_EMERGE); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && me->GetReactState() != REACT_PASSIVE) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_EMERGED: + me->RemoveAurasDueToSpell(SPELL_ROCK_BORER_EMERGE); + me->SetReactState(REACT_AGGRESSIVE); + break; + case EVENT_ROCK_BORE: + DoCast(SPELL_ROCK_BORE); + events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_rock_borerAI>(creature); + } +}; + +void AddSC_boss_corborus() +{ + new boss_corborus(); + new npc_rock_borer(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp new file mode 100644 index 00000000000..0535ac64a9f --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp @@ -0,0 +1,808 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "Player.h" +#include "Vehicle.h" +#include "stonecore.h" + +enum Spells +{ + SPELL_ENERGY_SHIELD = 82858, + + SPELL_CURSE_OF_BLOOD = 79345, + SPELL_FORCE_GRIP = 79351, + SPELL_SUMMON_GRAVITY_WELL = 79340, + SPELL_EARTH_FURY_ENERGY_SHIELD = 79050, + + // Gravity Well + SPELL_GRAVITY_WELL_VISUAL = 79245, + SPELL_GRAVITY_WELL_AURA_DAMAGE = 79244, + SPELL_GRAVITY_WELL_AURA_PULL = 79333, + + SPELL_GRAVITY_WELL_DAMAGE = 79249, + SPELL_GRAVITY_WELL_PULL = 79332, + + // Fury of Earth phase + SPELL_EARTH_FURY_CASTING_VISUAL = 79002, + SPELL_SEISMIC_SHARD_SUMMON_1 = 86860, + SPELL_SEISMIC_SHARD_SUMMON_2 = 86858, + SPELL_SEISMIC_SHARD_SUMMON_3 = 86856, + SPELL_SEISMIC_SHARD_VISUAL = 79009, + SPELL_SEISMIC_SHARD_PREPARE = 86862, + SPELL_SEISMIC_SHARD_TARGETING = 80511, + SPELL_SEISMIC_SHARD_LAUNCH = 79015, + SPELL_SEISMIC_SHARD_MISSLE = 79014, + SPELL_EJECT_ALL_PASSENGERS = 68576, + + // Add wave spells + SPELL_SUMMON_WAVE_SOUTH = 79200, + SPELL_SUMMON_WAVE_WEST = 79196, + SPELL_SUMMON_ADD_SOUTH = 79193, + SPELL_SUMMON_ADD_WEST = 79199, +}; + +enum NPCs +{ + NPC_DEVOUT_FOLLOWER = 42428, + NPC_SEISMIC_SHARD = 42355, +}; + +enum Texts +{ + SAY_AGGRO = 0, + SAY_PHASE_TWO = 1, + SAY_DEATH = 2, +}; + +enum Events +{ + EVENT_NONE, + + EVENT_INTRO_MOVE, + + EVENT_CURSE_OF_BLOOD, + EVENT_FORCE_GRIP, + EVENT_SUMMON_GRAVITY_WELL, + EVENT_ENERGY_SHIELD, + EVENT_EARTH_FURY, + + EVENT_SUMMON_WAVE_SOUTH, + EVENT_SUMMON_WAVE_WEST, + + EVENT_GRAVITY_WELL_AURA_DAMAGE, + EVENT_GRAVITY_WELL_AURA_PULL, + + // Phase 2: Fury of Earth + EVENT_EARTH_FURY_FLY_UP, + EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM, + EVENT_EARTH_FURY_CHECK_SEAT0, + EVENT_EARTH_FURY_LAUNCH_SHARD, + EVENT_EARTH_FURY_FLY_DOWN, + EVENT_START_ATTACK, + + EVENT_LAUNCH, + EVENT_SEISMIC_SHARD_MOUNT +}; + +enum EventGroups +{ + EVENT_GROUP_PHASE_ONE, + EVENT_GROUP_ADDS, +}; + +enum Points +{ + POINT_NONE, + + POINT_INTRO_MOVE, + POINT_FLY_UP, + POINT_ABOVE_PLATFORM, + POINT_PLATFORM, + POINT_GROUND, +}; + +Position const GroundPos = { 1331.82f, 980.314f, 207.542f }; +Position const AbovePlatformPos = { 1336.21f, 960.813f, 215.0f }; + +// TO-DO: +// - Find out why NPCs summoned by boss are usually two times bigger than their normal size. +// - Find more sniffs and script Force Grip spell (79351) + +class boss_high_priestess_azil : public CreatureScript +{ + public: + boss_high_priestess_azil() : CreatureScript("boss_high_priestess_azil") { } + + struct boss_high_priestess_azilAI : public BossAI + { + boss_high_priestess_azilAI(Creature* creature) : BossAI(creature, DATA_HIGH_PRIESTESS_AZIL), vehicle(creature->GetVehicleKit()) + { + ASSERT(vehicle); + } + + Vehicle* vehicle; + + void Reset() override + { + _Reset(); + + me->SetCanFly(false); + me->SetDisableGravity(false); + me->SetReactState(REACT_PASSIVE); + + events.ScheduleEvent(EVENT_INTRO_MOVE, 2000); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000,10000), EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_ENERGY_SHIELD, urand(35000,36000)); + events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 0); + events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 40000); + } + + void EnterCombat(Unit* /*victim*/) override + { + _EnterCombat(); + + DoCast(SPELL_ENERGY_SHIELD); + Talk(SAY_AGGRO); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + } + + /* + void PassengerBoarded(Unit* who, int8 seatId, bool apply) override + { + if (!apply || who->GetEntry() != NPC_SEISMIC_SHARD) + return; + + Movement::MoveSplineInit init(who); + init.DisableTransportPathTransformations(); + if (seatId == 0) + init.MoveTo(12.13748f, 0.0f, 2.442475f); + else if (seatId == 1) + init.MoveTo(12.13748f, 17.5f, 11.19248f); + else + init.MoveTo(12.13748f, -17.5f, 11.19248f); + init.Launch(); + } + */ + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE && id != POINT_INTRO_MOVE) + return; + + switch (id) + { + case POINT_INTRO_MOVE: + me->RemoveAurasDueToSpell(SPELL_ENERGY_SHIELD); + me->SetReactState(REACT_AGGRESSIVE); + break; + case POINT_FLY_UP: + me->SetCanFly(true); + me->SetDisableGravity(true); + events.ScheduleEvent(EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM, 1000); + break; + case POINT_ABOVE_PLATFORM: + me->SetFacingTo(5.218534f); + DoCast(SPELL_EARTH_FURY_CASTING_VISUAL); + DoCast(SPELL_SEISMIC_SHARD_SUMMON_1); + DoCast(SPELL_SEISMIC_SHARD_SUMMON_2); + DoCast(SPELL_SEISMIC_SHARD_SUMMON_3); + events.ScheduleEvent(EVENT_EARTH_FURY_CHECK_SEAT0, 6700); + break; + case POINT_GROUND: + DoCast(SPELL_EJECT_ALL_PASSENGERS); + me->SetCanFly(false); + me->SetDisableGravity(false); + me->SetReactState(REACT_AGGRESSIVE); + // Find more sniffs to correct these timers, this was copied from Reset() void. + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000, 10000), EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_MOVE: + me->GetMotionMaster()->MoveJump(GroundPos, me->GetSpeed(MOVE_FLIGHT), 1.918408f, POINT_INTRO_MOVE); + break; + case EVENT_CURSE_OF_BLOOD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_CURSE_OF_BLOOD); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE); + break; + case EVENT_FORCE_GRIP: + DoCastVictim(SPELL_FORCE_GRIP); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE); + break; + case EVENT_SUMMON_GRAVITY_WELL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_SUMMON_GRAVITY_WELL); + events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, urand(13000, 15000), EVENT_GROUP_PHASE_ONE); + break; + case EVENT_ENERGY_SHIELD: + events.CancelEventGroup(EVENT_GROUP_PHASE_ONE); + DoCast(SPELL_EARTH_FURY_ENERGY_SHIELD); + events.ScheduleEvent(EVENT_EARTH_FURY, 0); + break; + case EVENT_EARTH_FURY: + countSeismicShard = 3; + me->SetReactState(REACT_PASSIVE); + me->SetFacingTo(5.862942f); + events.ScheduleEvent(EVENT_EARTH_FURY_FLY_UP, 1600); + break; + case EVENT_EARTH_FURY_FLY_UP: + Talk(SAY_PHASE_TWO); + me->GetMotionMaster()->MovePoint(POINT_FLY_UP, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5); + break; + case EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM: + me->GetMotionMaster()->MovePoint(POINT_ABOVE_PLATFORM, AbovePlatformPos); + break; + case EVENT_EARTH_FURY_CHECK_SEAT0: + if (!vehicle->GetPassenger(0)) + DoCast(SPELL_SEISMIC_SHARD_PREPARE); + events.ScheduleEvent(EVENT_EARTH_FURY_LAUNCH_SHARD, 1800); + break; + case EVENT_EARTH_FURY_LAUNCH_SHARD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + { + me->SetFacingToObject(target); + DoCast(target, SPELL_SEISMIC_SHARD_TARGETING); + DoCast(SPELL_SEISMIC_SHARD_LAUNCH); + countSeismicShard -= 1; + } + events.ScheduleEvent(countSeismicShard > 0 ? EVENT_EARTH_FURY_CHECK_SEAT0 : EVENT_EARTH_FURY_FLY_DOWN, 4800); + break; + case EVENT_EARTH_FURY_FLY_DOWN: + { + me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_CASTING_VISUAL); + me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_ENERGY_SHIELD); + Position pos = me->GetPosition(); + pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); + me->GetMotionMaster()->MovePoint(POINT_GROUND, pos); + break; + } + case EVENT_SUMMON_WAVE_SOUTH: + if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f)) + worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_SOUTH); + events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 12000); + break; + case EVENT_SUMMON_WAVE_WEST: + if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f)) + worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_WEST); + events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 20000); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + uint8 countSeismicShard; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_high_priestess_azilAI>(creature); + } +}; + +// 42428 - Devout Follower +class npc_devout_follower : public CreatureScript +{ +public: + npc_devout_follower() : CreatureScript("npc_devout_follower") { } + + struct npc_devout_followerAI : public ScriptedAI + { + npc_devout_followerAI(Creature* creature) : ScriptedAI(creature) { } + + void IsSummonedBy(Unit* summoner) override + { + if (summoner->GetEntry() != NPC_WORLDTRIGGER) + return; + + if (Unit* target = me->SelectNearestPlayer(200.0f)) + { + me->AddThreat(target, 0.0f); + me->SetInCombatWith(target); + target->SetInCombatWith(me); + DoStartMovement(target); + me->Attack(target, true); + } + else + me->GetMotionMaster()->MovePoint(POINT_NONE, summoner->GetPosition()); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_devout_followerAI>(creature); + } +}; + +// 42499 - Gravity Well +class npc_gravity_well : public CreatureScript +{ +public: + npc_gravity_well() : CreatureScript("npc_gravity_well") { } + + struct npc_gravity_wellAI : public ScriptedAI + { + npc_gravity_wellAI(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + DoCast(SPELL_GRAVITY_WELL_VISUAL); + events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_DAMAGE, 3200); + events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_PULL, 4500); + if (!me->GetMap()->IsHeroic()) + me->DespawnOrUnsummon(23200); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetEntry() != NPC_DEVOUT_FOLLOWER) + return; + + me->SetObjectScale(me->GetObjectScale() - 0.25f); + if (me->GetObjectScale() <= 0.0f) + me->DespawnOrUnsummon(1000); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_GRAVITY_WELL_AURA_DAMAGE: + me->RemoveAurasDueToSpell(SPELL_GRAVITY_WELL_VISUAL); + DoCast(SPELL_GRAVITY_WELL_AURA_DAMAGE); + break; + case EVENT_GRAVITY_WELL_AURA_PULL: + DoCast(SPELL_GRAVITY_WELL_AURA_PULL); + break; + default: + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_gravity_wellAI>(creature); + } +}; + +// 42355 - Seismic Shard +class npc_seismic_shard : public CreatureScript +{ +public: + npc_seismic_shard() : CreatureScript("npc_seismic_shard") { } + + struct npc_seismic_shardAI : public ScriptedAI + { + npc_seismic_shardAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + me->SetDisableGravity(true); + me->SetReactState(REACT_PASSIVE); + DoCast(SPELL_SEISMIC_SHARD_VISUAL); + + Movement::MoveSplineInit init(me); + FillPath(me->GetPosition(), init.Path()); + init.SetFly(); + init.Launch(); + + events.ScheduleEvent(EVENT_SEISMIC_SHARD_MOUNT, 2400); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SEISMIC_SHARD_MOUNT: + if (Creature* highPriestAzil = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL))) + if (Vehicle* vehicle = highPriestAzil->GetVehicleKit()) + me->EnterVehicle(highPriestAzil, vehicle->GetNextEmptySeat(0, false)->first); + break; + default: + break; + } + } + + } + + private: + void FillPath(Position const& pos, Movement::PointsArray& path) + { + G3D::Vector3 point; + + point.x = pos.GetPositionX(); + point.y = pos.GetPositionY(); + point.z = pos.GetPositionZ(); + + point.x -= 1.0f; + path.push_back(point); + + point.x += 1.0f; + path.push_back(point); + + point.z += 25.0f; + path.push_back(point); + + path.push_back(point); + } + + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_seismic_shardAI>(creature); + } +}; + +// 79200 - Summon Follower +class spell_summon_wave_south : public SpellScriptLoader +{ +public: + spell_summon_wave_south() : SpellScriptLoader("spell_summon_wave_south") { } + + class spell_summon_wave_south_SpellScript : public SpellScript + { + PrepareSpellScript(spell_summon_wave_south_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_SOUTH)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + for (uint8 i = 0; i < 3; i++) + caster->CastSpell(caster, SPELL_SUMMON_ADD_SOUTH, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_summon_wave_south_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_summon_wave_south_SpellScript(); + } +}; + +// 79196 - Summon Follower +class spell_summon_wave_west : public SpellScriptLoader +{ +public: + spell_summon_wave_west() : SpellScriptLoader("spell_summon_wave_west") { } + + class spell_summon_wave_west_SpellScript : public SpellScript + { + PrepareSpellScript(spell_summon_wave_west_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_WEST)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + for (uint8 i = 0; i < 10; i++) + caster->CastSpell(caster, SPELL_SUMMON_ADD_WEST, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_summon_wave_west_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_summon_wave_west_SpellScript(); + } +}; + +// 79251 - Gravity Well (casts damage spell on units within 10 yards) +class PlayerPetOrDevoutFollowerCheck +{ +public: + bool operator()(WorldObject* object) const + { + // Valid targets are players, pets and Devout Followers + if (Creature* creature = object->ToCreature()) + return (!creature->ToPet() && object->GetEntry() != NPC_DEVOUT_FOLLOWER); + return (!object->ToPlayer()); + } +}; + +class spell_gravity_well_damage_nearby : public SpellScriptLoader +{ +public: + spell_gravity_well_damage_nearby() : SpellScriptLoader("spell_gravity_well_damage_nearby") { } + + class spell_gravity_well_damage_nearby_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gravity_well_damage_nearby_SpellScript); + + void SetRadiusMod() + { + GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3)); + } + + void FilterTargets(std::list<WorldObject*>& unitList) + { + unitList.remove_if(PlayerPetOrDevoutFollowerCheck()); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_GRAVITY_WELL_DAMAGE, true); + } + + void Register() override + { + BeforeCast += SpellCastFn(spell_gravity_well_damage_nearby_SpellScript::SetRadiusMod); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_damage_nearby_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_nearby_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gravity_well_damage_nearby_SpellScript(); + } +}; + +// 79249 - Gravity Well (damage) +class spell_gravity_well_damage : public SpellScriptLoader +{ +public: + spell_gravity_well_damage() : SpellScriptLoader("spell_gravity_well_damage") { } + + class spell_gravity_well_damage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gravity_well_damage_SpellScript); + + void CalculateDamage(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + if (!target) + return; + + float distance = GetCaster()->GetDistance2d(target); + + if (target->GetEntry() == NPC_DEVOUT_FOLLOWER) + SetHitDamage(int32(200000 - (1000 * distance))); //need more research on this formula, damage values from sniffs: 189264, 190318, 190478, 196134, 197672, 199735 + else + SetHitDamage(int32(4000 - (200 * distance))); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_SpellScript::CalculateDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gravity_well_damage_SpellScript(); + } +}; + +// 79332 - Gravity Well (pull units within 10 yards) +class PulledRecentlyCheck +{ +public: + bool operator()(WorldObject* object) const + { + return (object->ToUnit() && object->ToUnit()->HasAura(SPELL_GRAVITY_WELL_PULL)); + } +}; + +class spell_gravity_well_pull : public SpellScriptLoader +{ +public: + spell_gravity_well_pull() : SpellScriptLoader("spell_gravity_well_pull") { } + + class spell_gravity_well_pull_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gravity_well_pull_SpellScript); + + void SetRadiusMod() + { + GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3)); + } + + void FilterTargets(std::list<WorldObject*>& unitList) + { + unitList.remove_if(PulledRecentlyCheck()); + } + + void Register() override + { + BeforeCast += SpellCastFn(spell_gravity_well_pull_SpellScript::SetRadiusMod); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_pull_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gravity_well_pull_SpellScript(); + } +}; + +// 86862 - Seismic Shard (forces target to cast 86863) +class spell_seismic_shard_prepare : public SpellScriptLoader +{ +public: + spell_seismic_shard_prepare() : SpellScriptLoader("spell_seismic_shard_prepare") { } + + class spell_seismic_shard_prepare_SpellScript : public SpellScript + { + PrepareSpellScript(spell_seismic_shard_prepare_SpellScript); + + void SetTarget(WorldObject*& target) + { + target = GetCaster()->FindNearestCreature(NPC_SEISMIC_SHARD, 50.0f); + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_prepare_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_seismic_shard_prepare_SpellScript(); + } +}; + +// 86863 - Seismic Shard (moves shard to seat 0) +class spell_seismic_shard_change_seat : public SpellScriptLoader +{ +public: + spell_seismic_shard_change_seat() : SpellScriptLoader("spell_seismic_shard_change_seat") { } + + class spell_seismic_shard_change_seat_SpellScript : public SpellScript + { + PrepareSpellScript(spell_seismic_shard_change_seat_SpellScript); + + void SetTarget(WorldObject*& target) + { + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + target = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL)); + } + + void ChangeSeat(SpellEffIndex /*effIndex*/) + { + GetCaster()->ExitVehicle(); + if (GetHitUnit()->IsVehicle()) + GetCaster()->EnterVehicle(GetHitUnit(), 0); + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_change_seat_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_change_seat_SpellScript::ChangeSeat, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_seismic_shard_change_seat_SpellScript(); + } +}; + +// 79015 - Seismic Shard (launches shard) +class spell_seismic_shard : public SpellScriptLoader +{ +public: + spell_seismic_shard() : SpellScriptLoader("spell_seismic_shard") { } + + class spell_seismic_shard_SpellScript : public SpellScript + { + PrepareSpellScript(spell_seismic_shard_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Creature* target = GetHitUnit()->ToCreature(); + if (!target) + return; + + target->ExitVehicle(); + DynamicObject* dynamicObject = GetCaster()->GetDynObject(SPELL_SEISMIC_SHARD_TARGETING); + target->CastSpell(dynamicObject->GetPositionX(), dynamicObject->GetPositionY(), dynamicObject->GetPositionZ(), SPELL_SEISMIC_SHARD_MISSLE, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_seismic_shard_SpellScript(); + } +}; + +void AddSC_boss_high_priestess_azil() +{ + new boss_high_priestess_azil(); + new npc_devout_follower(); + new npc_gravity_well(); + new npc_seismic_shard(); + new spell_summon_wave_south(); + new spell_summon_wave_west(); + new spell_gravity_well_damage_nearby(); + new spell_gravity_well_damage(); + new spell_gravity_well_pull(); + new spell_seismic_shard_prepare(); + new spell_seismic_shard_change_seat(); + new spell_seismic_shard(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp new file mode 100644 index 00000000000..92c9bba4bc1 --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "Vehicle.h" +#include "stonecore.h" + +enum Spells +{ + SPELL_ELEMENTIUM_BULWARK = 78939, + SPELL_GROUND_SLAM = 78903, + SPELL_ELEMENTIUM_SPIKE_SHIELD = 78835, + SPELL_SHATTER = 78807, + SPELL_ENRAGE = 80467, + + // Rupture Controller and Rupture + SPELL_RUPTURE = 92393, +// SPELL_RUPTURE_SUMMON_CENTER? = 95669, // summons rupture 8 yards front +// SPELL_RUPTURE_SUMMON_LEFT? = 95348, // summons rupture 3 yards left? +// SPELL_RUPTURE_SUMMON_RIGHT? = 92383, // summons rupture 3 yards right? + SPELL_RUPTURE_DAMAGE = 92381, +}; + +enum NPCs +{ + NPC_BOUNCER_SPIKE = 42189, + NPC_RUPTURE_CONTROLLER = 49597, + NPC_RUPTURE = 49576, +}; + +enum Texts +{ + SAY_AGGRO = 0, + SAY_ELEMENTIUM_BULWARK = 1, + SAY_ELEMENTIUM_SPIKE_SHIELD = 2, + SAY_ENRAGE = 3, + SAY_DEATH = 4, +}; + +enum Events +{ + EVENT_NONE, + + EVENT_ELEMENTIUM_BULWARK, + EVENT_GROUND_SLAM, + EVENT_ELEMENTIUM_SPIKE_SHIELD, + EVENT_SHATTER, + EVENT_ENRAGE, + + EVENT_START_ATTACK, +}; + +// TO-DO: +// - Find heroic sniffs and spawn Ruptures using spells commented above. +// - Make Bouncer Spikes enter ozruk without jump animation. + +class boss_ozruk : public CreatureScript +{ + public: + boss_ozruk() : CreatureScript("boss_ozruk") { } + + struct boss_ozrukAI : public BossAI + { + boss_ozrukAI(Creature* creature) : BossAI(creature, DATA_OZRUK) { } + + void Reset() override + { + _Reset(); + + me->SetReactState(REACT_AGGRESSIVE); + + events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, 5000); + events.ScheduleEvent(EVENT_GROUND_SLAM, 10000); + events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, 13000); + + RemoveBouncerSpikes(); + } + + void EnterCombat(Unit* /*victim*/) override + { + _EnterCombat(); + + Talk(SAY_AGGRO); + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_RUPTURE_CONTROLLER) + return; + + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_RUPTURE, true); + summon->DespawnOrUnsummon(10000); + } + + void DamageTaken(Unit* /*attacker*/, uint32 &damage) override + { + if (!me->HealthBelowPctDamaged(25, damage) || me->HasAura(SPELL_ENRAGE)) + return; + + DoCast(me, SPELL_ENRAGE); + me->Say(SAY_ENRAGE); + } + + void JustDied(Unit* killer) override + { + me->Say(SAY_DEATH, killer); // receiver is the killer, sniff source! + + RemoveBouncerSpikes(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_ELEMENTIUM_SPIKE_SHIELD)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ELEMENTIUM_BULWARK: + DoCast(me, SPELL_ELEMENTIUM_BULWARK); + Talk(SAY_ELEMENTIUM_BULWARK); + break; + case EVENT_GROUND_SLAM: + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + DoCast(me, SPELL_GROUND_SLAM); + events.ScheduleEvent(EVENT_START_ATTACK, 4600); + break; + case EVENT_ELEMENTIUM_SPIKE_SHIELD: + DoCast(me, SPELL_ELEMENTIUM_SPIKE_SHIELD); + Talk(SAY_ELEMENTIUM_SPIKE_SHIELD); + events.ScheduleEvent(EVENT_SHATTER, 10000); + break; + case EVENT_SHATTER: + RemoveBouncerSpikes(); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + DoCast(me, SPELL_SHATTER); + events.ScheduleEvent(EVENT_START_ATTACK, 4600); + // Spells are cast in same order everytime after Shatter, so we schedule them here + events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, urand(3000,4000)); + events.ScheduleEvent(EVENT_GROUND_SLAM, urand(7000,9000)); + events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, urand(10000,12000)); + break; + case EVENT_START_ATTACK: + me->SetReactState(REACT_AGGRESSIVE); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + void RemoveBouncerSpikes() + { + Vehicle* vehicle = me->GetVehicleKit(); + if (!vehicle) + return; + + for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++) + if (Unit* passenger = vehicle->GetPassenger(i)) + if (Creature* creature = passenger->ToCreature()) + creature->RemoveFromWorld(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_ozrukAI>(creature); + } +}; + +// 92393 - Rupture +class spell_rupture : public SpellScriptLoader +{ +public: + spell_rupture() : SpellScriptLoader("spell_rupture") { } + + class spell_rupture_AuraScript : public AuraScript + { + PrepareAuraScript(spell_rupture_AuraScript); + + void HandleEffectPeriodic(AuraEffect const* aurEff) + { + Unit* caster = GetCaster(); + + float dist = aurEff->GetTickNumber() * 8.0f; + + // probably hack, should use spells (see Spells enum above) + Position pos = caster->GetNearPosition(dist, 0.0f); + SummonRupture(caster, pos); + + pos = caster->GetNearPosition(dist, 0.2f); + SummonRupture(caster, pos); + + pos = caster->GetNearPosition(dist, -0.2f); + SummonRupture(caster, pos); + } + + void SummonRupture(Unit* caster, Position pos) + { + Creature* rupture = caster->SummonCreature(NPC_RUPTURE, pos, TEMPSUMMON_TIMED_DESPAWN, 2500); + if (!rupture) + return; + + rupture->SetReactState(REACT_PASSIVE); + rupture->CastSpell(rupture, SPELL_RUPTURE_DAMAGE, true); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_rupture_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_rupture_AuraScript(); + } +}; + +// 78835 - Elementium Spike Shield +class spell_elementium_spike_shield : public SpellScriptLoader +{ +public: + spell_elementium_spike_shield() : SpellScriptLoader("spell_elementium_spike_shield") { } + + class spell_elementium_spike_shield_SpellScript : public SpellScript + { + PrepareSpellScript(spell_elementium_spike_shield_SpellScript); + + void HandleBouncerSpikes() + { + Unit* caster = GetCaster(); + Vehicle* vehicle = caster->GetVehicleKit(); + if (!vehicle) + return; + + for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++) + if (Creature* summon = caster->SummonCreature(NPC_BOUNCER_SPIKE, caster->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 10000)) + summon->EnterVehicle(caster, i); + } + + void Register() override + { + OnCast += SpellCastFn(spell_elementium_spike_shield_SpellScript::HandleBouncerSpikes); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_elementium_spike_shield_SpellScript(); + } +}; + +void AddSC_boss_ozruk() +{ + new boss_ozruk(); + new spell_rupture(); + new spell_elementium_spike_shield(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp new file mode 100644 index 00000000000..6827312deef --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp @@ -0,0 +1,599 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "stonecore.h" + +enum Spells +{ + SPELL_FACE_RANDOM_PLAYER = 82530, + + // Stalactite Trigger - Trash, On Ground + SPELL_STALACTITE_SUMMON_TRIGGER = 81028, + + // Slabhide + SPELL_LAVA_FISSURE = 80803, + SPELL_SAND_BLAST = 80807, + SPELL_STALACTITE_SUMMON = 80656, +// SPELL_COOLDOWN_5S = 95323, Cooldown: Creature Special 1 (5s)? + SPELL_CRYSTAL_STORM = 92305, + SPELL_CRYSTAL_STORM_TRIGGER = 92265, + + // Lava Fissure + SPELL_LAVA_FISSURE_CRACK = 80798, + SPELL_LAVA_FISSURE_ERUPTION = 80800, + + // Stalactite Trigger - Boss + SPELL_STALACTITE_SHADE = 80654, + SPELL_STALACTITE_MISSLE = 80643, + SPELL_STALACTITE_CREATE = 80647, +}; + +enum Entries +{ + NPC_LAVA_FISSURE = 43242, + NPC_STALACTITE_TRIGGER_GROUND = 43357, + NPC_STALACTITE_TRIGGER = 43159, + GO_STALACTITE = 204337, +}; + +enum Actions +{ + ACTION_STALACTITE_MISSLE, +}; + +enum Events +{ + EVENT_NONE, + + // Intro events + EVENT_ROAR_EMOTE, + + // Slabhide combat + EVENT_HANDLE_ROCK_WALLS, + EVENT_LAVA_FISSURE, + EVENT_SAND_BLAST, + EVENT_AIR_PHASE, + EVENT_TAKEOFF, + EVENT_STALACTITE, + EVENT_LAND, + EVENT_ATTACK, + + // Lava Fissure + EVENT_LAVA_FISSURE_ERUPTION, + + // Stalactite Trigger - Boss + EVENT_STALACTITE_MISSLE, +}; + +enum MovementPoints +{ + POINT_NONE, + + POINT_SLABHIDE_INTRO, + POINT_SLABHIDE_INTRO_LAND, + + POINT_SLABHIDE_MIDDLE, + POINT_SLABHIDE_IN_AIR, + POINT_SLABHIDE_LAND, +}; + +Position const SlabhideIntroPos = { 1292.27f, 1226.16f, 265.573f }; +Position const SlabhideIntroLandPos = { 1292.352f, 1226.478f, 247.6368f, 3.630285f }; + +Position const SlabhideMiddlePos = { 1280.73f, 1212.31f, 247.3837f }; +Position const SlabhideInAirPos = { 1280.73f, 1212.31f, 257.3837f }; +Position const SlabhideLandPos = { 1282.7f, 1229.77f, 247.155f, 3.82227f }; + +class boss_slabhide : public CreatureScript +{ + public: + boss_slabhide() : CreatureScript("boss_slabhide") { } + + struct boss_slabhideAI : public BossAI + { + boss_slabhideAI(Creature* creature) : BossAI(creature, DATA_SLABHIDE) + { + me->setActive(true); + me->SetCanFly(true); + me->SetDisableGravity(true); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetReactState(REACT_PASSIVE); + instance->SetData(DATA_SLABHIDE_INTRO, NOT_STARTED); + } + + void Reset() + { + if (instance->GetData(DATA_SLABHIDE_INTRO) == NOT_STARTED) + return; + + _Reset(); + DespawnAll(); + + me->SetCanFly(false); + me->SetDisableGravity(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetReactState(REACT_AGGRESSIVE); + } + + void EnterCombat(Unit* /*victim*/) override + { + _EnterCombat(); + + events.ScheduleEvent(EVENT_HANDLE_ROCK_WALLS, 4000); + events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000)); + events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000)); + events.ScheduleEvent(EVENT_AIR_PHASE, 10000); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + + // Despawn related npcs and gameobjects + DespawnAll(); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_SLABHIDE_INTRO: + { + if (instance->GetData(DATA_SLABHIDE_INTRO) != NOT_STARTED) + return; + + instance->SetData(DATA_SLABHIDE_INTRO, IN_PROGRESS); + + // Execute Slabhide intro event + me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_INTRO, SlabhideIntroPos); + break; + } + default: + break; + } + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) + return; + + switch (id) + { + case POINT_SLABHIDE_INTRO: + me->SetFacingTo(SlabhideIntroLandPos.GetOrientation()); + me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_INTRO_LAND, SlabhideIntroLandPos); + break; + case POINT_SLABHIDE_INTRO_LAND: + me->SetCanFly(false); + me->SetDisableGravity(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetHover(false); + me->SetHomePosition(SlabhideIntroLandPos); + me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + instance->SetData(DATA_SLABHIDE_INTRO, DONE); + break; + case POINT_SLABHIDE_MIDDLE: + events.ScheduleEvent(EVENT_TAKEOFF, 100); + break; + case POINT_SLABHIDE_IN_AIR: + events.ScheduleEvent(EVENT_STALACTITE, 400); + break; + case POINT_SLABHIDE_LAND: + //DoCast(SPELL_COOLDOWN_5S); // unknown purpose + events.ScheduleEvent(EVENT_ATTACK, 1200); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_HANDLE_ROCK_WALLS: // Close rock walls + instance->SetData(DATA_SLABHIDE_ROCK_WALL, false); + break; + case EVENT_LAVA_FISSURE: + DoCast(SPELL_LAVA_FISSURE); + events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000)); + break; + case EVENT_SAND_BLAST: + DoCast(SPELL_SAND_BLAST); + events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 11000)); + break; + case EVENT_AIR_PHASE: + events.Reset(); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_MIDDLE, SlabhideMiddlePos); + events.ScheduleEvent(EVENT_AIR_PHASE, 60000); + break; + case EVENT_TAKEOFF: + me->GetMotionMaster()->MoveTakeoff(POINT_SLABHIDE_IN_AIR, SlabhideInAirPos); + break; + case EVENT_STALACTITE: + me->SetCanFly(true); + me->SetDisableGravity(true); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetHover(true); + + DoCast(SPELL_STALACTITE_SUMMON); + + events.ScheduleEvent(EVENT_LAND, 8000); + break; + case EVENT_LAND: + { + Position pos = me->GetPosition(); + pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); + me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_LAND, pos); + break; + } + case EVENT_ATTACK: + me->SetCanFly(false); + me->SetDisableGravity(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetHover(false); + + events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000)); + events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000)); + DoCast(SPELL_CRYSTAL_STORM); + me->SetReactState(REACT_AGGRESSIVE); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + void DespawnAll() + { + // Despawn stalactite triggers npcs + std::list<Creature*> listStalactiteTrigger; + me->GetCreatureListWithEntryInGrid(listStalactiteTrigger, NPC_STALACTITE_TRIGGER, 200.0f); + if (!listStalactiteTrigger.empty()) + for (std::list<Creature*>::const_iterator itr = listStalactiteTrigger.begin(); itr != listStalactiteTrigger.end(); ++itr) + (*itr)->DespawnOrUnsummon(); + + // Despawn stalactite objects + std::list<GameObject*> listStalactite; + me->GetGameObjectListWithEntryInGrid(listStalactite, GO_STALACTITE, 200.0f); + if (!listStalactite.empty()) + for (std::list<GameObject*>::const_iterator itr = listStalactite.begin(); itr != listStalactite.end(); ++itr) + (*itr)->Delete(); + } + + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_slabhideAI>(creature); + } +}; + +// 43242 - Lava Fissure +class npc_lava_fissure : public CreatureScript +{ +public: + npc_lava_fissure() : CreatureScript("npc_lava_fissure") { } + + struct npc_lava_fissureAI : public ScriptedAI + { + npc_lava_fissureAI(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + me->CastSpell(me, SPELL_LAVA_FISSURE_CRACK, true); + events.ScheduleEvent(EVENT_LAVA_FISSURE_ERUPTION, 6000); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_LAVA_FISSURE_ERUPTION: + me->RemoveAurasDueToSpell(SPELL_LAVA_FISSURE_CRACK); + me->CastSpell(me, SPELL_LAVA_FISSURE_ERUPTION, true); + me->DespawnOrUnsummon(14000); + break; + default: + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_lava_fissureAI>(creature); + } +}; + +// 43159 - Stalactite Trigger - Boss +class npc_stalactite_trigger : public CreatureScript +{ +public: + npc_stalactite_trigger() : CreatureScript("npc_stalactite_trigger") { } + + struct npc_stalactite_triggerAI : public ScriptedAI + { + npc_stalactite_triggerAI(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + me->SetDisableGravity(true); + me->CastSpell(me, SPELL_STALACTITE_SHADE, true); + events.ScheduleEvent(EVENT_STALACTITE_MISSLE, 5600); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STALACTITE_MISSLE: + DoCast(SPELL_STALACTITE_MISSLE); + me->DespawnOrUnsummon(11000); + break; + default: + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_stalactite_triggerAI>(creature); + } +}; + +// 81035 - Stalactite (check if player is near to summon stalactite) +class NotPlayerCheck +{ + public: + bool operator()(WorldObject* object) const + { + return (object->GetTypeId() != TYPEID_PLAYER); + } +}; + +class spell_s81035_stalactite : public SpellScriptLoader +{ +public: + spell_s81035_stalactite() : SpellScriptLoader("spell_s81035_stalactite") { } + + class spell_s81035_stalactite_SpellScript : public SpellScript + { + PrepareSpellScript(spell_s81035_stalactite_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(NotPlayerCheck()); + } + + void SummonStalactiteTrigger() + { + Unit* caster = GetCaster(); + caster->CastSpell(caster, SPELL_STALACTITE_SUMMON_TRIGGER, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s81035_stalactite_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnHit += SpellHitFn(spell_s81035_stalactite_SpellScript::SummonStalactiteTrigger); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_s81035_stalactite_SpellScript(); + } +}; + +// 81028 - Stalactite (summons "Stalactite Trigger - Boss", 20 yard radius) +// 80650 - Stalactite (summons "Stalactite Trigger - Boss", 40 yard radius) +class spell_s81028_s80650_stalactite : public SpellScriptLoader +{ +public: + spell_s81028_s80650_stalactite() : SpellScriptLoader("spell_s81028_s80650_stalactite") { } + + class spell_s81028_s80650_stalactite_SpellScript : public SpellScript + { + PrepareSpellScript(spell_s81028_s80650_stalactite_SpellScript); + + void ModDestHeight(SpellDestination& dest) + { + // All stalactite triggers should have Z position 301.3837f, but no way to relocate (not relocateoffset!) height only. + Position offset = { 0.0f, 0.0f, 50.0f, 0.0f }; + dest.RelocateOffset(offset); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_s81028_s80650_stalactite_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_RANDOM); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_s81028_s80650_stalactite_SpellScript(); + } +}; + +// 80654 - Stalactite (creates visual shade on ground) +// 80643/92653 - Stalactite (launches missle to the ground) +// 80647/92309 - Stalactite (creates stalactite object) +class spell_stalactite_mod_dest_height : public SpellScriptLoader +{ +public: + spell_stalactite_mod_dest_height() : SpellScriptLoader("spell_stalactite_mod_dest_height") { } + + class spell_stalactite_mod_dest_height_SpellScript : public SpellScript + { + PrepareSpellScript(spell_stalactite_mod_dest_height_SpellScript); + + void ModDestHeight(SpellDestination& dest) + { + Unit* caster = GetCaster(); + Position pos = caster->GetPosition(); + pos.m_positionZ = caster->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 100.0f); + dest.Relocate(pos); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_stalactite_mod_dest_height_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_stalactite_mod_dest_height_SpellScript(); + } +}; + +// 92306 - Crystal storm (heroic mode check) +class spell_s92306_crystal_storm : public SpellScriptLoader +{ +public: + spell_s92306_crystal_storm() : SpellScriptLoader("spell_s92306_crystal_storm") { } + + class spell_s92306_crystal_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_s92306_crystal_storm_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_CRYSTAL_STORM_TRIGGER)) + return false; + return true; + } + + void HandleDummyEffect(SpellEffIndex /*eff*/) + { + Unit* caster = GetCaster(); + if (caster->GetMap()->IsHeroic()) + caster->CastSpell(caster, SPELL_CRYSTAL_STORM_TRIGGER, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_s92306_crystal_storm_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_s92306_crystal_storm_SpellScript(); + } +}; + +// 92300 - Crystal Storm (damage) +class BehindObjectCheck +{ + public: + BehindObjectCheck(Unit* caster, std::list<GameObject*> objectList) : caster(caster), objectList(objectList) { } + + bool operator()(WorldObject* unit) + { + for (std::list<GameObject*>::const_iterator itr = objectList.begin(); itr != objectList.end(); ++itr) + if (!(*itr)->IsInvisibleDueToDespawn() && (*itr)->IsInBetween(caster, unit, 1.5f)) + return true; + return false; + } + + private: + Unit* caster; + std::list<GameObject*> objectList; +}; + +class spell_s92300_crystal_storm : public SpellScriptLoader +{ +public: + spell_s92300_crystal_storm() : SpellScriptLoader("spell_s92300_crystal_storm") { } + + class spell_s92300_crystal_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_s92300_crystal_storm_SpellScript); + + void FilterTargets(std::list<WorldObject*>& unitList) + { + Unit* caster = GetCaster(); + + std::list<GameObject*> goList; + caster->GetGameObjectListWithEntryInGrid(goList, GO_STALACTITE, 40.0f); + if (goList.empty()) + return; + + unitList.remove_if(BehindObjectCheck(caster, goList)); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s92300_crystal_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_s92300_crystal_storm_SpellScript(); + } +}; + +void AddSC_boss_slabhide() +{ + new boss_slabhide(); + new npc_lava_fissure(); + new npc_stalactite_trigger(); + new spell_s81035_stalactite(); + new spell_s81028_s80650_stalactite(); + new spell_stalactite_mod_dest_height(); + new spell_s92306_crystal_storm(); + new spell_s92300_crystal_storm(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp b/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp new file mode 100644 index 00000000000..ca5e40ab117 --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp @@ -0,0 +1,262 @@ +/* +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "ScriptMgr.h" +#include "Player.h" +#include "CreatureGroups.h" +#include "InstanceScript.h" +#include "stonecore.h" + +#define MAX_ENCOUNTER 4 + +/* Stonecore encounters: +0 - Corborus +1 - Slabhide +2 - Ozruk +3 - High Priestess Azil +*/ + +// TO-DO: +// - Find out spell IDs for both Stonecore Teleporters (spellclick). + +class instance_stonecore : public InstanceMapScript +{ + public: + instance_stonecore() : InstanceMapScript(SCScriptName, 725) { } + + struct instance_stonecore_InstanceScript : public InstanceScript + { + instance_stonecore_InstanceScript(Map* map) : InstanceScript(map) + { + SetHeaders(DataHeader); + SetBossNumber(MAX_ENCOUNTER); + } + + void OnGameObjectCreate(GameObject* go) override + { + switch (go->GetEntry()) + { + case GAMEOBJECT_CORBORUS_ROCKDOOR: + corborusRockDoorGUID = go->GetGUID(); + go->SetGoState(GetBossState(DATA_CORBORUS) != DONE ? GO_STATE_READY : GO_STATE_ACTIVE); + break; + case GAMEOBJECT_SLABHIDE_ROCK_WALL: + slabhideRockWallGUIDs.push_back(go->GetGUID()); + break; + default: + break; + } + } + + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) + { + case NPC_MILLHOUSE_MANASTORM: + millhouseGUID = creature->GetGUID(); + break; + case NPC_CORBORUS: + corobrusGUID = creature->GetGUID(); + break; + case NPC_SLABHIDE: + slabhideGUID = creature->GetGUID(); + break; + case NPC_HIGH_PRIESTESS_AZIL: + highPriestessAzilGUID = creature->GetGUID(); + break; + case NPC_STONECORE_TELEPORTER: + case NPC_STONECORE_TELEPORTER_2: + if (GetBossState(DATA_SLABHIDE) != DONE) + stonecoreTeleporterGUID[creature->GetEntry() - NPC_STONECORE_TELEPORTER] = creature->GetGUID(); + else // If Slabhide is already dead, no need to store teleporter guids + { + creature->CastSpell(creature, SPELL_TELEPORTER_ACTIVE_VISUAL, true); + creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + } + break; + default: + break; + } + + // Check if creature is part of Millhouse event + creature->SearchFormation(); + if (CreatureGroup* group = creature->GetFormation()) // TO-DO: Fix formations + { + switch (group->GetId()) + { + case CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH: + millhouseTrashGUIDs.push_back(creature->GetGUID()); + break; + case CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP: + millhouseLastGroupGUIDs.push_back(creature->GetGUID()); + creature->SetReactState(REACT_PASSIVE); + creature->SetMeleeAnimKitId(ANIM_READY2H); + break; + } + } + } + + bool SetBossState(uint32 type, EncounterState state) override + { + switch (type) + { + case DATA_SLABHIDE: + // Open rock walls (Slabhide AI handles closing because it must be delayed) + if (state != IN_PROGRESS) + SetData(DATA_SLABHIDE_ROCK_WALL, true); + + // Activate teleporters + if (state == DONE) + { + for (int8 i = 0; i < MAX_STONECORE_TELEPORTERS; i++) + { + if (Creature* teleporter = instance->GetCreature(stonecoreTeleporterGUID[i])) + { + teleporter->CastSpell(teleporter, SPELL_TELEPORTER_ACTIVE_VISUAL, true); + teleporter->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + } + } + } + + break; + default: + break; + } + + return InstanceScript::SetBossState(type, state); + } + + uint32 GetData(uint32 type) const override + { + switch (type) + { + case DATA_SLABHIDE_INTRO: + return slabhideIntro; + default: + break; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) override + { + switch (type) + { + case DATA_MILLHOUSE_EVENT_FACE: + MillhouseEvent_Face(); + break; + case DATA_MILLHOUSE_EVENT_KNOCKBACK: + MillhouseEvent_Knockback(); + break; + case DATA_MILLHOUSE_EVENT_DESPAWN: + MillhouseEvent_Despawn(); + break; + case DATA_SLABHIDE_INTRO: + slabhideIntro = EncounterState(data); + break; + case DATA_SLABHIDE_ROCK_WALL: // Handles rock walls + for (std::vector<ObjectGuid>::iterator itr = slabhideRockWallGUIDs.begin(); itr != slabhideRockWallGUIDs.end(); ++itr) + HandleGameObject((*itr), data ? true : false); + break; + default: + break; + } + } + + ObjectGuid GetGuidData(uint32 type) const override + { + switch (type) + { + case DATA_MILLHOUSE_MANASTORM: + return millhouseGUID; + case GAMEOBJECT_CORBORUS_ROCKDOOR: + return corborusRockDoorGUID; + case DATA_CORBORUS: + return corobrusGUID; + case DATA_SLABHIDE: + return slabhideGUID; + case DATA_HIGH_PRIESTESS_AZIL: + return highPriestessAzilGUID; + case NPC_STONECORE_TELEPORTER: + case NPC_STONECORE_TELEPORTER_2: + return stonecoreTeleporterGUID[type - NPC_STONECORE_TELEPORTER]; + default: + break; + } + + return ObjectGuid::Empty; + } + + private: + // Face Millhouse and other nearby mobs to Corborus + void MillhouseEvent_Face() + { + if (Creature* Millhouse = instance->GetCreature(millhouseGUID)) + Millhouse->SetFacingTo(1.570796f); + for (GuidVector::const_iterator i = millhouseLastGroupGUIDs.begin(); i != millhouseLastGroupGUIDs.end(); ++i) + if (Creature* creature = instance->GetCreature(*i)) + creature->SetFacingTo(1.570796f); + } + + // Knock back Millhouse and other mobs + void MillhouseEvent_Knockback() + { + if (Creature* Millhouse = instance->GetCreature(millhouseGUID)) + Millhouse->CastSpell(Millhouse, SPELL_RING_WYRM_KNOCKBACK, true); + for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr) + if (Creature* creature = instance->GetCreature(*itr)) + creature->CastSpell(creature, SPELL_RING_WYRM_KNOCKBACK, true); + } + + // Despawn all mobs + void MillhouseEvent_Despawn() + { + if (Creature* Millhouse = instance->GetCreature(millhouseGUID)) + Millhouse->DespawnOrUnsummon(3000); + for (GuidVector::const_iterator itr = millhouseTrashGUIDs.begin(); itr != millhouseTrashGUIDs.end(); ++itr) + if (Creature* creature = instance->GetCreature(*itr)) + creature->DespawnOrUnsummon(3000); + for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr) + if (Creature* creature = instance->GetCreature(*itr)) + creature->DespawnOrUnsummon(3000); + } + + ObjectGuid millhouseGUID; + GuidVector millhouseTrashGUIDs; + GuidVector millhouseLastGroupGUIDs; + ObjectGuid corborusRockDoorGUID; + ObjectGuid corobrusGUID; + ObjectGuid slabhideGUID; + ObjectGuid highPriestessAzilGUID; + ObjectGuid stonecoreTeleporterGUID[2]; + GuidVector slabhideRockWallGUIDs; + + EncounterState slabhideIntro; + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const override + { + return new instance_stonecore_InstanceScript(map); + } +}; + +void AddSC_instance_stonecore() +{ + new instance_stonecore(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp b/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp new file mode 100644 index 00000000000..4ed84732eff --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ObjectGuid.h" +#include "ObjectMgr.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "Player.h" +#include "stonecore.h" + +enum Texts +{ + // Millhouse Manastorm + SAY_MILLHOUSE_EVENT_1 = 0, + SAY_MILLHOUSE_EVENT_2 = 1, +}; + +enum NPCs +{ + NPC_GENERIC_TRIGGER_LAB = 40350, +}; + +enum Spells +{ + // Millhouse Manastorm + SPELL_SHADOW_BOLT = 81439, + SPELL_FROSTBOLT_VOLLEY = 81440, + SPELL_SHADOWFURY = 81441, + SPELL_FEAR = 81442, +// SPELL_MILLHOUSE_SAFE_CHECK = 81213, // unknown purpose + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_BLUR = 81216, + SPELL_ANCHOR_HERE = 45313, + SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND = 81220, + SPELL_IMPENDING_DOOM = 86838, + SPELL_IMPENDING_DOOM_CHANNEL = 86830, + +// SPELL_PORTAL_VISUAL = 79754, +}; + +enum Events +{ + EVENT_NONE, + + // Millhouse Manastorm + EVENT_FROSTBOLT_VOLLEY, + EVENT_SHADOWFURY, + EVENT_FEAR, + + EVENT_READY_FOR_COMBAT, + EVENT_CAST_IMPENDING_DOOM, + EVENT_INTERRUPT_IMPENDING_DOOM, +}; + +enum Phase +{ + PHASE_NONE, + + PHASE_MILLHOUSE_GROUP_1, + PHASE_MILLHOUSE_GROUP_2, + PHASE_MILLHOUSE_GROUP_3, + PHASE_MILLHOUSE_GROUP_4, + + PHASE_MASK_MILLHOUSE_GROUP_1 = (1 << (PHASE_MILLHOUSE_GROUP_1 - 1)), + PHASE_MASK_MILLHOUSE_GROUP_2 = (1 << (PHASE_MILLHOUSE_GROUP_2 - 1)), + PHASE_MASK_MILLHOUSE_GROUP_3 = (1 << (PHASE_MILLHOUSE_GROUP_3 - 1)), + PHASE_MASK_MILLHOUSE_GROUP_4 = (1 << (PHASE_MILLHOUSE_GROUP_4 - 1)), +}; + +enum MovementPoints +{ + POINT_NONE, + + POINT_MILLHOUSE_GROUP_2, + POINT_MILLHOUSE_GROUP_3, + POINT_MILLHOUSE_GROUP_4, +}; + +// Millhouse trash groups +Position const MillhousePointGroup2 = { 977.3045f, 895.2347f, 306.3298f }; +Position const MillhousePointGroup3 = { 1049.823f, 871.4349f, 295.006f }; +Position const MillhousePointGroup4 = { 1149.04f, 884.431f, 284.9406f }; + +// 43391 - Millhouse Manastorm +class npc_sc_millhouse_manastorm : public CreatureScript +{ + public: + npc_sc_millhouse_manastorm() : CreatureScript("npc_sc_millhouse_manastorm") { } + + struct npc_sc_millhouse_manastormAI : public ScriptedAI + { + npc_sc_millhouse_manastormAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + events.SetPhase(PHASE_MILLHOUSE_GROUP_1); + } + + void ScheduleEvents() + { + events.ScheduleEvent(EVENT_SHADOWFURY, 3000); + events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 5000); + events.ScheduleEvent(EVENT_FEAR, 8000); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + + if (!HealthBelowPct(50) || me->HasAura(SPELL_BLUR)) + return; + + switch (events.GetPhaseMask()) + { + case PHASE_MASK_MILLHOUSE_GROUP_1: + events.Reset(); + events.SetPhase(PHASE_MILLHOUSE_GROUP_2); + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + DoCast(me, SPELL_BLUR); + Talk(SAY_MILLHOUSE_EVENT_1); + me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_2, MillhousePointGroup2); + break; + case PHASE_MASK_MILLHOUSE_GROUP_2: + events.Reset(); + events.SetPhase(PHASE_MILLHOUSE_GROUP_3); + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + DoCast(me, SPELL_BLUR); + Talk(SAY_MILLHOUSE_EVENT_1); + me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_3, MillhousePointGroup3); + break; + case PHASE_MASK_MILLHOUSE_GROUP_3: + events.Reset(); + events.SetPhase(PHASE_MILLHOUSE_GROUP_4); + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + DoCast(me, SPELL_BLUR); + me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_4, MillhousePointGroup4); + break; + default: + break; + } + + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE) + return; + + if (pointId < POINT_MILLHOUSE_GROUP_2 || pointId > POINT_MILLHOUSE_GROUP_4) + return; + + me->RemoveAllAuras(); + me->CombatStop(true); + me->DeleteThreatList(); + + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + me->SetReactState(REACT_AGGRESSIVE); + + switch (pointId) + { + case POINT_MILLHOUSE_GROUP_2: + if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f)) + me->SetFacingToObject(worldtrigger); // o: 5.497359f (sniff data) + me->CastSpell(me, SPELL_ANCHOR_HERE, true); + me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me); + events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000); + break; + case POINT_MILLHOUSE_GROUP_3: + me->SetFacingTo(5.931499f); + me->CastSpell(me, SPELL_ANCHOR_HERE, true); + me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me); + events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000); + break; + case POINT_MILLHOUSE_GROUP_4: + me->SetFacingTo(3.455752f); + me->CastSpell(me, SPELL_ANCHOR_HERE, true); + Talk(SAY_MILLHOUSE_EVENT_2); + events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 1000); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + // Only update events if Millhouse is aggressive + if (me->GetReactState() != REACT_AGGRESSIVE) + return; + + events.Update(diff); + + // Impending Doom is exception because it needs to be interrupted. + if (me->HasUnitState(UNIT_STATE_CASTING) && !me->GetCurrentSpell(SPELL_IMPENDING_DOOM)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FROSTBOLT_VOLLEY: + DoCast(SPELL_FROSTBOLT_VOLLEY); + events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 7000); + break; + case EVENT_SHADOWFURY: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_SHADOWFURY); + events.ScheduleEvent(EVENT_SHADOWFURY, 7000); + break; + case EVENT_FEAR: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_FEAR); + events.ScheduleEvent(EVENT_FEAR, 18000); + break; + case EVENT_READY_FOR_COMBAT: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + me->SetReactState(REACT_AGGRESSIVE); + ScheduleEvents(); + break; + case EVENT_CAST_IMPENDING_DOOM: + DoCast(SPELL_IMPENDING_DOOM); + DoCast(SPELL_IMPENDING_DOOM_CHANNEL); + events.ScheduleEvent(EVENT_INTERRUPT_IMPENDING_DOOM, urand(15000,20000)); + break; + case EVENT_INTERRUPT_IMPENDING_DOOM: + me->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + me->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN); + events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 3000); + break; + default: + break; + } + } + + DoSpellAttackIfReady(SPELL_SHADOW_BOLT); + } + + private: + InstanceScript* _instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_sc_millhouse_manastormAI>(creature); + } +}; + +// 81459 - Force of Earth +class spell_force_of_earth : public SpellScriptLoader +{ + public: + spell_force_of_earth() : SpellScriptLoader("spell_force_of_earth") { } + + class spell_force_of_earth_SpellScript : public SpellScript + { + PrepareSpellScript(spell_force_of_earth_SpellScript); + + void DummyEffect(SpellEffIndex /*effIndex*/) + { + GetCaster()->SetDisplayId(26693); // can be moved to SAI part, need sniffs to see what this dummy does (note: npc 43552) + } + + void Register() + { + OnEffectLaunch += SpellEffectFn(spell_force_of_earth_SpellScript::DummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_force_of_earth_SpellScript(); + } +}; + +// 45313 - Anchor Here +class spell_sc_anchor_here : public SpellScriptLoader +{ +public: + spell_sc_anchor_here() : SpellScriptLoader("spell_sc_anchor_here") { } + + class spell_sc_anchor_here_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sc_anchor_here_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Creature* creature = GetHitUnit()->ToCreature()) + creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation()); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_sc_anchor_here_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_sc_anchor_here_SpellScript(); + } +}; + +// 93167 - Twilight Documents +class spell_sc_twilight_documents : public SpellScriptLoader +{ + public: + spell_sc_twilight_documents() : SpellScriptLoader("spell_sc_twilight_documents") { } + + class spell_sc_twilight_documents_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sc_twilight_documents_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sObjectMgr->GetGameObjectTemplate(GAMEOBJECT_TWILIGHT_DOCUMENTS)) + return false; + return true; + } + + void SetTarget(WorldObject*& target) + { + target = GetCaster()->FindNearestCreature(NPC_GENERIC_TRIGGER_LAB, 100.0f); + } + + void SpawnGameObject(SpellEffIndex /*effIndex*/) + { + if (WorldLocation* loc = GetHitDest()) + GetCaster()->SummonGameObject(GAMEOBJECT_TWILIGHT_DOCUMENTS, loc->GetPositionX(), loc->GetPositionY(), loc->GetPositionZ(), loc->GetOrientation(), 0, 0, 0, 0, 7200); + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_sc_twilight_documents_SpellScript::SetTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY); + OnEffectHit += SpellEffectFn(spell_sc_twilight_documents_SpellScript::SpawnGameObject, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_sc_twilight_documents_SpellScript(); + } +}; + +// 81008 - Quake +class JumpCheck +{ + public: + bool operator()(WorldObject* object) const + { + Player* player = object->ToPlayer(); + return (player && player->HasUnitState(UNIT_STATE_JUMPING)); + } +}; + +class spell_sc_quake : public SpellScriptLoader +{ + public: + spell_sc_quake() : SpellScriptLoader("spell_sc_quake") { } + + class spell_sc_quake_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sc_quake_SpellScript); + + void FilterTargets(std::list<WorldObject*>& unitList) + { + unitList.remove_if(JumpCheck()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sc_quake_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_sc_quake_SpellScript(); + } +}; + +class at_sc_corborus_intro : public AreaTriggerScript +{ +public: + at_sc_corborus_intro() : AreaTriggerScript("at_sc_corborus_intro") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + { + if (InstanceScript* instance = player->GetInstanceScript()) + if (Creature* corborus = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_CORBORUS))) + corborus->AI()->DoAction(ACTION_CORBORUS_INTRO); + return true; + } +}; + +class at_sc_slabhide_intro : public AreaTriggerScript +{ +public: + at_sc_slabhide_intro() : AreaTriggerScript("at_sc_slabhide_intro") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + { + if (InstanceScript* instance = player->GetInstanceScript()) + if (Creature* slabhide = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SLABHIDE))) + slabhide->AI()->DoAction(ACTION_SLABHIDE_INTRO); + return true; + } +}; + +void AddSC_stonecore() +{ + new npc_sc_millhouse_manastorm(); + new spell_force_of_earth(); + new spell_sc_anchor_here(); + new spell_sc_twilight_documents(); + new spell_sc_quake(); + new at_sc_corborus_intro(); + new at_sc_slabhide_intro(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/stonecore.h b/src/server/scripts/Maelstrom/Stonecore/stonecore.h new file mode 100644 index 00000000000..98a9878e0d3 --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/stonecore.h @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef DEF_STONECORE_H +#define DEF_STONECORE_H + +#define SCScriptName "instance_stonecore" +#define DataHeader "SC" + +enum DataTypes +{ + // Encounter States/Boss GUIDs + DATA_CORBORUS, + DATA_SLABHIDE, + DATA_OZRUK, + DATA_HIGH_PRIESTESS_AZIL, + + // Additional Data + DATA_MILLHOUSE_MANASTORM, + DATA_MILLHOUSE_EVENT_FACE, + DATA_MILLHOUSE_EVENT_KNOCKBACK, + DATA_MILLHOUSE_EVENT_DESPAWN, + + DATA_SLABHIDE_INTRO, + DATA_SLABHIDE_ROCK_WALL, +}; + +enum Misc +{ + ACTION_CORBORUS_INTRO, + ACTION_SLABHIDE_INTRO, + + NPC_WORLDTRIGGER = 22515, + NPC_MILLHOUSE_MANASTORM = 43391, + + NPC_CORBORUS = 43438, + NPC_SLABHIDE = 43214, + NPC_OZRUK = 42188, + NPC_HIGH_PRIESTESS_AZIL = 42333, + + // Stonecore Teleporter misc + MAX_STONECORE_TELEPORTERS = 2, + NPC_STONECORE_TELEPORTER = 51396, // Entrance teleporter + NPC_STONECORE_TELEPORTER_2 = 51397, // Slabhide teleporter + SPELL_TELEPORTER_ACTIVE_VISUAL = 95298, + + GAMEOBJECT_TWILIGHT_DOCUMENTS = 207415, + GAMEOBJECT_CORBORUS_ROCKDOOR = 207343, + GAMEOBJECT_SLABHIDE_ROCK_WALL = 204381, + + SPELL_RING_WYRM_KNOCKBACK = 81235, + + // Creature Formation IDs + CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH = 340418, + CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP = 340492, +}; + +#endif // DEF_STONECORE diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index 072dbd81fd8..69dc25892c1 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -205,10 +205,7 @@ class boss_anubarak_trial : public CreatureScript void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER) - { Talk(SAY_KILL_PLAYER); - instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0); - } } void MoveInLineOfSight(Unit* /*who*/) override @@ -611,9 +608,7 @@ class npc_frost_sphere : public CreatureScript struct npc_frost_sphereAI : public ScriptedAI { - npc_frost_sphereAI(Creature* creature) : ScriptedAI(creature) - { - } + npc_frost_sphereAI(Creature* creature) : ScriptedAI(creature) { } void Reset() override { @@ -766,7 +761,6 @@ class npc_anubarak_spike : public CreatureScript } void MoveInLineOfSight(Unit* pWho) override - { if (!pWho) return; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp index 562e67f4b6a..2b541e4b972 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp @@ -647,8 +647,6 @@ struct boss_faction_championsAI : public BossAI if (Creature* temp = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GARROSH))) temp->AI()->Talk(SAY_KILL_PLAYER); - - instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0); } } 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 f26ccd6bf25..7e8653c4a55 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp @@ -122,10 +122,7 @@ class boss_jaraxxus : public CreatureScript void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER) - { Talk(SAY_KILL_PLAYER); - instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0); - } } void JustDied(Unit* /*killer*/) override diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index 021cae3e623..f7bee426012 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -540,12 +540,6 @@ struct boss_jormungarAI : public BossAI me->DespawnOrUnsummon(); } - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER) - instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0); - } - void EnterCombat(Unit* /*who*/) override { _EnterCombat(); @@ -943,14 +937,6 @@ class boss_icehowl : public CreatureScript me->DespawnOrUnsummon(); } - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER) - { - instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0); - } - } - void EnterCombat(Unit* /*who*/) override { _EnterCombat(); 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 4c118f44e8e..dec2f44745d 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -212,10 +212,7 @@ struct boss_twin_baseAI : public BossAI void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER) - { Talk(SAY_KILL_PLAYER); - instance->SetData(DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE, 0); - } } void SummonedCreatureDespawn(Creature* summoned) override diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp index e3ad891fdc7..cb7e58cfe16 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp @@ -190,6 +190,13 @@ class instance_trial_of_the_crusader : public InstanceMapScript } } + void OnUnitDeath(Unit* unit) override + { + if (unit->GetTypeId() == TYPEID_PLAYER && IsEncounterInProgress()) + TributeToImmortalityEligible = false; + + } + bool SetBossState(uint32 type, EncounterState state) override { if (!InstanceScript::SetBossState(type, state)) @@ -427,9 +434,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript else if (data == DECREASE) --MistressOfPainCount; break; - case DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE: - TributeToImmortalityEligible = false; - break; default: break; } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h index e37148aa508..90b9781954f 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h @@ -24,9 +24,8 @@ enum DataTypes TYPE_EVENT_NPC = 102, TYPE_NORTHREND_BEASTS = 103, - DATA_SNOBOLD_COUNT = 301, - DATA_MISTRESS_OF_PAIN_COUNT = 302, - DATA_TRIBUTE_TO_IMMORTALITY_ELIGIBLE = 303, + DATA_SNOBOLD_COUNT = 301, + DATA_MISTRESS_OF_PAIN_COUNT = 302, INCREASE = 501, DECREASE = 502, diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 5e8273dce67..cdbbf755390 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -83,6 +83,7 @@ class instance_ulduar : public InstanceMapScript IsDriveMeCrazyEligible = true; _algalonSummoned = false; _summonAlgalon = false; + _CoUAchivePlayerDeathMask = 0; memset(_summonObservationRingKeeper, 0, sizeof(_summonObservationRingKeeper)); memset(_summonYSKeeper, 0, sizeof(_summonYSKeeper)); @@ -592,6 +593,19 @@ class instance_ulduar : public InstanceMapScript void OnUnitDeath(Unit* unit) override { + // Champion/Conqueror of Ulduar + if (unit->GetTypeId() == TYPEID_PLAYER) + { + for (uint8 i = 0; i < BOSS_ALGALON; i++) + { + if (GetBossState(i) == IN_PROGRESS) + { + _CoUAchivePlayerDeathMask |= (1 << i); + SaveToDB(); + } + } + } + Creature* creature = unit->ToCreature(); if (!creature) return; @@ -1007,6 +1021,45 @@ class instance_ulduar : public InstanceMapScript case CRITERIA_ALONE_IN_THE_DARKNESS_10: case CRITERIA_ALONE_IN_THE_DARKNESS_25: return keepersCount == 0; + case CRITERIA_C_O_U_LEVIATHAN_10: + case CRITERIA_C_O_U_LEVIATHAN_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_LEVIATHAN)) == 0; + case CRITERIA_C_O_U_IGNIS_10: + case CRITERIA_C_O_U_IGNIS_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_IGNIS)) == 0; + case CRITERIA_C_O_U_RAZORSCALE_10: + case CRITERIA_C_O_U_RAZORSCALE_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_RAZORSCALE)) == 0; + case CRITERIA_C_O_U_XT002_10: + case CRITERIA_C_O_U_XT002_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_XT002)) == 0; + case CRITERIA_C_O_U_IRON_COUNCIL_10: + case CRITERIA_C_O_U_IRON_COUNCIL_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_ASSEMBLY_OF_IRON)) == 0; + case CRITERIA_C_O_U_KOLOGARN_10: + case CRITERIA_C_O_U_KOLOGARN_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_KOLOGARN)) == 0; + case CRITERIA_C_O_U_AURIAYA_10: + case CRITERIA_C_O_U_AURIAYA_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_AURIAYA)) == 0; + case CRITERIA_C_O_U_HODIR_10: + case CRITERIA_C_O_U_HODIR_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_HODIR)) == 0; + case CRITERIA_C_O_U_THORIM_10: + case CRITERIA_C_O_U_THORIM_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_THORIM)) == 0; + case CRITERIA_C_O_U_FREYA_10: + case CRITERIA_C_O_U_FREYA_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_FREYA)) == 0; + case CRITERIA_C_O_U_MIMIRON_10: + case CRITERIA_C_O_U_MIMIRON_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_MIMIRON)) == 0; + case CRITERIA_C_O_U_VEZAX_10: + case CRITERIA_C_O_U_VEZAX_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_VEZAX)) == 0; + case CRITERIA_C_O_U_YOGG_SARON_10: + case CRITERIA_C_O_U_YOGG_SARON_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_YOGG_SARON)) == 0; } return false; @@ -1018,6 +1071,8 @@ class instance_ulduar : public InstanceMapScript for (uint8 i = 0; i < 4; ++i) data << ' ' << uint32(!KeeperGUIDs[i].IsEmpty() ? 1 : 0); + + data << ' ' << _CoUAchivePlayerDeathMask; } void ReadSaveDataMore(std::istringstream& data) override @@ -1056,6 +1111,8 @@ class instance_ulduar : public InstanceMapScript _summonObservationRingKeeper[2] = true; if (GetBossState(BOSS_MIMIRON) == DONE && !_summonYSKeeper[3]) _summonObservationRingKeeper[3] = true; + + data >> _CoUAchivePlayerDeathMask; } void Update(uint32 diff) override @@ -1095,6 +1152,7 @@ class instance_ulduar : public InstanceMapScript bool _summonYSKeeper[4]; uint32 _maxArmorItemLevel; uint32 _maxWeaponItemLevel; + uint32 _CoUAchivePlayerDeathMask; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 82c4ef140f1..1b4330b0faf 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -36,16 +36,16 @@ enum UlduarBosses BOSS_ASSEMBLY_OF_IRON = 4, BOSS_KOLOGARN = 5, BOSS_AURIAYA = 6, - BOSS_MIMIRON = 7, - BOSS_HODIR = 8, - BOSS_THORIM = 9, - BOSS_FREYA = 10, - BOSS_BRIGHTLEAF = 11, - BOSS_IRONBRANCH = 12, - BOSS_STONEBARK = 13, - BOSS_VEZAX = 14, - BOSS_YOGG_SARON = 15, - BOSS_ALGALON = 16, + BOSS_HODIR = 7, + BOSS_THORIM = 8, + BOSS_FREYA = 9, + BOSS_MIMIRON = 10, + BOSS_VEZAX = 11, + BOSS_YOGG_SARON = 12, + BOSS_ALGALON = 13, + BOSS_BRIGHTLEAF = 14, + BOSS_IRONBRANCH = 15, + BOSS_STONEBARK = 16, }; enum UlduarNPCs @@ -295,6 +295,35 @@ enum UlduarAchievementCriteriaIds CRITERIA_ALONE_IN_THE_DARKNESS_10 = 10412, CRITERIA_ALONE_IN_THE_DARKNESS_25 = 10417, CRITERIA_HERALD_OF_TITANS = 10678, + + // Champion of Ulduar + CRITERIA_C_O_U_LEVIATHAN_10 = 10042, + CRITERIA_C_O_U_IGNIS_10 = 10342, + CRITERIA_C_O_U_RAZORSCALE_10 = 10340, + CRITERIA_C_O_U_XT002_10 = 10341, + CRITERIA_C_O_U_IRON_COUNCIL_10 = 10598, + CRITERIA_C_O_U_KOLOGARN_10 = 10348, + CRITERIA_C_O_U_AURIAYA_10 = 10351, + CRITERIA_C_O_U_HODIR_10 = 10439, + CRITERIA_C_O_U_THORIM_10 = 10403, + CRITERIA_C_O_U_FREYA_10 = 10582, + CRITERIA_C_O_U_MIMIRON_10 = 10347, + CRITERIA_C_O_U_VEZAX_10 = 10349, + CRITERIA_C_O_U_YOGG_SARON_10 = 10350, + // Conqueror of Ulduar + CRITERIA_C_O_U_LEVIATHAN_25 = 10352, + CRITERIA_C_O_U_IGNIS_25 = 10355, + CRITERIA_C_O_U_RAZORSCALE_25 = 10353, + CRITERIA_C_O_U_XT002_25 = 10354, + CRITERIA_C_O_U_IRON_COUNCIL_25 = 10599, + CRITERIA_C_O_U_KOLOGARN_25 = 10357, + CRITERIA_C_O_U_AURIAYA_25 = 10363, + CRITERIA_C_O_U_HODIR_25 = 10719, + CRITERIA_C_O_U_THORIM_25 = 10404, + CRITERIA_C_O_U_FREYA_25 = 10583, + CRITERIA_C_O_U_MIMIRON_25 = 10361, + CRITERIA_C_O_U_VEZAX_25 = 10362, + CRITERIA_C_O_U_YOGG_SARON_25 = 10364 }; enum UlduarData |
