diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp index d2fd5b07e..410b32ca1 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp @@ -36,131 +36,87 @@ enum Enums SPELL_BANISH_DRAGON_HELPER = 31550 }; -enum Events +struct boss_aeonus : public BossAI { - EVENT_SANDBREATH = 1, - EVENT_TIMESTOP = 2, - EVENT_FRENZY = 3, - EVENT_CLEAVE = 4 -}; + boss_aeonus(Creature* creature) : BossAI(creature, DATA_AEONUS) { } -class boss_aeonus : public CreatureScript -{ -public: - boss_aeonus() : CreatureScript("boss_aeonus") { } - - struct boss_aeonusAI : public ScriptedAI + void JustReachedHome() override { - boss_aeonusAI(Creature* creature) : ScriptedAI(creature) + if (Creature* medivh = instance->GetCreature(DATA_MEDIVH)) { - instance = creature->GetInstanceScript(); - } - - EventMap events; - InstanceScript* instance; - - void Reset() override - { - events.Reset(); - } - - void JustReachedHome() override - { - if (Unit* medivh = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_MEDIVH))) - if (me->GetDistance2d(medivh) < 20.0f) - me->CastSpell(me, SPELL_CORRUPT_MEDIVH, false); - } - - void InitializeAI() override - { - Talk(SAY_ENTER); - ScriptedAI::InitializeAI(); - - if (Unit* medivh = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_MEDIVH))) + if (me->GetDistance2d(medivh) < 20.0f) { - me->SetHomePosition(medivh->GetPositionX() + 14.0f * cos(medivh->GetAngle(me)), medivh->GetPositionY() + 14.0f * std::sin(medivh->GetAngle(me)), medivh->GetPositionZ(), me->GetAngle(medivh)); - me->GetMotionMaster()->MoveTargetedHome(); + DoCastAOE(SPELL_CORRUPT_MEDIVH); } } + } - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_CLEAVE, 5000); - events.ScheduleEvent(EVENT_SANDBREATH, 20000); - events.ScheduleEvent(EVENT_TIMESTOP, 15000); - events.ScheduleEvent(EVENT_FRENZY, 30000); - - Talk(SAY_AGGRO); - } - - void MoveInLineOfSight(Unit* who) override - { - if (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_TIME_KEEPER) - { - if (me->IsWithinDistInMap(who, 20.0f)) - { - Talk(SAY_BANISH); - me->CastSpell(me, SPELL_BANISH_DRAGON_HELPER, true); - return; - } - } - - ScriptedAI::MoveInLineOfSight(who); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - instance->SetData(TYPE_AEONUS, DONE); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_CLEAVE: - me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false); - events.ScheduleEvent(EVENT_CLEAVE, 10000); - break; - case EVENT_SANDBREATH: - me->CastSpell(me->GetVictim(), SPELL_SAND_BREATH, false); - events.ScheduleEvent(EVENT_SANDBREATH, 20000); - break; - case EVENT_TIMESTOP: - me->CastSpell(me, SPELL_TIME_STOP, false); - events.ScheduleEvent(EVENT_TIMESTOP, 25000); - break; - case EVENT_FRENZY: - Talk(EMOTE_FRENZY); - me->CastSpell(me, SPELL_ENRAGE, false); - events.ScheduleEvent(EVENT_FRENZY, 30000); - break; - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void IsSummonedBy(WorldObject* /*summoner*/) override { - return GetTheBlackMorassAI(creature); + Talk(SAY_ENTER); + + if (Creature* medivh = instance->GetCreature(DATA_MEDIVH)) + { + me->SetHomePosition(medivh->GetPositionX() + 14.0f * cos(medivh->GetAngle(me)), medivh->GetPositionY() + 14.0f * std::sin(medivh->GetAngle(me)), medivh->GetPositionZ(), me->GetAngle(medivh)); + me->GetMotionMaster()->MoveTargetedHome(); + } + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + + scheduler.Schedule(5s, [this](TaskContext context) + { + DoCastVictim(SPELL_CLEAVE); + context.Repeat(10s); + }).Schedule(20s, [this](TaskContext context) + { + DoCastVictim(SPELL_SAND_BREATH); + context.Repeat(20s); + }).Schedule(15s, [this](TaskContext context) + { + DoCastAOE(SPELL_TIME_STOP); + context.Repeat(25s); + }).Schedule(30s, [this](TaskContext context) + { + Talk(EMOTE_FRENZY); + DoCastSelf(SPELL_ENRAGE); + context.Repeat(30s); + }); + } + + void MoveInLineOfSight(Unit* who) override + { + if (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_TIME_KEEPER) + { + if (me->IsWithinDistInMap(who, 20.0f)) + { + Talk(SAY_BANISH); + DoCastAOE(SPELL_BANISH_DRAGON_HELPER, true); + return; + } + } + + ScriptedAI::MoveInLineOfSight(who); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + _JustDied(); + } + + void KilledUnit(Unit* victim) override + { + if (victim->IsPlayer()) + { + Talk(SAY_SLAY); + } } }; void AddSC_boss_aeonus() { - new boss_aeonus(); + RegisterTheBlackMorassCreatureAI(boss_aeonus); } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_chrono_lord_deja.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_chrono_lord_deja.cpp index 8ef6ce89c..617fb5b38 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_chrono_lord_deja.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_chrono_lord_deja.cpp @@ -35,121 +35,84 @@ enum Enums SPELL_BANISH_DRAGON_HELPER = 31550, }; -enum Events -{ - EVENT_ARCANE_BLAST = 1, - EVENT_TIME_LAPSE = 2, - EVENT_ARCANE_DISCHARGE = 3, - EVENT_ATTRACTION = 4 -}; + struct boss_chrono_lord_deja : public BossAI + { + boss_chrono_lord_deja(Creature* creature) : BossAI(creature, DATA_CHRONO_LORD_DEJA) { } -class boss_chrono_lord_deja : public CreatureScript -{ -public: - boss_chrono_lord_deja() : CreatureScript("boss_chrono_lord_deja") { } + void OwnTalk(uint32 id) + { + if (me->GetEntry() == NPC_CHRONO_LORD_DEJA) + { + Talk(id); + } + } - struct boss_chrono_lord_dejaAI : public ScriptedAI - { - boss_chrono_lord_dejaAI(Creature* creature) : ScriptedAI(creature) { } + void InitializeAI() override + { + OwnTalk(SAY_ENTER); + ScriptedAI::InitializeAI(); + } - EventMap events; + void JustEngagedWith(Unit* /*who*/) override + { + OwnTalk(SAY_AGGRO); + _JustEngagedWith(); - void Reset() override - { - events.Reset(); - } + scheduler.Schedule(10s, [this](TaskContext context) + { + DoCastVictim(SPELL_ARCANE_BLAST); + context.Repeat(20s); + }).Schedule(15s, [this](TaskContext context) + { + DoCastAOE(SPELL_TIME_LAPSE); + context.Repeat(20s); + }).Schedule(20s, [this](TaskContext context) + { + DoCastAOE(SPELL_ARCANE_DISCHARGE); + context.Repeat(25s); + }); - void OwnTalk(uint32 id) - { - if (me->GetEntry() == NPC_CHRONO_LORD_DEJA) - Talk(id); - } + if (IsHeroic()) + { + scheduler.Schedule(20s, [this](TaskContext context) + { + DoCastAOE(SPELL_ATTRACTION); + context.Repeat(30s); + }); + } + } - void InitializeAI() override - { - OwnTalk(SAY_ENTER); - ScriptedAI::InitializeAI(); - } + void MoveInLineOfSight(Unit* who) override + { + if (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_TIME_KEEPER) + { + if (me->IsWithinDistInMap(who, 20.0f)) + { + OwnTalk(SAY_BANISH); + DoCastAOE(SPELL_BANISH_DRAGON_HELPER); + return; + } + } - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_ARCANE_BLAST, 10000); - events.ScheduleEvent(EVENT_TIME_LAPSE, 15000); - events.ScheduleEvent(EVENT_ARCANE_DISCHARGE, 25000); - if (IsHeroic()) - events.ScheduleEvent(EVENT_ATTRACTION, 20000); + ScriptedAI::MoveInLineOfSight(who); + } - OwnTalk(SAY_AGGRO); - } + void KilledUnit(Unit* victim) override + { + if (victim->IsPlayer()) + { + OwnTalk(SAY_SLAY); + } + } - void MoveInLineOfSight(Unit* who) override - { - if (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_TIME_KEEPER) - { - if (me->IsWithinDistInMap(who, 20.0f)) - { - OwnTalk(SAY_BANISH); - me->CastSpell(me, SPELL_BANISH_DRAGON_HELPER, true); - return; - } - } - - ScriptedAI::MoveInLineOfSight(who); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - OwnTalk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - OwnTalk(SAY_DEATH); - if (InstanceScript* instance = me->GetInstanceScript()) - instance->SetData(TYPE_CHRONO_LORD_DEJA, DONE); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - events.Update(diff); - switch (events.ExecuteEvent()) - { - case EVENT_ARCANE_BLAST: - me->CastSpell(me->GetVictim(), SPELL_ARCANE_BLAST, false); - events.ScheduleEvent(EVENT_ARCANE_BLAST, 20000); - break; - case EVENT_TIME_LAPSE: - me->CastSpell(me, SPELL_TIME_LAPSE, false); - events.ScheduleEvent(EVENT_TIME_LAPSE, 20000); - break; - case EVENT_ARCANE_DISCHARGE: - me->CastSpell(me, SPELL_ARCANE_DISCHARGE, false); - events.ScheduleEvent(EVENT_ARCANE_DISCHARGE, 25000); - break; - case EVENT_ATTRACTION: - me->CastSpell(me, SPELL_ATTRACTION, false); - events.ScheduleEvent(EVENT_ATTRACTION, 30000); - break; - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetTheBlackMorassAI(creature); - } -}; + void JustDied(Unit* /*killer*/) override + { + OwnTalk(SAY_DEATH); + _JustDied(); + } + }; void AddSC_boss_chrono_lord_deja() { - new boss_chrono_lord_deja(); + RegisterTheBlackMorassCreatureAI(boss_chrono_lord_deja); } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp index f17bc8f60..85577952a 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp @@ -34,121 +34,83 @@ enum Enums SPELL_BANISH_DRAGON_HELPER = 31550 }; -enum Events +struct boss_temporus : public BossAI { - EVENT_HASTEN = 1, - EVENT_MORTAL_WOUND = 2, - EVENT_WING_BUFFET = 3, - EVENT_SPELL_REFLECTION = 4 -}; + boss_temporus(Creature* creature) : BossAI(creature, DATA_TEMPORUS) { } -class boss_temporus : public CreatureScript -{ -public: - boss_temporus() : CreatureScript("boss_temporus") { } - - struct boss_temporusAI : public ScriptedAI + void OwnTalk(uint32 id) { - boss_temporusAI(Creature* creature) : ScriptedAI(creature) { } + if (me->GetEntry() == NPC_TEMPORUS) + Talk(id); + } - EventMap events; - - void OwnTalk(uint32 id) - { - if (me->GetEntry() == NPC_TEMPORUS) - Talk(id); - } - - void Reset() override - { - events.Reset(); - } - - void InitializeAI() override - { - OwnTalk(SAY_ENTER); - ScriptedAI::InitializeAI(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_HASTEN, 12000); - events.ScheduleEvent(EVENT_MORTAL_WOUND, 5000); - events.ScheduleEvent(EVENT_WING_BUFFET, 20000); - if (IsHeroic()) - events.ScheduleEvent(EVENT_SPELL_REFLECTION, 28000); - - OwnTalk(SAY_AGGRO); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - OwnTalk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - OwnTalk(SAY_DEATH); - if (InstanceScript* instance = me->GetInstanceScript()) - instance->SetData(TYPE_TEMPORUS, DONE); - } - - void MoveInLineOfSight(Unit* who) override - { - if (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_TIME_KEEPER) - { - if (me->IsWithinDistInMap(who, 20.0f)) - { - OwnTalk(SAY_BANISH); - me->CastSpell(me, SPELL_BANISH_DRAGON_HELPER, true); - return; - } - } - - ScriptedAI::MoveInLineOfSight(who); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_HASTEN: - me->CastSpell(me, SPELL_HASTEN, false); - events.ScheduleEvent(EVENT_HASTEN, 20000); - break; - case EVENT_MORTAL_WOUND: - me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false); - events.ScheduleEvent(EVENT_MORTAL_WOUND, 10000); - break; - case EVENT_WING_BUFFET: - me->CastSpell(me, SPELL_WING_BUFFET, false); - events.ScheduleEvent(EVENT_WING_BUFFET, 20000); - break; - case EVENT_SPELL_REFLECTION: - me->CastSpell(me, SPELL_REFLECT, false); - events.ScheduleEvent(EVENT_SPELL_REFLECTION, 30000); - break; - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void InitializeAI() override { - return GetTheBlackMorassAI(creature); + OwnTalk(SAY_ENTER); + ScriptedAI::InitializeAI(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + + scheduler.Schedule(12s, [this](TaskContext context) + { + DoCastSelf(SPELL_HASTEN); + context.Repeat(20s); + }).Schedule(5s, [this](TaskContext context) + { + DoCastVictim(SPELL_MORTAL_WOUND); + context.Repeat(10s); + }).Schedule(20s, [this](TaskContext context) + { + DoCastAOE(SPELL_WING_BUFFET); + context.Repeat(20s); + }); + + if (IsHeroic()) + { + scheduler.Schedule(28s, [this](TaskContext context) + { + DoCastSelf(SPELL_REFLECT); + context.Repeat(30s); + }); + } + + OwnTalk(SAY_AGGRO); + } + + void KilledUnit(Unit* victim) override + { + if (victim->IsPlayer()) + { + OwnTalk(SAY_SLAY); + } + } + + void JustDied(Unit* /*killer*/) override + { + OwnTalk(SAY_DEATH); + _JustDied(); + } + + void MoveInLineOfSight(Unit* who) override + { + if (who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_TIME_KEEPER) + { + if (me->IsWithinDistInMap(who, 20.0f)) + { + OwnTalk(SAY_BANISH); + me->CastSpell(me, SPELL_BANISH_DRAGON_HELPER, true); + return; + } + } + + ScriptedAI::MoveInLineOfSight(who); } }; void AddSC_boss_temporus() { - new boss_temporus(); + RegisterTheBlackMorassCreatureAI(boss_temporus); } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp index aa80861ad..e98a27561 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp @@ -23,8 +23,7 @@ #include "TemporarySummon.h" #include "the_black_morass.h" -#define MAX_PORTAL_LOCATIONS 4 -const Position PortalLocation[MAX_PORTAL_LOCATIONS] = +const Position PortalLocation[4] = { { -2030.8318f, 7024.9443f, 23.071817f, 3.14159f }, { -1961.7335f, 7029.5280f, 21.811401f, 2.12931f }, @@ -32,6 +31,11 @@ const Position PortalLocation[MAX_PORTAL_LOCATIONS] = { -1930.9106f, 7183.5970f, 23.007639f, 3.59537f } }; +ObjectData const creatureData[1] = +{ + { NPC_MEDIVH, DATA_MEDIVH } +}; + class instance_the_black_morass : public InstanceMapScript { public: @@ -44,67 +48,172 @@ public: struct instance_the_black_morass_InstanceMapScript : public InstanceScript { - instance_the_black_morass_InstanceMapScript(Map* map) : InstanceScript(map) { } - - GuidSet encounterNPCs; - uint32 encounters[MAX_ENCOUNTER]; - ObjectGuid _medivhGUID; - uint8 _currentRift; - int8 _shieldPercent; - - void Initialize() override + instance_the_black_morass_InstanceMapScript(Map* map) : InstanceScript(map) { SetHeaders(DataHeader); - memset(&encounters, 0, sizeof(encounters)); + SetBossNumber(EncounterCount); + LoadObjectData(creatureData, nullptr); _currentRift = 0; _shieldPercent = 100; - encounterNPCs.clear(); + _encounterNPCs.clear(); _timerToNextBoss = 0; } void CleanupInstance() { - Events.Reset(); _currentRift = 0; _shieldPercent = 100; - _usedRiftPostions.fill(ObjectGuid::Empty); + _availableRiftPositions.clear(); + _scheduler.CancelAll(); - instance->LoadGrid(-2023.0f, 7121.0f); - if (Creature* medivh = instance->GetCreature(_medivhGUID)) + for (Position const& pos : PortalLocation) { - medivh->DespawnOrUnsummon(); - medivh->SetRespawnTime(3); + _availableRiftPositions.push_back(pos); } - GuidSet eCopy = encounterNPCs; - for (ObjectGuid const& guid : eCopy) - if (Creature* creature = instance->GetCreature(guid)) - creature->DespawnOrUnsummon(); + instance->LoadGrid(-2023.0f, 7121.0f); + if (Creature* medivh = GetCreature(DATA_MEDIVH)) + { + medivh->DespawnOrUnsummon(0ms, 3s); + } } - bool IsEncounterInProgress() const override + bool SetBossState(uint32 type, EncounterState state) override { - return false; + if (!InstanceScript::SetBossState(type, state)) + { + return false; + } + + if (state == DONE) + { + switch (type) + { + case DATA_AEONUS: + { + if (Creature* medivh = GetCreature(DATA_MEDIVH)) + { + medivh->AI()->DoAction(ACTION_OUTRO); + } + + instance->DoForAllPlayers([&](Player* player) + { + if (player->GetQuestStatus(QUEST_OPENING_PORTAL) == QUEST_STATUS_INCOMPLETE) + { + player->AreaExploredOrEventHappens(QUEST_OPENING_PORTAL); + } + + if (player->GetQuestStatus(QUEST_MASTER_TOUCH) == QUEST_STATUS_INCOMPLETE) + { + player->AreaExploredOrEventHappens(QUEST_MASTER_TOUCH); + } + }); + break; + } + case DATA_CHRONO_LORD_DEJA: + case DATA_TEMPORUS: + { + for (ObjectGuid const& guid : _encounterNPCs) + { + if (Creature* creature = instance->GetCreature(guid)) + { + switch (creature->GetEntry()) + { + case NPC_RIFT_KEEPER_WARLOCK: + case NPC_RIFT_KEEPER_MAGE: + case NPC_RIFT_LORD: + case NPC_RIFT_LORD_2: + case NPC_TIME_RIFT: + creature->DespawnOrUnsummon(); + break; + default: + break; + } + } + } + + if (!_timerToNextBoss || _timerToNextBoss > 30 * IN_MILLISECONDS) + { + ScheduleNextPortal(30s); + } + else + { + ScheduleNextPortal(Milliseconds(_timerToNextBoss)); + } + + _timerToNextBoss = (instance->IsHeroic() ? 300 : 150) * IN_MILLISECONDS; + break; + } + default: + break; + } + } + + return true; } void OnPlayerEnter(Player* player) override { - if (instance->GetPlayersCountExceptGMs() <= 1 && GetData(TYPE_AEONUS) != DONE) + if (instance->GetPlayersCountExceptGMs() <= 1 && GetBossState(DATA_AEONUS) != DONE) + { CleanupInstance(); + } player->SendUpdateWorldState(WORLD_STATE_BM, _currentRift > 0 ? 1 : 0); player->SendUpdateWorldState(WORLD_STATE_BM_SHIELD, _shieldPercent); player->SendUpdateWorldState(WORLD_STATE_BM_RIFT, _currentRift); } + void ScheduleNextPortal(Milliseconds time) + { + _scheduler.CancelGroup(CONTEXT_GROUP_RIFTS); + + _scheduler.Schedule(time, [this](TaskContext context) + { + if (GetCreature(DATA_MEDIVH)) + { + Position spawnPos; + if (!_availableRiftPositions.empty()) + { + spawnPos = Acore::Containers::SelectRandomContainerElement(_availableRiftPositions); + _availableRiftPositions.remove(spawnPos); + + DoUpdateWorldState(WORLD_STATE_BM_RIFT, ++_currentRift); + + if (Creature* rift = instance->SummonCreature(NPC_TIME_RIFT, spawnPos)) + { + _scheduler.Schedule(6s, [this, rift](TaskContext) + { + SummonPortalKeeper(rift); + }); + } + + // Here we check if we have available rift spots. + // If there are spots available, spawn a rift instantly. + if (!_availableRiftPositions.empty()) + { + context.Repeat((_currentRift >= 13 ? 2min : 90s)); + } + else + { + context.Repeat(3s); + } + } + else + { + context.Repeat(3s); + } + + context.SetGroup(CONTEXT_GROUP_RIFTS); + } + }); + } + void OnCreatureCreate(Creature* creature) override { switch (creature->GetEntry()) { - case NPC_MEDIVH: - _medivhGUID = creature->GetGUID(); - break; case NPC_TIME_RIFT: case NPC_CHRONO_LORD_DEJA: case NPC_INFINITE_CHRONO_LORD: @@ -121,9 +230,11 @@ public: case NPC_INFINITE_EXECUTIONER: case NPC_INFINITE_VANQUISHER: case NPC_DP_BEAM_STALKER: - encounterNPCs.insert(creature->GetGUID()); + _encounterNPCs.insert(creature->GetGUID()); break; } + + InstanceScript::OnCreatureCreate(creature); } void OnCreatureRemove(Creature* creature) override @@ -131,6 +242,22 @@ public: switch (creature->GetEntry()) { case NPC_TIME_RIFT: + _availableRiftPositions.push_back(creature->GetHomePosition()); + + if (GetBossState(DATA_AEONUS) != DONE) + { + // Here we check if we have available rift spots. + // If there are spots available, spawn a rift instantly. + if (!_availableRiftPositions.empty()) + { + ScheduleNextPortal(4s); + } + else + { + ScheduleNextPortal((_currentRift >= 13 ? 2min : 90s)); + } + } + [[fallthrough]]; case NPC_CHRONO_LORD_DEJA: case NPC_INFINITE_CHRONO_LORD: case NPC_TEMPORUS: @@ -145,92 +272,28 @@ public: case NPC_INFINITE_CRONOMANCER: case NPC_INFINITE_EXECUTIONER: case NPC_INFINITE_VANQUISHER: - encounterNPCs.erase(creature->GetGUID()); + _encounterNPCs.erase(creature->GetGUID()); break; } + + InstanceScript::OnCreatureRemove(creature); } void SetData(uint32 type, uint32 data) override { switch (type) { - case TYPE_AEONUS: - { - encounters[type] = DONE; - SaveToDB(); - - if (Creature* medivh = instance->GetCreature(_medivhGUID)) - { - medivh->AI()->DoAction(ACTION_OUTRO); - } - - Map::PlayerList const& players = instance->GetPlayers(); - if (!players.IsEmpty()) - { - for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - if (Player* player = itr->GetSource()) - { - if (player->GetQuestStatus(QUEST_OPENING_PORTAL) == QUEST_STATUS_INCOMPLETE) - { - player->AreaExploredOrEventHappens(QUEST_OPENING_PORTAL); - } - - if (player->GetQuestStatus(QUEST_MASTER_TOUCH) == QUEST_STATUS_INCOMPLETE) - { - player->AreaExploredOrEventHappens(QUEST_MASTER_TOUCH); - } - } - } - } - break; - } - case TYPE_CHRONO_LORD_DEJA: - case TYPE_TEMPORUS: - { - GuidSet eCopy = encounterNPCs; - for (ObjectGuid const& guid : eCopy) - { - if (Creature* creature = instance->GetCreature(guid)) - { - switch (creature->GetEntry()) - { - case NPC_RIFT_KEEPER_WARLOCK: - case NPC_RIFT_KEEPER_MAGE: - case NPC_RIFT_LORD: - case NPC_RIFT_LORD_2: - case NPC_TIME_RIFT: - creature->DespawnOrUnsummon(); - break; - default: - break; - } - } - } - encounters[type] = DONE; - - if (!_timerToNextBoss || _timerToNextBoss > 30 * IN_MILLISECONDS) - { - Events.RescheduleEvent(EVENT_NEXT_PORTAL, 30 * IN_MILLISECONDS); - } - else - { - Events.RescheduleEvent(EVENT_NEXT_PORTAL, _timerToNextBoss); - } - Events.SetPhase(1); - SaveToDB(); - _timerToNextBoss = (instance->IsHeroic() ? 300 : 150) * IN_MILLISECONDS; - break; - } case DATA_MEDIVH: { DoUpdateWorldState(WORLD_STATE_BM, 1); DoUpdateWorldState(WORLD_STATE_BM_SHIELD, _shieldPercent); DoUpdateWorldState(WORLD_STATE_BM_RIFT, _currentRift); - Events.RescheduleEvent(EVENT_NEXT_PORTAL, 3000); + + ScheduleNextPortal(3s); + _timerToNextBoss = (instance->IsHeroic() ? 300 : 150) * IN_MILLISECONDS; - for (ObjectGuid const& guid : encounterNPCs) + for (ObjectGuid const& guid : _encounterNPCs) { if (guid.GetEntry() == NPC_DP_BEAM_STALKER) { @@ -264,26 +327,73 @@ public: if (!_shieldPercent) { - if (Creature* medivh = instance->GetCreature(_medivhGUID)) + if (Creature* medivh = GetCreature(DATA_MEDIVH)) { - if (medivh->IsAlive()) + if (medivh->IsAlive() && medivh->IsAIEnabled) { medivh->SetImmuneToNPC(true); + medivh->AI()->Talk(SAY_MEDIVH_DEATH); - if (medivh->IsAIEnabled) - { - medivh->AI()->Talk(SAY_MEDIVH_DEATH); - } - - Events.ScheduleEvent(EVENT_WIPE_1, 4s); - - for (ObjectGuid const& guid : encounterNPCs) + for (ObjectGuid const& guid : _encounterNPCs) { if (Creature* creature = instance->GetCreature(guid)) { creature->InterruptNonMeleeSpells(true); } } + + // Step 1 - Medivh loses all auras. + _scheduler.Schedule(4s, [this](TaskContext) + { + if (Creature* medivh = GetCreature(DATA_MEDIVH)) + { + medivh->RemoveAllAuras(); + } + + // Step 2 - Medivh dies and visual effect NPCs are despawned. + _scheduler.Schedule(500ms, [this](TaskContext) + { + if (Creature* medivh = GetCreature(DATA_MEDIVH)) + { + medivh->KillSelf(false); + + GuidSet encounterNPCSCopy = _encounterNPCs; + for (ObjectGuid const& guid : encounterNPCSCopy) + { + switch (guid.GetEntry()) + { + case NPC_TIME_RIFT: + case NPC_DP_EMITTER_STALKER: + case NPC_DP_CRYSTAL_STALKER: + case NPC_DP_BEAM_STALKER: + if (Creature* creature = instance->GetCreature(guid)) + { + creature->DespawnOrUnsummon(); + } + break; + default: + break; + } + } + } + + // Step 3 - All summoned creatures despawn + _scheduler.Schedule(2s, [this](TaskContext) + { + GuidSet encounterNPCSCopy = _encounterNPCs; + for (ObjectGuid const& guid : encounterNPCSCopy) + { + if (Creature* creature = instance->GetCreature(guid)) + { + creature->CastSpell(creature, SPELL_TELEPORT_VISUAL, true); + creature->DespawnOrUnsummon(1200ms, 0s); + } + } + + _scheduler.CancelAll(); + }); + }); + }); } } } @@ -298,10 +408,6 @@ public: { switch (type) { - case TYPE_CHRONO_LORD_DEJA: - case TYPE_TEMPORUS: - case TYPE_AEONUS: - return encounters[type]; case DATA_SHIELD_PERCENT: return _shieldPercent; case DATA_RIFT_NUMBER: @@ -310,66 +416,21 @@ public: return 0; } - void SetGuidData(uint32 type, ObjectGuid data) override + void SummonPortalKeeper(Creature* rift) { - if (type == DATA_SUMMONED_NPC) - encounterNPCs.insert(data); - else if (type == DATA_DELETED_NPC) - encounterNPCs.erase(data); - else if (type == DATA_RIFT_KILLED) - { - if (!Events.IsInPhase(1)) - { - uint8 emptySpots = 0; - for (uint8 i = 0; i < MAX_PORTAL_LOCATIONS; ++i) - { - if (!_usedRiftPostions[i]) - { - ++emptySpots; - } - - if (_usedRiftPostions[i] == data) - { - _usedRiftPostions[i].Clear(); - } - } - - if (emptySpots >= MAX_PORTAL_LOCATIONS - 1) - { - Events.RescheduleEvent(EVENT_NEXT_PORTAL, 4000); - } - else if (!emptySpots) - { - Events.RescheduleEvent(EVENT_NEXT_PORTAL, (_currentRift >= 13 ? 120 : 90) * IN_MILLISECONDS); - } - } - } - } - - ObjectGuid GetGuidData(uint32 data) const override - { - if (data == DATA_MEDIVH) - return _medivhGUID; - - return ObjectGuid::Empty; - } - - void SummonPortalKeeper(uint32 eventId) - { - uint8 riftPosition = eventId - EVENT_SUMMON_KEEPER_1; - ObjectGuid const& riftGUID = _usedRiftPostions[riftPosition]; - Creature* rift = instance->GetCreature(riftGUID); if (!rift) + { return; + } int32 entry = 0; switch (_currentRift) { case 6: - entry = GetData(TYPE_CHRONO_LORD_DEJA) == DONE ? (instance->IsHeroic() ? NPC_INFINITE_CHRONO_LORD : -NPC_CHRONO_LORD_DEJA) : NPC_CHRONO_LORD_DEJA; + entry = GetBossState(DATA_CHRONO_LORD_DEJA) == DONE ? (instance->IsHeroic() ? NPC_INFINITE_CHRONO_LORD : -NPC_CHRONO_LORD_DEJA) : NPC_CHRONO_LORD_DEJA; break; case 12: - entry = GetData(TYPE_TEMPORUS) == DONE ? (instance->IsHeroic() ? NPC_INFINITE_TIMEREAVER : -NPC_TEMPORUS) : NPC_TEMPORUS; + entry = GetBossState(DATA_TEMPORUS) == DONE ? (instance->IsHeroic() ? NPC_INFINITE_TIMEREAVER : -NPC_TEMPORUS) : NPC_TEMPORUS; break; case 18: entry = NPC_AEONUS; @@ -381,21 +442,22 @@ public: Position pos = rift->GetNearPosition(10.0f, 2 * M_PI * rand_norm()); - if (TempSummon* summon = instance->SummonCreature(std::abs(entry), pos)) + if (Creature* summon = rift->SummonCreature(std::abs(entry), pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3 * MINUTE * IN_MILLISECONDS)) { - summon->SetTempSummonType(TEMPSUMMON_CORPSE_TIMED_DESPAWN); - summon->SetTimer(3 * MINUTE * IN_MILLISECONDS); - if (entry < 0) + { summon->SetLootMode(0); + } if (summon->GetEntry() != NPC_AEONUS) { - rift->AI()->SetGUID(summon->GetGUID()); rift->CastSpell(summon, SPELL_RIFT_CHANNEL, false); } else + { summon->SetReactState(REACT_DEFENSIVE); + _scheduler.CancelGroup(CONTEXT_GROUP_RIFTS); + } } } @@ -413,130 +475,16 @@ public: } } - Events.Update(diff); - - uint32 eventId = Events.ExecuteEvent(); - switch (eventId) - { - case EVENT_NEXT_PORTAL: - { - if (instance->GetCreature(_medivhGUID)) - { - uint8 position = MAX_PORTAL_LOCATIONS; - - std::vector possibleSpots; - for (uint8 i = 0; i < MAX_PORTAL_LOCATIONS; ++i) - { - if (!_usedRiftPostions[i]) - { - possibleSpots.push_back(i); - } - } - - if (!possibleSpots.empty()) - { - position = Acore::Containers::SelectRandomContainerElement(possibleSpots); - } - - if (position < MAX_PORTAL_LOCATIONS) - { - ++_currentRift; - DoUpdateWorldState(WORLD_STATE_BM_RIFT, _currentRift); - Events.ScheduleEvent(EVENT_SUMMON_KEEPER_1 + position, 6000); - Events.SetPhase(0); - - if (Creature* rift = instance->SummonCreature(NPC_TIME_RIFT, PortalLocation[position])) - { - _usedRiftPostions[position] = rift->GetGUID(); - - for (uint8 i = 0; i < MAX_PORTAL_LOCATIONS; ++i) - { - if (!_usedRiftPostions[i]) - { - Events.RescheduleEvent(EVENT_NEXT_PORTAL, (_currentRift >= 13 ? 120 : 90) * IN_MILLISECONDS); - break; - } - } - } - } - } - break; - } - case EVENT_SUMMON_KEEPER_1: - case EVENT_SUMMON_KEEPER_2: - case EVENT_SUMMON_KEEPER_3: - case EVENT_SUMMON_KEEPER_4: - SummonPortalKeeper(eventId); - break; - case EVENT_WIPE_1: - if (Creature* medivh = instance->GetCreature(_medivhGUID)) - { - medivh->RemoveAllAuras(); - } - Events.ScheduleEvent(EVENT_WIPE_2, 500ms); - break; - case EVENT_WIPE_2: - if (Creature* medivh = instance->GetCreature(_medivhGUID)) - { - medivh->KillSelf(false); - - GuidSet encounterNPCSCopy = encounterNPCs; - for (ObjectGuid const& guid : encounterNPCSCopy) - { - switch (guid.GetEntry()) - { - case NPC_TIME_RIFT: - case NPC_DP_EMITTER_STALKER: - case NPC_DP_CRYSTAL_STALKER: - case NPC_DP_BEAM_STALKER: - if (Creature* creature = instance->GetCreature(guid)) - { - creature->DespawnOrUnsummon(); - } - break; - default: - break; - } - } - } - Events.ScheduleEvent(EVENT_WIPE_3, 2s); - break; - case EVENT_WIPE_3: - { - GuidSet encounterNPCSCopy = encounterNPCs; - for (ObjectGuid const& guid : encounterNPCSCopy) - { - if (Creature* creature = instance->GetCreature(guid)) - { - creature->CastSpell(creature, SPELL_TELEPORT_VISUAL, true); - creature->DespawnOrUnsummon(1200ms, 0s); - } - } - break; - } - default: - break; - } - } - - void ReadSaveDataMore(std::istringstream& data) override - { - data >> encounters[0]; - data >> encounters[1]; - data >> encounters[2]; - } - - void WriteSaveDataMore(std::ostringstream& data) override - { - data << encounters[0] << ' ' - << encounters[1] << ' ' - << encounters[2] << ' '; + _scheduler.Update(); } protected: - EventMap Events; - std::array _usedRiftPostions; + std::list _availableRiftPositions; uint32 _timerToNextBoss; + GuidSet _encounterNPCs; + uint8 _currentRift; + int8 _shieldPercent; + TaskScheduler _scheduler; }; }; 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 873411b44..cd8877d6c 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp @@ -91,7 +91,7 @@ struct npc_medivh_bm : public ScriptedAI events.Reset(); me->CastSpell(me, SPELL_MANA_SHIELD, true); - if (_instance->GetData(TYPE_AEONUS) != DONE) + if (_instance->GetBossState(DATA_AEONUS) != DONE) { me->CastSpell(me, SPELL_MEDIVH_CHANNEL, false); } @@ -101,8 +101,6 @@ struct npc_medivh_bm : public ScriptedAI void JustSummoned(Creature* summon) override { - _instance->SetGuidData(DATA_SUMMONED_NPC, summon->GetGUID()); - if (summon->GetEntry() == NPC_DP_CRYSTAL_STALKER) { summon->DespawnOrUnsummon(25000); @@ -119,14 +117,9 @@ struct npc_medivh_bm : public ScriptedAI } } - void SummonedCreatureDespawn(Creature* summon) override - { - _instance->SetGuidData(DATA_DELETED_NPC, summon->GetGUID()); - } - void MoveInLineOfSight(Unit* who) override { - if (!events.Empty() || _instance->GetData(TYPE_AEONUS) == DONE) + if (!events.Empty() || _instance->GetBossState(DATA_AEONUS) == DONE) { return; } @@ -274,9 +267,12 @@ struct npc_time_rift : public NullCreatureAI events.ScheduleEvent(EVENT_CHECK_DEATH, 8000); } - void SetGUID(ObjectGuid guid, int32) override + void JustSummoned(Creature* creature) override { - _riftKeeperGUID = guid; + if (creature->GetEntry() != NPC_AEONUS) + { + _riftKeeperGUID = creature->GetGUID(); + } } void DoSummonAtRift(uint32 entry) @@ -284,16 +280,15 @@ struct npc_time_rift : public NullCreatureAI Position pos = me->GetNearPosition(10.0f, 2 * M_PI * rand_norm()); if (Creature* summon = me->SummonCreature(entry, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 150000)) - if (_instance) + { + if (Creature* medivh = _instance->GetCreature(DATA_MEDIVH)) { - if (Unit* medivh = ObjectAccessor::GetUnit(*me, _instance->GetGuidData(DATA_MEDIVH))) - { - float o = medivh->GetAngle(summon) + frand(-1.0f, 1.0f); - summon->SetHomePosition(medivh->GetPositionX() + 14.0f * cos(o), medivh->GetPositionY() + 14.0f * std::sin(o), medivh->GetPositionZ(), summon->GetAngle(medivh)); - summon->GetMotionMaster()->MoveTargetedHome(true); - summon->SetReactState(REACT_DEFENSIVE); - } + float o = medivh->GetAngle(summon) + frand(-1.0f, 1.0f); + summon->SetHomePosition(medivh->GetPositionX() + 14.0f * cos(o), medivh->GetPositionY() + 14.0f * std::sin(o), medivh->GetPositionZ(), summon->GetAngle(medivh)); + summon->GetMotionMaster()->MoveTargetedHome(true); + summon->SetReactState(REACT_DEFENSIVE); } + } } void DoSelectSummon() @@ -326,8 +321,6 @@ struct npc_time_rift : public NullCreatureAI Creature* riftKeeper = ObjectAccessor::GetCreature(*me, _riftKeeperGUID); if (!riftKeeper || !riftKeeper->IsAlive()) { - _instance->SetGuidData(DATA_RIFT_KILLED, me->GetGUID()); - me->DespawnOrUnsummon(0); break; } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.h b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.h index 6d895c210..5fd011238 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.h @@ -24,13 +24,15 @@ #define DataHeader "TBM" +uint32 const EncounterCount = 3; + #define TheBlackMorassScriptName "instance_the_black_morass" enum DataTypes { - TYPE_CHRONO_LORD_DEJA = 0, - TYPE_TEMPORUS = 1, - TYPE_AEONUS = 2, + DATA_CHRONO_LORD_DEJA = 0, + DATA_TEMPORUS = 1, + DATA_AEONUS = 2, MAX_ENCOUNTER = 3, DATA_MEDIVH = 10, @@ -89,16 +91,9 @@ enum Misc SPELL_RIFT_CHANNEL = 31387, SPELL_TELEPORT_VISUAL = 7791, - EVENT_NEXT_PORTAL = 1, - EVENT_SUMMON_KEEPER_1 = 2, - EVENT_SUMMON_KEEPER_2 = 3, - EVENT_SUMMON_KEEPER_3 = 4, - EVENT_SUMMON_KEEPER_4 = 5, - EVENT_WIPE_1 = 6, - EVENT_WIPE_2 = 7, - EVENT_WIPE_3 = 8, + ACTION_OUTRO = 1, - ACTION_OUTRO = 1 + CONTEXT_GROUP_RIFTS = 1 }; enum medivhSays