diff options
Diffstat (limited to 'src/server/scripts')
34 files changed, 1793 insertions, 1308 deletions
diff --git a/src/server/scripts/Commands/cs_cast.cpp b/src/server/scripts/Commands/cs_cast.cpp index 44c606a360f..45e6c65cc6b 100644 --- a/src/server/scripts/Commands/cs_cast.cpp +++ b/src/server/scripts/Commands/cs_cast.cpp @@ -99,8 +99,7 @@ public: return false; } - bool triggered = (triggeredStr != NULL); - + TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE; handler->GetSession()->GetPlayer()->CastSpell(target, spellId, triggered); return true; @@ -132,8 +131,7 @@ public: return false; } - bool triggered = (triggeredStr != NULL); - + TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE; caster->CastSpell(handler->GetSession()->GetPlayer(), spellId, triggered); return true; @@ -167,8 +165,7 @@ public: return false; } - bool triggered = (triggeredStr != NULL); - + TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE; float x, y, z; handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, dist); @@ -230,8 +227,7 @@ public: return false; } - bool triggered = (triggeredStr != NULL); - + TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE; caster->CastSpell(caster->GetVictim(), spellId, triggered); return true; @@ -274,8 +270,7 @@ public: return false; } - bool triggered = (triggeredStr != NULL); - + TriggerCastFlags triggered = (triggeredStr != NULL) ? TRIGGERED_FULL_DEBUG_MASK : TRIGGERED_NONE; caster->CastSpell(x, y, z, spellId, triggered); return true; diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 16217fbaea6..1e4daaea2d2 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -2268,19 +2268,20 @@ public: // melee damage by specific school if (!spellStr) { - uint32 absorb = 0; - uint32 resist = 0; + Player* attacker = handler->GetSession()->GetPlayer(); + DamageInfo dmgInfo(attacker, target, damage, nullptr, schoolmask, SPELL_DIRECT_DAMAGE, BASE_ATTACK); + attacker->CalcAbsorbResist(dmgInfo); - handler->GetSession()->GetPlayer()->CalcAbsorbResist(target, schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - - if (damage <= absorb + resist) + if (!dmgInfo.GetDamage()) return true; - damage -= absorb + resist; + damage = dmgInfo.GetDamage(); - handler->GetSession()->GetPlayer()->DealDamageMods(target, damage, &absorb); - handler->GetSession()->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false); - handler->GetSession()->GetPlayer()->SendAttackStateUpdate (HITINFO_AFFECTS_VICTIM, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0); + uint32 absorb = dmgInfo.GetAbsorb(); + uint32 resist = dmgInfo.GetResist(); + attacker->DealDamageMods(target, damage, &absorb); + attacker->DealDamage(target, damage, nullptr, DIRECT_DAMAGE, schoolmask, nullptr, false); + attacker->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 0, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0); return true; } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h index 446cc48d2f7..2c0f16c4ff2 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h @@ -48,7 +48,8 @@ enum DataTypes DATA_HALL_RUNE_4 = 19, DATA_HALL_RUNE_5 = 20, DATA_HALL_RUNE_6 = 21, - DATA_HALL_RUNE_7 = 22 + DATA_HALL_RUNE_7 = 22, + DATA_SCARSHIELD_INFILTRATOR = 23 }; enum CreaturesIds @@ -71,7 +72,8 @@ enum CreaturesIds NPC_BLACKHAND_SUMMONER = 9818, NPC_BLACKHAND_VETERAN = 9819, NPC_BLACKHAND_INCARCERATOR = 10316, - NPC_LORD_VICTOR_NEFARIUS = 10162 + NPC_LORD_VICTOR_NEFARIUS = 10162, + NPC_SCARSHIELD_INFILTRATOR = 10299 }; enum AdditionalData diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp index bbe8fda37eb..89617a9f4ef 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp @@ -109,6 +109,9 @@ public: if (GetBossState(DATA_GYTH) == DONE) creature->DisappearAndDie(); break; + case NPC_SCARSHIELD_INFILTRATOR: + ScarshieldInfiltrator = creature->GetGUID(); + break; } } @@ -318,6 +321,8 @@ public: return TheBeast; case DATA_GENERAL_DRAKKISATH: return GeneralDrakkisath; + case DATA_SCARSHIELD_INFILTRATOR: + return ScarshieldInfiltrator; case GO_EMBERSEER_IN: return go_emberseerin; case GO_DOORS: @@ -496,6 +501,7 @@ public: ObjectGuid LordVictorNefarius; ObjectGuid TheBeast; ObjectGuid GeneralDrakkisath; + ObjectGuid ScarshieldInfiltrator; ObjectGuid go_emberseerin; ObjectGuid go_doors; ObjectGuid go_emberseerout; @@ -565,9 +571,33 @@ public: } }; +class at_nearby_scarshield_infiltrator : public AreaTriggerScript +{ +public: + at_nearby_scarshield_infiltrator() : AreaTriggerScript("at_nearby_scarshield_infiltrator") { } + + bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override + { + if (player->IsAlive()) + if (InstanceScript* instance = player->GetInstanceScript()) + if (Creature* infiltrator = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SCARSHIELD_INFILTRATOR))) + { + if (player->getLevel() >= 57) + infiltrator->AI()->SetData(1, 1); + else if (infiltrator->GetEntry() == NPC_SCARSHIELD_INFILTRATOR) + infiltrator->AI()->Talk(0, player); + + return true; + } + + return false; + } +}; + void AddSC_instance_blackrock_spire() { new instance_blackrock_spire(); new at_dragonspire_hall(); new at_blackrock_stadium(); + new at_nearby_scarshield_infiltrator(); } diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp index d0430ebb3e5..67bda699643 100644 --- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp +++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp @@ -54,7 +54,6 @@ enum Yells enum Spells { SPELL_UNLOCK = 6421, - SPELL_DARK_OFFERING = 7154 }; @@ -205,6 +204,123 @@ public: }; +enum ArugalSpells +{ + SPELL_TELE_UPPER = 7587, + SPELL_TELE_SPAWN = 7586, + SPELL_TELE_STAIRS = 7136, + NUM_TELEPORT_SPELLS = 3, + SPELL_ARUGAL_CURSE = 7621, + SPELL_THUNDERSHOCK = 7803, + SPELL_VOIDBOLT = 7588 +}; + +enum ArugalTexts +{ + SAY_AGGRO = 1, // You, too, shall serve! + SAY_TRANSFORM = 2, // Release your rage! + SAY_SLAY = 3 // Another falls! +}; + +enum ArugalEvents +{ + EVENT_VOID_BOLT = 1, + EVENT_TELEPORT, + EVENT_THUNDERSHOCK, + EVENT_CURSE +}; + +class boss_archmage_arugal : public CreatureScript +{ + public: + boss_archmage_arugal() : CreatureScript("boss_archmage_arugal") { } + + struct boss_archmage_arugalAI : public BossAI + { + boss_archmage_arugalAI(Creature* creature) : BossAI(creature, BOSS_ARUGAL) { } + + uint32 teleportSpells[NUM_TELEPORT_SPELLS] = + { + SPELL_TELE_SPAWN, + SPELL_TELE_UPPER, + SPELL_TELE_STAIRS + }; + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_ARUGAL_CURSE) + Talk(SAY_TRANSFORM); + } + + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_CURSE, Seconds(7)); + events.ScheduleEvent(EVENT_TELEPORT, Seconds(15)); + events.ScheduleEvent(EVENT_VOID_BOLT, Seconds(1)); + events.ScheduleEvent(EVENT_THUNDERSHOCK, Seconds(10)); + } + + void AttackStart(Unit* who) override + { + AttackStartCaster(who, 100.0f); // void bolt range is 100.f + } + + 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_CURSE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 30.0f, true)) + DoCast(target, SPELL_ARUGAL_CURSE); + events.Repeat(Seconds(15)); + break; + case EVENT_TELEPORT: + { + // ensure we never cast the same teleport twice in a row + uint8 spellIndex = urand(1, NUM_TELEPORT_SPELLS-1); + std::swap(teleportSpells[0], teleportSpells[spellIndex]); + DoCast(teleportSpells[0]); + events.Repeat(Seconds(20)); + break; + } + case EVENT_THUNDERSHOCK: + DoCastAOE(SPELL_THUNDERSHOCK); + events.Repeat(Seconds(30)); + break; + case EVENT_VOID_BOLT: + DoCastVictim(SPELL_VOIDBOLT); + events.Repeat(Seconds(5)); + break; + } + } + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_archmage_arugalAI>(creature); + } +}; + class spell_shadowfang_keep_haunting_spirits : public SpellScriptLoader { public: @@ -248,5 +364,6 @@ void AddSC_shadowfang_keep() { new npc_shadowfang_prisoner(); new npc_arugal_voidwalker(); + new boss_archmage_arugal(); new spell_shadowfang_keep_haunting_spirits(); } diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h index 88edc3f1ee1..7e508191f69 100644 --- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h +++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.h @@ -26,8 +26,8 @@ enum DataTypes TYPE_FREE_NPC = 1, TYPE_RETHILGORE = 2, TYPE_FENRUS = 3, - TYPE_NANDOS = 4 + TYPE_NANDOS = 4, + BOSS_ARUGAL = 5 }; #endif - diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp index adcb4f9fc9a..d9c929794cc 100644 --- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -175,7 +175,7 @@ void AddSC_arathi_highlands(); void AddSC_blasted_lands(); void AddSC_burning_steppes(); void AddSC_duskwood(); -void AddSC_eastern_plaguelands(); +//void AddSC_eastern_plaguelands(); void AddSC_ghostlands(); void AddSC_hinterlands(); void AddSC_isle_of_queldanas(); @@ -352,7 +352,7 @@ void AddEasternKingdomsScripts() AddSC_blasted_lands(); AddSC_burning_steppes(); AddSC_duskwood(); - AddSC_eastern_plaguelands(); + //AddSC_eastern_plaguelands(); AddSC_ghostlands(); AddSC_hinterlands(); AddSC_isle_of_queldanas(); diff --git a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp deleted file mode 100644 index c35c8629cef..00000000000 --- a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2008-2016 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/>. - */ - -/* ScriptData -SDName: Eastern_Plaguelands -SD%Complete: 100 -SDComment: Quest support: 5211. Special vendor Augustus the Touched -SDCategory: Eastern Plaguelands -EndScriptData */ - -/* ContentData -npc_ghoul_flayer -npc_augustus_the_touched -npc_darrowshire_spirit -EndContentData */ - -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "ScriptedGossip.h" -#include "Player.h" -#include "WorldSession.h" - -class npc_ghoul_flayer : public CreatureScript -{ -public: - npc_ghoul_flayer() : CreatureScript("npc_ghoul_flayer") { } - - struct npc_ghoul_flayerAI : public ScriptedAI - { - npc_ghoul_flayerAI(Creature* creature) : ScriptedAI(creature) { } - - void Reset() override { } - - void EnterCombat(Unit* /*who*/) override { } - - void JustDied(Unit* killer) override - { - if (killer->GetTypeId() == TYPEID_PLAYER) - me->SummonCreature(11064, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_ghoul_flayerAI(creature); - } -}; - -/*###### -## npc_augustus_the_touched -######*/ - -class npc_augustus_the_touched : public CreatureScript -{ -public: - npc_augustus_the_touched() : CreatureScript("npc_augustus_the_touched") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - ClearGossipMenuFor(player); - if (action == GOSSIP_ACTION_TRADE) - player->GetSession()->SendListInventory(creature->GetGUID()); - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (creature->IsVendor() && player->GetQuestRewardStatus(6164)) - AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID()); - return true; - } -}; - -/*###### -## npc_darrowshire_spirit -######*/ - -enum DarrowshireSpirit -{ - SPELL_SPIRIT_SPAWNIN = 17321 -}; - -class npc_darrowshire_spirit : public CreatureScript -{ -public: - npc_darrowshire_spirit() : CreatureScript("npc_darrowshire_spirit") { } - - bool OnGossipHello(Player* player, Creature* creature) override - { - SendGossipMenuFor(player, 3873, creature->GetGUID()); - player->TalkedToCreature(creature->GetEntry(), creature->GetGUID()); - creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - return true; - } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_darrowshire_spiritAI(creature); - } - - struct npc_darrowshire_spiritAI : public ScriptedAI - { - npc_darrowshire_spiritAI(Creature* creature) : ScriptedAI(creature) { } - - void Reset() override - { - DoCast(me, SPELL_SPIRIT_SPAWNIN); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void EnterCombat(Unit* /*who*/) override { } - }; -}; - -void AddSC_eastern_plaguelands() -{ - new npc_ghoul_flayer(); - new npc_augustus_the_touched(); - new npc_darrowshire_spirit(); -} diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp index 137da1002af..34a456ae502 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp @@ -16,19 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* -Name: The_Black_Morass -%Complete: 30 -Comment: Misc NPC's and mobs for instance. Most here far from complete. -Category: Caverns of Time, The Black Morass -*/ - -/* ContentData -npc_medivh_bm -npc_time_rift -npc_saat -EndContentData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" @@ -365,57 +352,8 @@ public: }; -enum Saat -{ - SPELL_CHRONO_BEACON = 34975, - ITEM_CHRONO_BEACON = 24289 -}; - -#define GOSSIP_ITEM_OBTAIN "[PH] Obtain Chrono-Beacon" - -class npc_saat : public CreatureScript -{ -public: - npc_saat() : CreatureScript("npc_saat") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - ClearGossipMenuFor(player); - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - CloseGossipMenuFor(player); - creature->CastSpell(player, SPELL_CHRONO_BEACON, false); - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(QUEST_OPENING_PORTAL) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(ITEM_CHRONO_BEACON)) - { - AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_OBTAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - SendGossipMenuFor(player, 10000, creature->GetGUID()); - return true; - } - else if (player->GetQuestRewardStatus(QUEST_OPENING_PORTAL) && !player->HasItemCount(ITEM_CHRONO_BEACON)) - { - AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_OBTAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - SendGossipMenuFor(player, 10001, creature->GetGUID()); - return true; - } - - SendGossipMenuFor(player, 10002, creature->GetGUID()); - return true; - } - -}; - void AddSC_the_black_morass() { new npc_medivh_bm(); new npc_time_rift(); - new npc_saat(); } diff --git a/src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp b/src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp index b7f88200077..7a7c104bdba 100644 --- a/src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp +++ b/src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp @@ -16,18 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Stonetalon_Mountains -SD%Complete: 95 -SDComment: Quest support: 6627, 6523 -SDCategory: Stonetalon Mountains -EndScriptData */ - -/* ContentData -npc_braug_dimspirit -npc_kaya_flathoof -EndContentData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" @@ -35,61 +23,6 @@ EndContentData */ #include "Player.h" /*###### -## npc_braug_dimspirit -######*/ - -#define GOSSIP_HBD1 "Ysera" -#define GOSSIP_HBD2 "Neltharion" -#define GOSSIP_HBD3 "Nozdormu" -#define GOSSIP_HBD4 "Alexstrasza" -#define GOSSIP_HBD5 "Malygos" - -class npc_braug_dimspirit : public CreatureScript -{ -public: - npc_braug_dimspirit() : CreatureScript("npc_braug_dimspirit") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - ClearGossipMenuFor(player); - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - CloseGossipMenuFor(player); - creature->CastSpell(player, 6766, false); - - } - if (action == GOSSIP_ACTION_INFO_DEF+2) - { - CloseGossipMenuFor(player); - player->AreaExploredOrEventHappens(6627); - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(6627) == QUEST_STATUS_INCOMPLETE) - { - AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HBD5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - SendGossipMenuFor(player, 5820, creature->GetGUID()); - } - else - SendGossipMenuFor(player, 5819, creature->GetGUID()); - - return true; - } - -}; - -/*###### ## npc_kaya_flathoof ######*/ @@ -174,6 +107,5 @@ public: void AddSC_stonetalon_mountains() { - new npc_braug_dimspirit(); new npc_kaya_flathoof(); } diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h index 685d0f51edd..2eda9509bb8 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h @@ -33,7 +33,8 @@ enum DataTypes DATA_WATCHER_NARJIL, DATA_WATCHER_GASHRA, DATA_WATCHER_SILTHIK, - DATA_ANUBARAK_WALL + DATA_ANUBARAK_WALL, + DATA_ANUBARAK_WALL_2 }; enum CreatureIds diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp index 06a91d58705..2860698a8b2 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp @@ -121,12 +121,16 @@ public: _petCount = 0; } + bool CanAIAttack(Unit const* /*who*/) const override { return true; } // do not check boundary here + void EnterCombat(Unit* who) override { BossAI::EnterCombat(who); if (GameObject* door = instance->GetGameObject(DATA_ANUBARAK_WALL)) door->SetGoState(GO_STATE_ACTIVE); // open door for now + if (GameObject* door2 = instance->GetGameObject(DATA_ANUBARAK_WALL_2)) + door2->SetGoState(GO_STATE_ACTIVE); Talk(SAY_AGGRO); instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_GOTTA_GO_START_EVENT); @@ -179,6 +183,8 @@ public: case EVENT_CLOSE_DOOR: if (GameObject* door = instance->GetGameObject(DATA_ANUBARAK_WALL)) door->SetGoState(GO_STATE_READY); + if (GameObject* door2 = instance->GetGameObject(DATA_ANUBARAK_WALL_2)) + door2->SetGoState(GO_STATE_READY); break; case EVENT_POUND: DoCastVictim(SPELL_POUND); diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp index 7338774c21e..c41ec1c488d 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp @@ -789,7 +789,7 @@ struct npc_hadronox_foeAI : public ScriptedAI me->GetMotionMaster()->MovePoint(MOVE_HADRONOX, hadronoxStep[2]); break; } - me->GetMotionMaster()->MoveChase(hadronox); + AttackStart(hadronox); } break; } diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp index ea912da4c3d..0d52a09bbdc 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp @@ -138,10 +138,10 @@ class boss_krik_thir : public CreatureScript for (uint8 i = 1; i <= 3; ++i) { - std::list<TempSummon*> summons; - me->SummonCreatureGroup(i, &summons); - for (TempSummon* summon : summons) - summon->AI()->SetData(DATA_PET_GROUP, i); + std::list<TempSummon*> adds; + me->SummonCreatureGroup(i, &adds); + for (TempSummon* add : adds) + add->AI()->SetData(DATA_PET_GROUP, i); } } @@ -416,10 +416,7 @@ class npc_watcher_gashra : public CreatureScript struct npc_watcher_gashraAI : public npc_gatewatcher_petAI { - npc_watcher_gashraAI(Creature* creature) : npc_gatewatcher_petAI(creature, true) - { - me->SetReactState(REACT_PASSIVE); - } + npc_watcher_gashraAI(Creature* creature) : npc_gatewatcher_petAI(creature, true) { } void Reset() override { @@ -928,11 +925,15 @@ class spell_gatewatcher_subboss_trigger : public SpellScriptLoader void HandleTargets(std::list<WorldObject*>& targetList) { // Remove any Watchers that are already in combat - for (std::list<WorldObject*>::iterator it = targetList.begin(); it != targetList.end(); ++it) + auto it = targetList.begin(); + while (it != targetList.end()) { if (Creature* creature = (*it)->ToCreature()) if (creature->IsAlive() && !creature->IsInCombat()) + { + ++it; continue; + } it = targetList.erase(it); } diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp index 8af4f6cecc4..7f0ce5c369e 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp @@ -41,7 +41,8 @@ ObjectData const creatureData[] = ObjectData const gameobjectData[] = { - { GO_ANUBARAK_DOOR_3, DATA_ANUBARAK_WALL }, + { GO_ANUBARAK_DOOR_1, DATA_ANUBARAK_WALL }, + { GO_ANUBARAK_DOOR_3, DATA_ANUBARAK_WALL_2 }, { 0, 0 } // END }; @@ -77,6 +78,17 @@ class instance_azjol_nerub : public InstanceMapScript if (Creature* gatewatcher = GetCreature(DATA_KRIKTHIR)) gatewatcher->AI()->DoAction(-ACTION_GATEWATCHER_GREET); } + + bool CheckRequiredBosses(uint32 bossId, Player const* player) const override + { + if (_SkipCheckRequiredBosses(player)) + return true; + + if (bossId > DATA_KRIKTHIR && GetBossState(DATA_KRIKTHIR) != DONE) + return false; + + return true; + } }; InstanceScript* GetInstanceScript(InstanceMap* map) const 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 1041d250cc7..976ef3e34db 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -16,9 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -// Known bugs: -// Gormok - Snobolled (creature at back) - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "trial_of_the_crusader.h" @@ -71,14 +68,16 @@ enum BossSpells //Gormok SPELL_IMPALE = 66331, SPELL_STAGGERING_STOMP = 67648, - SPELL_RISING_ANGER = 66636, //Snobold + SPELL_RISING_ANGER = 66636, SPELL_SNOBOLLED = 66406, SPELL_BATTER = 66408, SPELL_FIRE_BOMB = 66313, SPELL_FIRE_BOMB_1 = 66317, SPELL_FIRE_BOMB_DOT = 66318, SPELL_HEAD_CRACK = 66407, + SPELL_JUMP_TO_HAND = 66342, + SPELL_RIDE_PLAYER = 66245, //Acidmaw & Dreadscale Generic SPELL_SWEEP = 66794, @@ -117,38 +116,41 @@ enum BossSpells enum MyActions { ACTION_ENABLE_FIRE_BOMB = 1, - ACTION_DISABLE_FIRE_BOMB = 2 + ACTION_DISABLE_FIRE_BOMB = 2, + ACTION_ACTIVE_SNOBOLD = 3 }; enum Events { // Gormok EVENT_IMPALE = 1, - EVENT_STAGGERING_STOMP = 2, - EVENT_THROW = 3, + EVENT_STAGGERING_STOMP, + EVENT_THROW, // Snobold - EVENT_FIRE_BOMB = 4, - EVENT_BATTER = 5, - EVENT_HEAD_CRACK = 6, + EVENT_FIRE_BOMB, + EVENT_BATTER, + EVENT_HEAD_CRACK, + EVENT_SNOBOLLED, + EVENT_CHECK_MOUNT, // Acidmaw & Dreadscale - EVENT_BITE = 7, - EVENT_SPEW = 8, - EVENT_SLIME_POOL = 9, - EVENT_SPIT = 10, - EVENT_SPRAY = 11, - EVENT_SWEEP = 12, - EVENT_SUBMERGE = 13, - EVENT_EMERGE = 14, - EVENT_SUMMON_ACIDMAW = 15, + EVENT_BITE, + EVENT_SPEW, + EVENT_SLIME_POOL, + EVENT_SPIT, + EVENT_SPRAY, + EVENT_SWEEP, + EVENT_SUBMERGE, + EVENT_EMERGE, + EVENT_SUMMON_ACIDMAW, // Icehowl - EVENT_FEROCIOUS_BUTT = 16, - EVENT_MASSIVE_CRASH = 17, - EVENT_WHIRL = 18, - EVENT_ARCTIC_BREATH = 19, - EVENT_TRAMPLE = 20 + EVENT_FEROCIOUS_BUTT, + EVENT_MASSIVE_CRASH, + EVENT_WHIRL, + EVENT_ARCTIC_BREATH, + EVENT_TRAMPLE }; enum Phases @@ -158,6 +160,13 @@ enum Phases PHASE_SUBMERGED = 3 }; +enum GormokMisc +{ + DATA_NEW_TARGET = 1, + GORMOK_HAND_SEAT = 4, + PLAYER_VEHICLE_ID = 444, +}; + class boss_gormok : public CreatureScript { public: @@ -169,9 +178,9 @@ class boss_gormok : public CreatureScript void Reset() override { - events.ScheduleEvent(EVENT_IMPALE, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS)); - events.ScheduleEvent(EVENT_STAGGERING_STOMP, 15*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_THROW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_IMPALE, Seconds(8), Seconds(10)); + events.ScheduleEvent(EVENT_STAGGERING_STOMP, Seconds(15)); + events.ScheduleEvent(EVENT_THROW, Seconds(15), Seconds(30)); summons.DespawnAll(); } @@ -216,18 +225,7 @@ class boss_gormok : public CreatureScript void EnterCombat(Unit* /*who*/) override { _EnterCombat(); - me->SetInCombatWithZone(); instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_IN_PROGRESS); - - for (uint8 i = 0; i < MAX_SNOBOLDS; i++) - { - if (Creature* pSnobold = DoSpawnCreature(NPC_SNOBOLD_VASSAL, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0)) - { - pSnobold->EnterVehicle(me, i); - pSnobold->SetInCombatWithZone(); - pSnobold->AI()->DoAction(ACTION_ENABLE_FIRE_BOMB); - } - } } void DamageTaken(Unit* /*who*/, uint32& damage) override @@ -235,8 +233,14 @@ class boss_gormok : public CreatureScript // despawn the remaining passengers on death if (damage >= me->GetHealth()) for (uint8 i = 0; i < MAX_SNOBOLDS; ++i) - if (Unit* pSnobold = me->GetVehicleKit()->GetPassenger(i)) - pSnobold->ToCreature()->DespawnOrUnsummon(); + if (Unit* snobold = me->GetVehicleKit()->GetPassenger(i)) + snobold->ToCreature()->DespawnOrUnsummon(); + } + + void PassengerBoarded(Unit* who, int8 seatId, bool apply) override + { + if (apply && seatId == GORMOK_HAND_SEAT) + who->CastSpell(me, SPELL_RISING_ANGER, true); } void UpdateAI(uint32 diff) override @@ -255,30 +259,28 @@ class boss_gormok : public CreatureScript { case EVENT_IMPALE: DoCastVictim(SPELL_IMPALE); - events.ScheduleEvent(EVENT_IMPALE, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS)); - return; + events.Repeat(Seconds(8), Seconds(10)); + break; case EVENT_STAGGERING_STOMP: DoCastVictim(SPELL_STAGGERING_STOMP); - events.ScheduleEvent(EVENT_STAGGERING_STOMP, 15*IN_MILLISECONDS); - return; + events.Repeat(Seconds(15)); + break; case EVENT_THROW: for (uint8 i = 0; i < MAX_SNOBOLDS; ++i) { - if (Unit* pSnobold = me->GetVehicleKit()->GetPassenger(i)) + if (Unit* snobold = me->GetVehicleKit()->GetPassenger(i)) { - pSnobold->ExitVehicle(); - pSnobold->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - pSnobold->ToCreature()->SetReactState(REACT_AGGRESSIVE); - pSnobold->ToCreature()->AI()->DoAction(ACTION_DISABLE_FIRE_BOMB); - pSnobold->CastSpell(me, SPELL_RISING_ANGER, true); - Talk(EMOTE_SNOBOLLED); + snobold->ExitVehicle(); + snobold->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + snobold->GetAI()->DoAction(ACTION_DISABLE_FIRE_BOMB); + snobold->CastSpell(me, SPELL_JUMP_TO_HAND, true); break; } } - events.ScheduleEvent(EVENT_THROW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); - return; + events.Repeat(Seconds(15), Seconds(30)); + break; default: - return; + break; } } @@ -292,6 +294,23 @@ class boss_gormok : public CreatureScript } }; +class SnobolledTargetSelector : public std::unary_function<Unit*, bool> +{ +public: + SnobolledTargetSelector(Unit const* /*unit*/) { } + + bool operator()(Unit* unit) const + { + if (unit->GetTypeId() != TYPEID_PLAYER) + return false; + + if (unit->HasAura(SPELL_RIDE_PLAYER) || unit->HasAura(SPELL_SNOBOLLED)) + return false; + + return true; + } +}; + class npc_snobold_vassal : public CreatureScript { public: @@ -299,59 +318,24 @@ class npc_snobold_vassal : public CreatureScript struct npc_snobold_vassalAI : public ScriptedAI { - npc_snobold_vassalAI(Creature* creature) : ScriptedAI(creature) + npc_snobold_vassalAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _isActive(false) { - _targetDied = false; - _instance = creature->GetInstanceScript(); _instance->SetData(DATA_SNOBOLD_COUNT, INCREASE); + SetCombatMovement(false); } void Reset() override { - _events.ScheduleEvent(EVENT_BATTER, 5*IN_MILLISECONDS); - _events.ScheduleEvent(EVENT_HEAD_CRACK, 25*IN_MILLISECONDS); - - _targetGUID.Clear(); - _targetDied = false; - - //Workaround for Snobold me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - } - - void EnterCombat(Unit* who) override - { - _targetGUID = who->GetGUID(); - me->TauntApply(who); - DoCast(who, SPELL_SNOBOLLED); - } - - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) override - { - if (pDoneBy->GetGUID() == _targetGUID) - uiDamage = 0; - } - - void MovementInform(uint32 type, uint32 pointId) override - { - if (type != POINT_MOTION_TYPE) - return; - - switch (pointId) - { - case 0: - if (_targetDied) - me->DespawnOrUnsummon(); - break; - default: - break; - } + me->SetInCombatWithZone(); + _events.ScheduleEvent(EVENT_CHECK_MOUNT, Seconds(1)); + _events.ScheduleEvent(EVENT_FIRE_BOMB, Seconds(5), Seconds(30)); } void JustDied(Unit* /*killer*/) override { if (Unit* target = ObjectAccessor::GetPlayer(*me, _targetGUID)) - if (target->IsAlive()) - target->RemoveAurasDueToSpell(SPELL_SNOBOLLED); + target->RemoveAurasDueToSpell(SPELL_SNOBOLLED); _instance->SetData(DATA_SNOBOLD_COUNT, DECREASE); } @@ -360,50 +344,69 @@ class npc_snobold_vassal : public CreatureScript switch (action) { case ACTION_ENABLE_FIRE_BOMB: - _events.ScheduleEvent(EVENT_FIRE_BOMB, urand(5*IN_MILLISECONDS, 30*IN_MILLISECONDS)); + _events.ScheduleEvent(EVENT_FIRE_BOMB, Seconds(5), Seconds(30)); break; case ACTION_DISABLE_FIRE_BOMB: _events.CancelEvent(EVENT_FIRE_BOMB); break; + case ACTION_ACTIVE_SNOBOLD: + _isActive = true; + break; default: break; } } - void UpdateAI(uint32 diff) override + void SetGUID(ObjectGuid guid, int32 id) override { - if (!UpdateVictim() || _targetDied) + if (id == DATA_NEW_TARGET) + if (Unit* target = ObjectAccessor::GetPlayer(*me, guid)) + { + _targetGUID = guid; + AttackStart(target); + _events.ScheduleEvent(EVENT_BATTER, Seconds(5)); + _events.ScheduleEvent(EVENT_HEAD_CRACK, Seconds(25)); + _events.ScheduleEvent(EVENT_SNOBOLLED, Milliseconds(500)); + } + } + + void AttackStart(Unit* who) override + { + //Snobold only melee attack players that is your vehicle + if (!_isActive || who->GetGUID() != _targetGUID) return; - if (Unit* target = ObjectAccessor::GetPlayer(*me, _targetGUID)) + ScriptedAI::AttackStart(who); + } + + void MountOnBoss() + { + Unit* gormok = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(NPC_GORMOK)); + if (gormok && gormok->IsAlive()) { - if (!target->IsAlive()) - { - Unit* gormok = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(NPC_GORMOK)); - if (gormok && gormok->IsAlive()) - { - SetCombatMovement(false); - _targetDied = true; + me->AttackStop(); + _targetGUID.Clear(); + _isActive = false; + _events.CancelEvent(EVENT_BATTER); + _events.CancelEvent(EVENT_HEAD_CRACK); - // looping through Gormoks seats - for (uint8 i = 0; i < MAX_SNOBOLDS; i++) - { - if (!gormok->GetVehicleKit()->GetPassenger(i)) - { - me->EnterVehicle(gormok, i); - DoAction(ACTION_ENABLE_FIRE_BOMB); - break; - } - } - } - else if (Unit* target2 = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + for (uint8 i = 0; i < MAX_SNOBOLDS; i++) + { + if (!gormok->GetVehicleKit()->GetPassenger(i)) { - _targetGUID = target2->GetGUID(); - me->GetMotionMaster()->MoveJump(*target2, 15.0f, 15.0f); + me->EnterVehicle(gormok, i); + DoAction(ACTION_ENABLE_FIRE_BOMB); + break; } } } + //Without Boss, snobolds should jump in another players + else if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, SnobolledTargetSelector(me))) + me->CastSpell(target, SPELL_RIDE_PLAYER, true); + } + void UpdateAI(uint32 diff) override + { _events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) @@ -416,35 +419,46 @@ class npc_snobold_vassal : public CreatureScript case EVENT_FIRE_BOMB: if (me->GetVehicleBase()) if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, -me->GetVehicleBase()->GetCombatReach(), true)) - me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_FIRE_BOMB, true); - _events.ScheduleEvent(EVENT_FIRE_BOMB, 20*IN_MILLISECONDS); - return; + me->CastSpell(target, SPELL_FIRE_BOMB); + _events.Repeat(Seconds(20)); + break; case EVENT_HEAD_CRACK: - // commented out while SPELL_SNOBOLLED gets fixed - //if (Unit* target = ObjectAccessor::GetPlayer(*me, m_uiTargetGUID)) - DoCastVictim(SPELL_HEAD_CRACK); - _events.ScheduleEvent(EVENT_HEAD_CRACK, 30*IN_MILLISECONDS); - return; + DoCast(me->GetVehicleBase(), SPELL_HEAD_CRACK); + _events.Repeat(Seconds(30)); + break; case EVENT_BATTER: - // commented out while SPELL_SNOBOLLED gets fixed - //if (Unit* target = ObjectAccessor::GetPlayer(*me, m_uiTargetGUID)) - DoCastVictim(SPELL_BATTER); - _events.ScheduleEvent(EVENT_BATTER, 10*IN_MILLISECONDS); - return; + DoCast(me->GetVehicleBase(), SPELL_BATTER); + _events.Repeat(Seconds(10)); + break; + case EVENT_SNOBOLLED: + DoCastAOE(SPELL_SNOBOLLED); + break; + case EVENT_CHECK_MOUNT: + if (!me->GetVehicleBase()) + MountOnBoss(); + _events.Repeat(Seconds(1)); + break; default: - return; + break; } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } - // do melee attack only when not on Gormoks back - if (!me->GetVehicleBase()) + if (!UpdateVictim()) + return; + + // do melee attack only if is in player back. + if (_isActive) DoMeleeAttackIfReady(); } + private: EventMap _events; InstanceScript* _instance; ObjectGuid _targetGUID; - bool _targetDied; + bool _isActive; }; CreatureAI* GetAI(Creature* creature) const override @@ -1145,6 +1159,138 @@ class boss_icehowl : public CreatureScript } }; +class spell_gormok_jump_to_hand : public SpellScriptLoader +{ +public: + spell_gormok_jump_to_hand() : SpellScriptLoader("spell_gormok_jump_to_hand") { } + + class spell_gormok_jump_to_hand_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gormok_jump_to_hand_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_RIDE_PLAYER)) + return false; + return true; + } + + bool Load() override + { + if (GetCaster() && GetCaster()->GetEntry() == NPC_SNOBOLD_VASSAL) + return true; + return false; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + { + if (CreatureAI* gormokAI = GetTarget()->ToCreature()->AI()) + { + if (Unit* target = gormokAI->SelectTarget(SELECT_TARGET_RANDOM, 0, SnobolledTargetSelector(GetTarget()))) + { + gormokAI->Talk(EMOTE_SNOBOLLED); + caster->GetAI()->DoAction(ACTION_ACTIVE_SNOBOLD); + caster->CastSpell(target, SPELL_RIDE_PLAYER, true); + } + } + } + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_gormok_jump_to_hand_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_gormok_jump_to_hand_AuraScript(); + } +}; + +class spell_gormok_ride_player : public SpellScriptLoader +{ +public: + spell_gormok_ride_player() : SpellScriptLoader("spell_gormok_ride_player") { } + + class spell_gormok_ride_player_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gormok_ride_player_AuraScript); + + bool Load() override + { + if (GetCaster() && GetCaster()->GetEntry() == NPC_SNOBOLD_VASSAL) + return true; + return false; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld()) + return; + + if (!target->CreateVehicleKit(PLAYER_VEHICLE_ID, 0)) + return; + + if (Unit *caster = GetCaster()) + caster->GetAI()->SetGUID(target->GetGUID(), DATA_NEW_TARGET); + } + + void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->RemoveVehicleKit(); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_gormok_ride_player_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_gormok_ride_player_AuraScript::AfterRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_gormok_ride_player_AuraScript(); + } +}; + +class spell_gormok_snobolled : public SpellScriptLoader +{ +public: + spell_gormok_snobolled() : SpellScriptLoader("spell_gormok_snobolled") { } + + class spell_gormok_snobolled_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gormok_snobolled_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_RIDE_PLAYER)) + return false; + return true; + } + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + if (!GetTarget()->HasAura(SPELL_RIDE_PLAYER)) + Remove(); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_gormok_snobolled_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_gormok_snobolled_AuraScript(); + } +}; + class spell_jormungars_paralytic_toxin : public SpellScriptLoader { public: @@ -1293,6 +1439,9 @@ void AddSC_boss_northrend_beasts() new npc_snobold_vassal(); new npc_firebomb(); new spell_gormok_fire_bomb(); + new spell_gormok_jump_to_hand(); + new spell_gormok_ride_player(); + new spell_gormok_snobolled(); new boss_acidmaw(); new boss_dreadscale(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index 5f884ccee9e..85126b35cdb 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -56,21 +56,26 @@ enum Spells SPELL_MANA_BARRIER = 70842, SPELL_SHADOW_BOLT = 71254, SPELL_DEATH_AND_DECAY = 71001, - SPELL_DOMINATE_MIND_H = 71289, + SPELL_DOMINATE_MIND = 71289, + SPELL_DOMINATE_MIND_SCALE = 71290, SPELL_FROSTBOLT = 71420, SPELL_FROSTBOLT_VOLLEY = 72905, SPELL_TOUCH_OF_INSIGNIFICANCE = 71204, SPELL_SUMMON_SHADE = 71363, - SPELL_SHADOW_CHANNELING = 43897, // Prefight, during intro + SPELL_SHADOW_CHANNELING = 43897, SPELL_DARK_TRANSFORMATION_T = 70895, SPELL_DARK_EMPOWERMENT_T = 70896, SPELL_DARK_MARTYRDOM_T = 70897, + SPELL_SUMMON_SPIRITS = 72478, // Achievement SPELL_FULL_HOUSE = 72827, // does not exist in dbc but still can be used for criteria check // Both Adds SPELL_TELEPORT_VISUAL = 41236, + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_FULL_HEAL = 17683, + SPELL_PERMANENT_FEIGN_DEATH = 70628, // Fanatics SPELL_DARK_TRANSFORMATION = 70900, @@ -86,7 +91,7 @@ enum Spells SPELL_DEATHCHILL_BOLT = 70594, SPELL_DEATHCHILL_BLAST = 70906, SPELL_CURSE_OF_TORPOR = 71237, - SPELL_SHORUD_OF_THE_OCCULT = 70768, + SPELL_SHROUD_OF_THE_OCCULT = 70768, SPELL_ADHERENT_S_DETERMINATION = 71234, SPELL_DARK_MARTYRDOM_ADHERENT = 70903, @@ -108,44 +113,6 @@ enum Spells enum EventTypes { - // Lady Deathwhisper - EVENT_INTRO_2 = 1, - EVENT_INTRO_3 = 2, - EVENT_INTRO_4 = 3, - EVENT_INTRO_5 = 4, - EVENT_INTRO_6 = 5, - EVENT_INTRO_7 = 6, - EVENT_BERSERK = 7, - EVENT_DEATH_AND_DECAY = 8, - EVENT_DOMINATE_MIND_H = 9, - - // Phase 1 only - EVENT_P1_SUMMON_WAVE = 10, - EVENT_P1_SHADOW_BOLT = 11, - EVENT_P1_EMPOWER_CULTIST = 12, - EVENT_P1_REANIMATE_CULTIST = 13, - - // Phase 2 only - EVENT_P2_SUMMON_WAVE = 14, - EVENT_P2_FROSTBOLT = 15, - EVENT_P2_FROSTBOLT_VOLLEY = 16, - EVENT_P2_TOUCH_OF_INSIGNIFICANCE = 17, - EVENT_P2_SUMMON_SHADE = 18, - - // Shared adds events - EVENT_CULTIST_DARK_MARTYRDOM = 19, - - // Cult Fanatic - EVENT_FANATIC_NECROTIC_STRIKE = 20, - EVENT_FANATIC_SHADOW_CLEAVE = 21, - EVENT_FANATIC_VAMPIRIC_MIGHT = 22, - - // Cult Adherent - EVENT_ADHERENT_FROST_FEVER = 23, - EVENT_ADHERENT_DEATHCHILL = 24, - EVENT_ADHERENT_CURSE_OF_TORPOR = 25, - EVENT_ADHERENT_SHORUD_OF_THE_OCCULT = 26, - // Darnavan EVENT_DARNAVAN_BLADESTORM = 27, EVENT_DARNAVAN_CHARGE = 28, @@ -163,6 +130,13 @@ enum Phases PHASE_TWO = 3 }; +enum Groups +{ + GROUP_INTRO = 0, + GROUP_ONE = 1, + GROUP_TWO = 2 +}; + enum DeprogrammingData { NPC_DARNAVAN_10 = 38472, @@ -185,8 +159,6 @@ enum Actions uint32 const SummonEntries[2] = {NPC_CULT_FANATIC, NPC_CULT_ADHERENT}; -#define GUID_CULTIST 1 - Position const SummonPositions[7] = { {-578.7066f, 2154.167f, 51.01529f, 1.692969f}, // 1 Left Door 1 (Cult Fanatic) @@ -229,43 +201,67 @@ class boss_lady_deathwhisper : public CreatureScript void Initialize() { _waveCounter = 0; - _nextVengefulShadeTargetGUID.Clear(); + _nextVengefulShadeTargetGUID.clear(); + _cultistQueue.clear(); _darnavanGUID.Clear(); + _phase = PHASE_ALL; + scheduler.SetValidator([this] + { + return !(me->HasUnitState(UNIT_STATE_CASTING) && _phase != PHASE_INTRO); + }); } void Reset() override { - _Reset(); - me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA)); - events.SetPhase(PHASE_ONE); Initialize(); - DoCast(me, SPELL_SHADOW_CHANNELING); - me->RemoveAurasDueToSpell(SPELL_BERSERK); - me->RemoveAurasDueToSpell(SPELL_MANA_BARRIER); + _phase = PHASE_ONE; + DoCastSelf(SPELL_SHADOW_CHANNELING); + me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA)); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); } void DoAction(int32 action) override { - switch (action) + if (action != ACTION_START_INTRO) + return; + + if (!_introDone) { - case ACTION_START_INTRO: - if (!_introDone) + _introDone = true; + Talk(SAY_INTRO_1); + _phase = PHASE_INTRO; + scheduler.Schedule(Seconds(10), GROUP_INTRO, [this](TaskContext context) + { + switch (context.GetRepeatCounter()) { - _introDone = true; - Talk(SAY_INTRO_1); - events.SetPhase(PHASE_INTRO); - events.ScheduleEvent(EVENT_INTRO_2, 11000, 0, PHASE_INTRO); - events.ScheduleEvent(EVENT_INTRO_3, 21000, 0, PHASE_INTRO); - events.ScheduleEvent(EVENT_INTRO_4, 31500, 0, PHASE_INTRO); - events.ScheduleEvent(EVENT_INTRO_5, 39500, 0, PHASE_INTRO); - events.ScheduleEvent(EVENT_INTRO_6, 48500, 0, PHASE_INTRO); - events.ScheduleEvent(EVENT_INTRO_7, 58000, 0, PHASE_INTRO); + case 0: + Talk(SAY_INTRO_2); + context.Repeat(Seconds(21)); + break; + case 1: + Talk(SAY_INTRO_3); + context.Repeat(Seconds(11)); + break; + case 2: + Talk(SAY_INTRO_4); + context.Repeat(Seconds(9)); + break; + case 3: + Talk(SAY_INTRO_5); + context.Repeat(Seconds(21)); + break; + case 4: + Talk(SAY_INTRO_6); + context.Repeat(Seconds(10)); + break; + case 5: + Talk(SAY_INTRO_7); + return; + default: + break; } - break; - default: - break; + }); } } @@ -274,7 +270,7 @@ class boss_lady_deathwhisper : public CreatureScript if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; - if (victim && me->Attack(victim, true) && !events.IsInPhase(PHASE_ONE)) + if (victim && me->Attack(victim, true) && _phase != PHASE_ONE) me->GetMotionMaster()->MoveChase(victim); } @@ -282,31 +278,61 @@ class boss_lady_deathwhisper : public CreatureScript { if (!instance->CheckRequiredBosses(DATA_LADY_DEATHWHISPER, who->ToPlayer())) { - EnterEvadeMode(); + EnterEvadeMode(EVADE_REASON_SEQUENCE_BREAK); instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT); return; } + me->SetCombatPulseDelay(5); me->setActive(true); DoZoneInCombat(); - - events.Reset(); - events.SetPhase(PHASE_ONE); + _phase = PHASE_ONE; + scheduler.CancelGroup(GROUP_INTRO); // phase-independent events - events.ScheduleEvent(EVENT_BERSERK, 600000); - events.ScheduleEvent(EVENT_DEATH_AND_DECAY, 10000); + scheduler + .Schedule(Minutes(10), [this](TaskContext /*context*/) + { + DoCastSelf(SPELL_BERSERK); + Talk(SAY_BERSERK); + }) + .Schedule(Seconds(17), [this](TaskContext death_and_decay) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_DEATH_AND_DECAY); + death_and_decay.Repeat(Seconds(22), Seconds(30)); + }); + if (GetDifficulty() != RAID_DIFFICULTY_10MAN_NORMAL) + scheduler.Schedule(Seconds(27), [this](TaskContext dominate_mind) + { + Talk(SAY_DOMINATE_MIND); + for (uint8 i = 0; i < _dominateMindCount; i++) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_DOMINATE_MIND)) + DoCast(target, SPELL_DOMINATE_MIND); + dominate_mind.Repeat(Seconds(40), Seconds(45)); + }); // phase one only - events.ScheduleEvent(EVENT_P1_SUMMON_WAVE, 5000, 0, PHASE_ONE); - events.ScheduleEvent(EVENT_P1_SHADOW_BOLT, urand(5500, 6000), 0, PHASE_ONE); - events.ScheduleEvent(EVENT_P1_EMPOWER_CULTIST, urand(20000, 30000), 0, PHASE_ONE); - if (GetDifficulty() != RAID_DIFFICULTY_10MAN_NORMAL) - events.ScheduleEvent(EVENT_DOMINATE_MIND_H, 27000); + scheduler + .Schedule(Seconds(5), GROUP_ONE, [this](TaskContext wave) + { + SummonWaveP1(); + wave.Repeat(Seconds(IsHeroic() ? 45 : 60)); + }) + .Schedule(Seconds(2), GROUP_ONE, [this](TaskContext shadow_bolt) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_SHADOW_BOLT); + shadow_bolt.Repeat(Milliseconds(2450), Milliseconds(3600)); + }) + .Schedule(Seconds(15), GROUP_ONE, [this](TaskContext context) + { + DoImproveCultist(); + context.Repeat(Seconds(25)); + }); Talk(SAY_AGGRO); DoStartNoMovement(who); me->RemoveAurasDueToSpell(SPELL_SHADOW_CHANNELING); - DoCast(me, SPELL_MANA_BARRIER, true); - + DoCastSelf(SPELL_MANA_BARRIER, true); instance->SetBossState(DATA_LADY_DEATHWHISPER, IN_PROGRESS); } @@ -338,7 +364,7 @@ class boss_lady_deathwhisper : public CreatureScript { if (Group* group = owner->GetGroup()) { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) if (Player* member = itr->GetSource()) member->KilledMonsterCredit(NPC_DARNAVAN_CREDIT); } @@ -351,17 +377,14 @@ class boss_lady_deathwhisper : public CreatureScript _JustDied(); } - void JustReachedHome() override + void EnterEvadeMode(EvadeReason /*why*/) override { - _JustReachedHome(); - instance->SetBossState(DATA_LADY_DEATHWHISPER, FAIL); - + scheduler.CancelAll(); summons.DespawnAll(); if (Creature* darnavan = ObjectAccessor::GetCreature(*me, _darnavanGUID)) - { darnavan->DespawnOrUnsummon(); - _darnavanGUID.Clear(); - } + + _DespawnAtEvade(); } void KilledUnit(Unit* victim) override @@ -373,151 +396,98 @@ class boss_lady_deathwhisper : public CreatureScript void DamageTaken(Unit* /*damageDealer*/, uint32& damage) override { // phase transition - if (events.IsInPhase(PHASE_ONE) && damage > me->GetPower(POWER_MANA)) + if (_phase == PHASE_ONE && damage > me->GetPower(POWER_MANA)) { + _phase = PHASE_TWO; Talk(SAY_PHASE_2); Talk(EMOTE_PHASE_2); DoStartMovement(me->GetVictim()); + DoResetThreat(); damage -= me->GetPower(POWER_MANA); me->SetPower(POWER_MANA, 0); me->RemoveAurasDueToSpell(SPELL_MANA_BARRIER); - events.SetPhase(PHASE_TWO); - events.ScheduleEvent(EVENT_P2_FROSTBOLT, urand(10000, 12000), 0, PHASE_TWO); - events.ScheduleEvent(EVENT_P2_FROSTBOLT_VOLLEY, urand(19000, 21000), 0, PHASE_TWO); - events.ScheduleEvent(EVENT_P2_TOUCH_OF_INSIGNIFICANCE, urand(6000, 9000), 0, PHASE_TWO); - events.ScheduleEvent(EVENT_P2_SUMMON_SHADE, urand(12000, 15000), 0, PHASE_TWO); + scheduler.CancelGroup(GROUP_ONE); + + scheduler + .Schedule(Seconds(12), GROUP_TWO, [this](TaskContext frostbolt) + { + DoCastVictim(SPELL_FROSTBOLT); + frostbolt.Repeat(); + }) + .Schedule(Seconds(20), GROUP_TWO, [this](TaskContext frostboldVolley) + { + DoCastAOE(SPELL_FROSTBOLT_VOLLEY); + frostboldVolley.Repeat(); + }) + .Schedule(Seconds(6), Seconds(9), GROUP_TWO, [this](TaskContext touch) + { + if (me->GetVictim()) + me->AddAura(SPELL_TOUCH_OF_INSIGNIFICANCE, me->EnsureVictim()); + touch.Repeat(); + }) + .Schedule(Seconds(12), GROUP_TWO, [this](TaskContext summonShade) + { + me->CastCustomSpell(SPELL_SUMMON_SPIRITS, SPELLVALUE_MAX_TARGETS, Is25ManRaid() ? 2 : 1); + summonShade.Repeat(); + }); + // on heroic mode Lady Deathwhisper is immune to taunt effects in phase 2 and continues summoning adds if (IsHeroic()) { me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); - events.ScheduleEvent(EVENT_P2_SUMMON_WAVE, 45000, 0, PHASE_TWO); + scheduler.Schedule(Seconds(), GROUP_TWO, [this](TaskContext context) + { + SummonWaveP2(); + context.Repeat(Seconds(45)); + }); } } } - void JustSummoned(Creature* summon) override + void SpellHitTarget(Unit* target, const SpellInfo* spell) override { - if (summon->GetEntry() == NPC_DARNAVAN) - _darnavanGUID = summon->GetGUID(); - else - summons.Summon(summon); + if (spell->Id == SPELL_SUMMON_SPIRITS) + _nextVengefulShadeTargetGUID.push_back(target->GetGUID()); + } - Unit* target = NULL; - if (summon->GetEntry() == NPC_VENGEFUL_SHADE) + void JustSummoned(Creature* summon) override + { + switch (summon->GetEntry()) { - target = ObjectAccessor::GetUnit(*me, _nextVengefulShadeTargetGUID); // Vengeful Shade - _nextVengefulShadeTargetGUID.Clear(); + case NPC_DARNAVAN_10: + case NPC_DARNAVAN_25: + _darnavanGUID = summon->GetGUID(); + summon->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM)); + return; + case NPC_VENGEFUL_SHADE: + if (_nextVengefulShadeTargetGUID.empty()) + break; + summon->AI()->SetGUID(_nextVengefulShadeTargetGUID.front()); + _nextVengefulShadeTargetGUID.pop_front(); + break; + case NPC_CULT_ADHERENT: + case NPC_CULT_FANATIC: + _cultistQueue.push_back(summon->GetGUID()); + summon->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM)); + break; + default: + break; } - else - target = SelectTarget(SELECT_TARGET_RANDOM); // Wave adds - - summon->AI()->AttackStart(target); // CAN be NULL - if (summon->GetEntry() == NPC_REANIMATED_FANATIC) - summon->CastSpell(summon, SPELL_FANATIC_S_DETERMINATION, true); - else if (summon->GetEntry() == NPC_REANIMATED_ADHERENT) - summon->CastSpell(summon, SPELL_ADHERENT_S_DETERMINATION, true); + summons.Summon(summon); } void UpdateAI(uint32 diff) override { - if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) + if (!UpdateVictim() && _phase != PHASE_INTRO) return; - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING) && !events.IsInPhase(PHASE_INTRO)) - return; - - while (uint32 eventId = events.ExecuteEvent()) + scheduler.Update(diff, [this] { - switch (eventId) - { - case EVENT_INTRO_2: - Talk(SAY_INTRO_2); - break; - case EVENT_INTRO_3: - Talk(SAY_INTRO_3); - break; - case EVENT_INTRO_4: - Talk(SAY_INTRO_4); - break; - case EVENT_INTRO_5: - Talk(SAY_INTRO_5); - break; - case EVENT_INTRO_6: - Talk(SAY_INTRO_6); - break; - case EVENT_INTRO_7: - Talk(SAY_INTRO_7); - break; - case EVENT_DEATH_AND_DECAY: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_DEATH_AND_DECAY); - events.ScheduleEvent(EVENT_DEATH_AND_DECAY, urand(22000, 30000)); - break; - case EVENT_DOMINATE_MIND_H: - Talk(SAY_DOMINATE_MIND); - for (uint8 i = 0; i < _dominateMindCount; i++) - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_DOMINATE_MIND_H)) - DoCast(target, SPELL_DOMINATE_MIND_H); - events.ScheduleEvent(EVENT_DOMINATE_MIND_H, urand(40000, 45000)); - break; - case EVENT_P1_SUMMON_WAVE: - SummonWaveP1(); - events.ScheduleEvent(EVENT_P1_SUMMON_WAVE, IsHeroic() ? 45000 : 60000, 0, PHASE_ONE); - break; - case EVENT_P1_SHADOW_BOLT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_SHADOW_BOLT); - events.ScheduleEvent(EVENT_P1_SHADOW_BOLT, urand(5000, 8000), 0, PHASE_ONE); - break; - case EVENT_P1_REANIMATE_CULTIST: - ReanimateCultist(); - break; - case EVENT_P1_EMPOWER_CULTIST: - EmpowerCultist(); - events.ScheduleEvent(EVENT_P1_EMPOWER_CULTIST, urand(18000, 25000)); - break; - case EVENT_P2_FROSTBOLT: - DoCastVictim(SPELL_FROSTBOLT); - events.ScheduleEvent(EVENT_P2_FROSTBOLT, urand(10000, 11000), 0, PHASE_TWO); - break; - case EVENT_P2_FROSTBOLT_VOLLEY: - DoCastAOE(SPELL_FROSTBOLT_VOLLEY); - events.ScheduleEvent(EVENT_P2_FROSTBOLT_VOLLEY, urand(13000, 15000), 0, PHASE_TWO); - break; - case EVENT_P2_TOUCH_OF_INSIGNIFICANCE: - DoCastVictim(SPELL_TOUCH_OF_INSIGNIFICANCE); - events.ScheduleEvent(EVENT_P2_TOUCH_OF_INSIGNIFICANCE, urand(9000, 13000), 0, PHASE_TWO); - break; - case EVENT_P2_SUMMON_SHADE: - if (Unit* shadeTarget = SelectTarget(SELECT_TARGET_RANDOM, 1)) - { - _nextVengefulShadeTargetGUID = shadeTarget->GetGUID(); - DoCast(shadeTarget, SPELL_SUMMON_SHADE); - } - events.ScheduleEvent(EVENT_P2_SUMMON_SHADE, urand(18000, 23000), 0, PHASE_TWO); - break; - case EVENT_P2_SUMMON_WAVE: - SummonWaveP2(); - events.ScheduleEvent(EVENT_P2_SUMMON_WAVE, 45000, 0, PHASE_TWO); - break; - case EVENT_BERSERK: - DoCast(me, SPELL_BERSERK); - Talk(SAY_BERSERK); - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING) && !events.IsInPhase(PHASE_INTRO)) - return; - } - - // We should not melee attack when barrier is up - if (me->HasAura(SPELL_MANA_BARRIER)) - return; - - DoMeleeAttackIfReady(); + // We should not melee attack when barrier is up + if (!me->HasAura(SPELL_MANA_BARRIER)) + DoMeleeAttackIfReady(); + }); } // summoning function for first phase @@ -568,72 +538,40 @@ class boss_lady_deathwhisper : public CreatureScript summon->CastSpell(summon, SPELL_TELEPORT_VISUAL); } - void SetGUID(ObjectGuid guid, int32 id/* = 0*/) override + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override { - if (id != GUID_CULTIST) - return; - - _reanimationQueue.push_back(guid); - events.ScheduleEvent(EVENT_P1_REANIMATE_CULTIST, 3000, 0, PHASE_ONE); + if (summon->GetEntry() == NPC_CULT_ADHERENT || summon->GetEntry() == NPC_CULT_FANATIC) + _cultistQueue.remove(summon->GetGUID()); } - void ReanimateCultist() + void DoImproveCultist() { - if (_reanimationQueue.empty()) + if (_cultistQueue.empty()) return; - ObjectGuid cultistGUID = _reanimationQueue.front(); - Creature* cultist = ObjectAccessor::GetCreature(*me, cultistGUID); - _reanimationQueue.pop_front(); + _cultistGUID = Trinity::Containers::SelectRandomContainerElement(_cultistQueue); + _cultistQueue.remove(_cultistGUID); + Creature* cultist = ObjectAccessor::GetCreature(*me, _cultistGUID); if (!cultist) return; - Talk(SAY_ANIMATE_DEAD); - DoCast(cultist, SPELL_DARK_MARTYRDOM_T); - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - if (spell->Id == SPELL_DARK_MARTYRDOM_T) + if (RAND(0,1)) + me->CastSpell(cultist, SPELL_DARK_MARTYRDOM_T); + else { - Position pos = target->GetPosition(); - if (target->GetEntry() == NPC_CULT_FANATIC) - me->SummonCreature(NPC_REANIMATED_FANATIC, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); - else - me->SummonCreature(NPC_REANIMATED_ADHERENT, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); - - if (TempSummon* summon = target->ToTempSummon()) - summon->UnSummon(); + me->CastSpell(cultist, cultist->GetEntry() == NPC_CULT_FANATIC ? SPELL_DARK_TRANSFORMATION_T : SPELL_DARK_EMPOWERMENT_T, true); + Talk(uint8(cultist->GetEntry() == NPC_CULT_FANATIC ? SAY_DARK_TRANSFORMATION : SAY_DARK_EMPOWERMENT)); } } - void EmpowerCultist() - { - if (summons.empty()) - return; - - std::list<Creature*> temp; - for (SummonList::iterator itr = summons.begin(); itr != summons.end(); ++itr) - if (Creature* cre = ObjectAccessor::GetCreature(*me, *itr)) - if (cre->IsAlive() && (cre->GetEntry() == NPC_CULT_FANATIC || cre->GetEntry() == NPC_CULT_ADHERENT)) - temp.push_back(cre); - - // noone to empower - if (temp.empty()) - return; - - // select random cultist - Creature* cultist = Trinity::Containers::SelectRandomContainerElement(temp); - DoCast(cultist, cultist->GetEntry() == NPC_CULT_FANATIC ? SPELL_DARK_TRANSFORMATION_T : SPELL_DARK_EMPOWERMENT_T, true); - Talk(uint8(cultist->GetEntry() == NPC_CULT_FANATIC ? SAY_DARK_TRANSFORMATION : SAY_DARK_EMPOWERMENT)); - } - private: - ObjectGuid _nextVengefulShadeTargetGUID; ObjectGuid _darnavanGUID; - GuidDeque _reanimationQueue; + ObjectGuid _cultistGUID; + GuidList _cultistQueue; + GuidList _nextVengefulShadeTargetGUID; uint32 _waveCounter; uint8 const _dominateMindCount; + uint8 _phase; bool _introDone; }; @@ -643,8 +581,6 @@ class boss_lady_deathwhisper : public CreatureScript } }; -typedef boss_lady_deathwhisper::boss_lady_deathwhisperAI DeathwisperAI; - class npc_cult_fanatic : public CreatureScript { public: @@ -652,71 +588,91 @@ class npc_cult_fanatic : public CreatureScript struct npc_cult_fanaticAI : public ScriptedAI { - npc_cult_fanaticAI(Creature* creature) : ScriptedAI(creature) { } + npc_cult_fanaticAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } void Reset() override { - Events.Reset(); - Events.ScheduleEvent(EVENT_FANATIC_NECROTIC_STRIKE, urand(10000, 12000)); - Events.ScheduleEvent(EVENT_FANATIC_SHADOW_CLEAVE, urand(14000, 16000)); - Events.ScheduleEvent(EVENT_FANATIC_VAMPIRIC_MIGHT, urand(20000, 27000)); - if (me->GetEntry() == NPC_CULT_FANATIC) - Events.ScheduleEvent(EVENT_CULTIST_DARK_MARTYRDOM, urand(18000, 32000)); + _scheduler.CancelAll(); + _scheduler + .SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }) + .Schedule(Seconds(17), [this](TaskContext vampiric_might) + { + DoCastSelf(SPELL_VAMPIRIC_MIGHT); + vampiric_might.Repeat(Seconds(25)); + }) + .Schedule(Seconds(12), [this](TaskContext shadow_cleave) + { + DoCastVictim(SPELL_SHADOW_CLEAVE); + shadow_cleave.Repeat(Seconds(14)); + }) + .Schedule(Seconds(10), [this](TaskContext necrotic_strike) + { + DoCastVictim(SPELL_NECROTIC_STRIKE); + necrotic_strike.Repeat(Seconds(17)); + }); } void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override { - if (spell->Id == SPELL_DARK_TRANSFORMATION) - me->UpdateEntry(NPC_DEFORMED_FANATIC); - else if (spell->Id == SPELL_DARK_TRANSFORMATION_T) + switch (spell->Id) { - Events.CancelEvent(EVENT_CULTIST_DARK_MARTYRDOM); - me->InterruptNonMeleeSpells(true); - DoCast(me, SPELL_DARK_TRANSFORMATION); + case SPELL_DARK_TRANSFORMATION_T: + me->InterruptNonMeleeSpells(true); + DoCastSelf(SPELL_DARK_TRANSFORMATION); + break; + case SPELL_DARK_TRANSFORMATION: + DoCastSelf(SPELL_FULL_HEAL); + me->UpdateEntry(NPC_DEFORMED_FANATIC); + break; + case SPELL_DARK_MARTYRDOM_T: + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + me->AttackStop(); + DoCastSelf(SPELL_DARK_MARTYRDOM_FANATIC); + break; + case SPELL_DARK_MARTYRDOM_FANATIC: + _scheduler + .Schedule(Seconds(2), [this](TaskContext /*context*/) + { + me->UpdateEntry(NPC_REANIMATED_FANATIC); + DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH); + DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS); + DoCastSelf(SPELL_FULL_HEAL, true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_UNK_29 | UNIT_FLAG_NOT_SELECTABLE); + }) + .Schedule(Seconds(6), [this](TaskContext /*context*/) + { + me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_UNK_29 | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(me); + + if (Creature* ladyDeathwhisper = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_LADY_DEATHWHISPER))) + ladyDeathwhisper->AI()->Talk(SAY_ANIMATE_DEAD); + }); + break; + default: + break; } } void UpdateAI(uint32 diff) override { - if (!UpdateVictim()) - return; - - Events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) + if (!UpdateVictim() && !me->HasAura(SPELL_PERMANENT_FEIGN_DEATH)) return; - while (uint32 eventId = Events.ExecuteEvent()) + _scheduler.Update(diff, [this] { - switch (eventId) - { - case EVENT_FANATIC_NECROTIC_STRIKE: - DoCastVictim(SPELL_NECROTIC_STRIKE); - Events.ScheduleEvent(EVENT_FANATIC_NECROTIC_STRIKE, urand(11000, 13000)); - break; - case EVENT_FANATIC_SHADOW_CLEAVE: - DoCastVictim(SPELL_SHADOW_CLEAVE); - Events.ScheduleEvent(EVENT_FANATIC_SHADOW_CLEAVE, urand(9500, 11000)); - break; - case EVENT_FANATIC_VAMPIRIC_MIGHT: - DoCast(me, SPELL_VAMPIRIC_MIGHT); - Events.ScheduleEvent(EVENT_FANATIC_VAMPIRIC_MIGHT, urand(20000, 27000)); - break; - case EVENT_CULTIST_DARK_MARTYRDOM: - DoCast(me, SPELL_DARK_MARTYRDOM_FANATIC); - Events.ScheduleEvent(EVENT_CULTIST_DARK_MARTYRDOM, urand(16000, 21000)); - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); + DoMeleeAttackIfReady(); + }); } protected: - EventMap Events; + TaskScheduler _scheduler; + InstanceScript* _instance; }; CreatureAI* GetAI(Creature* creature) const override @@ -732,80 +688,88 @@ class npc_cult_adherent : public CreatureScript struct npc_cult_adherentAI : public ScriptedAI { - npc_cult_adherentAI(Creature* creature) : ScriptedAI(creature) { } + npc_cult_adherentAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } void Reset() override { - Events.Reset(); - Events.ScheduleEvent(EVENT_ADHERENT_FROST_FEVER, urand(10000, 12000)); - Events.ScheduleEvent(EVENT_ADHERENT_DEATHCHILL, urand(14000, 16000)); - Events.ScheduleEvent(EVENT_ADHERENT_CURSE_OF_TORPOR, urand(14000, 16000)); - Events.ScheduleEvent(EVENT_ADHERENT_SHORUD_OF_THE_OCCULT, urand(32000, 39000)); - if (me->GetEntry() == NPC_CULT_ADHERENT) - Events.ScheduleEvent(EVENT_CULTIST_DARK_MARTYRDOM, urand(18000, 32000)); + _scheduler.CancelAll(); + _scheduler + .SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }) + .Schedule(Seconds(5), [this](TaskContext deathchill) + { + if (me->GetEntry() == NPC_EMPOWERED_ADHERENT) + DoCastVictim(SPELL_DEATHCHILL_BLAST); + else + DoCastVictim(SPELL_DEATHCHILL_BOLT); + deathchill.Repeat(Milliseconds(2500)); + }) + .Schedule(Seconds(15), [this](TaskContext shroud_of_the_occult) + { + DoCastSelf(SPELL_SHROUD_OF_THE_OCCULT); + shroud_of_the_occult.Repeat(Seconds(10)); + }) + .Schedule(Seconds(15), [this](TaskContext curse_of_torpor) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) + DoCast(target, SPELL_CURSE_OF_TORPOR); + curse_of_torpor.Repeat(Seconds(18)); + }); } void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override { - if (spell->Id == SPELL_DARK_EMPOWERMENT) - me->UpdateEntry(NPC_EMPOWERED_ADHERENT); - else if (spell->Id == SPELL_DARK_EMPOWERMENT_T) + switch (spell->Id) { - Events.CancelEvent(EVENT_CULTIST_DARK_MARTYRDOM); - me->InterruptNonMeleeSpells(true); - DoCast(me, SPELL_DARK_EMPOWERMENT); + case SPELL_DARK_EMPOWERMENT_T: + me->UpdateEntry(NPC_EMPOWERED_ADHERENT); + break; + case SPELL_DARK_MARTYRDOM_T: + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + me->AttackStop(); + DoCastSelf(SPELL_DARK_MARTYRDOM_ADHERENT); + break; + case SPELL_DARK_MARTYRDOM_ADHERENT: + _scheduler + .Schedule(Seconds(2), [this](TaskContext /*context*/) + { + me->UpdateEntry(NPC_REANIMATED_ADHERENT); + DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH); + DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS); + DoCastSelf(SPELL_FULL_HEAL, true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_UNK_29 | UNIT_FLAG_NOT_SELECTABLE); + }) + .Schedule(Seconds(6), [this](TaskContext /*context*/) + { + me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_UNK_29 | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + DoCastSelf(SPELL_SHROUD_OF_THE_OCCULT); + DoZoneInCombat(me); + + if (Creature* ladyDeathwhisper = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_LADY_DEATHWHISPER))) + ladyDeathwhisper->AI()->Talk(SAY_ANIMATE_DEAD); + }); + break; + default: + break; } } void UpdateAI(uint32 diff) override { - if (!UpdateVictim()) + if (!UpdateVictim() && !me->HasAura(SPELL_PERMANENT_FEIGN_DEATH)) return; - Events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = Events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_ADHERENT_FROST_FEVER: - DoCastVictim(SPELL_FROST_FEVER); - Events.ScheduleEvent(EVENT_ADHERENT_FROST_FEVER, urand(9000, 13000)); - break; - case EVENT_ADHERENT_DEATHCHILL: - if (me->GetEntry() == NPC_EMPOWERED_ADHERENT) - DoCastVictim(SPELL_DEATHCHILL_BLAST); - else - DoCastVictim(SPELL_DEATHCHILL_BOLT); - Events.ScheduleEvent(EVENT_ADHERENT_DEATHCHILL, urand(9000, 13000)); - break; - case EVENT_ADHERENT_CURSE_OF_TORPOR: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) - DoCast(target, SPELL_CURSE_OF_TORPOR); - Events.ScheduleEvent(EVENT_ADHERENT_CURSE_OF_TORPOR, urand(9000, 13000)); - break; - case EVENT_ADHERENT_SHORUD_OF_THE_OCCULT: - DoCast(me, SPELL_SHORUD_OF_THE_OCCULT); - Events.ScheduleEvent(EVENT_ADHERENT_SHORUD_OF_THE_OCCULT, urand(27000, 32000)); - break; - case EVENT_CULTIST_DARK_MARTYRDOM: - DoCast(me, SPELL_DARK_MARTYRDOM_ADHERENT); - Events.ScheduleEvent(EVENT_CULTIST_DARK_MARTYRDOM, urand(16000, 21000)); - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); + _scheduler.Update(diff); } protected: - EventMap Events; + TaskScheduler _scheduler; + InstanceScript* _instance; }; CreatureAI* GetAI(Creature* creature) const override @@ -821,15 +785,28 @@ class npc_vengeful_shade : public CreatureScript struct npc_vengeful_shadeAI : public ScriptedAI { - npc_vengeful_shadeAI(Creature* creature) : ScriptedAI(creature) - { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } + npc_vengeful_shadeAI(Creature* creature) : ScriptedAI(creature) { } void Reset() override { + me->SetReactState(REACT_PASSIVE); me->AddAura(SPELL_VENGEFUL_BLAST_PASSIVE, me); + + _scheduler + .Schedule(Seconds(2), [this](TaskContext /*context*/) + { + me->SetReactState(REACT_AGGRESSIVE); + me->AI()->AttackStart(ObjectAccessor::GetUnit(*me, _targetGUID)); + }) + .Schedule(Seconds(7), [this](TaskContext /*context*/) + { + me->KillSelf(); + }); + } + + void SetGUID(ObjectGuid guid, int32 /*type*/) override + { + _targetGUID = guid; } void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override @@ -846,6 +823,18 @@ class npc_vengeful_shade : public CreatureScript break; } } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff, [this] + { + DoMeleeAttackIfReady(); + }); + } + + private: + TaskScheduler _scheduler; + ObjectGuid _targetGUID; }; CreatureAI* GetAI(Creature* creature) const override @@ -875,10 +864,10 @@ class npc_darnavan : public CreatureScript void Reset() override { _events.Reset(); - _events.ScheduleEvent(EVENT_DARNAVAN_BLADESTORM, 10000); - _events.ScheduleEvent(EVENT_DARNAVAN_INTIMIDATING_SHOUT, urand(20000, 25000)); - _events.ScheduleEvent(EVENT_DARNAVAN_MORTAL_STRIKE, urand(25000, 30000)); - _events.ScheduleEvent(EVENT_DARNAVAN_SUNDER_ARMOR, urand(5000, 8000)); + _events.ScheduleEvent(EVENT_DARNAVAN_BLADESTORM, Seconds(10)); + _events.ScheduleEvent(EVENT_DARNAVAN_INTIMIDATING_SHOUT, Seconds(20), Seconds(25)); + _events.ScheduleEvent(EVENT_DARNAVAN_MORTAL_STRIKE, Seconds(25), Seconds(30)); + _events.ScheduleEvent(EVENT_DARNAVAN_SUNDER_ARMOR, Seconds(5), Seconds(8)); Initialize(); } @@ -889,7 +878,7 @@ class npc_darnavan : public CreatureScript { if (Group* group = owner->GetGroup()) { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) if (Player* member = itr->GetSource()) member->FailQuest(QUEST_DEPROGRAMMING); } @@ -925,7 +914,7 @@ class npc_darnavan : public CreatureScript { DoCastVictim(SPELL_SHATTERING_THROW); _canShatter = false; - _events.ScheduleEvent(EVENT_DARNAVAN_SHATTERING_THROW, 30000); + _events.ScheduleEvent(EVENT_DARNAVAN_SHATTERING_THROW, Seconds(30)); return; } @@ -933,7 +922,7 @@ class npc_darnavan : public CreatureScript { DoCastVictim(SPELL_CHARGE); _canCharge = false; - _events.ScheduleEvent(EVENT_DARNAVAN_CHARGE, 20000); + _events.ScheduleEvent(EVENT_DARNAVAN_CHARGE, Seconds(20)); return; } @@ -943,25 +932,25 @@ class npc_darnavan : public CreatureScript { case EVENT_DARNAVAN_BLADESTORM: DoCast(SPELL_BLADESTORM); - _events.ScheduleEvent(EVENT_DARNAVAN_BLADESTORM, urand(90000, 100000)); + _events.ScheduleEvent(EVENT_DARNAVAN_BLADESTORM, Seconds(90), Seconds(100)); break; case EVENT_DARNAVAN_CHARGE: _canCharge = true; break; case EVENT_DARNAVAN_INTIMIDATING_SHOUT: DoCast(SPELL_INTIMIDATING_SHOUT); - _events.ScheduleEvent(EVENT_DARNAVAN_INTIMIDATING_SHOUT, urand(90000, 120000)); + _events.ScheduleEvent(EVENT_DARNAVAN_INTIMIDATING_SHOUT, Seconds(90), Minutes(2)); break; case EVENT_DARNAVAN_MORTAL_STRIKE: DoCastVictim(SPELL_MORTAL_STRIKE); - _events.ScheduleEvent(EVENT_DARNAVAN_MORTAL_STRIKE, urand(15000, 30000)); + _events.ScheduleEvent(EVENT_DARNAVAN_MORTAL_STRIKE, Seconds(15), Seconds(30)); break; case EVENT_DARNAVAN_SHATTERING_THROW: _canShatter = true; break; case EVENT_DARNAVAN_SUNDER_ARMOR: DoCastVictim(SPELL_SUNDER_ARMOR); - _events.ScheduleEvent(EVENT_DARNAVAN_SUNDER_ARMOR, urand(3000, 7000)); + _events.ScheduleEvent(EVENT_DARNAVAN_SUNDER_ARMOR, Seconds(3), Seconds(7)); break; } } @@ -1013,50 +1002,86 @@ class spell_deathwhisper_mana_barrier : public SpellScriptLoader } }; -class spell_cultist_dark_martyrdom : public SpellScriptLoader +class at_lady_deathwhisper_entrance : public AreaTriggerScript { public: - spell_cultist_dark_martyrdom() : SpellScriptLoader("spell_cultist_dark_martyrdom") { } + at_lady_deathwhisper_entrance() : AreaTriggerScript("at_lady_deathwhisper_entrance") { } - class spell_cultist_dark_martyrdom_SpellScript : public SpellScript + bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override { - PrepareSpellScript(spell_cultist_dark_martyrdom_SpellScript); + if (InstanceScript* instance = player->GetInstanceScript()) + if (instance->GetBossState(DATA_LADY_DEATHWHISPER) != DONE) + if (Creature* ladyDeathwhisper = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_LADY_DEATHWHISPER))) + ladyDeathwhisper->AI()->DoAction(ACTION_START_INTRO); + + return true; + } +}; + +class spell_deathwhisper_dominated_mind : public SpellScriptLoader +{ + public: + spell_deathwhisper_dominated_mind() : SpellScriptLoader("spell_deathwhisper_dominated_mind") { } - void HandleEffect(SpellEffIndex /*effIndex*/) + class spell_deathwhisper_dominated_mind_AuraScript : public AuraScript + { + PrepareAuraScript(spell_deathwhisper_dominated_mind_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override { - if (GetCaster()->IsSummon()) - if (Unit* owner = GetCaster()->ToTempSummon()->GetSummoner()) - owner->GetAI()->SetGUID(GetCaster()->GetGUID(), GUID_CULTIST); + if (!sSpellMgr->GetSpellInfo(SPELL_DOMINATE_MIND_SCALE)) + return false; + return true; + } - GetCaster()->KillSelf(); - GetCaster()->SetDisplayId(uint32(GetCaster()->GetEntry() == NPC_CULT_FANATIC ? 38009 : 38010)); + void HandleApply(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + target->CastSpell(target, SPELL_DOMINATE_MIND_SCALE, true); } void Register() override { - OnEffectHitTarget += SpellEffectFn(spell_cultist_dark_martyrdom_SpellScript::HandleEffect, EFFECT_2, SPELL_EFFECT_FORCE_DESELECT); + AfterEffectApply += AuraEffectApplyFn(spell_deathwhisper_dominated_mind_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); } }; - SpellScript* GetSpellScript() const override + AuraScript* GetAuraScript() const override { - return new spell_cultist_dark_martyrdom_SpellScript(); + return new spell_deathwhisper_dominated_mind_AuraScript(); } }; -class at_lady_deathwhisper_entrance : public AreaTriggerScript +class spell_deathwhisper_summon_spirits : public SpellScriptLoader { public: - at_lady_deathwhisper_entrance() : AreaTriggerScript("at_lady_deathwhisper_entrance") { } + spell_deathwhisper_summon_spirits() : SpellScriptLoader("spell_deathwhisper_summon_spirits") { } - bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + class spell_deathwhisper_summon_spirits_SpellScript : public SpellScript { - if (InstanceScript* instance = player->GetInstanceScript()) - if (instance->GetBossState(DATA_LADY_DEATHWHISPER) != DONE) - if (Creature* ladyDeathwhisper = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_LADY_DEATHWHISPER))) - ladyDeathwhisper->AI()->DoAction(ACTION_START_INTRO); + PrepareSpellScript(spell_deathwhisper_summon_spirits_SpellScript); - return true; + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_SHADE)) + return false; + return true; + } + + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_SUMMON_SHADE, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_deathwhisper_summon_spirits_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_deathwhisper_summon_spirits_SpellScript(); } }; @@ -1068,6 +1093,7 @@ void AddSC_boss_lady_deathwhisper() new npc_vengeful_shade(); new npc_darnavan(); new spell_deathwhisper_mana_barrier(); - new spell_cultist_dark_martyrdom(); + new spell_deathwhisper_dominated_mind(); + new spell_deathwhisper_summon_spirits(); new at_lady_deathwhisper_entrance(); } diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp index c22cd2d9ad7..cb5a7462000 100644 --- a/src/server/scripts/Northrend/zone_dragonblight.cpp +++ b/src/server/scripts/Northrend/zone_dragonblight.cpp @@ -701,6 +701,31 @@ class npc_torturer_lecraft : public CreatureScript } }; +enum MessengerTorvus +{ + NPC_MESSENGER_TORVUS = 26649, + QUEST_MESSAGE_FROM_THE_WEST = 12033, + + TALK_0 = 0 +}; + +class at_nearby_messenger_torvus : public AreaTriggerScript +{ +public: + at_nearby_messenger_torvus() : AreaTriggerScript("at_nearby_messenger_torvus") { } + + bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override + { + if (player->IsAlive()) + if (Quest const* quest = sObjectMgr->GetQuestTemplate(QUEST_MESSAGE_FROM_THE_WEST)) + if (player->CanTakeQuest(quest, false)) + if (Creature* creature = player->FindNearestCreature(NPC_MESSENGER_TORVUS, 50.0f, true)) + creature->AI()->Talk(TALK_0, player); + + return true; + } +}; + void AddSC_dragonblight() { new npc_commander_eligor_dawnbringer(); @@ -708,4 +733,5 @@ void AddSC_dragonblight() new spell_q12096_q12092_bark(); new npc_wyrmrest_defender(); new npc_torturer_lecraft(); + new at_nearby_messenger_torvus(); } diff --git a/src/server/scripts/Northrend/zone_wintergrasp.cpp b/src/server/scripts/Northrend/zone_wintergrasp.cpp index a85d97d4c1d..e45b1f42fa1 100644 --- a/src/server/scripts/Northrend/zone_wintergrasp.cpp +++ b/src/server/scripts/Northrend/zone_wintergrasp.cpp @@ -247,39 +247,39 @@ class npc_wg_queue : public CreatureScript public: npc_wg_queue() : CreatureScript("npc_wg_queue") { } - struct npc_wg_queueAI : public ScriptedAI - { - npc_wg_queueAI(Creature* creature) : ScriptedAI(creature) + struct npc_wg_queueAI : public ScriptedAI { - FrostArmor_Timer = 0; - } + npc_wg_queueAI(Creature* creature) : ScriptedAI(creature) + { + FrostArmor_Timer = 0; + } - uint32 FrostArmor_Timer; + uint32 FrostArmor_Timer; - void Reset() override - { - FrostArmor_Timer = 0; - } + void Reset() override + { + FrostArmor_Timer = 0; + } - void EnterCombat(Unit* /*who*/) override { } + void EnterCombat(Unit* /*who*/) override { } - void UpdateAI(uint32 diff) override - { - if (FrostArmor_Timer <= diff) + void UpdateAI(uint32 diff) override { - DoCast(me, SPELL_FROST_ARMOR); - FrostArmor_Timer = 180000; + if (FrostArmor_Timer <= diff) + { + DoCast(me, SPELL_FROST_ARMOR); + FrostArmor_Timer = 180000; + } + else FrostArmor_Timer -= diff; + + DoMeleeAttackIfReady(); } - else FrostArmor_Timer -= diff; + }; - DoMeleeAttackIfReady(); + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_wg_queueAI(creature); } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_wg_queueAI(creature); - } bool OnGossipHello(Player* player, Creature* creature) override { @@ -474,26 +474,26 @@ class spell_wintergrasp_grab_passenger : public SpellScriptLoader class achievement_wg_didnt_stand_a_chance : public AchievementCriteriaScript { -public: - achievement_wg_didnt_stand_a_chance() : AchievementCriteriaScript("achievement_wg_didnt_stand_a_chance") { } - - bool OnCheck(Player* source, Unit* target) override - { - if (!target) - return false; + public: + achievement_wg_didnt_stand_a_chance() : AchievementCriteriaScript("achievement_wg_didnt_stand_a_chance") { } - if (Player* victim = target->ToPlayer()) + bool OnCheck(Player* source, Unit* target) override { - if (!victim->IsMounted()) + if (!target) return false; - if (Vehicle* vehicle = source->GetVehicle()) - if (vehicle->GetVehicleInfo()->m_ID == 244) // Wintergrasp Tower Cannon - return true; - } + if (Player* victim = target->ToPlayer()) + { + if (!victim->IsMounted()) + return false; - return false; - } + if (Vehicle* vehicle = source->GetVehicle()) + if (vehicle->GetVehicleInfo()->m_ID == 244) // Wintergrasp Tower Cannon + return true; + } + + return false; + } }; enum WgTeleport @@ -503,91 +503,91 @@ enum WgTeleport class spell_wintergrasp_defender_teleport : public SpellScriptLoader { -public: - spell_wintergrasp_defender_teleport() : SpellScriptLoader("spell_wintergrasp_defender_teleport") { } - - class spell_wintergrasp_defender_teleport_SpellScript : public SpellScript - { - PrepareSpellScript(spell_wintergrasp_defender_teleport_SpellScript); + public: + spell_wintergrasp_defender_teleport() : SpellScriptLoader("spell_wintergrasp_defender_teleport") { } - SpellCastResult CheckCast() + class spell_wintergrasp_defender_teleport_SpellScript : public SpellScript { - if (Battlefield* wg = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG)) - if (Player* target = GetExplTargetUnit()->ToPlayer()) - // check if we are in Wintergrasp at all, SotA uses same teleport spells - if ((target->GetZoneId() == 4197 && target->GetTeamId() != wg->GetDefenderTeam()) || target->HasAura(SPELL_WINTERGRASP_TELEPORT_TRIGGER)) - return SPELL_FAILED_BAD_TARGETS; - return SPELL_CAST_OK; - } + PrepareSpellScript(spell_wintergrasp_defender_teleport_SpellScript); + + SpellCastResult CheckCast() + { + if (Battlefield* wg = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG)) + if (Player* target = GetExplTargetUnit()->ToPlayer()) + // check if we are in Wintergrasp at all, SotA uses same teleport spells + if ((target->GetZoneId() == 4197 && target->GetTeamId() != wg->GetDefenderTeam()) || target->HasAura(SPELL_WINTERGRASP_TELEPORT_TRIGGER)) + return SPELL_FAILED_BAD_TARGETS; + return SPELL_CAST_OK; + } - void Register() override + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_wintergrasp_defender_teleport_SpellScript::CheckCast); + } + }; + + SpellScript* GetSpellScript() const override { - OnCheckCast += SpellCheckCastFn(spell_wintergrasp_defender_teleport_SpellScript::CheckCast); + return new spell_wintergrasp_defender_teleport_SpellScript(); } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_wintergrasp_defender_teleport_SpellScript(); - } }; class spell_wintergrasp_defender_teleport_trigger : public SpellScriptLoader { -public: - spell_wintergrasp_defender_teleport_trigger() : SpellScriptLoader("spell_wintergrasp_defender_teleport_trigger") { } - - class spell_wintergrasp_defender_teleport_trigger_SpellScript : public SpellScript - { - PrepareSpellScript(spell_wintergrasp_defender_teleport_trigger_SpellScript); + public: + spell_wintergrasp_defender_teleport_trigger() : SpellScriptLoader("spell_wintergrasp_defender_teleport_trigger") { } - void HandleDummy(SpellEffIndex /*effindex*/) + class spell_wintergrasp_defender_teleport_trigger_SpellScript : public SpellScript { - if (Unit* target = GetHitUnit()) + PrepareSpellScript(spell_wintergrasp_defender_teleport_trigger_SpellScript); + + void HandleDummy(SpellEffIndex /*effindex*/) { - WorldLocation loc = target->GetWorldLocation(); - SetExplTargetDest(loc); + if (Unit* target = GetHitUnit()) + { + WorldLocation loc = target->GetWorldLocation(); + SetExplTargetDest(loc); + } } - } - void Register() override + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_wintergrasp_defender_teleport_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override { - OnEffectHitTarget += SpellEffectFn(spell_wintergrasp_defender_teleport_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + return new spell_wintergrasp_defender_teleport_trigger_SpellScript(); } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_wintergrasp_defender_teleport_trigger_SpellScript(); - } }; class condition_is_wintergrasp_horde : public ConditionScript { -public: - condition_is_wintergrasp_horde() : ConditionScript("condition_is_wintergrasp_horde") { } + public: + condition_is_wintergrasp_horde() : ConditionScript("condition_is_wintergrasp_horde") { } - bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& /* sourceInfo */) - { - Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); - if (wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_HORDE) - return true; - return false; - } + bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& /* sourceInfo */) + { + Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); + if (wintergrasp && wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_HORDE) + return true; + return false; + } }; class condition_is_wintergrasp_alliance : public ConditionScript { -public: - condition_is_wintergrasp_alliance() : ConditionScript("condition_is_wintergrasp_alliance") { } + public: + condition_is_wintergrasp_alliance() : ConditionScript("condition_is_wintergrasp_alliance") { } - bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& /* sourceInfo */) - { - Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); - if (wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_ALLIANCE) - return true; - return false; - } + bool OnConditionCheck(Condition const* /* condition */, ConditionSourceInfo& /* sourceInfo */) + { + Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); + if (wintergrasp && wintergrasp->IsEnabled() && wintergrasp->GetDefenderTeam() == TEAM_ALLIANCE) + return true; + return false; + } }; void AddSC_wintergrasp() diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.h b/src/server/scripts/Outland/BlackTemple/black_temple.h index 0856639f4c2..9d2c3dacb3f 100644 --- a/src/server/scripts/Outland/BlackTemple/black_temple.h +++ b/src/server/scripts/Outland/BlackTemple/black_temple.h @@ -47,27 +47,29 @@ enum DataTypes DATA_BLOOD_ELF_COUNCIL_VOICE = 15, DATA_GO_ILLIDAN_GATE = 16, - DATA_GO_ILLIDAN_DOOR_R = 17, - DATA_GO_ILLIDAN_DOOR_L = 18 }; enum CreatureIds { + //Bosses NPC_HIGH_WARLORD_NAJENTUS = 22887, NPC_SUPREMUS = 22898, NPC_SHADE_OF_AKAMA = 22841, - NPC_AKAMA_SHADE = 23191, // This is the Akama that starts the Shade of Akama encounter. - NPC_AKAMA = 23089, // This is the Akama that starts the Illidan encounter. + NPC_TERON_GOREFIEND = 22871, + NPC_GURTOGG_BLOODBOIL = 22948, + NPC_RELIQUARY_OF_SOULS = 22856, + NPC_MOTHER_SHAHRAZ = 22947, + NPC_ILLIDARI_COUNCIL = 23426, + NPC_ILLIDAN_STORMRAGE = 22917, + //Misc NPC_GATHIOS_THE_SHATTERER = 22949, NPC_HIGH_NETHERMANCER_ZEREVOR = 22950, NPC_LADY_MALANDE = 22951, NPC_VERAS_DARKSHADOW = 22952, - NPC_ILLIDARI_COUNCIL = 23426, NPC_BLOOD_ELF_COUNCIL_VOICE = 23499, - - NPC_ILLIDAN_STORMRAGE = 22917, - + NPC_AKAMA = 23089, // This is the Akama that starts the Illidan encounter. + NPC_AKAMA_SHADE = 23191, // This is the Akama that starts the Shade of Akama encounter. NPC_SUPREMUS_VOLCANO = 23085 }; diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index a2215862219..07578b4c9ae 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -539,8 +539,7 @@ public: void EnterCombat(Unit* /*who*/) override { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); - me->setActive(true); - DoZoneInCombat(); + _EnterCombat(); } void AttackStart(Unit* who) override @@ -561,9 +560,6 @@ public: { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - for (uint8 i = DATA_GO_ILLIDAN_DOOR_R; i < DATA_GO_ILLIDAN_DOOR_L + 1; ++i) - instance->HandleGameObject(instance->GetGuidData(i), true); - _JustDied(); } @@ -1412,23 +1408,13 @@ public: IllidanGUID = instance->GetGuidData(DATA_ILLIDAN_STORMRAGE); GateGUID = instance->GetGuidData(DATA_GO_ILLIDAN_GATE); - DoorGUID[0] = instance->GetGuidData(DATA_GO_ILLIDAN_DOOR_R); - DoorGUID[1] = instance->GetGuidData(DATA_GO_ILLIDAN_DOOR_L); if (JustCreated) // close all doors at create - { instance->HandleGameObject(GateGUID, false); - - for (uint8 i = 0; i < 2; ++i) - instance->HandleGameObject(DoorGUID[i], false); - } else // open all doors, raid wiped { instance->HandleGameObject(GateGUID, true); WalkCount = 1; // skip first wp - - for (uint8 i = 0; i < 2; ++i) - instance->HandleGameObject(DoorGUID[i], true); } KillAllElites(); @@ -1480,9 +1466,6 @@ public: void BeginTalk() { - instance->SetBossState(DATA_ILLIDAN_STORMRAGE, IN_PROGRESS); - for (uint8 i = 0; i < 2; ++i) - instance->HandleGameObject(DoorGUID[i], false); if (Creature* illidan = ObjectAccessor::GetCreature(*me, IllidanGUID)) { illidan->RemoveAurasDueToSpell(SPELL_KNEEL); @@ -1674,10 +1657,6 @@ public: { switch (WalkCount) { - case 6: - for (uint8 i = 0; i < 2; ++i) - instance->HandleGameObject(DoorGUID[i], true); - break; case 8: if (Phase == PHASE_WALK) EnterPhase(PHASE_TALK); @@ -1795,7 +1774,6 @@ public: ObjectGuid ChannelGUID; ObjectGuid SpiritGUID[2]; ObjectGuid GateGUID; - ObjectGuid DoorGUID[2]; uint32 ChannelCount; uint32 WalkCount; uint32 TalkCount; diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp index 347843ec7ff..d83e9f8aed9 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp @@ -46,7 +46,7 @@ enum Spells SPELL_FIXATE = 40607, SPELL_CHAIN_LIGHTNING = 39945, SPELL_DESTRUCTIVE_POISON = 40874, - SPELL_AKAMA_SOUL_EXPEL = 40902, + SPELL_AKAMA_SOUL_RETRIEVE = 40902, // Shade SPELL_THREAT = 41602, SPELL_SHADE_OF_AKAMA_TRIGGER = 40955, @@ -108,7 +108,7 @@ enum Events EVENT_CHAIN_LIGHTNING = 4, EVENT_DESTRUCTIVE_POISON = 5, EVENT_START_BROKEN_FREE = 6, - EVENT_START_SOUL_EXPEL = 7, + EVENT_START_SOUL_RETRIEVE = 7, EVENT_EVADE_CHECK = 8, EVENT_BROKEN_FREE_1 = 9, EVENT_BROKEN_FREE_2 = 10, @@ -246,11 +246,11 @@ public: events.ScheduleEvent(EVENT_START_CHANNELERS_AND_SPAWNERS, Seconds(1)); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); events.ScheduleEvent(EVENT_EVADE_CHECK, Seconds(10)); - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE))) + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) AttackStart(akama); } - if (spell->Id == SPELL_AKAMA_SOUL_EXPEL) + if (spell->Id == SPELL_AKAMA_SOUL_RETRIEVE) DoCastSelf(SPELL_AKAMA_SOUL_EXPEL_CHANNEL); } @@ -273,7 +273,7 @@ public: { DoCastSelf(SPELL_SHADE_OF_AKAMA_TRIGGER); - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE))) + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) akama->AI()->DoAction(ACTION_SHADE_OF_AKAMA_DEAD); for (ObjectGuid const& spawnerGuid : _spawners) @@ -401,7 +401,7 @@ public: _isInCombat = true; me->SetWalk(false); me->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL); - if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA))) + if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) { shade->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL); AttackStart(shade); @@ -445,7 +445,7 @@ public: { me->SetWalk(false); me->SetFacingTo(0.08726646f, true); - _events.ScheduleEvent(EVENT_START_SOUL_EXPEL, Seconds(1)); + _events.ScheduleEvent(EVENT_START_SOUL_RETRIEVE, Seconds(1)); } } @@ -489,14 +489,14 @@ public: break; case EVENT_CHAIN_LIGHTNING: DoCastVictim(SPELL_CHAIN_LIGHTNING); - _events.Repeat(randtime(Seconds(8), Seconds(15))); + _events.Repeat(Seconds(8), Seconds(15)); break; case EVENT_DESTRUCTIVE_POISON: DoCastSelf(SPELL_DESTRUCTIVE_POISON); - _events.Repeat(randtime(Seconds(3), Seconds(7))); + _events.Repeat(Seconds(3), Seconds(7)); break; - case EVENT_START_SOUL_EXPEL: - DoCast(SPELL_AKAMA_SOUL_EXPEL); + case EVENT_START_SOUL_RETRIEVE: + DoCast(SPELL_AKAMA_SOUL_RETRIEVE); _events.ScheduleEvent(EVENT_START_BROKEN_FREE, Seconds(15)); break; case EVENT_START_BROKEN_FREE: @@ -541,7 +541,7 @@ public: { _summons.DespawnAll(); Talk(SAY_DEAD); - if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA))) + if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) if (shade->IsAlive()) shade->AI()->EnterEvadeMode(EVADE_REASON_OTHER); } @@ -587,7 +587,7 @@ public: { _scheduler.Schedule(Seconds(2), [this](TaskContext channel) { - if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA))) + if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) { if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) DoCastSelf(SPELL_SHADE_SOUL_CHANNEL); @@ -657,12 +657,12 @@ public: if (_leftSide) { _events.ScheduleEvent(EVENT_SPAWN_WAVE_B, Milliseconds(100)); - _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, randtime(Seconds(2), Seconds(5))); + _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, Seconds(2), Seconds(5)); } else { _events.ScheduleEvent(EVENT_SPAWN_WAVE_B, Seconds(10)); - _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, randtime(Seconds(2), Seconds(5))); + _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, Seconds(2), Seconds(5)); } break; case ACTION_STOP_SPAWNING: @@ -687,15 +687,15 @@ public: { case EVENT_SPAWN_WAVE_B: DoCastSelf(SPELL_ASHTONGUE_WAVE_B); - _events.Repeat(randtime(Seconds(50), Seconds(60))); + _events.Repeat(Seconds(50), Seconds(60)); break; case EVENT_SUMMON_ASHTONGUE_SORCERER: // left DoCastSelf(SPELL_SUMMON_ASHTONGUE_SORCERER); - _events.Repeat(randtime(Seconds(30), Seconds(35))); + _events.Repeat(Seconds(30), Seconds(35)); break; case EVENT_SUMMON_ASHTONGUE_DEFENDER: // right DoCastSelf(SPELL_SUMMON_ASHTONGUE_DEFENDER); - _events.Repeat(randtime(Seconds(30), Seconds(40))); + _events.Repeat(Seconds(30), Seconds(40)); break; default: break; @@ -736,16 +736,13 @@ public: void Reset() override { - if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA))) + if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) { if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) me->GetMotionMaster()->MovePoint(0, shade->GetPosition()); - else - { - if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE))) - AttackStart(akama); - } + else if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) + AttackStart(akama); } Initialize(); } @@ -777,7 +774,7 @@ public: _scheduler.Schedule(Seconds(1) + Milliseconds(500), [this](TaskContext sorcer_channel) { - if (Creature* shade = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SHADE_OF_AKAMA))) + if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) { if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) { @@ -789,7 +786,7 @@ public: { me->InterruptSpell(CURRENT_CHANNELED_SPELL); _switchToCombat = true; - if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE))) + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) AttackStart(akama); } } @@ -837,7 +834,7 @@ public: void Reset() override { - if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE))) + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) AttackStart(akama); } @@ -849,9 +846,9 @@ public: void EnterCombat(Unit* /*who*/) override { _events.ScheduleEvent(EVENT_HEROIC_STRIKE, Seconds(5)); - _events.ScheduleEvent(EVENT_SHIELD_BASH, randtime(Seconds(10), Seconds(16))); - _events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, randtime(Seconds(10), Seconds(16))); - _events.ScheduleEvent(EVENT_WINDFURY, randtime(Seconds(8), Seconds(12))); + _events.ScheduleEvent(EVENT_SHIELD_BASH, Seconds(10), Seconds(16)); + _events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, Seconds(10), Seconds(16)); + _events.ScheduleEvent(EVENT_WINDFURY, Seconds(8), Seconds(12)); } @@ -868,19 +865,19 @@ public: { case EVENT_DEBILITATING_STRIKE: DoCastVictim(SPELL_DEBILITATING_STRIKE); - _events.Repeat(randtime(Seconds(20), Seconds(25))); + _events.Repeat(Seconds(20), Seconds(25)); break; case EVENT_HEROIC_STRIKE: DoCastSelf(SPELL_HEROIC_STRIKE); - _events.Repeat(randtime(Seconds(5), Seconds(15))); + _events.Repeat(Seconds(5), Seconds(15)); break; case EVENT_SHIELD_BASH: DoCastVictim(SPELL_SHIELD_BASH); - _events.Repeat(randtime(Seconds(10), Seconds(20))); + _events.Repeat(Seconds(10), Seconds(20)); break; case EVENT_WINDFURY: DoCastVictim(SPELL_WINDFURY); - _events.Repeat(randtime(Seconds(6), Seconds(8))); + _events.Repeat(Seconds(6), Seconds(8)); break; default: break; @@ -915,7 +912,7 @@ public: void Reset() override { - if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE))) + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) AttackStart(akama); } @@ -926,8 +923,8 @@ public: void EnterCombat(Unit* /*who*/) override { - _events.ScheduleEvent(EVENT_DEBILITATING_POISON, randtime(Milliseconds(500), Seconds(2))); - _events.ScheduleEvent(EVENT_EVISCERATE, randtime(Seconds(2), Seconds(5))); + _events.ScheduleEvent(EVENT_DEBILITATING_POISON, Milliseconds(500), Seconds(2)); + _events.ScheduleEvent(EVENT_EVISCERATE, Seconds(2), Seconds(5)); } void EnterEvadeMode(EvadeReason /*why*/) override { } @@ -945,11 +942,11 @@ public: { case EVENT_DEBILITATING_POISON: DoCastVictim(SPELL_DEBILITATING_POISON); - _events.Repeat(randtime(Seconds(15), Seconds(20))); + _events.Repeat(Seconds(15), Seconds(20)); break; case EVENT_EVISCERATE: DoCastVictim(SPELL_EVISCERATE); - _events.Repeat(randtime(Seconds(12), Seconds(20))); + _events.Repeat(Seconds(12), Seconds(20)); break; default: break; @@ -984,7 +981,7 @@ public: void Reset() override { - if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE))) + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) AttackStart(akama); } @@ -1014,11 +1011,11 @@ public: { case EVENT_RAIN_OF_FIRE: DoCastVictim(SPELL_RAIN_OF_FIRE); - _events.Repeat(randtime(Seconds(15), Seconds(20))); + _events.Repeat(Seconds(15), Seconds(20)); break; case EVENT_LIGHTNING_BOLT: DoCastVictim(SPELL_LIGHTNING_BOLT); - _events.Repeat(randtime(Seconds(8), Seconds(15))); + _events.Repeat(Seconds(8), Seconds(15)); break; default: break; @@ -1062,7 +1059,7 @@ public: { Initialize(); - if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE))) + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) AttackStart(akama); } @@ -1073,7 +1070,7 @@ public: void EnterCombat(Unit* /*who*/) override { - _events.ScheduleEvent(EVENT_SPIRIT_HEAL, randtime(Seconds(5), Seconds(6))); + _events.ScheduleEvent(EVENT_SPIRIT_HEAL, Seconds(5), Seconds(6)); } void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override @@ -1083,7 +1080,7 @@ public: { DoCastSelf(SPELL_SPIRIT_MEND); _spiritMend = true; - _events.ScheduleEvent(EVENT_SPIRIT_MEND_RESET, randtime(Seconds(10),Seconds(15))); + _events.ScheduleEvent(EVENT_SPIRIT_MEND_RESET, Seconds(10),Seconds(15)); } if (!_chainHeal) @@ -1091,7 +1088,7 @@ public: { DoCastSelf(SPELL_CHAIN_HEAL); _chainHeal = true; - _events.ScheduleEvent(EVENT_CHAIN_HEAL_RESET, randtime(Seconds(10), Seconds(15))); + _events.ScheduleEvent(EVENT_CHAIN_HEAL_RESET, Seconds(10), Seconds(15)); } } @@ -1108,7 +1105,7 @@ public: { case EVENT_SPIRIT_HEAL: DoCastSelf(SPELL_SPIRITBINDER_SPIRIT_HEAL); - _events.Repeat(randtime(Seconds(13), Seconds(16))); + _events.Repeat(Seconds(13), Seconds(16)); break; case EVENT_SPIRIT_MEND_RESET: _spiritMend = false; @@ -1157,7 +1154,7 @@ public: if (motionType != POINT_MOTION_TYPE) return; - if (Creature* akama = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_AKAMA_SHADE))) + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) me->SetFacingToObject(akama); } diff --git a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp index bac996918ac..2784792fe8d 100644 --- a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp @@ -22,17 +22,20 @@ DoorData const doorData[] = { { GO_NAJENTUS_GATE, DATA_HIGH_WARLORD_NAJENTUS, DOOR_TYPE_PASSAGE }, - { GO_NAJENTUS_GATE, DATA_SUPREMUS, DOOR_TYPE_ROOM }, + { GO_NAJENTUS_GATE, DATA_SUPREMUS, DOOR_TYPE_ROOM }, { GO_SUPREMUS_GATE, DATA_SUPREMUS, DOOR_TYPE_PASSAGE }, - { GO_SHADE_OF_AKAMA_DOOR, DATA_SHADE_OF_AKAMA, DOOR_TYPE_ROOM }, - { GO_TERON_DOOR_1, DATA_TERON_GOREFIEND, DOOR_TYPE_ROOM }, - { GO_TERON_DOOR_2, DATA_TERON_GOREFIEND, DOOR_TYPE_ROOM }, + { GO_SHADE_OF_AKAMA_DOOR, DATA_SHADE_OF_AKAMA, DOOR_TYPE_ROOM }, + { GO_TERON_DOOR_1, DATA_TERON_GOREFIEND, DOOR_TYPE_ROOM }, + { GO_TERON_DOOR_2, DATA_TERON_GOREFIEND, DOOR_TYPE_ROOM }, { GO_GURTOGG_DOOR, DATA_GURTOGG_BLOODBOIL, DOOR_TYPE_PASSAGE }, { GO_TEMPLE_DOOR, DATA_RELIQUARY_OF_SOULS, DOOR_TYPE_PASSAGE }, { GO_MOTHER_SHAHRAZ_DOOR, DATA_MOTHER_SHAHRAZ, DOOR_TYPE_PASSAGE }, - { GO_COUNCIL_DOOR_1, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM }, - { GO_COUNCIL_DOOR_2, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM }, - { 0, 0, DOOR_TYPE_ROOM } // END + { GO_COUNCIL_DOOR_1, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM }, + { GO_COUNCIL_DOOR_2, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM }, + //{ GO_ILLIDAN_GATE, DATA_GO_ILLIDAN_GATE, DOOR_TYPE_PASSAGE }, + { GO_ILLIDAN_DOOR_R, DATA_ILLIDAN_STORMRAGE, DOOR_TYPE_ROOM }, + { GO_ILLIDAN_DOOR_L, DATA_ILLIDAN_STORMRAGE, DOOR_TYPE_ROOM }, + { 0, 0, DOOR_TYPE_ROOM } // END }; BossBoundaryData const boundaries = @@ -49,6 +52,27 @@ BossBoundaryData const boundaries = { DATA_ILLIDAN_STORMRAGE, new EllipseBoundary(Position(694.8f, 309.0f), 70.0 , 85.0) } }; +ObjectData const creatureData[] = +{ + { NPC_HIGH_WARLORD_NAJENTUS, DATA_HIGH_WARLORD_NAJENTUS }, + { NPC_SUPREMUS, DATA_SUPREMUS }, + { NPC_SHADE_OF_AKAMA, DATA_SHADE_OF_AKAMA }, + { NPC_TERON_GOREFIEND, DATA_TERON_GOREFIEND }, + { NPC_GURTOGG_BLOODBOIL, DATA_GURTOGG_BLOODBOIL }, + { NPC_RELIQUARY_OF_SOULS, DATA_RELIQUARY_OF_SOULS }, + { NPC_MOTHER_SHAHRAZ, DATA_MOTHER_SHAHRAZ }, + { NPC_ILLIDARI_COUNCIL, DATA_ILLIDARI_COUNCIL }, + { NPC_ILLIDAN_STORMRAGE, DATA_ILLIDAN_STORMRAGE }, + { NPC_AKAMA_SHADE, DATA_AKAMA_SHADE }, + { NPC_AKAMA, DATA_AKAMA }, + { NPC_GATHIOS_THE_SHATTERER, DATA_GATHIOS_THE_SHATTERER }, + { NPC_HIGH_NETHERMANCER_ZEREVOR, DATA_HIGH_NETHERMANCER_ZEREVOR }, + { NPC_LADY_MALANDE, DATA_LADY_MALANDE }, + { NPC_VERAS_DARKSHADOW, DATA_VERAS_DARKSHADOW }, + { NPC_BLOOD_ELF_COUNCIL_VOICE, DATA_BLOOD_ELF_COUNCIL_VOICE }, + { 0, 0 } // end +}; + class instance_black_temple : public InstanceMapScript { public: @@ -61,165 +85,28 @@ class instance_black_temple : public InstanceMapScript SetHeaders(DataHeader); SetBossNumber(EncounterCount); LoadDoorData(doorData); + LoadObjectData(creatureData, nullptr); LoadBossBoundaries(boundaries); } - void OnCreatureCreate(Creature* creature) override - { - switch (creature->GetEntry()) - { - case NPC_HIGH_WARLORD_NAJENTUS: - NajentusGUID = creature->GetGUID(); - break; - case NPC_SUPREMUS: - SupremusGUID = creature->GetGUID(); - break; - case NPC_SHADE_OF_AKAMA: - ShadeOfAkamaGUID = creature->GetGUID(); - break; - case NPC_AKAMA_SHADE: - AkamaShadeGUID = creature->GetGUID(); - break; - case NPC_AKAMA: - AkamaGUID = creature->GetGUID(); - break; - case NPC_GATHIOS_THE_SHATTERER: - GathiosTheShattererGUID = creature->GetGUID(); - break; - case NPC_HIGH_NETHERMANCER_ZEREVOR: - HighNethermancerZerevorGUID = creature->GetGUID(); - break; - case NPC_LADY_MALANDE: - LadyMalandeGUID = creature->GetGUID(); - break; - case NPC_VERAS_DARKSHADOW: - VerasDarkshadowGUID = creature->GetGUID(); - break; - case NPC_ILLIDARI_COUNCIL: - IllidariCouncilGUID = creature->GetGUID(); - break; - case NPC_BLOOD_ELF_COUNCIL_VOICE: - BloodElfCouncilVoiceGUID = creature->GetGUID(); - break; - case NPC_ILLIDAN_STORMRAGE: - IllidanStormrageGUID = creature->GetGUID(); - break; - default: - break; - } - } - void OnGameObjectCreate(GameObject* go) override { - switch (go->GetEntry()) - { - case GO_NAJENTUS_GATE: - case GO_SUPREMUS_GATE: - case GO_SHADE_OF_AKAMA_DOOR: - case GO_TERON_DOOR_1: - case GO_TERON_DOOR_2: - case GO_GURTOGG_DOOR: - case GO_TEMPLE_DOOR: - case GO_MOTHER_SHAHRAZ_DOOR: - case GO_COUNCIL_DOOR_1: - case GO_COUNCIL_DOOR_2: - AddDoor(go, true); - break; - case GO_ILLIDAN_GATE: - IllidanGateGUID = go->GetGUID(); - break; - case GO_ILLIDAN_DOOR_R: - IllidanDoorGUIDs[0] = go->GetGUID(); - break; - case GO_ILLIDAN_DOOR_L: - IllidanDoorGUIDs[1] = go->GetGUID(); - break; - default: - break; - } - } + if (go->GetEntry() == GO_ILLIDAN_GATE) + IllidanGateGUID = go->GetGUID(); - void OnGameObjectRemove(GameObject* go) override - { - switch (go->GetEntry()) - { - case GO_NAJENTUS_GATE: - case GO_SUPREMUS_GATE: - case GO_SHADE_OF_AKAMA_DOOR: - case GO_TERON_DOOR_1: - case GO_TERON_DOOR_2: - case GO_GURTOGG_DOOR: - case GO_TEMPLE_DOOR: - case GO_MOTHER_SHAHRAZ_DOOR: - case GO_COUNCIL_DOOR_1: - case GO_COUNCIL_DOOR_2: - AddDoor(go, false); - break; - default: - break; - } + InstanceScript::OnGameObjectCreate(go); } ObjectGuid GetGuidData(uint32 type) const override { - switch (type) - { - case DATA_HIGH_WARLORD_NAJENTUS: - return NajentusGUID; - case DATA_SUPREMUS: - return SupremusGUID; - case DATA_SHADE_OF_AKAMA: - return ShadeOfAkamaGUID; - case DATA_AKAMA_SHADE: - return AkamaShadeGUID; - case DATA_AKAMA: - return AkamaGUID; - case DATA_GATHIOS_THE_SHATTERER: - return GathiosTheShattererGUID; - case DATA_HIGH_NETHERMANCER_ZEREVOR: - return HighNethermancerZerevorGUID; - case DATA_LADY_MALANDE: - return LadyMalandeGUID; - case DATA_VERAS_DARKSHADOW: - return VerasDarkshadowGUID; - case DATA_ILLIDARI_COUNCIL: - return IllidariCouncilGUID; - case DATA_BLOOD_ELF_COUNCIL_VOICE: - return BloodElfCouncilVoiceGUID; - case DATA_ILLIDAN_STORMRAGE: - return IllidanStormrageGUID; - case DATA_GO_ILLIDAN_GATE: - return IllidanGateGUID; - case DATA_GO_ILLIDAN_DOOR_R: - return IllidanDoorGUIDs[0]; - case DATA_GO_ILLIDAN_DOOR_L: - return IllidanDoorGUIDs[1]; - default: - break; - } + if (type == DATA_GO_ILLIDAN_GATE) + return IllidanGateGUID; - return ObjectGuid::Empty; + return InstanceScript::GetGuidData(type); } protected: - ObjectGuid NajentusGUID; - ObjectGuid SupremusGUID; - ObjectGuid ShadeOfAkamaGUID; - ObjectGuid AkamaShadeGUID; - ObjectGuid AkamaGUID; - - ObjectGuid GathiosTheShattererGUID; - ObjectGuid HighNethermancerZerevorGUID; - ObjectGuid LadyMalandeGUID; - ObjectGuid VerasDarkshadowGUID; - - ObjectGuid IllidariCouncilGUID; - ObjectGuid BloodElfCouncilVoiceGUID; - - ObjectGuid IllidanStormrageGUID; - ObjectGuid IllidanGateGUID; - ObjectGuid IllidanDoorGUIDs[2]; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index 90bf8bb1948..3b364d557ed 100644 --- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp +++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp @@ -332,8 +332,14 @@ public: enum FelGuard { - SPELL_SUMMON_POO = 37688, - NPC_DERANGED_HELBOAR = 16863 + SPELL_SUMMON_POO = 37688, + SPELL_FAKE_BLOOD = 37692, + NPC_DERANGED_HELBOAR = 16863, + + EVENT_SEARCH_HELBOAR = 1, + EVENT_HELBOAR_FOUND = 2, + EVENT_SUMMON_POO = 3, + EVENT_FOLLOW_PLAYER = 4 }; class npc_fel_guard_hound : public CreatureScript @@ -350,8 +356,8 @@ public: void Initialize() { - checkTimer = 5000; //check for creature every 5 sec helboarGUID.Clear(); + _events.ScheduleEvent(EVENT_SEARCH_HELBOAR, Seconds(3)); } void Reset() override @@ -366,29 +372,54 @@ public: if (Creature* helboar = ObjectAccessor::GetCreature(*me, helboarGUID)) { - helboar->RemoveCorpse(); - DoCast(SPELL_SUMMON_POO); - - if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) - me->GetMotionMaster()->MoveFollow(owner, 0.0f, 0.0f); + _events.CancelEvent(EVENT_SEARCH_HELBOAR); + me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED); + me->CastSpell(helboar, SPELL_FAKE_BLOOD); + _events.ScheduleEvent(EVENT_HELBOAR_FOUND, Seconds(2)); } } void UpdateAI(uint32 diff) override { - if (checkTimer <= diff) + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) { - if (Creature* helboar = me->FindNearestCreature(NPC_DERANGED_HELBOAR, 10.0f, false)) + switch (eventId) { - if (helboar->GetGUID() != helboarGUID && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE && !me->FindCurrentSpellBySpellId(SPELL_SUMMON_POO)) - { - helboarGUID = helboar->GetGUID(); - me->GetMotionMaster()->MovePoint(1, helboar->GetPositionX(), helboar->GetPositionY(), helboar->GetPositionZ()); - } + case EVENT_SEARCH_HELBOAR: + if (Creature* helboar = me->FindNearestCreature(NPC_DERANGED_HELBOAR, 10.0f, false)) + { + if (helboar->GetGUID() != helboarGUID && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE && !me->FindCurrentSpellBySpellId(SPELL_SUMMON_POO)) + { + helboarGUID = helboar->GetGUID(); + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(1, helboar->GetPositionX(), helboar->GetPositionY(), helboar->GetPositionZ()); + helboar->DespawnOrUnsummon(Seconds(10)); + } + } + _events.Repeat(Seconds(3)); + break; + case EVENT_HELBOAR_FOUND: + if (Creature* helboar = ObjectAccessor::GetCreature(*me, helboarGUID)) + { + me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED); + me->CastSpell(helboar, SPELL_FAKE_BLOOD); + _events.ScheduleEvent(EVENT_SUMMON_POO, Seconds(1)); + } + break; + case EVENT_SUMMON_POO: + DoCast(SPELL_SUMMON_POO); + _events.ScheduleEvent(EVENT_FOLLOW_PLAYER, Seconds(2)); + break; + case EVENT_FOLLOW_PLAYER: + me->SetWalk(false); + if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) + me->GetMotionMaster()->MoveFollow(owner, 0.0f, 0.0f); + _events.ScheduleEvent(EVENT_SEARCH_HELBOAR, Seconds(3)); + break; } - checkTimer = 5000; } - else checkTimer -= diff; if (!UpdateVictim()) return; @@ -397,7 +428,7 @@ public: } private: - uint32 checkTimer; + EventMap _events; ObjectGuid helboarGUID; }; @@ -892,6 +923,122 @@ public: } }; +enum Aledis +{ + SAY_CHALLENGE = 0, + SAY_DEFEATED = 1, + EVENT_TALK = 1, + EVENT_ATTACK = 2, + EVENT_EVADE = 3, + EVENT_FIREBALL = 4, + EVENT_FROSTNOVA = 5, + SPELL_FIREBALL = 20823, + SPELL_FROSTNOVA = 11831 +}; + +class npc_magister_aledis : public CreatureScript +{ +public: + npc_magister_aledis() : CreatureScript("npc_magister_aledis") { } + + bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 /*action*/) override + { + CloseGossipMenuFor(player); + creature->StopMoving(); + ENSURE_AI(npc_magister_aledis::npc_magister_aledisAI, creature->AI())->StartFight(player); + return true; + } + + struct npc_magister_aledisAI : public ScriptedAI + { + npc_magister_aledisAI(Creature* creature) : ScriptedAI(creature) { } + + void StartFight(Player* player) + { + me->Dismount(); + me->SetFacingToObject(player, true); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + _playerGUID = player->GetGUID(); + _events.ScheduleEvent(EVENT_TALK, Seconds(2)); + } + + void Reset() override + { + me->RestoreFaction(); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + } + + void DamageTaken(Unit* /*attacker*/, uint32 &damage) override + { + if (damage > me->GetHealth() || me->HealthBelowPctDamaged(20, damage)) + { + damage = 0; + + _events.Reset(); + me->RestoreFaction(); + me->RemoveAllAuras(); + me->DeleteThreatList(); + me->CombatStop(true); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + Talk(SAY_DEFEATED); + + _events.ScheduleEvent(EVENT_EVADE, Minutes(1)); + } + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_TALK: + Talk(SAY_CHALLENGE); + _events.ScheduleEvent(EVENT_ATTACK, Seconds(2)); + break; + case EVENT_ATTACK: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + me->setFaction(FACTION_HOSTILE); + me->CombatStart(ObjectAccessor::GetPlayer(*me, _playerGUID)); + _events.ScheduleEvent(EVENT_FIREBALL, 1); + _events.ScheduleEvent(EVENT_FROSTNOVA, Seconds(5)); + break; + case EVENT_FIREBALL: + DoCast(SPELL_FIREBALL); + _events.ScheduleEvent(EVENT_FIREBALL, Seconds(10)); + break; + case EVENT_FROSTNOVA: + DoCastAOE(SPELL_FROSTNOVA); + _events.ScheduleEvent(EVENT_FROSTNOVA, Seconds(20)); + break; + case EVENT_EVADE: + EnterEvadeMode(); + break; + } + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + ObjectGuid _playerGUID; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_magister_aledisAI(creature); + } +}; + void AddSC_hellfire_peninsula() { new npc_aeranas(); @@ -900,4 +1047,5 @@ void AddSC_hellfire_peninsula() new npc_fel_guard_hound(); new npc_colonel_jules(); new npc_barada(); + new npc_magister_aledis(); } diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp index 5b4b26e599e..a155dbc36c4 100644 --- a/src/server/scripts/Pet/pet_hunter.cpp +++ b/src/server/scripts/Pet/pet_hunter.cpp @@ -215,7 +215,7 @@ class spell_pet_guard_dog : public SpellScriptLoader Unit* caster = eventInfo.GetActor(); caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true); - float addThreat = CalculatePct(eventInfo.GetSpellInfo()->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); + float addThreat = CalculatePct(ASSERT_NOTNULL(eventInfo.GetSpellInfo())->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); eventInfo.GetProcTarget()->AddThreat(caster, addThreat); } diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index a1543e1199c..7cce7e4655e 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -2801,17 +2801,25 @@ public: class player_ghoulAI : public PlayerAI { public: - player_ghoulAI(Player* player, ObjectGuid ghoulGUID) : PlayerAI(player), _ghoulGUID(ghoulGUID) { } + player_ghoulAI(Player* player, ObjectGuid ghoulGUID) : PlayerAI(player), _ghoulGUID(ghoulGUID), _ghoulCheckTimer(1000){ } - void UpdateAI(uint32 /*diff*/) override + void UpdateAI(uint32 diff) override { - Creature* ghoul = ObjectAccessor::GetCreature(*me, _ghoulGUID); - if (!ghoul || !ghoul->IsAlive()) - me->RemoveAura(SPELL_DK_RAISE_ALLY); + if (_ghoulCheckTimer <= diff) + { + _ghoulCheckTimer = 1000; + + Creature* ghoul = ObjectAccessor::GetCreature(*me, _ghoulGUID); + if (!ghoul || !ghoul->IsAlive()) + me->RemoveAura(SPELL_DK_RAISE_ALLY); + } + else + _ghoulCheckTimer -= diff; } private: ObjectGuid _ghoulGUID; + uint32 _ghoulCheckTimer; }; // 46619 - Raise Ally @@ -2833,7 +2841,7 @@ public: void SendText() { if (Unit* original = GetOriginalCaster()) - original->Whisper(TEXT_RISE_ALLY, GetCaster()->ToPlayer(), true); + original->Unit::Whisper(TEXT_RISE_ALLY, GetCaster()->ToPlayer(), true); } void HandleSummon(SpellEffIndex effIndex) diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 794ef470d40..f1eaf45770e 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1100,9 +1100,17 @@ class spell_gen_creature_permanent_feign_death : public SpellScriptLoader target->ToCreature()->SetReactState(REACT_PASSIVE); } + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); + target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH); + } + void Register() override { OnEffectApply += AuraEffectApplyFn(spell_gen_creature_permanent_feign_death_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_gen_creature_permanent_feign_death_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index e95bfe4395c..e18dc838965 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -275,6 +275,70 @@ class spell_hun_chimera_shot : public SpellScriptLoader } }; +// -53256 - Cobra Strikes +class spell_hun_cobra_strikes : public SpellScriptLoader +{ + public: + spell_hun_cobra_strikes() : SpellScriptLoader("spell_hun_cobra_strikes") { } + + class spell_hun_cobra_strikes_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hun_cobra_strikes_AuraScript); + + bool Validate(SpellInfo const* spellInfo) override + { + if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + + SpellInfo const* triggeredSpellInfo = sSpellMgr->AssertSpellInfo(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell); + GetTarget()->CastCustomSpell(triggeredSpellInfo->Id, SPELLVALUE_AURA_STACK, triggeredSpellInfo->StackAmount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_hun_cobra_strikes_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_hun_cobra_strikes_AuraScript(); + } +}; + +// 53257 - Cobra Strikes (triggered spell) +class spell_hun_cobra_strikes_triggered : public SpellScriptLoader +{ + public: + spell_hun_cobra_strikes_triggered() : SpellScriptLoader("spell_hun_cobra_strikes_triggered") { } + + class spell_hun_cobra_strikes_triggered_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hun_cobra_strikes_triggered_AuraScript); + + void HandleStackDrop(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + { + ModStackAmount(-1); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_hun_cobra_strikes_triggered_AuraScript::HandleStackDrop, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_hun_cobra_strikes_triggered_AuraScript(); + } +}; + // 781 - Disengage class spell_hun_disengage : public SpellScriptLoader { @@ -388,7 +452,7 @@ class spell_hun_glyph_of_mend_pet : public SpellScriptLoader void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true); + eventInfo.GetProcTarget()->CastSpell((Unit*)nullptr, SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true); } void Register() override @@ -664,35 +728,6 @@ class spell_hun_lock_and_load : public SpellScriptLoader } }; -// 56342 - Lock and Load (Rank 1) -class spell_hun_lock_and_load_dummy : public SpellScriptLoader -{ - public: - spell_hun_lock_and_load_dummy() : SpellScriptLoader("spell_hun_lock_and_load_dummy") { } - - class spell_hun_lock_and_load_dummy_AuraScript : public AuraScript - { - PrepareAuraScript(spell_hun_lock_and_load_dummy_AuraScript); - - bool DummyCheck(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) - { - // Prevents Aura proc from this dummy effect - // Only rank 1 has this aura - return false; - } - - void Register() override - { - DoCheckEffectProc += AuraCheckEffectProcFn(spell_hun_lock_and_load_dummy_AuraScript::DummyCheck, EFFECT_2, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_hun_lock_and_load_dummy_AuraScript(); - } -}; - // 53271 - Masters Call class spell_hun_masters_call : public SpellScriptLoader { @@ -710,30 +745,58 @@ class spell_hun_masters_call : public SpellScriptLoader return true; } + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + SpellCastResult DoCheckCast() + { + Pet* pet = GetCaster()->ToPlayer()->GetPet(); + ASSERT(pet); // checked in Spell::CheckCast + + if (!pet->IsAlive()) + return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; + + // Do a mini Spell::CheckCasterAuras on the pet, no other way of doing this + SpellCastResult result = SPELL_CAST_OK; + uint32 const unitflag = pet->GetUInt32Value(UNIT_FIELD_FLAGS); + if (pet->GetCharmerGUID()) + result = SPELL_FAILED_CHARMED; + else if (unitflag & UNIT_FLAG_STUNNED) + result = SPELL_FAILED_STUNNED; + else if (unitflag & UNIT_FLAG_FLEEING) + result = SPELL_FAILED_FLEEING; + else if (unitflag & UNIT_FLAG_CONFUSED) + result = SPELL_FAILED_CONFUSED; + + if (result != SPELL_CAST_OK) + return result; + + Unit* target = GetExplTargetUnit(); + if (!target) + return SPELL_FAILED_BAD_TARGETS; + + if (!pet->IsWithinLOSInMap(target)) + return SPELL_FAILED_LINE_OF_SIGHT; + + return SPELL_CAST_OK; + } + void HandleDummy(SpellEffIndex /*effIndex*/) { - if (Unit* ally = GetHitUnit()) - if (Player* caster = GetCaster()->ToPlayer()) - if (Pet* target = caster->GetPet()) - { - TriggerCastFlags castMask = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_CASTER_AURASTATE); - target->CastSpell(ally, GetEffectValue(), castMask); - target->CastSpell(ally, GetSpellInfo()->Effects[EFFECT_0].CalcValue(), castMask); - } + GetCaster()->ToPlayer()->GetPet()->CastSpell(GetHitUnit(), GetEffectValue(), true); } void HandleScriptEffect(SpellEffIndex /*effIndex*/) { - if (Unit* target = GetHitUnit()) - { - // Cannot be processed while pet is dead - TriggerCastFlags castMask = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_CASTER_AURASTATE); - target->CastSpell(target, SPELL_HUNTER_MASTERS_CALL_TRIGGERED, castMask); - } + GetHitUnit()->CastSpell((Unit*)nullptr, SPELL_HUNTER_MASTERS_CALL_TRIGGERED, true); } void Register() override { + OnCheckCast += SpellCheckCastFn(spell_hun_masters_call_SpellScript::DoCheckCast); + OnEffectHitTarget += SpellEffectFn(spell_hun_masters_call_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); OnEffectHitTarget += SpellEffectFn(spell_hun_masters_call_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); } @@ -1505,6 +1568,8 @@ void AddSC_hunter_spell_scripts() new spell_hun_aspect_of_the_beast(); new spell_hun_ascpect_of_the_viper(); new spell_hun_chimera_shot(); + new spell_hun_cobra_strikes(); + new spell_hun_cobra_strikes_triggered(); new spell_hun_disengage(); new spell_hun_glyph_of_arcane_shot(); new spell_hun_glyph_of_mend_pet(); @@ -1514,7 +1579,6 @@ void AddSC_hunter_spell_scripts() new spell_hun_kill_command_pet(); new spell_hun_last_stand_pet(); new spell_hun_lock_and_load(); - new spell_hun_lock_and_load_dummy(); new spell_hun_masters_call(); new spell_hun_misdirection(); new spell_hun_misdirection_proc(); diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index f51b9e8e965..b45df66e0ac 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -1961,6 +1961,8 @@ class spell_item_shadows_fate : public SpellScriptLoader void HandleProc(ProcEventInfo& procInfo) { + PreventDefaultAction(); + Unit* caster = procInfo.GetActor(); Unit* target = GetCaster(); if (!caster || !target) @@ -4343,6 +4345,119 @@ class spell_item_taunt_flag_targeting : public SpellScriptLoader } }; +// 13180 - Gnomish Mind Control Cap +enum MindControlCap +{ + ROLL_CHANCE_DULLARD = 32, + ROLL_CHANCE_NO_BACKFIRE = 95, + SPELL_GNOMISH_MIND_CONTROL_CAP = 13181, + SPELL_DULLARD = 67809 +}; + +class spell_item_mind_control_cap : public SpellScriptLoader +{ + public: + spell_item_mind_control_cap() : SpellScriptLoader("spell_item_mind_control_cap") { } + + class spell_item_mind_control_cap_SpellScript : public SpellScript + { + PrepareSpellScript(spell_item_mind_control_cap_SpellScript); + + bool Load() override + { + if (!GetCastItem()) + return false; + return true; + } + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_GNOMISH_MIND_CONTROL_CAP) || !sSpellMgr->GetSpellInfo(SPELL_DULLARD)) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /* effIndex */) + { + Unit* caster = GetCaster(); + if (Unit* target = GetHitUnit()) + { + if (roll_chance_i(ROLL_CHANCE_NO_BACKFIRE)) + caster->CastSpell(target, roll_chance_i(ROLL_CHANCE_DULLARD) ? SPELL_DULLARD : SPELL_GNOMISH_MIND_CONTROL_CAP, true, GetCastItem()); + else + target->CastSpell(caster, SPELL_GNOMISH_MIND_CONTROL_CAP, true); // backfire - 5% chance + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_item_mind_control_cap_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_item_mind_control_cap_SpellScript(); + } +}; + +// 8344 - Universal Remote (Gnomish Universal Remote) +enum UniversalRemote +{ + SPELL_CONTROL_MACHINE = 8345, + SPELL_MOBILITY_MALFUNCTION = 8346, + SPELL_TARGET_LOCK = 8347 +}; + +class spell_item_universal_remote : public SpellScriptLoader +{ + public: + spell_item_universal_remote() : SpellScriptLoader("spell_item_universal_remote") { } + + class spell_item_universal_remote_SpellScript : public SpellScript + { + PrepareSpellScript(spell_item_universal_remote_SpellScript); + + bool Load() override + { + if (!GetCastItem()) + return false; + return true; + } + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_CONTROL_MACHINE) || !sSpellMgr->GetSpellInfo(SPELL_MOBILITY_MALFUNCTION) || !sSpellMgr->GetSpellInfo(SPELL_TARGET_LOCK)) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + uint8 chance = urand(0, 99); + if (chance < 15) + GetCaster()->CastSpell(target, SPELL_TARGET_LOCK, true, GetCastItem()); + else if (chance < 25) + GetCaster()->CastSpell(target, SPELL_MOBILITY_MALFUNCTION, true, GetCastItem()); + else + GetCaster()->CastSpell(target, SPELL_CONTROL_MACHINE, true, GetCastItem()); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_item_universal_remote_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_item_universal_remote_SpellScript(); + } +}; + enum ZandalarianCharms { SPELL_UNSTABLE_POWER_AURA_STACK = 24659, @@ -4515,6 +4630,8 @@ void AddSC_item_spell_scripts() new spell_item_charm_witch_doctor(); new spell_item_mana_drain(); new spell_item_taunt_flag_targeting(); + new spell_item_mind_control_cap(); + new spell_item_universal_remote(); new spell_item_zandalarian_charm("spell_item_unstable_power", SPELL_UNSTABLE_POWER_AURA_STACK); new spell_item_zandalarian_charm("spell_item_restless_strength", SPELL_RESTLESS_STRENGTH_AURA_STACK); diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index 30dfd2cd5d0..2aaa2e29d9c 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -1303,6 +1303,8 @@ class spell_pal_infusion_of_light : public SpellScriptLoader Unit* target = GetTarget(); int32 duration = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_FLASH_OF_LIGHT_PROC)->GetMaxDuration() / 1000; int32 pct = GetSpellInfo()->Effects[EFFECT_2].CalcValue(); + ASSERT(duration > 0); + int32 bp0 = CalculatePct(healInfo->GetHeal() / duration, pct); // Item - Paladin T9 Holy 4P Bonus @@ -1540,7 +1542,7 @@ class spell_pal_judgement_of_light_heal : public SpellScriptLoader Unit* caster = eventInfo.GetProcTarget(); int32 amount = static_cast<int32>(caster->CountPctFromMaxHealth(aurEff->GetAmount())); - caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff, GetCasterGUID()); } void Register() override @@ -1584,7 +1586,7 @@ class spell_pal_judgement_of_wisdom_mana : public SpellScriptLoader Unit* caster = eventInfo.GetProcTarget(); int32 amount = CalculatePct(static_cast<int32>(caster->GetCreateMana()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff, GetCasterGUID()); } void Register() override diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 2eca20199b4..fd99888f8d9 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -2565,6 +2565,146 @@ public: } }; +enum ApplyHeatAndStir +{ + SPELL_SPURTS_AND_SMOKE = 38594, + SPELL_FAILED_MIX_1 = 43376, + SPELL_FAILED_MIX_2 = 43378, + SPELL_FAILED_MIX_3 = 43970, + SPELL_SUCCESSFUL_MIX = 43377, + + CREATURE_GENERIC_TRIGGER_LAB = 24042, + + TALK_0 = 0, + TALK_1 = 1 +}; + +class spell_q11306_mixing_blood : public SpellScriptLoader +{ +public: + spell_q11306_mixing_blood() : SpellScriptLoader("spell_q11306_mixing_blood") { } + + class spell_q11306_mixing_blood_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q11306_mixing_blood_SpellScript); + + void HandleEffect(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + if (Creature* trigger = caster->FindNearestCreature(CREATURE_GENERIC_TRIGGER_LAB, 100.0f)) + trigger->AI()->DoCastSelf(SPELL_SPURTS_AND_SMOKE); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_q11306_mixing_blood_SpellScript::HandleEffect, EFFECT_1, SPELL_EFFECT_SEND_EVENT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_q11306_mixing_blood_SpellScript(); + } +}; + +class spell_q11306_mixing_vrykul_blood : public SpellScriptLoader +{ + public: + spell_q11306_mixing_vrykul_blood() : SpellScriptLoader("spell_q11306_mixing_vrykul_blood") { } + + class spell_q11306_mixing_vrykul_blood_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q11306_mixing_vrykul_blood_SpellScript); + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + { + uint8 chance = urand(0, 99); + uint32 spellId = 0; + + // 90% chance of getting one out of three failure effects + if (chance < 30) + spellId = SPELL_FAILED_MIX_1; + else if (chance < 60) + spellId = SPELL_FAILED_MIX_2; + else if (chance < 90) + spellId = SPELL_FAILED_MIX_3; + else // 10% chance of successful cast + spellId = SPELL_SUCCESSFUL_MIX; + + caster->CastSpell(caster, spellId, true); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_q11306_mixing_vrykul_blood_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_q11306_mixing_vrykul_blood_SpellScript(); + } +}; + +class spell_q11306_failed_mix_43376 : public SpellScriptLoader +{ +public: + spell_q11306_failed_mix_43376() : SpellScriptLoader("spell_q11306_failed_mix_43376") { } + + class spell_q11306_failed_mix_43376_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q11306_failed_mix_43376_SpellScript); + + void HandleEffect(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + if (Creature* trigger = caster->FindNearestCreature(CREATURE_GENERIC_TRIGGER_LAB, 100.0f)) + trigger->AI()->Talk(TALK_0, caster); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_q11306_failed_mix_43376_SpellScript::HandleEffect, EFFECT_1, SPELL_EFFECT_SEND_EVENT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_q11306_failed_mix_43376_SpellScript(); + } +}; + +class spell_q11306_failed_mix_43378 : public SpellScriptLoader +{ +public: + spell_q11306_failed_mix_43378() : SpellScriptLoader("spell_q11306_failed_mix_43378") { } + + class spell_q11306_failed_mix_43378_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q11306_failed_mix_43378_SpellScript); + + void HandleEffect(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + if (Creature* trigger = caster->FindNearestCreature(CREATURE_GENERIC_TRIGGER_LAB, 100.0f)) + trigger->AI()->Talk(TALK_1, caster); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_q11306_failed_mix_43378_SpellScript::HandleEffect, EFFECT_2, SPELL_EFFECT_SEND_EVENT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_q11306_failed_mix_43378_SpellScript(); + } +}; + void AddSC_quest_spell_scripts() { new spell_q55_sacred_cleansing(); @@ -2628,4 +2768,8 @@ void AddSC_quest_spell_scripts() new spell_q12414_hand_over_reins(); new spell_q13665_q13790_bested_trigger(); new spell_59064_59439_portals(); + new spell_q11306_mixing_blood(); + new spell_q11306_mixing_vrykul_blood(); + new spell_q11306_failed_mix_43376(); + new spell_q11306_failed_mix_43378(); } diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index cff94b6e219..397427b505f 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -83,7 +83,8 @@ enum ShamanSpells SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1 = 26364, SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC = 30824, SPELL_SHAMAN_MAELSTROM_POWER = 70831, - SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS = 70832 + SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS = 70832, + SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1 = 51554 }; enum ShamanSpellIcons @@ -537,6 +538,46 @@ class spell_sha_earthen_power : public SpellScriptLoader } }; +// -51940 - Earthliving Weapon (Passive) +class spell_sha_earthliving_weapon : public SpellScriptLoader +{ + public: + spell_sha_earthliving_weapon() : SpellScriptLoader("spell_sha_earthliving_weapon") { } + + class spell_sha_earthliving_weapon_AuraScript : public AuraScript + { + PrepareAuraScript(spell_sha_earthliving_weapon_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + int32 chance = 20; + Unit* caster = eventInfo.GetActor(); + if (AuraEffect const* aurEff = caster->GetAuraEffectOfRankedSpell(SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1, EFFECT_1, caster->GetGUID())) + if (eventInfo.GetProcTarget()->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT)) + chance += aurEff->GetAmount(); + + return roll_chance_i(chance); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_sha_earthliving_weapon_AuraScript::CheckProc); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_sha_earthliving_weapon_AuraScript(); + } +}; + // -1535 - Fire Nova class spell_sha_fire_nova : public SpellScriptLoader { @@ -1222,19 +1263,12 @@ class spell_sha_item_mana_surge : public SpellScriptLoader return true; } - bool CheckProc(ProcEventInfo& eventInfo) - { - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetSpellInfo()) - return false; - - return true; - } - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; int32 mana = spellInfo->CalcPowerCost(GetTarget(), eventInfo.GetSchoolMask()); int32 damage = CalculatePct(mana, 35); @@ -1244,7 +1278,6 @@ class spell_sha_item_mana_surge : public SpellScriptLoader void Register() override { - DoCheckProc += AuraCheckProcFn(spell_sha_item_mana_surge_AuraScript::CheckProc); OnEffectProc += AuraEffectProcFn(spell_sha_item_mana_surge_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); } }; @@ -2276,6 +2309,7 @@ void AddSC_shaman_spell_scripts() new spell_sha_earth_shield(); new spell_sha_earthbind_totem(); new spell_sha_earthen_power(); + new spell_sha_earthliving_weapon(); new spell_sha_fire_nova(); new spell_sha_flame_shock(); new spell_sha_flametongue_weapon(); diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 492da48c455..cccebab6259 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -74,6 +74,7 @@ enum WarlockSpells SPELL_WARLOCK_SHADOWFLAME = 37378, SPELL_WARLOCK_FLAMESHADOW = 37379, SPELL_WARLOCK_GLYPH_OF_SUCCUBUS = 56250, + SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1 = 18213, SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371 }; @@ -449,6 +450,50 @@ class spell_warl_demonic_empowerment : public SpellScriptLoader } }; +// -1120 - Drain Soul +class spell_warl_drain_soul : public SpellScriptLoader +{ + public: + spell_warl_drain_soul() : SpellScriptLoader("spell_warl_drain_soul") { } + + class spell_warl_drain_soul_AuraScript : public AuraScript + { + PrepareAuraScript(spell_warl_drain_soul_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1) || + !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + // Improved Drain Soul + Aura const* impDrainSoul = caster->GetAuraOfRankedSpell(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1, caster->GetGUID()); + if (!impDrainSoul) + return; + + int32 amount = CalculatePct(caster->GetMaxPower(POWER_MANA), impDrainSoul->GetSpellInfo()->Effects[EFFECT_2].CalcValue()); + caster->CastCustomSpell(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_warl_drain_soul_AuraScript::HandleProc, EFFECT_2, SPELL_AURA_PROC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_warl_drain_soul_AuraScript(); + } +}; + // 47422 - Everlasting Affliction class spell_warl_everlasting_affliction : public SpellScriptLoader { @@ -509,7 +554,7 @@ class spell_warl_fel_synergy : public SpellScriptLoader if (!damageInfo || !damageInfo->GetDamage()) return false; - return GetTarget()->GetGuardianPet(); + return GetTarget()->GetGuardianPet() != nullptr; } void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) @@ -744,44 +789,6 @@ class spell_warl_health_funnel : public SpellScriptLoader } }; -// -18213 - Improved Drain Soul -class spell_warl_improved_drain_soul : public SpellScriptLoader -{ - public: - spell_warl_improved_drain_soul() : SpellScriptLoader("spell_warl_improved_drain_soul") { } - - class spell_warl_improved_drain_soul_AuraScript : public AuraScript - { - PrepareAuraScript(spell_warl_improved_drain_soul_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC)) - return false; - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - - Unit* target = GetTarget(); - int32 bp0 = CalculatePct(target->GetMaxPower(POWER_MANA), GetSpellInfo()->Effects[EFFECT_2].BasePoints); - target->CastCustomSpell(SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC, SPELLVALUE_BASE_POINT0, bp0, target, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_warl_improved_drain_soul_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_warl_improved_drain_soul_AuraScript(); - } -}; - // -1454 - Life Tap class spell_warl_life_tap : public SpellScriptLoader { @@ -1484,6 +1491,7 @@ void AddSC_warlock_spell_scripts() new spell_warl_demonic_circle_teleport(); new spell_warl_demonic_empowerment(); new spell_warl_demonic_pact(); + new spell_warl_drain_soul(); new spell_warl_everlasting_affliction(); new spell_warl_fel_synergy(); new spell_warl_glyph_of_life_tap(); @@ -1491,7 +1499,6 @@ void AddSC_warlock_spell_scripts() new spell_warl_haunt(); new spell_warl_health_funnel(); new spell_warl_glyph_of_corruption_nightfall(); - new spell_warl_improved_drain_soul(); new spell_warl_life_tap(); new spell_warl_nether_protection(); new spell_warl_ritual_of_doom_effect(); diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 272ba71d609..91166294355 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -1429,30 +1429,23 @@ public: { switch (eventId) { - case EVENT_MM_START_MUSIC: - { - if (!IsHolidayActive(HOLIDAY_FIRE_FESTIVAL)) - break; - - Map::PlayerList const &players = go->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + case EVENT_MM_START_MUSIC: { - if (Player* player = itr->GetSource()) + if (!IsHolidayActive(HOLIDAY_FIRE_FESTIVAL)) + break; + + std::vector<Player*> playersNearby; + go->GetPlayerListInGrid(playersNearby, go->GetMap()->GetVisibilityRange()); + for (Player* player : playersNearby) { if (player->GetTeamId() == TEAM_HORDE) - { go->PlayDirectMusic(EVENTMIDSUMMERFIREFESTIVAL_H, player); - } else - { go->PlayDirectMusic(EVENTMIDSUMMERFIREFESTIVAL_A, player); - } } + _events.ScheduleEvent(EVENT_MM_START_MUSIC, 5000); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client (sniffed value) + break; } - - _events.ScheduleEvent(EVENT_MM_START_MUSIC, 5000); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client (sniffed value) - break; - } default: break; } |
