diff --git a/sql/updates/world/4.3.4/2020_10_29_01_world.sql b/sql/updates/world/4.3.4/2020_10_29_01_world.sql new file mode 100644 index 00000000000..be436104555 --- /dev/null +++ b/sql/updates/world/4.3.4/2020_10_29_01_world.sql @@ -0,0 +1,13 @@ +UPDATE `creature_template` SET `ScriptName`= 'npc_scarlet_commander_mograine' WHERE `entry`= 3976; +UPDATE `creature_template_addon` SET `auras`= '' WHERE `entry`= 3976; + +UPDATE `creature_template` SET `ScriptName`= 'npc_high_inquisitor_whitemane', `minlevel`= 40, `maxlevel`= 40 WHERE `entry`= 3977; + +DELETE FROM `spawn_group_template` WHERE `groupId`= 451; +INSERT INTO `spawn_group_template` (`groupId`, `groupName`, `groupFlags`) VALUES +(451, 'The Scarlet Monastery - Mograine and Whitemane', 4); + +DELETE FROM `spawn_group` WHERE `groupId`= 451; +INSERT INTO `spawn_group` (`groupId`, `spawnType`, `spawnId`) VALUES +(451, 0, 39946), +(451, 0, 40029); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp index 66c87d65c02..e20aa3bfcb5 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp @@ -123,5 +123,5 @@ private: void AddSC_boss_arcanist_doan() { - RegisterScarletMonastryCreatureAI(boss_arcanist_doan); + RegisterScarletMonasteryCreatureAI(boss_arcanist_doan); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp index 5543ed79748..bbe56d58b3a 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp @@ -180,5 +180,5 @@ private: void AddSC_boss_bloodmage_thalnos() { - RegisterScarletMonastryCreatureAI(boss_bloodmage_thalnos); + RegisterScarletMonasteryCreatureAI(boss_bloodmage_thalnos); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp index 365801db0a9..7c0e749e993 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp @@ -97,5 +97,5 @@ struct boss_houndmaster_loksey : public BossAI void AddSC_boss_houndmaster_loksey() { - RegisterScarletMonastryCreatureAI(boss_houndmaster_loksey); + RegisterScarletMonasteryCreatureAI(boss_houndmaster_loksey); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp index 5d5e0bb6c6c..8a98503d136 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp @@ -108,5 +108,5 @@ private: void AddSC_boss_interrogator_vishas() { - RegisterScarletMonastryCreatureAI(boss_interrogator_vishas); + RegisterScarletMonasteryCreatureAI(boss_interrogator_vishas); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp index 325209f60da..2929936dfe1 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp @@ -15,366 +15,404 @@ * with this program. If not, see . */ -/* ScriptData -SDName: Boss_Mograine_And_Whitemane -SD%Complete: 90 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - #include "ScriptMgr.h" +#include "GameObject.h" #include "InstanceScript.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "scarlet_monastery.h" #include "ScriptedCreature.h" +#include "Spell.h" #include "SpellInfo.h" enum Says { - //Mograine says + // Scarlet Commander Mograine SAY_MO_AGGRO = 0, SAY_MO_KILL = 1, SAY_MO_RESURRECTED = 2, - //Whitemane says + // High Inquisitor Whitemane SAY_WH_INTRO = 0, SAY_WH_KILL = 1, - SAY_WH_RESURRECT = 2, + SAY_WH_RESURRECT = 2 }; enum Spells { - //Mograine Spells - SPELL_CRUSADERSTRIKE = 14518, - SPELL_HAMMEROFJUSTICE = 5589, - SPELL_LAYONHANDS = 9257, - SPELL_RETRIBUTIONAURA = 8990, + // Scarlet Commander Mograine + SPELL_CRUSADER_STRIKE = 14518, + SPELL_HAMMER_OF_JUSTICE = 77787, + SPELL_DIVINE_SHIELD = 63148, + SPELL_LAY_ON_HANDS = 9257, + SPELL_RETRIBUTION_AURA = 8990, - //Whitemanes Spells - SPELL_DEEPSLEEP = 9256, - SPELL_SCARLETRESURRECTION = 9232, - SPELL_DOMINATEMIND = 14515, - SPELL_HOLYSMITE = 9481, - SPELL_HEAL = 12039, - SPELL_POWERWORDSHIELD = 22187 + // High Inquisitor Whitemane + SPELL_HOLY_SMITE = 25054, + SPELL_DEEP_SLEEP = 9256, + SPELL_SCARLET_RESURRECTION = 9232, + SPELL_HEAL = 12039, + SPELL_POWER_WORD_SHIELD = 22187 }; -class boss_scarlet_commander_mograine : public CreatureScript +enum Events { -public: - boss_scarlet_commander_mograine() : CreatureScript("boss_scarlet_commander_mograine") { } + // Scarlet Commander Mograine + EVENT_RESURRECTED = 1, + EVENT_HAMMER_OF_JUSTICE, + EVENT_CRUSADER_STRIKE, + EVENT_DIVINE_SHIELD, + EVENT_RETRIBUTION_AURA, - struct boss_scarlet_commander_mograineAI : public ScriptedAI + // High Inquisitor Whitemane + EVENT_HOLY_SMITE, + EVENT_DEEP_SLEEP, + EVENT_SCARLET_RESURRECTION, + EVENT_SALUTE_EMOTE, + EVENT_REENGAGE_PLAYERS, + EVENT_HEAL, + EVENT_POWER_WORD_SHIELD +}; + +enum Actions +{ + ACTION_MOGRAINE_DIED = 1, + ACTION_RESURRECTED +}; + +enum Points +{ + POINT_NONE = 0, + POINT_RESURRECT_MOGRAINE +}; + +enum Misc +{ + SOUND_ID_MOGRAINE_DEATH = 1326 +}; + +Position const WhitemaneIntroPosition = { 1150.1221f, 1397.4794f, 32.337616f }; + +struct npc_scarlet_commander_mograine : public ScriptedAI +{ + npc_scarlet_commander_mograine(Creature* creature) : ScriptedAI(creature), _resurrected(false), _killed(false) { } + + void InitializeAI() override { - boss_scarlet_commander_mograineAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } + _instance = me->GetInstanceScript(); + } - void Initialize() - { - CrusaderStrike_Timer = 10000; - HammerOfJustice_Timer = 10000; - _bHasDied = false; - _bHeal = false; - _bFakeDeath = false; - } + void JustAppeared() override + { + DoCastSelf(SPELL_RETRIBUTION_AURA); + } - InstanceScript* instance; + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_MO_AGGRO); + _instance->SetBossState(DATA_MOGRAINE_AND_WHITEMANE, IN_PROGRESS); + me->CallForHelp(VISIBLE_RANGE); + } - uint32 CrusaderStrike_Timer; - uint32 HammerOfJustice_Timer; + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + // The Instance Script will take care of the reset + _instance->SetBossState(DATA_MOGRAINE_AND_WHITEMANE, FAIL); + } - bool _bHasDied; - bool _bHeal; - bool _bFakeDeath; - - void Reset() override - { - Initialize(); - - //Incase wipe during phase that mograine fake death - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetStandState(UNIT_STAND_STATE_STAND); - - if (me->IsAlive()) - instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); - } - - void JustReachedHome() override - { - if (instance->GetBossState(DATA_MOGRAINE_AND_WHITE_EVENT) != NOT_STARTED) - instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, FAIL); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_MO_AGGRO); - DoCast(me, SPELL_RETRIBUTIONAURA); - - me->CallForHelp(VISIBLE_RANGE); - } - - void KilledUnit(Unit* /*victim*/) override - { + void KilledUnit(Unit* who) override + { + if (who->IsPlayer()) Talk(SAY_MO_KILL); - } + } - void DamageTaken(Unit* /*doneBy*/, uint32 &damage) override + void JustDied(Unit* /*killer*/) override + { + _events.Reset(); + if (Creature* whitemane = _instance->GetCreature(DATA_HIGH_INQUISITOR_WHITEMANE)) + if (whitemane->isDead()) + _instance->SetBossState(DATA_MOGRAINE_AND_WHITEMANE, DONE); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + // Mograine cannot die when he has not been resurrected yet. + if (!_resurrected && damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + + if (!_killed && !_resurrected && me->HealthBelowPctDamaged(1, damage)) { - if (damage < me->GetHealth() || _bHasDied || _bFakeDeath) - return; + _killed = true; + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->PlayDistanceSound(SOUND_ID_MOGRAINE_DEATH); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToPC(true, true); + me->SetStandState(UNIT_STAND_STATE_DEAD); + me->RemoveAllAuras(); - //On first death, fake death and open door, as well as initiate whitemane if exist - if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_WHITEMANE))) - { - instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS); - - Whitemane->GetMotionMaster()->MovePoint(1, 1163.113370f, 1398.856812f, 32.527786f); - - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MoveIdle(); - - me->SetHealth(0); - - if (me->IsNonMeleeSpellCast(false)) - me->InterruptNonMeleeSpells(false); - - me->ClearComboPointHolders(); - me->RemoveAllAuras(); - me->ClearAllReactives(); - - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetStandState(UNIT_STAND_STATE_DEAD); - - _bHasDied = true; - _bFakeDeath = true; - - damage = 0; - } + if (Creature* whitemane = _instance->GetCreature(DATA_HIGH_INQUISITOR_WHITEMANE)) + if (whitemane->IsAIEnabled) + whitemane->AI()->DoAction(ACTION_MOGRAINE_DIED); } + } - void SpellHit(Unit* /*who*/, SpellInfo const* spell) override + void DoAction(int32 action) override + { + switch (action) { - //When hit with resurrection say text - if (spell->Id == SPELL_SCARLETRESURRECTION) - { - Talk(SAY_MO_RESURRECTED); - _bFakeDeath = false; - - instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, SPECIAL); - } + case ACTION_RESURRECTED: + _events.ScheduleEvent(EVENT_RESURRECTED, 3s + 500ms); + break; + default: + break; } + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + if (!_killed && !UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) { - if (!UpdateVictim()) - return; - - if (_bHasDied && !_bHeal && instance->GetBossState(DATA_MOGRAINE_AND_WHITE_EVENT) == SPECIAL) + switch (eventId) { - //On resurrection, stop fake death and heal whitemane and resume fight - if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_WHITEMANE))) - { + case EVENT_RESURRECTED: + Talk(SAY_MO_RESURRECTED); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToPC(false, true); me->SetStandState(UNIT_STAND_STATE_STAND); - DoCast(Whitemane, SPELL_LAYONHANDS); + me->SetReactState(REACT_AGGRESSIVE); + DoCastSelf(SPELL_LAY_ON_HANDS); + _resurrected = true; + _killed = false; - CrusaderStrike_Timer = 10000; - HammerOfJustice_Timer = 10000; - - if (me->GetVictim()) - me->GetMotionMaster()->MoveChase(me->GetVictim()); - - _bHeal = true; - } + _events.ScheduleEvent(EVENT_HAMMER_OF_JUSTICE, 6s); + _events.ScheduleEvent(EVENT_RETRIBUTION_AURA, 7s); + _events.ScheduleEvent(EVENT_CRUSADER_STRIKE, 20s); + _events.ScheduleEvent(EVENT_DIVINE_SHIELD, 29s); + break; + case EVENT_HAMMER_OF_JUSTICE: + DoCastVictim(SPELL_HAMMER_OF_JUSTICE); + _events.Repeat(8s, 10s); + break; + case EVENT_CRUSADER_STRIKE: + DoCastVictim(SPELL_CRUSADER_STRIKE); + _events.Repeat(6s); + break; + case EVENT_DIVINE_SHIELD: + DoCastSelf(SPELL_DIVINE_SHIELD); + // @todo: repeat timer + break; + case EVENT_RETRIBUTION_AURA: + DoCastSelf(SPELL_RETRIBUTION_AURA); + break; + default: + break; } - //This if-check to make sure mograine does not attack while fake death - if (_bFakeDeath) + if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - //CrusaderStrike_Timer - if (CrusaderStrike_Timer <= diff) - { - DoCastVictim(SPELL_CRUSADERSTRIKE); - CrusaderStrike_Timer = 10000; - } - else CrusaderStrike_Timer -= diff; - - //HammerOfJustice_Timer - if (HammerOfJustice_Timer <= diff) - { - DoCastVictim(SPELL_HAMMEROFJUSTICE); - HammerOfJustice_Timer = 60000; - } - else HammerOfJustice_Timer -= diff; - - DoMeleeAttackIfReady(); } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetScarletMonasteryAI(creature); + DoMeleeAttackIfReady(); } +private: + InstanceScript* _instance; + EventMap _events; + bool _resurrected; + bool _killed; }; -class boss_high_inquisitor_whitemane : public CreatureScript +struct npc_high_inquisitor_whitemane : public ScriptedAI { -public: - boss_high_inquisitor_whitemane() : CreatureScript("boss_high_inquisitor_whitemane") { } + npc_high_inquisitor_whitemane(Creature* creature) : ScriptedAI(creature), _below50PctHealth(false), _resurrectedMograine(false){ } - struct boss_high_inquisitor_whitemaneAI : public ScriptedAI + void InitializeAI() override { - boss_high_inquisitor_whitemaneAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } - - void Initialize() - { - Wait_Timer = 7000; - Heal_Timer = 10000; - PowerWordShield_Timer = 15000; - HolySmite_Timer = 6000; - - _bCanResurrectCheck = false; - _bCanResurrect = false; - } - - InstanceScript* instance; - - uint32 Heal_Timer; - uint32 PowerWordShield_Timer; - uint32 HolySmite_Timer; - uint32 Wait_Timer; - - bool _bCanResurrectCheck; - bool _bCanResurrect; - - void Reset() override - { - Initialize(); - - if (me->IsAlive()) - instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); - } - - void AttackStart(Unit* who) override - { - if (instance->GetBossState(DATA_MOGRAINE_AND_WHITE_EVENT) == NOT_STARTED) - return; - - ScriptedAI::AttackStart(who); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_WH_INTRO); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_WH_KILL); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - if (!_bCanResurrectCheck && damage >= me->GetHealth()) - damage = me->GetHealth() - 1; - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (_bCanResurrect) - { - //When casting resuruction make sure to delay so on rez when reinstate battle deepsleep runs out - if (Wait_Timer <= diff) - { - if (Creature* mograine = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MOGRAINE))) - { - DoCast(mograine, SPELL_SCARLETRESURRECTION); - Talk(SAY_WH_RESURRECT); - _bCanResurrect = false; - } - } - else Wait_Timer -= diff; - } - - //Cast Deep sleep when health is less than 50% - if (!_bCanResurrectCheck && !HealthAbovePct(50)) - { - if (me->IsNonMeleeSpellCast(false)) - me->InterruptNonMeleeSpells(false); - - DoCastVictim(SPELL_DEEPSLEEP); - _bCanResurrectCheck = true; - _bCanResurrect = true; - return; - } - - //while in "resurrect-mode", don't do anything - if (_bCanResurrect) - return; - - //If we are <75% hp cast healing spells at self or Mograine - if (Heal_Timer <= diff) - { - Creature* target = nullptr; - - if (!HealthAbovePct(75)) - target = me; - - if (Creature* mograine = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MOGRAINE))) - { - // checking _bCanResurrectCheck prevents her healing Mograine while he is "faking death" - if (_bCanResurrectCheck && mograine->IsAlive() && !mograine->HealthAbovePct(75)) - target = mograine; - } - - if (target) - DoCast(target, SPELL_HEAL); - - Heal_Timer = 13000; - } - else Heal_Timer -= diff; - - //PowerWordShield_Timer - if (PowerWordShield_Timer <= diff) - { - DoCast(me, SPELL_POWERWORDSHIELD); - PowerWordShield_Timer = 15000; - } - else PowerWordShield_Timer -= diff; - - //HolySmite_Timer - if (HolySmite_Timer <= diff) - { - DoCastVictim(SPELL_HOLYSMITE); - HolySmite_Timer = 6000; - } - else HolySmite_Timer -= diff; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetScarletMonasteryAI(creature); + me->SetReactState(REACT_PASSIVE); + _instance = me->GetInstanceScript(); } + + void JustEngagedWith(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_HOLY_SMITE, 1ms); + _events.ScheduleEvent(EVENT_HEAL, 12s); + _events.ScheduleEvent(EVENT_POWER_WORD_SHIELD, 22s); // @todo: validate timer + } + + void KilledUnit(Unit* who) override + { + if (who->IsPlayer()) + Talk(SAY_WH_KILL); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + // The Instance Script will take care of the reset + _instance->SetBossState(DATA_MOGRAINE_AND_WHITEMANE, FAIL); + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* mograine = _instance->GetCreature(DATA_SCARLET_COMMANDER_MOGRAINE)) + if (mograine->isDead()) + _instance->SetBossState(DATA_MOGRAINE_AND_WHITEMANE, DONE); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + // Do not allow Whitemane to die before she has resurrected Mograine. + // This bug can actually happen on retail but for the sake of it, we wont allow it to happen. + if (!_resurrectedMograine && damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + + if (!_below50PctHealth && me->HealthBelowPctDamaged(50, damage)) + { + _below50PctHealth = true; + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + _events.Reset(); + _events.ScheduleEvent(EVENT_DEEP_SLEEP, 1ms); + } + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_MOGRAINE_DIED: + Talk(SAY_WH_INTRO); + if (GameObject* door = _instance->GetGameObject(DATA_HIGH_INQUISITORS_DOOR)) + door->UseDoorOrButton(); + me->GetMotionMaster()->MovePoint(POINT_NONE, WhitemaneIntroPosition); + me->SetReactState(REACT_AGGRESSIVE); + break; + default: + break; + } + } + + void MovementInform(uint32 type, uint32 pointId) + { + if (type != POINT_MOTION_TYPE) + return; + + switch (pointId) + { + case POINT_RESURRECT_MOGRAINE: + _events.ScheduleEvent(EVENT_SCARLET_RESURRECTION, 3s); + break; + default: + break; + } + } + + void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override + { + if (spell->Id == SPELL_SCARLET_RESURRECTION && reason == SPELL_FINISHED_SUCCESSFUL_CAST) + { + Talk(SAY_WH_RESURRECT); + _resurrectedMograine = true; + _events.ScheduleEvent(EVENT_SALUTE_EMOTE, 1s); + _events.ScheduleEvent(EVENT_REENGAGE_PLAYERS, 5s); + + if (Creature* mograine = _instance->GetCreature(DATA_SCARLET_COMMANDER_MOGRAINE)) + if (mograine->IsAIEnabled) + mograine->AI()->DoAction(ACTION_RESURRECTED); + } + } + + 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_HOLY_SMITE: + DoCastVictim(SPELL_HOLY_SMITE); + _events.Repeat(5s, 7s); + break; + case EVENT_DEEP_SLEEP: + DoCastAOE(SPELL_DEEP_SLEEP); + if (Creature* mograine = _instance->GetCreature(DATA_SCARLET_COMMANDER_MOGRAINE)) + { + Position pos = mograine->GetPosition(); + mograine->MovePositionToFirstCollision(pos, 2.f, mograine->GetRelativeAngle(me)); + me->GetMotionMaster()->MovePoint(POINT_RESURRECT_MOGRAINE, pos); + } + break; + case EVENT_SCARLET_RESURRECTION: + DoCastAOE(SPELL_SCARLET_RESURRECTION); + break; + case EVENT_SALUTE_EMOTE: + me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + break; + case EVENT_REENGAGE_PLAYERS: + me->SetReactState(REACT_AGGRESSIVE); + _events.ScheduleEvent(EVENT_HOLY_SMITE, 1ms); + _events.ScheduleEvent(EVENT_HEAL, 12s); + _events.ScheduleEvent(EVENT_POWER_WORD_SHIELD, 22s); + break; + case EVENT_HEAL: + { + // @todo: This logic has been ported from CMangos since there is very little sniff information about conditions and repeat timers + Unit* target = nullptr; + if (me->GetHealthPct() < 75.f) + target = me; + else if (Creature* mograine = _instance->GetCreature(DATA_SCARLET_COMMANDER_MOGRAINE)) + if (mograine->GetHealthPct() < 75.f) + target = mograine; + + if (target) + { + DoCast(target, SPELL_HEAL); + _events.Repeat(13s); + } + else + _events.Repeat(1s); + break; + } + case EVENT_POWER_WORD_SHIELD: + DoCastSelf(SPELL_POWER_WORD_SHIELD); + _events.Repeat(22s, 45s); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoMeleeAttackIfReady(); + } +private: + InstanceScript* _instance; + EventMap _events; + bool _below50PctHealth; + bool _resurrectedMograine; }; + void AddSC_boss_mograine_and_whitemane() { - new boss_scarlet_commander_mograine(); - new boss_high_inquisitor_whitemane(); + RegisterScarletMonasteryCreatureAI(npc_scarlet_commander_mograine); + RegisterScarletMonasteryCreatureAI(npc_high_inquisitor_whitemane); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp index f431b904a07..9a202beec09 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp @@ -17,6 +17,7 @@ #include "ScriptMgr.h" #include "Creature.h" +#include "EventMap.h" #include "GameObject.h" #include "InstanceScript.h" #include "Map.h" @@ -24,17 +25,29 @@ ObjectData const creatureData[] = { - { BOSS_INTERROGATOR_VISHAS, DATA_INTERROGATOR_VISHAS }, - { BOSS_BLOODMAGE_THALNOS, DATA_BLOODMAGE_THALNOS }, - { BOSS_HOUNDMASTER_LOKSEY, DATA_HOUNDMASTER_LOKSEY }, - { BOSS_ARCANIST_DOAN, DATA_ARCANIST_DOAN }, - { 0, 0 } // END + { BOSS_INTERROGATOR_VISHAS, DATA_INTERROGATOR_VISHAS }, + { BOSS_BLOODMAGE_THALNOS, DATA_BLOODMAGE_THALNOS }, + { BOSS_HOUNDMASTER_LOKSEY, DATA_HOUNDMASTER_LOKSEY }, + { BOSS_ARCANIST_DOAN, DATA_ARCANIST_DOAN }, + { BOSS_HIGH_INQUISITOR_WHITEMANE, DATA_HIGH_INQUISITOR_WHITEMANE }, + { BOSS_SCARLET_COMMANDER_MOGRAINE, DATA_SCARLET_COMMANDER_MOGRAINE }, + { 0, 0 } // END }; -DoorData const doorData[] = +ObjectData const gameObjectData[] = { - { GO_HIGH_INQUISITORS_DOOR, DATA_MOGRAINE_AND_WHITE_EVENT, DOOR_TYPE_ROOM }, - { 0, 0, DOOR_TYPE_ROOM } // END + { GO_HIGH_INQUISITORS_DOOR, DATA_HIGH_INQUISITORS_DOOR }, + { 0, 0 } // END +}; + +enum SpawnGroups +{ + SPAWN_GROUP_ID_WHITEMANE_AND_MOGRAINE = 451 +}; + +enum Events +{ + EVENT_RESPAWN_MOGRAINE_AND_WHITEMANE = 1 }; class instance_scarlet_monastery : public InstanceMapScript @@ -48,34 +61,29 @@ class instance_scarlet_monastery : public InstanceMapScript { SetHeaders(DataHeader); SetBossNumber(EncounterCount); - LoadObjectData(creatureData, nullptr); - LoadDoorData(doorData); + LoadObjectData(creatureData, gameObjectData); + } - HorsemanAdds.clear(); + void Create() override + { + instance->SpawnGroupSpawn(SPAWN_GROUP_ID_WHITEMANE_AND_MOGRAINE, true); + } + + void Load(char const* /*data*/) override + { + if (GetBossState(DATA_MOGRAINE_AND_WHITEMANE) != DONE) + instance->SpawnGroupSpawn(SPAWN_GROUP_ID_WHITEMANE_AND_MOGRAINE, true, true); } void OnGameObjectCreate(GameObject* go) override { + InstanceScript::OnGameObjectCreate(go); + switch (go->GetEntry()) { case GO_PUMPKIN_SHRINE: PumpkinShrineGUID = go->GetGUID(); break; - case GO_HIGH_INQUISITORS_DOOR: - AddDoor(go, true); - break; - default: - break; - } - } - - void OnGameObjectRemove(GameObject* go) override - { - switch (go->GetEntry()) - { - case GO_HIGH_INQUISITORS_DOOR: - AddDoor(go, false); - break; default: break; } @@ -83,6 +91,8 @@ class instance_scarlet_monastery : public InstanceMapScript void OnCreatureCreate(Creature* creature) override { + InstanceScript::OnCreatureCreate(creature); + switch (creature->GetEntry()) { case NPC_HORSEMAN: @@ -94,12 +104,6 @@ class instance_scarlet_monastery : public InstanceMapScript case NPC_PUMPKIN: HorsemanAdds.insert(creature->GetGUID()); break; - case NPC_MOGRAINE: - MograineGUID = creature->GetGUID(); - break; - case NPC_WHITEMANE: - WhitemaneGUID = creature->GetGUID(); - break; case NPC_VORREL: VorrelGUID = creature->GetGUID(); break; @@ -140,20 +144,43 @@ class instance_scarlet_monastery : public InstanceMapScript HandleGameObject(PumpkinShrineGUID, false); } break; + case DATA_MOGRAINE_AND_WHITEMANE: + if (state == FAIL) + { + instance->SpawnGroupDespawn(SPAWN_GROUP_ID_WHITEMANE_AND_MOGRAINE); + _events.ScheduleEvent(EVENT_RESPAWN_MOGRAINE_AND_WHITEMANE, 30s); + + if (GameObject* door = GetGameObject(DATA_HIGH_INQUISITORS_DOOR)) + door->ResetDoorOrButton(); + } + break; default: break; } return true; } + void Update(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RESPAWN_MOGRAINE_AND_WHITEMANE: + instance->SpawnGroupSpawn(SPAWN_GROUP_ID_WHITEMANE_AND_MOGRAINE); + break; + default: + break; + } + } + } + ObjectGuid GetGuidData(uint32 type) const override { switch (type) { - case DATA_MOGRAINE: - return MograineGUID; - case DATA_WHITEMANE: - return WhitemaneGUID; case DATA_VORREL: return VorrelGUID; default: @@ -162,14 +189,13 @@ class instance_scarlet_monastery : public InstanceMapScript return ObjectGuid::Empty; } - protected: + private: + EventMap _events; + ObjectGuid PumpkinShrineGUID; ObjectGuid HorsemanGUID; ObjectGuid HeadGUID; - ObjectGuid MograineGUID; - ObjectGuid WhitemaneGUID; ObjectGuid VorrelGUID; - GuidSet HorsemanAdds; }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h index a66789ccd5b..9859cce402f 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h @@ -30,40 +30,43 @@ enum SMDataTypes // Bosses DATA_INTERROGATOR_VISHAS = 1, DATA_BLOODMAGE_THALNOS = 2, + DATA_ARCANIST_DOAN = 3, + DATA_HOUNDMASTER_LOKSEY = 4, + DATA_MOGRAINE_AND_WHITEMANE = 5, - DATA_MOGRAINE_AND_WHITE_EVENT, - DATA_MOGRAINE, - DATA_WHITEMANE, + + // Additional Data Types + DATA_SCARLET_COMMANDER_MOGRAINE, + DATA_HIGH_INQUISITOR_WHITEMANE, DATA_HORSEMAN_EVENT, DATA_PUMPKIN_SHRINE, DATA_VORREL, - DATA_ARCANIST_DOAN, DATA_AZSHIR, DATA_HEROD, DATA_HIGH_INQUISITOR_FAIRBANKS, - DATA_HOUNDMASTER_LOKSEY, - DATA_SCORN + DATA_SCORN, + DATA_HIGH_INQUISITORS_DOOR, }; enum SMCreatureIds { // Bosses - BOSS_INTERROGATOR_VISHAS = 3983, - BOSS_BLOODMAGE_THALNOS = 4543, - BOSS_HOUNDMASTER_LOKSEY = 3974, - BOSS_ARCANIST_DOAN = 6487, + BOSS_INTERROGATOR_VISHAS = 3983, + BOSS_BLOODMAGE_THALNOS = 4543, + BOSS_HOUNDMASTER_LOKSEY = 3974, + BOSS_ARCANIST_DOAN = 6487, + BOSS_HIGH_INQUISITOR_WHITEMANE = 3977, + BOSS_SCARLET_COMMANDER_MOGRAINE = 3976, // Encounter related creature /*Houndmaster Loksey*/ - NPC_SCARLET_TRACKING_HOUND = 4304, + NPC_SCARLET_TRACKING_HOUND = 4304, - NPC_MOGRAINE = 3976, - NPC_WHITEMANE = 3977, - NPC_VORREL = 3981, + NPC_VORREL = 3981, - NPC_HORSEMAN = 23682, - NPC_HEAD = 23775, - NPC_PUMPKIN = 23694 + NPC_HORSEMAN = 23682, + NPC_HEAD = 23775, + NPC_PUMPKIN = 23694 }; enum SMGameObjectIds @@ -78,7 +81,7 @@ inline AI* GetScarletMonasteryAI(T* obj) return GetInstanceAI(obj, SMScriptName); } -#define RegisterScarletMonastryCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetScarletMonasteryAI) +#define RegisterScarletMonasteryCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetScarletMonasteryAI) #endif // SCARLET_M_