summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/sql/updates/pending_db_world/rev_1604614793984918900.sql16
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp1742
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp181
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h28
4 files changed, 1080 insertions, 887 deletions
diff --git a/data/sql/updates/pending_db_world/rev_1604614793984918900.sql b/data/sql/updates/pending_db_world/rev_1604614793984918900.sql
new file mode 100644
index 0000000000..4ff84af525
--- /dev/null
+++ b/data/sql/updates/pending_db_world/rev_1604614793984918900.sql
@@ -0,0 +1,16 @@
+INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1604614793984918900');
+-- Pyrobuffet (57557)
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceGroup`=7 AND `SourceEntry`=57557 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=26 AND `ConditionTarget`=0 AND `ConditionValue1`=1 AND `ConditionValue2`=0 AND `ConditionValue3`=0;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(13, 7, 57557, 0, 0, 26, 0, 1, 0, 0, 0, 0, 0, '', 'Pyrobuffet - Target players which has phase mask 1');
+
+-- Twilight Torment (57935)
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceGroup`=7 AND `SourceEntry`=57935 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=26 AND `ConditionTarget`=0 AND `ConditionValue1`=1 AND `ConditionValue2`=0 AND `ConditionValue3`=0;
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=17 AND `SourceGroup`=0 AND `SourceEntry`=57935 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=26 AND `ConditionTarget`=1 AND `ConditionValue1`=1 AND `ConditionValue2`=0 AND `ConditionValue3`=0;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(17, 0, 57935, 0, 0, 26, 1, 1, 0, 0, 0, 0, 0, '', 'Twilight Torment - Target players which has phase mask 1');
+
+-- Twilight Shift aura removes Twilight Torment
+DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=57620 AND `spell_effect`=-57935 AND `type`=0;
+INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES
+(57620, -57935, 0, 'Twilight Shift aura removes Twilight Torment');
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp
index 15899a79ae..9c198bf38a 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp
@@ -108,17 +108,28 @@ enum NPCs
enum Misc
{
+ // Actions
ACTION_SWITCH_PHASE = 1,
ACTION_CALL_DRAGON = 2,
ACTION_DRAKE_DIED = 3,
- DRAGON_TENEBRON = 0,
- DRAGON_SHADRON = 1,
- DRAGON_VESPERON = 2,
-
+ // Movement points
POINT_FINAL_TENEBRON = 8,
POINT_FINAL_SHADRON = 4,
POINT_FINAL_VESPERON = 4,
+
+ // Lava directions. Its used to identify to which side lava was moving by last time
+ LAVA_LEFT_SIDE = 0,
+ LAVA_RIGHT_SIDE = 1,
+
+ // Counters
+ MAX_LEFT_LAVA_TSUNAMIS = 3,
+ MAX_RIGHT_LAVA_TSUNAMIS = 2,
+ MAX_DRAGONS = 3,
+ MAX_AREA_TRIGGER_COUNT = 2,
+ MAX_CYCLONE_COUNT = 5,
+ MAX_TENEBORN_EGGS_SUMMONS = 6,
+ MAX_BOUNDARY_POSITIONS = 4,
};
enum Events
@@ -139,43 +150,76 @@ enum Events
EVENT_SARTHARION_START_LAVA = 14,
EVENT_SARTHARION_FINISH_LAVA = 15,
EVENT_SARTHARION_LAVA_STRIKE = 16,
- EVENT_SARTHARION_HEALTH_CHECK = 17,
- EVENT_SARTHARION_BERSERK = 18,
+ EVENT_SARTHARION_BERSERK = 17,
// Drake abilities called by sartharion
EVENT_SARTHARION_CALL_TENEBRON = 30,
EVENT_SARTHARION_CALL_SHADRON = 31,
EVENT_SARTHARION_CALL_VESPERON = 32,
- EVENT_SARTHARION_BOUNDARY = 33
+ EVENT_SARTHARION_BOUNDARY = 33,
+ EVENT_MINIDRAKE_SPEECH = 34,
};
const Position portalPos[4] =
{
- {3247.29f, 529.804f, 58.9595f, 0.0f},
- {3248.62f, 646.739f, 85.2939f, 0.0f},
- {3151.20f, 517.862f, 90.3389f, 0.0f},
- {3351.78f, 517.138f, 99.1620f, 0.0f},
+ { 3247.29f, 529.804f, 58.9595f, 0.0f },
+ { 3248.62f, 646.739f, 85.2939f, 0.0f },
+ { 3151.20f, 517.862f, 90.3389f, 0.0f },
+ { 3351.78f, 517.138f, 99.1620f, 0.0f },
};
-const Position EggsPos[12] =
+// 0 = Tenebron normal
+// 1 = Tenebron was called by Sartharion
+const Position TenebronEggsPos[2][MAX_TENEBORN_EGGS_SUMMONS] =
{
- // Tenebron
- {3253.09f, 657.439f, 86.9921f, 3.16334f},
- {3247.76f, 662.413f, 87.7281f, 4.12938f},
- {3246.01f, 656.606f, 86.8737f, 4.12938f},
- {3246.7f, 649.558f, 85.8179f, 4.12938f},
- {3238.72f, 650.386f, 85.9625f, 0.897469f},
- {3257.89f, 651.323f, 85.9177f, 0.897469f},
- // Sartharion
- {3237.24f, 524.20f, 58.95f, 0.0f},
- {3238.95f, 513.96f, 58.662f, 0.7f},
- {3245.66f, 519.685f, 58.78f, 0.7f},
- {3254.64f, 524.6f, 58.811f, 1.966f},
- {3258.9f, 534.41f, 58.811f, 2.08f},
- {3248.23f, 541.93f, 58.718f, 3.29f}
+ // Teneborn normal
+ {
+ { 3253.09f, 657.439f, 86.9921f, 3.16334f },
+ { 3247.76f, 662.413f, 87.7281f, 4.12938f },
+ { 3246.01f, 656.606f, 86.8737f, 4.12938f },
+ { 3246.7f, 649.558f, 85.8179f, 4.12938f },
+ { 3238.72f, 650.386f, 85.9625f, 0.897469f },
+ { 3257.89f, 651.323f, 85.9177f, 0.897469f },
+ },
+ // Tenebron eggs positions when he is called by Sartharion
+ {
+ { 3237.24f, 524.20f, 58.95f, 0.0f },
+ { 3238.95f, 513.96f, 58.662f, 0.7f },
+ { 3245.66f, 519.685f, 58.78f, 0.7f },
+ { 3254.64f, 524.6f, 58.811f, 1.966f },
+ { 3258.9f, 534.41f, 58.811f, 2.08f },
+ { 3248.23f, 541.93f, 58.718f, 3.29f }
+ }
+};
+
+const Position CycloneSummonPos[MAX_CYCLONE_COUNT] =
+{
+ { 3235.28f, 591.180f, 57.0833f, 0.59037f },
+ { 3200.97f, 480.929f, 57.0833f, 5.86197f },
+ { 3281.57f, 507.984f, 57.0833f, 5.54346f },
+ { 3210.11f, 531.957f, 57.0833f, 3.76777f },
+ { 3286.42f, 585.010f, 57.0833f, 4.10307f },
+};
+
+const Position AreaTriggerSummonPos[MAX_AREA_TRIGGER_COUNT] =
+{
+ { 3244.14f, 512.597f, 58.6534f, 0.0f },
+ { 3242.84f, 553.979f, 58.8272f, 0.0f },
};
+const float SartharionBoundary[MAX_BOUNDARY_POSITIONS] =
+{
+ 3218.86f, // South X
+ 3275.69f, // North X
+ 484.68f, // East Y
+ 572.4f // West Y
+};
+
+const Position bigIslandMiddlePos = { 3242.822754f, 477.279816f, 57.430473f };
+
+const uint32 dragons[MAX_DRAGONS] = { DATA_TENEBRON, DATA_VESPERON, DATA_SHADRON };
+
/////////////////////////////
// SARTHARION
/////////////////////////////
@@ -190,631 +234,950 @@ public:
return new boss_sartharionAI (pCreature);
}
- struct boss_sartharionAI : public ScriptedAI
+ struct boss_sartharionAI : public BossAI
{
- boss_sartharionAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ boss_sartharionAI(Creature* pCreature) : BossAI(pCreature, DATA_SARTHARION),
+ dragonsCount(0),
+ lastLavaSide(LAVA_RIGHT_SIDE),
+ usedBerserk(false),
+ below11PctReached(false)
{
- pInstance = me->GetInstanceScript();
- dragons[0] = dragons[1] = dragons[2] = 0;
}
- InstanceScript* pInstance;
- SummonList summons;
- EventMap events;
- uint64 dragons[3];
- uint8 dragonsCount;
- bool usedBerserk;
- std::list<uint32> volcanoBlows;
+ void Reset() override
+ {
+ _Reset();
+ extraEvents.Reset();
+ RespawnDragons(false);
+ SummonStartingTriggers();
+ usedBerserk = false;
+ below11PctReached = false;
+ dragonsCount = 0;
+ volcanoBlows.clear();
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_SHIFT);
+ }
- void HandleSartharionAbilities();
- void HandleDrakeAbilities();
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_DRAKE_DIED)
+ {
+ DoCastSelf(SPELL_SARTHARION_TWILIGHT_REVENGE, true);
+ }
+ }
- void SummonStartingTriggers()
+ void EnterCombat(Unit* pWho) override
{
- me->SummonCreature(NPC_FIRE_CYCLONE, 3235.28f, 591.180f, 57.0833f, 0.59037f);
- me->SummonCreature(NPC_FIRE_CYCLONE, 3200.97f, 480.929f, 57.0833f, 5.86197f);
- me->SummonCreature(NPC_FIRE_CYCLONE, 3281.57f, 507.984f, 57.0833f, 5.54346f);
- me->SummonCreature(NPC_FIRE_CYCLONE, 3210.11f, 531.957f, 57.0833f, 3.76777f);
- me->SummonCreature(NPC_FIRE_CYCLONE, 3286.42f, 585.010f, 57.0833f, 4.10307f);
-
- me->SummonCreature(NPC_SAFE_AREA_TRIGGER, 3244.14f, 512.597f, 58.6534f, 0.0f);
- me->SummonCreature(NPC_SAFE_AREA_TRIGGER, 3242.84f, 553.979f, 58.8272f, 0.0f);
+ if (pWho && !IsTargetInBounds(pWho))
+ {
+ EnterEvadeMode();
+ return;
+ }
+
+ _EnterCombat();
+ DoCastSelf(SPELL_SARTHARION_PYROBUFFET, true);
+ Talk(SAY_SARTHARION_AGGRO);
+
+ // Combat events
+ events.ScheduleEvent(EVENT_SARTHARION_CAST_CLEAVE, 7000);
+ events.ScheduleEvent(EVENT_SARTHARION_CAST_FLAME_BREATH, 15000);
+ events.ScheduleEvent(EVENT_SARTHARION_CAST_TAIL_LASH, 11000);
+
+ // Extra events
+ extraEvents.ScheduleEvent(EVENT_SARTHARION_SUMMON_LAVA, 20000);
+ extraEvents.ScheduleEvent(EVENT_SARTHARION_LAVA_STRIKE, 5000);
+ extraEvents.ScheduleEvent(EVENT_SARTHARION_BERSERK, 900000);
+ extraEvents.ScheduleEvent(EVENT_SARTHARION_BOUNDARY, 250);
+
+ // Store dragons
+ for (uint8 i = 0; i < MAX_DRAGONS; ++i)
+ {
+ Creature* dragon = ObjectAccessor::GetCreature(*me, instance->GetData64(dragons[i]));
+ if (!dragon || !dragon->IsAlive() || instance->GetBossState(dragons[i]) == DONE)
+ {
+ continue;
+ }
+
+ dragon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
+ dragon->SetFullHealth();
+
+ ++dragonsCount;
+ me->AddLootMode(1 << dragonsCount);
+
+ switch (dragons[i])
+ {
+ case DATA_TENEBRON:
+ {
+ dragon->CastSpell(dragon, SPELL_POWER_OF_TENEBRON, true);
+ extraEvents.ScheduleEvent(EVENT_SARTHARION_CALL_TENEBRON, 10000);
+ break;
+ }
+ case DATA_SHADRON:
+ {
+ dragon->CastSpell(dragon, SPELL_POWER_OF_SHADRON, true);
+ extraEvents.ScheduleEvent(EVENT_SARTHARION_CALL_SHADRON, 65000);
+ break;
+ }
+ case DATA_VESPERON:
+ {
+ dragon->CastSpell(dragon, SPELL_POWER_OF_VESPERON, true);
+ extraEvents.ScheduleEvent(EVENT_SARTHARION_CALL_VESPERON, 115000);
+ break;
+ }
+ }
+ }
+
+ if (dragonsCount)
+ {
+ DoCastSelf(SPELL_WILL_OF_SARTHARION, true);
+ }
+
+ me->CallForHelp(500.0f);
}
- void SummonLavaWaves()
+ void JustDied(Unit* /*pKiller*/) override
{
- summons.RemoveNotExisting();
- Talk(WHISPER_LAVA_CHURN);
- events.ScheduleEvent(EVENT_SARTHARION_START_LAVA, 2000);
- events.ScheduleEvent(EVENT_SARTHARION_FINISH_LAVA, 9000);
+ RespawnDragons(true);
+ _JustDied();
+ Talk(SAY_SARTHARION_DEATH);
+ }
- // Send wave from left
- if (urand(0, 1))
+ void SetData(uint32 type, uint32 data) override
+ {
+ if (type == DATA_VOLCANO_BLOWS && data)
{
- for (uint8 i = 0; i < 3; ++i)
- me->SummonCreature(NPC_FLAME_TSUNAMI, 3208.44f, 580.0f - (i * 50.0f), 55.8f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 12000);
+ if (!volcanoBlows.empty() && std::find(volcanoBlows.begin(), volcanoBlows.end(), data) != volcanoBlows.end())
+ {
+ return;
+ }
+
+ volcanoBlows.push_back(data);
}
- // from right
- else
+ }
+
+ uint32 GetData(uint32 dataOrGuid) const override
+ {
+ // it means we want dragons count
+ if (dataOrGuid == DATA_ACHIEVEMENT_DRAGONS_COUNT)
{
- for (uint8 i = 0; i < 2; ++i)
- me->SummonCreature(NPC_FLAME_TSUNAMI, 3283.44f, 555.0f - (i * 50.0f), 55.8f, 3.14f, TEMPSUMMON_TIMED_DESPAWN, 12000);
+ return dragonsCount;
+ }
+
+ // otherwise it is guid to check if player was hit by lava strike :)
+ if (!volcanoBlows.empty() && std::find(volcanoBlows.begin(), volcanoBlows.end(), dataOrGuid) != volcanoBlows.end())
+ {
+ return 1;
}
+
+ return 0;
}
- void SendLavaWaves(bool start)
+ void KilledUnit(Unit* pVictim) override
{
- Unit* cr = nullptr;
- for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
+ if (!urand(0, 2) && pVictim->GetTypeId() == TYPEID_PLAYER)
{
- cr = ObjectAccessor::GetUnit(*me, *itr);
- if (!cr || cr->GetEntry() != NPC_FLAME_TSUNAMI)
- continue;
+ Talk(SAY_SARTHARION_SLAY);
+ }
+ }
- if (start)
- cr->GetMotionMaster()->MovePoint(0, ((cr->GetPositionX() < 3250.0f) ? 3283.44f : 3208.44f), cr->GetPositionY(), cr->GetPositionZ());
- else
- cr->SetObjectScale(0.1f);
+ void JustSummoned(Creature* summon) override
+ {
+ switch (summon->GetEntry())
+ {
+ case NPC_FLAME_TSUNAMI:
+ {
+ summon->SetSpeed(MOVE_FLIGHT, 1.5f);
+ break;
+ }
+ case NPC_FIRE_CYCLONE:
+ {
+ summon->GetMotionMaster()->MoveRandom(5.0f);
+ break;
+ }
}
+
+ summons.Summon(summon);
}
- void StoreDragons()
+ void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
- if (pInstance)
+ // Temporal hack, by some case some melee spells can bypass this aura damage reduction
+ if (me->HasAura(SPELL_GIFT_OF_TWILIGHT_FIRE))
{
- Unit* cr = nullptr;
- for (uint8 i = 0; i < 3; ++i)
- if ((cr = ObjectAccessor::GetUnit(*me, pInstance->GetData64(DATA_TENEBRON + i))))
- {
- if (!cr->IsAlive())
- continue;
+ damage = 0;
+ return;
+ }
- cr->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
- dragons[i] = cr->GetGUID();
- dragonsCount++;
- me->AddLootMode(1 << dragonsCount);
+ if (!usedBerserk && me->HealthBelowPctDamaged(30, damage))
+ {
+ DoCastSelf(SPELL_SARTHARION_BERSERK, true);
+ usedBerserk = true;
+ return;
+ }
- cr->SetHealth(cr->GetMaxHealth());
- switch(DATA_TENEBRON + i)
+ // Soft enrage
+ if (!below11PctReached && me->HealthBelowPctDamaged(10, damage))
+ {
+ summons.RemoveNotExisting();
+ if (!summons.empty())
+ {
+ for (uint64 const summonGuid : summons)
+ {
+ Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid);
+ if (summon && summon->GetEntry() == NPC_FIRE_CYCLONE)
{
- case DATA_TENEBRON:
- cr->CastSpell(cr, SPELL_POWER_OF_TENEBRON, true);
- events.ScheduleEvent(EVENT_SARTHARION_CALL_TENEBRON, 10000);
- break;
- case DATA_SHADRON:
- cr->CastSpell(cr, SPELL_POWER_OF_SHADRON, true);
- events.ScheduleEvent(EVENT_SARTHARION_CALL_SHADRON, 65000);
- break;
- case DATA_VESPERON:
- cr->CastSpell(cr, SPELL_POWER_OF_VESPERON, true);
- events.ScheduleEvent(EVENT_SARTHARION_CALL_VESPERON, 115000);
- break;
+ summon->CastSpell(summon, SPELL_CYCLONE_AURA_PERIODIC, true);
}
}
-
- if (dragonsCount)
- me->CastSpell(me, SPELL_WILL_OF_SARTHARION, true);
+ }
+ Talk(SAY_SARTHARION_BERSERK);
+ below11PctReached = true;
}
}
- void RespawnDragons(bool combat)
+ void UpdateAI(uint32 diff) override
{
- if (pInstance)
+ if (!UpdateVictim())
{
- Creature* cr = nullptr;
- for (uint8 i = 0; i < 3; ++i)
- if (dragons[i])
- if ((cr = ObjectAccessor::GetCreature(*me, dragons[i])))
+ return;
+ }
+
+ extraEvents.Update(diff);
+
+ // Special events which needs to be fired immidiately
+ while (uint32 const eventId = extraEvents.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SARTHARION_BOUNDARY:
+ {
+ if (!IsTargetInBounds(me->GetVictim()))
+ {
+ EnterEvadeMode();
+ }
+ else
+ {
+ extraEvents.RepeatEvent(250);
+ }
+ break;
+ }
+ case EVENT_SARTHARION_SUMMON_LAVA:
+ {
+ if (!urand(0, 3))
{
- if (combat && cr->IsInCombat())
- continue;
+ Talk(SAY_SARTHARION_SPECIAL);
+ }
- cr->DespawnOrUnsummon();
- cr->SetRespawnTime(10);
+ SummonLavaWaves();
+ extraEvents.RepeatEvent(25000);
+ return;
+ }
+ case EVENT_SARTHARION_START_LAVA:
+ {
+ SendLavaWaves(true);
+ return;
+ }
+ case EVENT_SARTHARION_FINISH_LAVA:
+ {
+ SendLavaWaves(false);
+ return;
+ }
+ // Handling of Drakes Events
+ // Dragon Calls
+ case EVENT_SARTHARION_CALL_TENEBRON:
+ {
+ Talk(SAY_SARTHARION_CALL_TENEBRON);
+ if (Creature* tenebron = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_TENEBRON)))
+ {
+ tenebron->AI()->DoAction(ACTION_CALL_DRAGON);
+ }
+ break;
+ }
+ case EVENT_SARTHARION_CALL_SHADRON:
+ {
+ Talk(SAY_SARTHARION_CALL_SHADRON);
+ if (Creature* shadron = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SHADRON)))
+ {
+ shadron->AI()->DoAction(ACTION_CALL_DRAGON);
+ }
+ break;
+ }
+ case EVENT_SARTHARION_CALL_VESPERON:
+ {
+ Talk(SAY_SARTHARION_CALL_VESPERON);
+ if (Creature* vesperon = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_VESPERON)))
+ {
+ vesperon->AI()->DoAction(ACTION_CALL_DRAGON);
}
- dragons[0] = dragons[1] = dragons[2] = 0;
- dragonsCount = 0;
+ break;
+ }
+ }
}
- }
- void Reset()
- {
- events.Reset();
- summons.DespawnAll();
- me->ResetLootMode();
- RespawnDragons(false);
- SummonStartingTriggers();
- usedBerserk = false;
- volcanoBlows.clear();
+ // Handle Sartharion combat abbilities
+ events.Update(diff);
- if (pInstance)
+ if (me->HasUnitState(UNIT_STATE_CASTING))
{
- pInstance->SetData(BOSS_SARTHARION_EVENT, NOT_STARTED);
- pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_SHIFT);
+ return;
}
- }
- void DoAction(int32 param)
- {
- if (param == ACTION_DRAKE_DIED)
- me->CastSpell(me, SPELL_SARTHARION_TWILIGHT_REVENGE, true);
- }
+ while (uint32 const eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SARTHARION_CAST_CLEAVE:
+ {
+ DoCastVictim(SPELL_SARTHARION_CLEAVE, false);
+ events.RepeatEvent(10000);
+ break;
+ }
+ case EVENT_SARTHARION_CAST_FLAME_BREATH:
+ {
+ DoCastVictim(SPELL_SARTHARION_FLAME_BREATH, false);
+ events.RepeatEvent(20000);
+ break;
+ }
+ case EVENT_SARTHARION_CAST_TAIL_LASH:
+ {
+ DoCastSelf(SPELL_SARTHARION_TAIL_LASH, false);
+ events.RepeatEvent(18000);
+ break;
+ }
+ case EVENT_SARTHARION_LAVA_STRIKE:
+ {
+ if (!urand(0, 2))
+ {
+ Talk(SAY_SARTHARION_SPECIAL_4);
+ }
- void EnterCombat(Unit* /*pWho*/)
- {
- me->CastSpell(me, SPELL_SARTHARION_PYROBUFFET, true);
- me->SetInCombatWithZone();
- Talk(SAY_SARTHARION_AGGRO);
- if (pInstance)
- pInstance->SetData(BOSS_SARTHARION_EVENT, IN_PROGRESS);
+ summons.RemoveNotExisting();
+ uint8 rand = urand(0, MAX_CYCLONE_COUNT - 1); // 5 - numer of cyclones
+ uint8 iter = 0;
+ if (!summons.empty())
+ {
+ for (uint64 const summonGuid : summons)
+ {
+ Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid);
+ if (summon && summon->GetEntry() == NPC_FIRE_CYCLONE && iter == rand)
+ {
+ summon->CastSpell(summon, SPELL_CYCLONE_AURA_PERIODIC, true);
+ ++iter;
+ }
+ }
+ }
- events.ScheduleEvent(EVENT_SARTHARION_CAST_CLEAVE, 7000);
- events.ScheduleEvent(EVENT_SARTHARION_CAST_FLAME_BREATH, 15000);
- events.ScheduleEvent(EVENT_SARTHARION_CAST_TAIL_LASH, 11000);
- events.ScheduleEvent(EVENT_SARTHARION_SUMMON_LAVA, 20000);
- events.ScheduleEvent(EVENT_SARTHARION_LAVA_STRIKE, 5000);
- events.ScheduleEvent(EVENT_SARTHARION_HEALTH_CHECK, 10000);
- events.ScheduleEvent(EVENT_SARTHARION_BERSERK, 900000);
- events.ScheduleEvent(EVENT_SARTHARION_BOUNDARY, 1000);
+ events.RepeatEvent((below11PctReached ? urand(1400, 2000) : urand(5000, 20000)));
+ break;
+ }
+ case EVENT_SARTHARION_BERSERK:
+ {
+ summons.DespawnEntry(NPC_SAFE_AREA_TRIGGER);
+ break;
+ }
+ }
- StoreDragons();
- me->CallForHelp(500.0f);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ {
+ return;
+ }
+ }
+
+ DoMeleeAttackIfReady();
}
- void JustDied(Unit* /*pKiller*/)
+ private:
+ void SummonStartingTriggers()
{
- RespawnDragons(true);
- summons.DespawnAll();
- Talk(SAY_SARTHARION_DEATH);
+ for (uint8 i = 0; i < MAX_CYCLONE_COUNT; ++i)
+ {
+ me->SummonCreature(NPC_FIRE_CYCLONE, CycloneSummonPos[i]);
+ }
- if (pInstance)
- pInstance->SetData(BOSS_SARTHARION_EVENT, DONE);
+ for (uint8 i = 0; i < MAX_AREA_TRIGGER_COUNT; ++i)
+ {
+ me->SummonCreature(NPC_SAFE_AREA_TRIGGER, AreaTriggerSummonPos[i]);
+ }
}
- void KilledUnit(Unit* pVictim)
+ void SummonLavaWaves()
{
- if (!urand(0, 2) && pVictim->GetTypeId() == TYPEID_PLAYER)
- Talk(SAY_SARTHARION_SLAY);
- }
+ summons.RemoveNotExisting();
+ Talk(WHISPER_LAVA_CHURN);
+ extraEvents.ScheduleEvent(EVENT_SARTHARION_START_LAVA, 2000);
+ extraEvents.ScheduleEvent(EVENT_SARTHARION_FINISH_LAVA, 9000);
- void JustSummoned(Creature* cr)
- {
- if (cr->GetEntry() == NPC_FLAME_TSUNAMI)
- cr->SetSpeed(MOVE_FLIGHT, 1.5f);
- else if (cr->GetEntry() == NPC_FIRE_CYCLONE)
- cr->GetMotionMaster()->MoveRandom(5.0f);
+ // Send wave from left
+ if (lastLavaSide == LAVA_RIGHT_SIDE)
+ {
+ for (uint8 i = 0; i < MAX_LEFT_LAVA_TSUNAMIS; ++i)
+ {
+ me->SummonCreature(NPC_FLAME_TSUNAMI, 3208.44f, 580.0f - (i * 50.0f), 55.8f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 12000);
+ }
- summons.Summon(cr);
+ lastLavaSide = LAVA_LEFT_SIDE;
+ }
+ // from right
+ else
+ {
+ for (uint8 i = 0; i < MAX_RIGHT_LAVA_TSUNAMIS; ++i)
+ {
+ me->SummonCreature(NPC_FLAME_TSUNAMI, 3283.44f, 555.0f - (i * 50.0f), 55.8f, 3.14f, TEMPSUMMON_TIMED_DESPAWN, 12000);
+ }
+
+ lastLavaSide = LAVA_RIGHT_SIDE;
+ }
}
- void SetData(uint32 type, uint32 data)
+ void SendLavaWaves(bool start)
{
- if (type != DATA_VOLCANO_BLOWS)
+ if (summons.empty())
+ {
return;
+ }
- if (!volcanoBlows.empty())
- for (std::list<uint32>::const_iterator itr = volcanoBlows.begin(); itr != volcanoBlows.end(); ++itr)
- if (data == (*itr))
- return;
+ for (uint64 const guid : summons)
+ {
+ Creature* tsunami = ObjectAccessor::GetCreature(*me, guid);
+ if (!tsunami || tsunami->GetEntry() != NPC_FLAME_TSUNAMI)
+ {
+ continue;
+ }
- volcanoBlows.push_back(data);
+ if (start)
+ {
+ tsunami->GetMotionMaster()->MovePoint(0, ((tsunami->GetPositionX() < 3250.0f) ? 3283.44f : 3208.44f), tsunami->GetPositionY(), tsunami->GetPositionZ());
+ }
+ else
+ {
+ tsunami->SetObjectScale(0.1f);
+ }
+ }
}
- uint32 GetData(uint32 dataOrGuid) const
- {
- // it means we want dragons count
- if (dataOrGuid == DATA_ACHIEVEMENT_DRAGONS_COUNT)
- return dragonsCount;
+ void RespawnDragons(bool checkCombat)
+ {
+ for (uint8 i = 0; i < MAX_DRAGONS; ++i)
+ {
+ if (instance->GetBossState(dragons[i]) == DONE)
+ {
+ continue;
+ }
- // otherwise it is guid to check if player was hit by lava strike :)
- if (!volcanoBlows.empty())
- for (std::list<uint32>::const_iterator itr = volcanoBlows.begin(); itr != volcanoBlows.end(); ++itr)
- if (dataOrGuid == (*itr))
- return true;
+ if (Creature* dragon = ObjectAccessor::GetCreature(*me, instance->GetData64(dragons[i])))
+ {
+ if (checkCombat && dragon->IsInCombat())
+ {
+ continue;
+ }
+
+ dragon->DespawnOrUnsummon();
+ dragon->SetRespawnTime(5);
+ }
+ }
- return false;
+ dragonsCount = 0;
}
- void UpdateAI(uint32 diff)
+ bool IsTargetInBounds(Unit const* victim) const
{
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
-
- // Special events which needs to be fired immidiately
- switch(events.ExecuteEvent())
+ if (!victim || victim->GetPositionX() < SartharionBoundary[0] || victim->GetPositionX() > SartharionBoundary[1] || victim->GetPositionY() > SartharionBoundary[3])
{
- case EVENT_SARTHARION_BOUNDARY:
- if (me->GetPositionX() < 3218.86f || me->GetPositionX() > 3275.69f || me->GetPositionY() < 484.68f || me->GetPositionY() > 572.4f) // https://github.com/TrinityCore/TrinityCore/blob/3.3.5/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp#L31
- EnterEvadeMode();
-
- events.RepeatEvent(1000);
- break;
- case EVENT_SARTHARION_SUMMON_LAVA:
- if (!urand(0, 3))
- Talk(SAY_SARTHARION_SPECIAL);
-
- SummonLavaWaves();
- events.RepeatEvent(25000);
- return;
- case EVENT_SARTHARION_START_LAVA:
- SendLavaWaves(true);
-
- return;
- case EVENT_SARTHARION_FINISH_LAVA:
- SendLavaWaves(false);
-
- return;
+ return false;
}
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- HandleSartharionAbilities();
- HandleDrakeAbilities();
+ // Big island handling
+ if (victim->GetPositionY() < SartharionBoundary[2])
+ {
+ return victim->GetDistance(bigIslandMiddlePos) <= 6.0f;
+ }
- DoMeleeAttackIfReady();
+ return true;
}
+
+ EventMap extraEvents;
+ std::list<uint32> volcanoBlows;
+ uint8 dragonsCount;
+ uint8 lastLavaSide; // 0 = left, 1 = right
+ bool usedBerserk;
+ bool below11PctReached;
};
};
-void boss_sartharion::boss_sartharionAI::HandleSartharionAbilities()
+struct boss_sartharion_dragonAI : public BossAI
{
- // Handling of Sartharion Events
- switch (events.ExecuteEvent())
+ boss_sartharion_dragonAI(Creature* pCreature, uint32 bossId) : BossAI(pCreature, bossId),
+ portalGUID(0),
+ isCalledBySartharion(false)
{
- case EVENT_SARTHARION_CAST_CLEAVE:
- me->CastSpell(me->GetVictim(), SPELL_SARTHARION_CLEAVE, false);
- events.RepeatEvent(10000);
- break;
- case EVENT_SARTHARION_CAST_FLAME_BREATH:
- me->CastSpell(me->GetVictim(), SPELL_SARTHARION_FLAME_BREATH, false);
- events.RepeatEvent(20000);
- break;
- case EVENT_SARTHARION_CAST_TAIL_LASH:
- me->CastSpell(me, SPELL_SARTHARION_TAIL_LASH, false);
- events.RepeatEvent(18000);
- break;
- case EVENT_SARTHARION_LAVA_STRIKE:
- {
- if (!urand(0, 2))
- Talk(SAY_SARTHARION_SPECIAL_4);
+ }
- Creature* cr = nullptr;
- summons.RemoveNotExisting();
- uint8 rand = urand(0, 4); // 5 - numer of cyclones
- uint8 iter = 0;
- for (SummonList::iterator i = summons.begin(); i != summons.end(); ++i)
+ void Reset() override
+ {
+ _Reset();
+ events.Reset();
+ ClearInstance();
+
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
+ me->SetSpeed(MOVE_FLIGHT, 1.0f);
+ me->SetCanFly(false);
+ me->ResetLootMode();
+ portalGUID = 0;
+ isCalledBySartharion = false;
+ instance->DoAction(ACTION_CLEAR_PORTAL);
+ }
+
+ void DoAction(int32 param) final
+ {
+ if (param == ACTION_CALL_DRAGON && !isCalledBySartharion)
+ {
+ isCalledBySartharion = true;
+ extraEvents.RescheduleEvent(EVENT_MINIDRAKE_SPEECH, 4000);
+ }
+ }
+
+ void MoveInLineOfSight(Unit* who) final
+ {
+ if (isCalledBySartharion)
+ return;
+
+ ScriptedAI::MoveInLineOfSight(who);
+ }
+
+ void MovementInform(uint32 type, uint32 pointId) final
+ {
+ if (type != WAYPOINT_MOTION_TYPE)
+ {
+ return;
+ }
+
+ switch (me->GetEntry())
+ {
+ case NPC_TENEBRON:
+ {
+ if (pointId != POINT_FINAL_TENEBRON)
{
- if ((cr = ObjectAccessor::GetCreature(*me, *i)))
- if (cr->GetEntry() == NPC_FIRE_CYCLONE)
- {
- if (iter == rand)
- {
- cr->CastSpell(cr, SPELL_CYCLONE_AURA_PERIODIC, true);
- break;
- }
- ++iter;
- }
+ return;
}
-
- events.RepeatEvent(20000);
break;
}
- case EVENT_SARTHARION_HEALTH_CHECK:
- if (dragonsCount && !usedBerserk && me->HealthBelowPct(36))
+ case NPC_SHADRON:
{
- me->CastSpell(me, SPELL_SARTHARION_BERSERK, true);
- usedBerserk = true;
- events.RepeatEvent(2000);
+ if (pointId != POINT_FINAL_SHADRON)
+ {
+ return;
+ }
break;
}
-
- if (me->HealthBelowPct(11))
+ case NPC_VESPERON:
{
- Creature* cr = nullptr;
- summons.RemoveNotExisting();
- for (SummonList::iterator i = summons.begin(); i != summons.end(); ++i)
+ if (pointId != POINT_FINAL_VESPERON)
{
- if ((cr = ObjectAccessor::GetCreature(*me, *i)))
- if (cr->GetEntry() == NPC_FIRE_CYCLONE)
- cr->CastSpell(cr, SPELL_CYCLONE_AURA_PERIODIC, true);
+ return;
}
- Talk(SAY_SARTHARION_BERSERK);
-
break;
}
- events.RepeatEvent(2000);
- break;
- case EVENT_SARTHARION_BERSERK:
- summons.DespawnEntry(NPC_SAFE_AREA_TRIGGER);
-
- break;
- }
-}
+ }
-void boss_sartharion::boss_sartharionAI::HandleDrakeAbilities()
-{
- // Handling of Drakes Events
- switch (events.ExecuteEvent())
- {
- // Dragon Calls
- case EVENT_SARTHARION_CALL_TENEBRON:
- Talk(SAY_SARTHARION_CALL_TENEBRON);
- if (Creature* tenebron = ObjectAccessor::GetCreature(*me, dragons[DRAGON_TENEBRON]))
- tenebron->AI()->DoAction(ACTION_CALL_DRAGON);
-
- break;
- case EVENT_SARTHARION_CALL_SHADRON:
- Talk(SAY_SARTHARION_CALL_SHADRON);
- if (Creature* shadron = ObjectAccessor::GetCreature(*me, dragons[DRAGON_SHADRON]))
- shadron->AI()->DoAction(ACTION_CALL_DRAGON);
-
- break;
- case EVENT_SARTHARION_CALL_VESPERON:
- Talk(SAY_SARTHARION_CALL_VESPERON);
- if (Creature* vesperon = ObjectAccessor::GetCreature(*me, dragons[DRAGON_VESPERON]))
- vesperon->AI()->DoAction(ACTION_CALL_DRAGON);
-
- break;
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
+ me->SetInCombatWithZone();
}
-}
-
-/////////////////////////////
-// TENEBRON
-/////////////////////////////
-
-class boss_sartharion_tenebron : public CreatureScript
-{
-public:
- boss_sartharion_tenebron() : CreatureScript("boss_sartharion_tenebron") { }
- CreatureAI* GetAI(Creature* pCreature) const
+ void JustSummoned(Creature* summon) override
{
- return new boss_sartharion_tenebronAI (pCreature);
+ // Transfer summons to Sartharion
+ if (isCalledBySartharion && instance->GetBossState(DATA_SARTHARION) == IN_PROGRESS)
+ {
+ if (Creature* sartharion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SARTHARION)))
+ {
+ sartharion->AI()->JustSummoned(summon);
+ }
+ }
+
+ BossAI::JustSummoned(summon);
}
- struct boss_sartharion_tenebronAI : public ScriptedAI
+ void EnterCombat(Unit* /*who*/) final
{
- boss_sartharion_tenebronAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me), summons2(me)
+ me->setActive(true);
+ DoZoneInCombat();
+ Talk(SAY_TENEBRON_AGGRO);
+
+ if (me->IsFlying())
{
- portalGUID = 0;
- pInstance = me->GetInstanceScript();
+ me->SetSpeed(MOVE_FLIGHT, 1.0f);
+ me->SetCanFly(false);
}
- EventMap events;
- SummonList summons;
- SummonList summons2;
- uint64 portalGUID;
- InstanceScript* pInstance;
- bool isSartharion;
- uint32 timer;
-
- void ClearInstance()
+ if (!isCalledBySartharion || instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS)
{
- events.Reset();
- summons.DespawnAll();
- // Remove phase shift
- if (pInstance)
- pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_SHIFT);
-
- RemoveTwilightPortal();
+ switch (me->GetEntry())
+ {
+ case NPC_TENEBRON:
+ {
+ instance->SetBossState(DATA_TENEBRON, IN_PROGRESS);
+ break;
+ }
+ case NPC_SHADRON:
+ {
+ instance->SetBossState(DATA_SHADRON, IN_PROGRESS);
+ break;
+ }
+ case NPC_VESPERON:
+ {
+ instance->SetBossState(DATA_VESPERON, IN_PROGRESS);
+ break;
+ }
+ }
}
- void RemoveTwilightPortal()
+ if (isCalledBySartharion || instance->GetBossState(DATA_SARTHARION) == DONE)
{
- if (portalGUID)
- if (GameObject* gobj = me->GetMap()->GetGameObject(portalGUID))
- gobj->Delete();
-
- portalGUID = 0;
+ me->SetLootMode(0);
}
- void DoAction(int32 param)
+ if (isCalledBySartharion)
{
- if (param == ACTION_CALL_DRAGON)
+ if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1, 500, true))
{
- isSartharion = true;
- timer++;
+ AttackStart(target);
}
}
+ }
- void MoveInLineOfSight(Unit* who)
- {
- if (isSartharion)
- return;
+ void JustDied(Unit* /*killer*/) override
+ {
+ //_JustDied();
+ events.Reset();
- ScriptedAI::MoveInLineOfSight(who);
+ // Despawn minions only if not called by Sartharion
+ if (!isCalledBySartharion)
+ {
+ summons.DespawnAll();
}
- void Reset()
+ switch (me->GetEntry())
{
- summons2.DespawnAll();
- ClearInstance();
+ case NPC_TENEBRON:
+ {
+ Talk(SAY_TENEBRON_DEATH);
+ if (!isCalledBySartharion || instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS)
+ {
+ instance->SetBossState(DATA_SHADRON, DONE);
+ }
+ break;
+ }
+ case NPC_SHADRON:
+ {
+ Talk(SAY_SHADRON_DEATH);
+ if (isCalledBySartharion)
+ {
+ if (Creature* sartharion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SARTHARION)))
+ {
+ sartharion->RemoveAura(SPELL_GIFT_OF_TWILIGHT_FIRE);
+ }
+ }
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
- me->SetDisableGravity(false);
- me->SetSpeed(MOVE_FLIGHT, 1.0f);
- me->SetCanFly(false);
- me->ResetLootMode();
- isSartharion = false;
- timer = 0;
+ if (!isCalledBySartharion || instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS)
+ {
+ instance->SetBossState(DATA_SHADRON, DONE);
+ }
+ break;
+ }
+ case NPC_VESPERON:
+ {
+ Talk(SAY_VESPERON_DEATH);
+ instance->DoAction(ACTION_CLEAR_PORTAL);
+ if (!isCalledBySartharion || instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS)
+ {
+ instance->SetBossState(DATA_VESPERON, DONE);
+ }
+ break;
+ }
+ }
- if (pInstance)
+ if (!isCalledBySartharion)
+ {
+ ClearInstance();
+ }
+ else
+ {
+ if (Creature* sartharion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SARTHARION)))
{
- pInstance->SetData(BOSS_TENEBRON_EVENT, NOT_STARTED);
- pInstance->SetData(DATA_CLEAR_PORTAL, 0);
+ sartharion->AI()->DoAction(ACTION_DRAKE_DIED);
}
}
+ }
- void EnterCombat(Unit* )
+ void KilledUnit(Unit* victim) final
+ {
+ if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
{
- Talk(SAY_TENEBRON_AGGRO);
- me->SetInCombatWithZone();
+ return;
+ }
- if (me->IsFlying())
+ switch (me->GetEntry())
+ {
+ case NPC_TENEBRON:
+ {
+ Talk(SAY_TENEBRON_SLAY);
+ break;
+ }
+ case NPC_SHADRON:
+ {
+ Talk(SAY_SHADRON_SLAY);
+ break;
+ }
+ case NPC_VESPERON:
{
- me->SetSpeed(MOVE_FLIGHT, 1.0f);
- me->SetCanFly(false);
+ Talk(SAY_VESPERON_SLAY);
+ break;
}
+ }
+ }
- events.ScheduleEvent(EVENT_MINIBOSS_SHADOW_FISSURE, 20000);
- events.ScheduleEvent(EVENT_MINIBOSS_SHADOW_BREATH, 10000);
- events.ScheduleEvent(EVENT_MINIBOSS_OPEN_PORTAL, 15000);
+ void UpdateAI(uint32 diff) final
+ {
+ extraEvents.Update(diff);
+ while (uint32 const eventId = extraEvents.ExecuteEvent())
+ {
+ HandleExtraEvent(eventId);
+ }
- if (pInstance && !isSartharion)
- pInstance->SetData(BOSS_TENEBRON_EVENT, IN_PROGRESS);
+ if (!UpdateVictim())
+ {
+ return;
+ }
- if (isSartharion || (pInstance && pInstance->GetData(BOSS_SARTHARION_EVENT) == DONE))
- me->SetLootMode(0);
+ events.Update(diff);
- if (isSartharion)
- if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1, 500, true))
- me->AI()->AttackStart(target);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ {
+ return;
}
- void JustDied(Unit* )
+ while (uint32 const eventId = events.ExecuteEvent())
{
- Talk(SAY_TENEBRON_DEATH);
+ ExecuteEvent(eventId);
- if (!isSartharion)
+ if (me->HasUnitState(UNIT_STATE_CASTING))
{
- ClearInstance();
- if (pInstance)
- pInstance->SetData(BOSS_TENEBRON_EVENT, DONE);
+ return;
}
- else if (pInstance)
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ virtual void ClearInstance()
+ {
+ events.Reset();
+ summons.DespawnAll();
+ // Remove phase shift
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_SHIFT);
+ RemoveTwilightPortal();
+ }
+
+ virtual void HandleExtraEvent(uint32 const /*eventId*/) { }
+protected:
+ void RemoveTwilightPortal()
+ {
+ if (portalGUID)
+ {
+ if (GameObject* gobj = me->GetMap()->GetGameObject(portalGUID))
{
- pInstance->SetData(DATA_CLEAR_PORTAL, 0);
- if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetData64(DATA_SARTHARION)))
- cr->AI()->DoAction(ACTION_DRAKE_DIED);
+ gobj->Delete();
}
+
+ portalGUID = 0;
+ }
+ }
+
+ EventMap extraEvents;
+ uint64 portalGUID;
+ bool isCalledBySartharion;
+};
+
+/////////////////////////////
+// TENEBRON
+/////////////////////////////
+
+class boss_sartharion_tenebron : public CreatureScript
+{
+public:
+ boss_sartharion_tenebron() : CreatureScript("boss_sartharion_tenebron") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const
+ {
+ return new boss_sartharion_tenebronAI (pCreature);
+ }
+
+ struct boss_sartharion_tenebronAI : public boss_sartharion_dragonAI
+ {
+ boss_sartharion_tenebronAI(Creature* pCreature) : boss_sartharion_dragonAI(pCreature, DATA_TENEBRON), summons2(pCreature)
+ {
}
- void JustKilled(Unit* victim)
+ void Reset() override
{
- if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
- return;
+ boss_sartharion_dragonAI::Reset();
+ if (!isCalledBySartharion)
+ {
+ summons2.DespawnAll();
+ }
- Talk(SAY_TENEBRON_SLAY);
+ events.ScheduleEvent(EVENT_MINIBOSS_SHADOW_FISSURE, 20000);
+ events.ScheduleEvent(EVENT_MINIBOSS_SHADOW_BREATH, 10000);
+ events.ScheduleEvent(EVENT_MINIBOSS_OPEN_PORTAL, 15000);
}
- void MovementInform(uint32 type, uint32 pointId)
+ void JustSummoned(Creature* summon) override
{
- if (type == WAYPOINT_MOTION_TYPE && pointId == POINT_FINAL_TENEBRON)
+ if (summon->GetEntry() != NPC_TWILIGHT_EGG)
{
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
- me->SetInCombatWithZone();
+ summons.Summon(summon);
}
+ // Summons to Sartharion are linked manually
}
- void UpdateAI(uint32 diff)
+ void JustDied(Unit* killer) override
{
- // Call speach
- if (timer)
+ if (!isCalledBySartharion)
{
- timer += diff;
- if (timer >= 4000)
- {
- Talk(SAY_TENEBRON_RESPOND);
- me->SetCanFly(true);
- me->SetSpeed(MOVE_FLIGHT, 3.0f);
- me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
- timer = 0;
- }
+ summons2.DespawnAll();
}
- if (!UpdateVictim())
- return;
+ boss_sartharion_dragonAI::JustDied(killer);
+ }
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
+ void HandleExtraEvent(uint32 const eventId) override
+ {
+ if (eventId == EVENT_MINIDRAKE_SPEECH)
+ {
+ Talk(SAY_TENEBRON_RESPOND);
+ me->SetCanFly(true);
+ me->SetSpeed(MOVE_FLIGHT, 3.0f);
+ me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
+ }
+ }
- switch (events.ExecuteEvent())
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
{
case EVENT_MINIBOSS_SHADOW_BREATH:
+ {
if (!urand(0, 10))
+ {
Talk(SAY_TENEBRON_BREATH);
- me->CastSpell(me->GetVictim(), SPELL_SHADOW_BREATH, false);
+ }
+ DoCastVictim(SPELL_SHADOW_BREATH, false);
events.RepeatEvent(17500);
break;
+ }
case EVENT_MINIBOSS_SHADOW_FISSURE:
+ {
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
- me->CastSpell(target, SPELL_SHADOW_FISSURE, false);
+ {
+ DoCast(target, SPELL_SHADOW_FISSURE, false);
+ }
events.RepeatEvent(22500);
break;
+ }
case EVENT_MINIBOSS_OPEN_PORTAL:
+ {
Talk(WHISPER_OPEN_PORTAL);
Talk(SAY_TENEBRON_SPECIAL);
- if (!isSartharion)
+ if (!isCalledBySartharion)
{
- if (GameObject* Portal = me->GetVictim()->SummonGameObject(GO_TWILIGHT_PORTAL, portalPos[BOSS_TENEBRON_EVENT].GetPositionX(), portalPos[BOSS_TENEBRON_EVENT].GetPositionY(), portalPos[BOSS_TENEBRON_EVENT].GetPositionZ(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
+ if (GameObject* Portal = me->GetVictim()->SummonGameObject(GO_TWILIGHT_PORTAL, portalPos[DATA_TENEBRON].GetPositionX(), portalPos[DATA_TENEBRON].GetPositionY(), portalPos[DATA_TENEBRON].GetPositionZ(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
+ {
portalGUID = Portal->GetGUID();
+ }
+ }
+ else
+ {
+ instance->DoAction(ACTION_ADD_PORTAL);
}
- else if (pInstance)
- pInstance->SetData(DATA_ADD_PORTAL, 0);
-
events.ScheduleEvent(EVENT_MINIBOSS_SPAWN_HELPERS, 2000);
events.RepeatEvent(60000);
break;
+ }
case EVENT_MINIBOSS_SPAWN_HELPERS:
+ {
+ Talk(WHISPER_HATCH_EGGS);
+ for (uint8 i = 0; i < MAX_TENEBORN_EGGS_SUMMONS; ++i)
{
- Talk(WHISPER_HATCH_EGGS);
- Creature* cr = nullptr;
- for (uint8 i = 0; i < 6; ++i)
+ if (Creature* egg = me->SummonCreature(NPC_TWILIGHT_EGG, TenebronEggsPos[isCalledBySartharion ? 1 : 0][i], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000))
{
- if ((cr = me->SummonCreature(NPC_TWILIGHT_EGG, EggsPos[isSartharion ? i + 6 : i].GetPositionX(), EggsPos[isSartharion ? i + 6 : i].GetPositionY(), EggsPos[isSartharion ? i + 6 : i].GetPositionZ(), EggsPos[isSartharion ? i + 6 : i].GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000)))
+ summons.Summon(egg);
+ if (isCalledBySartharion && instance->GetBossState(DATA_SARTHARION) == IN_PROGRESS)
{
- summons.Summon(cr);
- cr->SetPhaseMask(16, true);
+ if (Creature* sartharion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SARTHARION)))
+ {
+ sartharion->AI()->JustSummoned(egg);
+ }
}
+ egg->SetPhaseMask(16, true);
}
-
- events.ScheduleEvent(EVENT_MINIBOSS_HATCH_EGGS, 25000);
- break;
}
+
+ events.ScheduleEvent(EVENT_MINIBOSS_HATCH_EGGS, 25000);
+ break;
+ }
case EVENT_MINIBOSS_HATCH_EGGS:
+ {
+ summons.RemoveNotExisting();
+ summons.DespawnEntry(NPC_TWILIGHT_WHELP);
+ for (uint64 const summonGuid : summons)
{
- Creature* cr = nullptr;
- summons.RemoveNotExisting();
- summons.DespawnEntry(NPC_TWILIGHT_WHELP);
- for (SummonList::iterator i = summons.begin(); i != summons.end(); ++i)
+ Creature const* summon = ObjectAccessor::GetCreature(*me, summonGuid);
+ if (!summon || !summon->IsAlive() || summon->GetEntry() != NPC_TWILIGHT_EGG)
{
- if ((cr = ObjectAccessor::GetCreature(*me, *i)))
- {
- if (!cr->IsAlive())
- continue;
-
- if (cr->GetEntry() == NPC_TWILIGHT_EGG)
- if ((cr = me->SummonCreature(NPC_TWILIGHT_WHELP, cr->GetPositionX(), cr->GetPositionY(), cr->GetPositionZ(), cr->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000)))
- summons2.Summon(cr);
- }
+ continue;
}
- if (!isSartharion)
+ if (Creature* whelp = me->SummonCreature(NPC_TWILIGHT_WHELP, summon->GetPosition(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000))
{
- // Remove phase shift
- if (InstanceScript* instance = me->GetInstanceScript())
- instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_SHIFT);
-
- RemoveTwilightPortal();
+ summons2.Summon(whelp);
+ if (isCalledBySartharion && instance->GetBossState(DATA_SARTHARION) == IN_PROGRESS)
+ {
+ if (Creature* sartharion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SARTHARION)))
+ {
+ sartharion->AI()->JustSummoned(whelp);
+ }
+ }
}
- else if (pInstance)
- pInstance->SetData(DATA_CLEAR_PORTAL, 0);
+ }
- EntryCheckPredicate pred(NPC_TWILIGHT_EGG);
- summons.DoAction(ACTION_SWITCH_PHASE, pred);
- break;
+ if (!isCalledBySartharion)
+ {
+ // Remove phase shift
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_SHIFT);
+ RemoveTwilightPortal();
}
+ else
+ {
+ instance->DoAction(ACTION_CLEAR_PORTAL);
+ }
+
+ EntryCheckPredicate pred(NPC_TWILIGHT_EGG);
+ summons.DoAction(ACTION_SWITCH_PHASE, pred);
+ break;
+ }
}
+ }
- DoMeleeAttackIfReady();
+ void ClearInstance() override
+ {
+ boss_sartharion_dragonAI::ClearInstance();
+ summons2.DespawnAll();
}
+
+ private:
+ SummonList summons2;
};
};
@@ -832,135 +1195,34 @@ public:
return new boss_sartharion_shadronAI (pCreature);
}
- struct boss_sartharion_shadronAI : public ScriptedAI
+ struct boss_sartharion_shadronAI : public boss_sartharion_dragonAI
{
- boss_sartharion_shadronAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- portalGUID = 0;
- pInstance = me->GetInstanceScript();
- }
-
- EventMap events;
- SummonList summons;
- uint64 portalGUID;
- InstanceScript* pInstance;
- bool isSartharion;
- uint32 timer;
-
- void ClearInstance()
+ boss_sartharion_shadronAI(Creature* pCreature) : boss_sartharion_dragonAI(pCreature, DATA_SHADRON)
{
- summons.DespawnAll();
- // Remove phase shift
- if (pInstance)
- pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_SHIFT);
-
- RemoveTwilightPortal();
}
- void RemoveTwilightPortal()
+ void Reset() override
{
- if (portalGUID)
- if (GameObject* gobj = me->GetMap()->GetGameObject(portalGUID))
- gobj->Delete();
-
- portalGUID = 0;
- }
-
- void DoAction(int32 param)
- {
- if (param == ACTION_CALL_DRAGON)
- {
- isSartharion = true;
- timer++;
- }
- }
-
- void MoveInLineOfSight(Unit* who)
- {
- if (isSartharion)
- return;
-
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- void Reset()
- {
- events.Reset();
- ClearInstance();
-
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
- me->SetSpeed(MOVE_FLIGHT, 1.0f);
- me->SetCanFly(false);
- me->ResetLootMode();
- isSartharion = false;
- timer = 0;
-
- if (pInstance)
- {
- pInstance->SetData(BOSS_SHADRON_EVENT, NOT_STARTED);
- pInstance->SetData(DATA_CLEAR_PORTAL, 0);
- }
- }
-
- void EnterCombat(Unit* )
- {
- Talk(SAY_SHADRON_AGGRO);
- me->SetInCombatWithZone();
- me->SetDisableGravity(false);
- if (me->IsFlying())
- {
- me->SetSpeed(MOVE_FLIGHT, 1.0f);
- me->SetCanFly(false);
- }
-
+ boss_sartharion_dragonAI::Reset();
events.ScheduleEvent(EVENT_MINIBOSS_SHADOW_FISSURE, 20000);
events.ScheduleEvent(EVENT_MINIBOSS_SHADOW_BREATH, 10000);
events.ScheduleEvent(EVENT_MINIBOSS_OPEN_PORTAL, 15000);
-
- if (pInstance && !isSartharion)
- pInstance->SetData(BOSS_SHADRON_EVENT, IN_PROGRESS);
-
- if (isSartharion || (pInstance && pInstance->GetData(BOSS_SARTHARION_EVENT) == DONE))
- me->SetLootMode(0);
-
- if (isSartharion)
- if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1, 500, true))
- me->AI()->AttackStart(target);
- }
-
- void JustDied(Unit* )
- {
- Talk(SAY_SHADRON_DEATH);
-
- if (!isSartharion)
- {
- ClearInstance();
- if (pInstance)
- pInstance->SetData(BOSS_SHADRON_EVENT, DONE);
- }
- else if (pInstance)
- {
- if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetData64(DATA_SARTHARION)))
- cr->AI()->DoAction(ACTION_DRAKE_DIED);
- }
- }
-
- void JustKilled(Unit* victim)
- {
- if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
- return;
-
- Talk(SAY_SHADRON_SLAY);
}
- void SummonedCreatureDies(Creature* /*summon*/, Unit*)
+ void SummonedCreatureDies(Creature* /*summon*/, Unit* /*summon*/) override
{
- if (isSartharion && pInstance)
+ if (isCalledBySartharion)
{
- if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetData64(DATA_SARTHARION)))
- cr->RemoveAura(SPELL_GIFT_OF_TWILIGHT_FIRE);
+ // Acolytes are dead
+ if (!summons.HasEntry(NPC_ACOLYTE_OF_SHADRON))
+ {
+ instance->DoAction(ACTION_CLEAR_PORTAL);
+ }
- pInstance->SetData(DATA_CLEAR_PORTAL, 0);
+ if (Creature* sartharion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SARTHARION)))
+ {
+ sartharion->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGHT_FIRE);
+ }
}
else
{
@@ -971,79 +1233,75 @@ public:
events.ScheduleEvent(EVENT_MINIBOSS_OPEN_PORTAL, 30000);
}
- void MovementInform(uint32 type, uint32 pointId)
+ void HandleExtraEvent(uint32 const eventId) override
{
- if (type == WAYPOINT_MOTION_TYPE && pointId == POINT_FINAL_SHADRON)
+ if (eventId == EVENT_MINIDRAKE_SPEECH)
{
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
- me->SetInCombatWithZone();
+ Talk(SAY_SHADRON_RESPOND);
+ me->SetCanFly(true);
+ me->SetSpeed(MOVE_FLIGHT, 3.0f);
+ me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
}
}
- void UpdateAI(uint32 diff)
+ void ExecuteEvent(uint32 eventId) override
{
- // Call speach
- if (timer)
- {
- timer += diff;
- if (timer >= 4000)
- {
- Talk(SAY_SHADRON_RESPOND);
- me->SetCanFly(true);
- me->SetSpeed(MOVE_FLIGHT, 3.0f);
- me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
- timer = 0;
- }
- }
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
+ switch (eventId)
{
case EVENT_MINIBOSS_SHADOW_BREATH:
+ {
if (!urand(0, 10))
+ {
Talk(SAY_SHADRON_BREATH);
- me->CastSpell(me->GetVictim(), SPELL_SHADOW_BREATH, false);
+ }
+
+ DoCastVictim(SPELL_SHADOW_BREATH, false);
events.RepeatEvent(17500);
break;
+ }
case EVENT_MINIBOSS_SHADOW_FISSURE:
+ {
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
- me->CastSpell(target, SPELL_SHADOW_FISSURE, false);
+ {
+ DoCast(target, SPELL_SHADOW_FISSURE, false);
+ }
events.RepeatEvent(22500);
break;
+ }
case EVENT_MINIBOSS_OPEN_PORTAL:
+ {
Talk(WHISPER_OPEN_PORTAL);
Talk(SAY_SHADRON_SPECIAL);
- if (!isSartharion)
+ if (!isCalledBySartharion)
{
- if (GameObject* Portal = me->GetVictim()->SummonGameObject(GO_TWILIGHT_PORTAL, portalPos[BOSS_SHADRON_EVENT].GetPositionX(), portalPos[BOSS_SHADRON_EVENT].GetPositionY(), portalPos[BOSS_SHADRON_EVENT].GetPositionZ(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
+ if (GameObject* Portal = me->GetVictim()->SummonGameObject(GO_TWILIGHT_PORTAL, portalPos[DATA_SHADRON].GetPositionX(), portalPos[DATA_SHADRON].GetPositionY(), portalPos[DATA_SHADRON].GetPositionZ(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
+ {
portalGUID = Portal->GetGUID();
+ }
+ }
+ else
+ {
+ instance->DoAction(ACTION_ADD_PORTAL);
}
- else if (pInstance)
- pInstance->SetData(DATA_ADD_PORTAL, 0);
events.ScheduleEvent(EVENT_MINIBOSS_SPAWN_HELPERS, 2000);
-
break;
+ }
case EVENT_MINIBOSS_SPAWN_HELPERS:
+ {
Talk(WHISPER_SUMMON_DICIPLE);
- me->CastSpell(me, (isSartharion ? SPELL_GIFT_OF_TWILIGHT_FIRE : SPELL_GIFT_OF_TWILIGHT_SHADOW), true);
- if (Creature* cr = me->SummonCreature((isSartharion ? NPC_ACOLYTE_OF_SHADRON : NPC_DISCIPLE_OF_SHADRON), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()))
+ DoCastAOE(static_cast<uint32>((isCalledBySartharion ? SPELL_GIFT_OF_TWILIGHT_FIRE : SPELL_GIFT_OF_TWILIGHT_SHADOW)), true);
+
+ if (Creature* acolyte = me->SummonCreature((isCalledBySartharion ? NPC_ACOLYTE_OF_SHADRON : NPC_DISCIPLE_OF_SHADRON), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()))
{
- summons.Summon(cr);
- cr->SetPhaseMask(16, true);
+ // TODO: inpect JustSummoned
+ summons.Summon(acolyte);
+ acolyte->SetPhaseMask(16, true);
}
-
break;
+ }
}
-
- DoMeleeAttackIfReady();
}
};
};
@@ -1062,218 +1320,113 @@ public:
return new boss_sartharion_vesperonAI (pCreature);
}
- struct boss_sartharion_vesperonAI : public ScriptedAI
+ struct boss_sartharion_vesperonAI : public boss_sartharion_dragonAI
{
- boss_sartharion_vesperonAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- portalGUID = 0;
- pInstance = me->GetInstanceScript();
- }
-
- EventMap events;
- SummonList summons;
- uint64 portalGUID;
- InstanceScript* pInstance;
- bool isSartharion;
- uint32 timer;
-
- void ClearInstance()
+ boss_sartharion_vesperonAI(Creature* pCreature) : boss_sartharion_dragonAI(pCreature, DATA_VESPERON)
{
- // Remove phase shift
- if (pInstance)
- {
- pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_SHIFT);
- pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_VESPERON);
- pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_SARTHARION);
- }
-
- summons.DespawnAll();
- RemoveTwilightPortal();
}
- void RemoveTwilightPortal()
+ void Reset() override
{
- if (portalGUID)
- if (GameObject* gobj = me->GetMap()->GetGameObject(portalGUID))
- gobj->Delete();
-
- portalGUID = 0;
- }
-
- void DoAction(int32 param)
- {
- if (param == ACTION_CALL_DRAGON)
- {
- isSartharion = true;
- timer++;
- }
- }
-
- void MoveInLineOfSight(Unit* who)
- {
- if (isSartharion)
- return;
-
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- void Reset()
- {
- events.Reset();
- ClearInstance();
-
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
- me->SetSpeed(MOVE_FLIGHT, 1.0f);
- me->SetCanFly(false);
- me->ResetLootMode();
- isSartharion = false;
- timer = 0;
-
- if (pInstance)
- {
- pInstance->SetData(BOSS_VESPERON_EVENT, NOT_STARTED);
- pInstance->SetData(DATA_CLEAR_PORTAL, 1);
- }
- }
-
- void EnterCombat(Unit* )
- {
- Talk(SAY_VESPERON_AGGRO);
- me->SetInCombatWithZone();
-
- if (me->IsFlying())
- {
- me->SetSpeed(MOVE_FLIGHT, 1.0f);
- me->SetCanFly(false);
- }
-
+ boss_sartharion_dragonAI::Reset();
events.ScheduleEvent(EVENT_MINIBOSS_SHADOW_FISSURE, 20000);
events.ScheduleEvent(EVENT_MINIBOSS_SHADOW_BREATH, 10000);
events.ScheduleEvent(EVENT_MINIBOSS_OPEN_PORTAL, 30000);
-
- if (pInstance && !isSartharion)
- pInstance->SetData(BOSS_VESPERON_EVENT, IN_PROGRESS);
-
- if (isSartharion || (pInstance && pInstance->GetData(BOSS_SARTHARION_EVENT) == DONE))
- me->SetLootMode(0);
-
- if (isSartharion)
- if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1, 500, true))
- me->AI()->AttackStart(target);
}
- void JustDied(Unit* )
+ void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) override
{
- Talk(SAY_VESPERON_DEATH);
-
- if (!isSartharion)
+ if (!isCalledBySartharion)
{
ClearInstance();
- if (pInstance)
- pInstance->SetData(BOSS_VESPERON_EVENT, DONE);
- }
- else if (pInstance)
- {
- if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetData64(DATA_SARTHARION)))
- cr->AI()->DoAction(ACTION_DRAKE_DIED);
}
- }
-
- void JustKilled(Unit* victim)
- {
- if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
- return;
-
- Talk(SAY_VESPERON_SLAY);
- }
-
- void SummonedCreatureDies(Creature* /*summon*/, Unit*)
- {
- if (!isSartharion)
- ClearInstance();
- else if (pInstance)
+ else
{
- pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_SARTHARION);
- pInstance->SetData(DATA_CLEAR_PORTAL, 1);
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_SARTHARION);
+ instance->DoAction(ACTION_CLEAR_PORTAL);
}
events.ScheduleEvent(EVENT_MINIBOSS_OPEN_PORTAL, 30000);
}
- void MovementInform(uint32 type, uint32 pointId)
+ void HandleExtraEvent(uint32 const eventId) override
{
- if (type == WAYPOINT_MOTION_TYPE && pointId == POINT_FINAL_VESPERON)
+ if (eventId == EVENT_MINIDRAKE_SPEECH)
{
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
- me->SetInCombatWithZone();
+ Talk(SAY_SHADRON_RESPOND);
+ me->SetCanFly(true);
+ me->SetSpeed(MOVE_FLIGHT, 3.0f);
+ me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
}
}
- void UpdateAI(uint32 diff)
+ void ExecuteEvent(uint32 eventId) override
{
- // Call speach
- if (timer)
- {
- timer += diff;
- if (timer >= 4000)
- {
- Talk(SAY_VESPERON_RESPOND);
- me->SetCanFly(true);
- me->SetSpeed(MOVE_FLIGHT, 3.0f);
- me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
- timer = 0;
- }
- return;
- }
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
+ switch (eventId)
{
case EVENT_MINIBOSS_SHADOW_BREATH:
+ {
if (!urand(0, 10))
+ {
Talk(SAY_SHADRON_BREATH);
- me->CastSpell(me->GetVictim(), SPELL_SHADOW_BREATH, false);
+ }
+
+ DoCastVictim(SPELL_SHADOW_BREATH, false);
events.RepeatEvent(17500);
break;
+ }
case EVENT_MINIBOSS_SHADOW_FISSURE:
+ {
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
- me->CastSpell(target, SPELL_SHADOW_FISSURE, false);
+ {
+ DoCast(target, SPELL_SHADOW_FISSURE, false);
+ }
+
events.RepeatEvent(22500);
break;
+ }
case EVENT_MINIBOSS_OPEN_PORTAL:
+ {
Talk(WHISPER_OPEN_PORTAL);
Talk(SAY_VESPERON_SPECIAL);
- if (!isSartharion)
+ if (!isCalledBySartharion)
{
- if (GameObject* Portal = me->GetVictim()->SummonGameObject(GO_TWILIGHT_PORTAL, portalPos[BOSS_VESPERON_EVENT].GetPositionX(), portalPos[BOSS_VESPERON_EVENT].GetPositionY(), portalPos[BOSS_VESPERON_EVENT].GetPositionZ(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
+ if (GameObject* Portal = me->GetVictim()->SummonGameObject(GO_TWILIGHT_PORTAL, portalPos[DATA_VESPERON].GetPositionX(), portalPos[DATA_VESPERON].GetPositionY(), portalPos[DATA_VESPERON].GetPositionZ(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
+ {
portalGUID = Portal->GetGUID();
+ }
+ }
+ else
+ {
+ instance->DoAction(ACTION_ADD_PORTAL);
}
- else if (pInstance)
- pInstance->SetData(DATA_ADD_PORTAL, 0);
events.ScheduleEvent(EVENT_MINIBOSS_SPAWN_HELPERS, 2000);
-
break;
+ }
case EVENT_MINIBOSS_SPAWN_HELPERS:
+ {
Talk(WHISPER_SUMMON_DICIPLE);
- me->CastSpell(me, (isSartharion ? (uint32)SPELL_TWILIGHT_TORMENT_SARTHARION : (uint32)SPELL_TWILIGHT_TORMENT_VESPERON), true);
- if (Creature* cr = me->SummonCreature((isSartharion ? NPC_ACOLYTE_OF_VESPERON : NPC_DISCIPLE_OF_VESPERON), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()))
+ DoCastSelf(isCalledBySartharion ? static_cast<uint32>(SPELL_TWILIGHT_TORMENT_SARTHARION) : static_cast<uint32>(SPELL_TWILIGHT_TORMENT_VESPERON), true);
+ if (Creature* acolyte = me->SummonCreature((isCalledBySartharion ? NPC_ACOLYTE_OF_VESPERON : NPC_DISCIPLE_OF_VESPERON), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()))
{
- summons.Summon(cr);
- cr->SetPhaseMask(16, true);
+ summons.Summon(acolyte);
+ acolyte->SetPhaseMask(16, true);
}
-
break;
+ }
}
+ }
- DoMeleeAttackIfReady();
+ private:
+ void ClearInstance() override
+ {
+ boss_sartharion_dragonAI::ClearInstance();
+
+ // Remove phase shift
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_VESPERON);
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_SARTHARION);
}
};
};
@@ -1291,21 +1444,25 @@ public:
struct npc_twilight_summonAI : public ScriptedAI
{
- npc_twilight_summonAI(Creature* pCreature) : ScriptedAI(pCreature)
+ npc_twilight_summonAI(Creature* pCreature) : ScriptedAI(pCreature),
+ fadeArmorTimer(urand(0, 15000))
{
}
- uint32 timer;
- void Reset()
+ void Reset() override
{
- timer = urand(0, 15000);
+ fadeArmorTimer = urand(0, 15000);
if (me->GetEntry() == NPC_TWILIGHT_EGG)
+ {
me->SetControlled(true, UNIT_STATE_STUNNED);
+ }
else
+ {
me->SetInCombatWithZone();
+ }
}
- void DoAction(int32 param)
+ void DoAction(int32 param) override
{
if (param == ACTION_SWITCH_PHASE)
{
@@ -1313,24 +1470,33 @@ public:
}
}
- void UpdateAI(uint32 diff)
+ void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() || me->GetEntry() == NPC_TWILIGHT_EGG)
+ {
return;
+ }
- timer += diff;
- if (timer >= 15000)
+ fadeArmorTimer += diff;
+ if (fadeArmorTimer >= 15000)
{
if (Aura* aur = me->GetVictim()->GetAura(SPELL_FADE_ARMOR))
+ {
aur->ModStackAmount(1);
+ }
else
- me->CastSpell(me->GetVictim(), SPELL_FADE_ARMOR, false);
+ {
+ DoCastVictim(SPELL_FADE_ARMOR, false);
+ }
- timer = 0;
+ fadeArmorTimer = 0;
}
DoMeleeAttackIfReady();
}
+
+ private:
+ uint32 fadeArmorTimer;
};
};
@@ -1345,7 +1511,11 @@ public:
bool spawned;
- bool Load() { spawned = false; return true; }
+ bool Load() override
+ {
+ spawned = false;
+ return true;
+ }
void HandleDummy(SpellEffIndex /*effIndex*/)
{
@@ -1358,23 +1528,31 @@ public:
void HandleSchoolDamage(SpellEffIndex /*effIndex*/)
{
if (!GetCaster() || !GetHitUnit() || spawned)
+ {
return;
+ }
if (InstanceScript* pInstance = GetCaster()->GetInstanceScript())
+ {
if (Creature* sarth = ObjectAccessor::GetCreature(*GetHitUnit(), pInstance->GetData64(DATA_SARTHARION)))
{
sarth->AI()->SetData(DATA_VOLCANO_BLOWS, GetHitUnit()->GetGUIDLow());
sarth->CastSpell(GetHitUnit(), SPELL_LAVA_STRIKE_SUMMON, true);
spawned = true;
}
+ }
}
- void Register()
+ void Register() override
{
if (m_scriptSpellId == 57578) // Dummy lava strike
+ {
OnEffectHitTarget += SpellEffectFn(spell_sartharion_lava_strike_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
else
+ {
OnEffectHitTarget += SpellEffectFn(spell_sartharion_lava_strike_SpellScript::HandleSchoolDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
+ }
}
};
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp
index 97fdf3ada7..66bde45863 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp
@@ -19,36 +19,29 @@ public:
struct instance_obsidian_sanctum_InstanceMapScript : public InstanceScript
{
- instance_obsidian_sanctum_InstanceMapScript(Map* pMap) : InstanceScript(pMap) {}
-
- uint64 m_uiSartharionGUID;
- uint64 m_uiTenebronGUID;
- uint64 m_uiShadronGUID;
- uint64 m_uiVesperonGUID;
- uint32 Encounters[MAX_ENCOUNTERS];
- uint64 m_uiPortalGUID;
- uint8 portalCount;
-
- void Initialize()
+ instance_obsidian_sanctum_InstanceMapScript(Map* pMap) : InstanceScript(pMap),
+ m_uiSartharionGUID(0),
+ m_uiTenebronGUID(0),
+ m_uiShadronGUID(0),
+ m_uiVesperonGUID(0),
+ m_uiPortalGUID(0),
+ portalCount(0)
{
- m_uiSartharionGUID = 0;
- m_uiTenebronGUID = 0;
- m_uiShadronGUID = 0;
- m_uiVesperonGUID = 0;
- m_uiPortalGUID = 0;
- portalCount = 0;
- memset(&Encounters, 0, sizeof(Encounters));
- };
-
- bool IsEncounterInProgress() const
+ SetBossNumber(MAX_ENCOUNTERS);
+ }
+
+ bool IsEncounterInProgress() const override
{
- if (Encounters[BOSS_SARTHARION_EVENT] == IN_PROGRESS)
- return true;
+ for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i)
+ {
+ if (GetBossState(i) == IN_PROGRESS)
+ return true;
+ }
return false;
}
- void OnCreatureCreate(Creature* pCreature)
+ void OnCreatureCreate(Creature* pCreature) override
{
switch(pCreature->GetEntry())
{
@@ -67,21 +60,7 @@ public:
}
}
- uint32 GetData(uint32 id) const
- {
- switch (id)
- {
- case BOSS_SARTHARION_EVENT:
- case BOSS_TENEBRON_EVENT:
- case BOSS_SHADRON_EVENT:
- case BOSS_VESPERON_EVENT:
- return Encounters[id];
- }
-
- return 0;
- }
-
- uint64 GetData64(uint32 uiData) const
+ uint64 GetData64(uint32 uiData) const override
{
switch(uiData)
{
@@ -97,7 +76,7 @@ public:
return 0;
}
- bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* source, Unit const* /*target*/, uint32 /*miscvalue1*/)
+ bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* source, Unit const* /*target*/, uint32 /*miscvalue1*/) override
{
switch(criteria_id)
{
@@ -105,109 +84,122 @@ public:
case 7326:
// Gonna Go When the Volcano Blows (25 player) (2048)
case 7327:
- if (Creature* cr = instance->GetCreature(m_uiSartharionGUID))
- if (!cr->AI()->GetData(source->GetGUIDLow()))
- return true;
- break;
+ {
+ Creature const* sartharion = instance->GetCreature(m_uiSartharionGUID);
+ return sartharion && !sartharion->AI()->GetData(source->GetGUIDLow());
+ }
// Less Is More (10 player) (624)
case 7189:
case 7190:
case 7191:
case 522:
- if (instance->GetPlayersCountExceptGMs() < 9)
- return true;
- break;
+ {
+ return instance->GetPlayersCountExceptGMs() < 9;
+ }
// Less Is More (25 player) (1877)
case 7185:
case 7186:
case 7187:
case 7188:
- if (instance->GetPlayersCountExceptGMs() < 21)
- return true;
- break;
+ {
+ return instance->GetPlayersCountExceptGMs() < 21;
+ }
// Twilight Assist (10 player) (2049)
case 7328:
// Twilight Assist (25 player) (2052)
case 7331:
- if (Creature* cr = instance->GetCreature(m_uiSartharionGUID))
- if (cr->AI()->GetData(DATA_ACHIEVEMENT_DRAGONS_COUNT) >= 1)
- return true;
- break;
+ {
+ Creature const* sartharion = instance->GetCreature(m_uiSartharionGUID);
+ return sartharion && sartharion->AI()->GetData(DATA_ACHIEVEMENT_DRAGONS_COUNT) >= 1;
+ }
// Twilight Duo (10 player) (2050)
case 7329:
// Twilight Duo (25 player) (2053)
case 7332:
- if (Creature* cr = instance->GetCreature(m_uiSartharionGUID))
- if (cr->AI()->GetData(DATA_ACHIEVEMENT_DRAGONS_COUNT) >= 2)
- return true;
- break;
+ {
+ Creature const* sartharion = instance->GetCreature(m_uiSartharionGUID);
+ return sartharion && sartharion->AI()->GetData(DATA_ACHIEVEMENT_DRAGONS_COUNT) >= 2;
+ }
// Twilight Zone (10 player) (2051)
case 7330:
// Twilight Zone (25 player) (2054)
case 7333:
- if (Creature* cr = instance->GetCreature(m_uiSartharionGUID))
- if (cr->AI()->GetData(DATA_ACHIEVEMENT_DRAGONS_COUNT) >= 3)
- return true;
- break;
-
+ {
+ Creature const* sartharion = instance->GetCreature(m_uiSartharionGUID);
+ return sartharion && sartharion->AI()->GetData(DATA_ACHIEVEMENT_DRAGONS_COUNT) >= 3;
+ }
}
+
return false;
}
- void SetData(uint32 type, uint32 data)
+ bool SetBossState(uint32 type, EncounterState state) override
{
- switch(type)
+ if (InstanceScript::SetBossState(type, state))
{
- case BOSS_SARTHARION_EVENT:
- case BOSS_TENEBRON_EVENT:
- case BOSS_SHADRON_EVENT:
- case BOSS_VESPERON_EVENT:
- Encounters[type] = data;
- break;
- case DATA_ADD_PORTAL:
+ return false;
+ }
+
+ if (state == DONE)
+ {
+ SaveToDB();
+ }
+ return true;
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_ADD_PORTAL:
+ {
if (!m_uiPortalGUID)
{
- if (Creature* cr = instance->GetCreature(m_uiSartharionGUID))
- if (GameObject* go = cr->SummonGameObject(GO_TWILIGHT_PORTAL, 3247.29f, 529.804f, 58.9595f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
+ if (Creature* sartharion = instance->GetCreature(m_uiSartharionGUID))
+ {
+ if (GameObject* portal = sartharion->SummonGameObject(GO_TWILIGHT_PORTAL, 3247.29f, 529.804f, 58.9595f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
{
- cr->RemoveGameObject(go, false);
- m_uiPortalGUID = go->GetGUID();
+ sartharion->RemoveGameObject(portal, false);
+ m_uiPortalGUID = portal->GetGUID();
}
+ }
portalCount = 0;
}
- portalCount++;
+ ++portalCount;
break;
- case DATA_CLEAR_PORTAL:
- portalCount--;
- if (!portalCount || data == 2)
+ }
+ case ACTION_CLEAR_PORTAL:
+ {
+ --portalCount;
+ if (!portalCount)
{
if (GameObject* go = instance->GetGameObject(m_uiPortalGUID))
+ {
go->Delete();
+ }
DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_SHIFT);
m_uiPortalGUID = 0;
}
break;
+ }
}
-
- if (data == DONE)
- SaveToDB();
}
- std::string GetSaveData()
+ std::string GetSaveData() override
{
OUT_SAVE_INST_DATA;
std::ostringstream saveStream;
- saveStream << "O S " << Encounters[0] << ' ' << Encounters[1] << ' ' << Encounters[2] << ' ' << Encounters[3];
+ saveStream << "O S " << GetBossSaveData();
OUT_SAVE_INST_DATA_COMPLETE;
return saveStream.str();
}
- void Load(const char* strIn)
+ void Load(const char* strIn) override
{
if (!strIn)
{
@@ -226,14 +218,25 @@ public:
{
for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i)
{
- loadStream >> Encounters[i];
- if (Encounters[i] == IN_PROGRESS)
- Encounters[i] = NOT_STARTED;
+ uint32 temp;
+ loadStream >> temp;
+ if (temp == IN_PROGRESS)
+ temp = NOT_STARTED;
+
+ SetBossState(i, static_cast<EncounterState>(temp));
}
}
OUT_LOAD_INST_DATA_COMPLETE;
}
+
+ private:
+ uint64 m_uiSartharionGUID;
+ uint64 m_uiTenebronGUID;
+ uint64 m_uiShadronGUID;
+ uint64 m_uiVesperonGUID;
+ uint64 m_uiPortalGUID;
+ uint8 portalCount;
};
};
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h
index 56c8268d3f..8c0dc705ba 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h
+++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h
@@ -5,25 +5,15 @@
#ifndef DEF_OBSIDIAN_SANCTUM_H
#define DEF_OBSIDIAN_SANCTUM_H
-enum Data
+enum Data : uint32
{
- // Encounter
- BOSS_SARTHARION_EVENT = 0,
- BOSS_TENEBRON_EVENT = 1,
- BOSS_VESPERON_EVENT = 2,
- BOSS_SHADRON_EVENT = 3,
+ // Encounters
+ DATA_SARTHARION = 0,
+ DATA_TENEBRON = 1,
+ DATA_VESPERON = 2,
+ DATA_SHADRON = 3,
MAX_ENCOUNTERS = 4,
- // GUIDs
- DATA_SARTHARION = 10,
- DATA_TENEBRON = 11,
- DATA_SHADRON = 12,
- DATA_VESPERON = 13,
-
- // Portal
- DATA_CLEAR_PORTAL = 20,
- DATA_ADD_PORTAL = 21,
-
// Achievements
DATA_ACHIEVEMENT_DRAGONS_COUNT = 30,
DATA_VOLCANO_BLOWS = 31,
@@ -44,4 +34,10 @@ enum Data
SPELL_TWILIGHT_TORMENT_SARTHARION = 58835,
};
+enum OSActions
+{
+ // Portal
+ ACTION_CLEAR_PORTAL = -1,
+ ACTION_ADD_PORTAL = -2,
+};
#endif