diff options
| author | Gustavo <sirikfoll@hotmail.com> | 2016-07-05 10:54:31 +0200 |
|---|---|---|
| committer | joschiwald <joschiwald.trinity@gmail.com> | 2017-02-04 23:33:26 +0100 |
| commit | e55420af8653cd52697a94c85badc91c9a1774a7 (patch) | |
| tree | f7fcff37c4a55487e27ebc3012c4e19c5bb4402d | |
| parent | 752c789aaf3be7afaf76dc1464296d553f35528a (diff) | |
Core/Scripts Corrections on Halion's Encounter (#16725)
Core/Scripts: Updates to Halion
* Fixed Combustion and Consumption.
* Fixed Living Embers and Blazing Auras.
* Timer changes.
(cherry picked from commit dfe278459d79ade500a66356a98b4065c0722572)
# Conflicts:
# src/server/game/Spells/SpellMgr.cpp
# src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
Fix sql for merged PR
(cherry picked from commit 7f944695ddad14cec021ff5a0527a5a92fb4cf81)
Derp.
github editor is bad.
(cherry picked from commit 182904946174cd635b7478bd38507235d0d45aa2)
4 files changed, 353 insertions, 263 deletions
diff --git a/sql/updates/world/master/2017_02_04_25_world_2016_07_05_00_world.sql b/sql/updates/world/master/2017_02_04_25_world_2016_07_05_00_world.sql new file mode 100644 index 00000000000..f21f7a04959 --- /dev/null +++ b/sql/updates/world/master/2017_02_04_25_world_2016_07_05_00_world.sql @@ -0,0 +1,21 @@ +SET @CGUID := 11003; + +-- UPDATE `spell_dbc` SET `EffectBasePoints1`=20 WHERE `Id`=70507; +UPDATE `creature_template` SET `unit_flags`=32832 WHERE `entry` IN(40142,40143,40144,40145); +UPDATE `creature_template` SET `flags_extra`=128 WHERE `entry` IN (40081,40470,40471,40472); + +DELETE FROM `creature` WHERE `guid`=@CGUID; +INSERT INTO `creature` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `PhaseId`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `VerifiedBuild`) VALUES +(@CGUID, 40146, 724, 0, 0, 120, 174, 0, 0, 3156.037, 533.2656, 72.97205, 0, 604800, 0, 0, 0, 0, 0, 0, 0, 0, 0); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN( 'spell_halion_blazing_aura','spell_halion_combustion_consumption_periodic'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(75886, 'spell_halion_blazing_aura'), +(75887, 'spell_halion_blazing_aura'), +(74803, 'spell_halion_combustion_consumption_periodic'), +(74629, 'spell_halion_combustion_consumption_periodic'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry` IN(75886,75887); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 2, 75886, 0, 0, 31, 0, 3, 40683, 0, 0, 0, 0, '', 'Blazing Aura can only target Living Embers'), +(13, 2, 75887, 0, 0, 31, 0, 3, 40683, 0, 0, 0, 0, '', 'Blazing Aura can only target Living Embers'); diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index be0db42ab81..2138cac8bf8 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -136,7 +136,8 @@ enum Events EVENT_CHECK_CORPOREALITY = 13, EVENT_SHADOW_PULSARS_SHOOT = 14, EVENT_TRIGGER_BERSERK = 15, - EVENT_TWILIGHT_MENDING = 16 + EVENT_TWILIGHT_MENDING = 16, + EVENT_ACTIVATE_EMBERS = 17 }; enum Actions @@ -149,7 +150,9 @@ enum Actions ACTION_MONITOR_CORPOREALITY = 3, // Orb Carrier - ACTION_SHOOT = 4 + ACTION_WARNING_SHOOT = 4, + ACTION_SHOOT = 5, + ACTION_ACTIVATE_EMBERS = 6 }; enum Phases @@ -167,8 +170,7 @@ enum Misc DATA_MATERIAL_DAMAGE_TAKEN = 2, DATA_STACKS_DISPELLED = 3, DATA_FIGHT_PHASE = 4, - DATA_EVADE_METHOD = 5, - DATA_SPAWNED_FLAMES = 6, + DATA_SPAWNED_FLAMES = 5, }; enum OrbCarrierSeats @@ -188,6 +190,7 @@ enum CorporealityEvent }; Position const HalionSpawnPos = {3156.67f, 533.8108f, 72.98822f, 3.159046f}; +Position const HalionRespawnPos = {3156.625f, 533.2674f, 72.97205f, 0.0f}; uint8 const MAX_CORPOREALITY_STATE = 11; @@ -211,132 +214,39 @@ CorporealityEntry const _corporealityReference[MAX_CORPOREALITY_STATE] = { {74831, 74836} }; -struct generic_halionAI : public BossAI -{ - generic_halionAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId), _canEvade(false) { } - - void EnterCombat(Unit* /*who*/) override - { - _EnterCombat(); - me->AddAura(SPELL_TWILIGHT_PRECISION, me); - _canEvade = false; - events.ScheduleEvent(EVENT_CLEAVE, urand(8000, 10000)); - events.ScheduleEvent(EVENT_TAIL_LASH, 10000); - events.ScheduleEvent(EVENT_BREATH, urand(10000, 15000)); - } - - void Reset() override - { - _canEvade = false; - _Reset(); - } - - void JustReachedHome() override - { - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - _JustReachedHome(); - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) - { - case EVENT_CLEAVE: - DoCastVictim(SPELL_CLEAVE); - events.ScheduleEvent(EVENT_CLEAVE, urand(8000, 10000)); - break; - case EVENT_TAIL_LASH: - DoCastAOE(SPELL_TAIL_LASH); - events.ScheduleEvent(EVENT_TAIL_LASH, 10000); - break; - case EVENT_BREATH: - DoCast(me, me->GetEntry() == NPC_HALION ? SPELL_FLAME_BREATH : SPELL_DARK_BREATH); - events.ScheduleEvent(EVENT_BREATH, urand(10000, 12000)); - break; - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING)) - return; - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - ExecuteEvent(eventId); - - DoMeleeAttackIfReady(); - } - - void SetData(uint32 index, uint32 dataValue) override - { - switch (index) - { - case DATA_EVADE_METHOD: - _canEvade = (dataValue == 1); - break; - default: - break; - } - } - - void SpellHit(Unit* /*who*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_TWILIGHT_MENDING) - Talk(SAY_REGENERATE); - } - -protected: - bool _canEvade; -}; - class boss_halion : public CreatureScript { public: boss_halion() : CreatureScript("boss_halion") { } - struct boss_halionAI : public generic_halionAI + struct boss_halionAI : public BossAI { - boss_halionAI(Creature* creature) : generic_halionAI(creature, DATA_HALION) - { - me->SetHomePosition(HalionSpawnPos); - } - - void Reset() override - { - generic_halionAI::Reset(); - me->SetReactState(REACT_DEFENSIVE); - me->RemoveAurasDueToSpell(SPELL_TWILIGHT_PHASING); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } + boss_halionAI(Creature* creature) : BossAI(creature, DATA_HALION) { } void EnterEvadeMode(EvadeReason why) override { - if (why == EVADE_REASON_BOUNDARY) + if (why == EVADE_REASON_BOUNDARY || events.IsInPhase(PHASE_ONE)) if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER))) - controller->AI()->EnterEvadeMode(); - - // Phase 1: We always can evade. Phase 2 & 3: We can evade if and only if the controller tells us to. - if (events.IsInPhase(PHASE_ONE) || _canEvade) - generic_halionAI::EnterEvadeMode(why); + controller->AI()->EnterEvadeMode(why); } - void EnterCombat(Unit* who) override + void EnterCombat(Unit* /*who*/) override { Talk(SAY_AGGRO); events.Reset(); events.SetPhase(PHASE_ONE); - generic_halionAI::EnterCombat(who); + _EnterCombat(); + me->AddAura(SPELL_TWILIGHT_PRECISION, me); + events.ScheduleEvent(EVENT_ACTIVATE_FIREWALL, Seconds(5)); + events.ScheduleEvent(EVENT_BREATH, randtime(Seconds(5), Seconds(15))); + events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(6), Seconds(10))); + events.ScheduleEvent(EVENT_TAIL_LASH, randtime(Seconds(7), Seconds(12))); + events.ScheduleEvent(EVENT_FIERY_COMBUSTION, randtime(Seconds(15), Seconds(18))); + events.ScheduleEvent(EVENT_METEOR_STRIKE, Seconds(18)); instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1); - instance->SetBossState(DATA_HALION, IN_PROGRESS); - - events.ScheduleEvent(EVENT_ACTIVATE_FIREWALL, 5000); - events.ScheduleEvent(EVENT_METEOR_STRIKE, urand(20000, 25000)); - events.ScheduleEvent(EVENT_FIERY_COMBUSTION, urand(15000, 18000)); if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER))) controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_ONE); @@ -387,58 +297,76 @@ class boss_halion : public CreatureScript } } + void SpellHit(Unit* /*who*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_TWILIGHT_MENDING) + Talk(SAY_REGENERATE); + } + void UpdateAI(uint32 diff) override { if (events.IsInPhase(PHASE_TWO)) return; - generic_halionAI::UpdateAI(diff); - } + if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING)) + return; - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) { - case EVENT_ACTIVATE_FIREWALL: - // Flame ring is activated 5 seconds after starting encounter, DOOR_TYPE_ROOM is only instant. - for (uint8 i = DATA_FLAME_RING; i <= DATA_TWILIGHT_FLAME_RING; ++i) - if (GameObject* flameRing = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(i))) - instance->HandleGameObject(instance->GetGuidData(DATA_FLAME_RING), false, flameRing); - break; - case EVENT_METEOR_STRIKE: + switch (eventId) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_TWILIGHT_REALM)) + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(8), Seconds(10))); + break; + case EVENT_TAIL_LASH: + DoCastAOE(SPELL_TAIL_LASH); + events.ScheduleEvent(EVENT_TAIL_LASH, randtime(Seconds(11), Seconds(16))); + break; + case EVENT_BREATH: + DoCast(me, SPELL_FLAME_BREATH); + events.ScheduleEvent(EVENT_BREATH, randtime(Seconds(16), Seconds(25))); + break; + case EVENT_ACTIVATE_FIREWALL: + // Flame ring is activated 5 seconds after starting encounter, DOOR_TYPE_ROOM is only instant. + for (uint8 i = DATA_FLAME_RING; i <= DATA_TWILIGHT_FLAME_RING; ++i) + if (GameObject* flameRing = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(i))) + instance->HandleGameObject(instance->GetGuidData(DATA_FLAME_RING), false, flameRing); + break; + case EVENT_METEOR_STRIKE: { - _meteorStrikePos = target->GetPosition(); - me->CastSpell(_meteorStrikePos.GetPositionX(), _meteorStrikePos.GetPositionY(), _meteorStrikePos.GetPositionZ(), SPELL_METEOR_STRIKE, true, NULL, NULL, me->GetGUID()); - Talk(SAY_METEOR_STRIKE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_TWILIGHT_REALM)) + { + _meteorStrikePos = target->GetPosition(); + me->CastSpell(_meteorStrikePos.GetPositionX(), _meteorStrikePos.GetPositionY(), _meteorStrikePos.GetPositionZ(), SPELL_METEOR_STRIKE, true, nullptr, nullptr, me->GetGUID()); + Talk(SAY_METEOR_STRIKE); + } + events.ScheduleEvent(EVENT_METEOR_STRIKE, Seconds(38)); + break; } - events.ScheduleEvent(EVENT_METEOR_STRIKE, 40000); - break; - } - case EVENT_FIERY_COMBUSTION: - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_TWILIGHT_REALM)) - DoCast(target, SPELL_FIERY_COMBUSTION); - events.ScheduleEvent(EVENT_FIERY_COMBUSTION, 25000); - break; + case EVENT_FIERY_COMBUSTION: + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_TWILIGHT_REALM)) + me->CastSpell(target, SPELL_FIERY_COMBUSTION, TRIGGERED_IGNORE_SET_FACING); + events.ScheduleEvent(EVENT_FIERY_COMBUSTION, Seconds(25)); + break; + } + default: + break; } - default: - generic_halionAI::ExecuteEvent(eventId); - break; } + + DoMeleeAttackIfReady(); } void SetData(uint32 index, uint32 value) override { - switch (index) - { - case DATA_FIGHT_PHASE: - events.SetPhase(value); - break; - default: - generic_halionAI::SetData(index, value); - } + if (index != DATA_FIGHT_PHASE) + return; + + events.SetPhase(value); } private: @@ -458,9 +386,9 @@ class boss_twilight_halion : public CreatureScript public: boss_twilight_halion() : CreatureScript("boss_twilight_halion") { } - struct boss_twilight_halionAI : public generic_halionAI + struct boss_twilight_halionAI : public BossAI { - boss_twilight_halionAI(Creature* creature) : generic_halionAI(creature, DATA_TWILIGHT_HALION) + boss_twilight_halionAI(Creature* creature) : BossAI(creature, DATA_TWILIGHT_HALION) { Creature* halion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION)); if (!halion) @@ -469,26 +397,29 @@ class boss_twilight_halion : public CreatureScript // Using AddAura because no spell cast packet in sniffs. halion->AddAura(SPELL_COPY_DAMAGE, me); // We use explicit targeting here to avoid conditions + SPELL_ATTR6_CANT_TARGET_SELF. me->AddAura(SPELL_COPY_DAMAGE, halion); - me->AddAura(SPELL_DUSK_SHROUD, me); + DoCast(me, SPELL_DUSK_SHROUD, true); me->SetHealth(halion->GetHealth()); me->SetPhaseMask(0x20, true); - me->SetReactState(REACT_AGGRESSIVE); + me->SetReactState(REACT_DEFENSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + events.ScheduleEvent(EVENT_TAIL_LASH, Seconds(12)); + events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, Seconds(15)); } - void EnterCombat(Unit* who) override + void EnterCombat(Unit* /*who*/) override { - events.Reset(); events.SetPhase(PHASE_TWO); - generic_halionAI::EnterCombat(who); - - events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20000); + _EnterCombat(); + me->AddAura(SPELL_TWILIGHT_PRECISION, me); + events.ScheduleEvent(EVENT_CLEAVE, Seconds(3)); + events.ScheduleEvent(EVENT_BREATH, Seconds(12)); instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2); } - // Never evade + void Reset() override { } void EnterEvadeMode(EvadeReason /*why*/) override { } void KilledUnit(Unit* victim) override @@ -521,6 +452,10 @@ class boss_twilight_halion : public CreatureScript void DamageTaken(Unit* attacker, uint32& damage) override { + //Needed because we already have UNIT_FLAG_IN_COMBAT, otherwise EnterCombat won't ever be called + if (!events.IsInPhase(PHASE_TWO) && !events.IsInPhase(PHASE_THREE)) + EnterCombat(attacker); + if (me->HealthBelowPctDamaged(50, damage) && events.IsInPhase(PHASE_TWO)) { events.SetPhase(PHASE_THREE); @@ -541,7 +476,7 @@ class boss_twilight_halion : public CreatureScript } } - void SpellHit(Unit* who, SpellInfo const* spell) override + void SpellHit(Unit* /*who*/, SpellInfo const* spell) override { switch (spell->Id) { @@ -549,25 +484,51 @@ class boss_twilight_halion : public CreatureScript if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER))) controller->AI()->DoAction(ACTION_MONITOR_CORPOREALITY); break; + case SPELL_TWILIGHT_MENDING: + Talk(SAY_REGENERATE); + break; default: - generic_halionAI::SpellHit(who, spell); break; } } - void ExecuteEvent(uint32 eventId) override + void UpdateAI(uint32 diff) override { - switch (eventId) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (!UpdateVictim()) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) { - case EVENT_SOUL_CONSUMPTION: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, SPELL_TWILIGHT_REALM)) - DoCast(target, SPELL_SOUL_CONSUMPTION); - events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20000); - break; - default: - generic_halionAI::ExecuteEvent(eventId); - break; + switch (eventId) + { + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(7), Seconds(10))); + break; + case EVENT_TAIL_LASH: + DoCastAOE(SPELL_TAIL_LASH); + events.ScheduleEvent(EVENT_TAIL_LASH, randtime(Seconds(12), Seconds(16))); + break; + case EVENT_BREATH: + DoCast(me, SPELL_DARK_BREATH); + events.ScheduleEvent(EVENT_BREATH, randtime(Seconds(10), Seconds(14))); + break; + case EVENT_SOUL_CONSUMPTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, SPELL_TWILIGHT_REALM)) + me->CastSpell(target, SPELL_SOUL_CONSUMPTION, TRIGGERED_IGNORE_SET_FACING); + events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, Seconds(20)); + break; + default: + break; + } } + + DoMeleeAttackIfReady(); } }; @@ -588,7 +549,6 @@ class npc_halion_controller : public CreatureScript _instance(creature->GetInstanceScript()), _summons(me) { Initialize(); - me->SetPhaseMask(me->GetPhaseMask() | 0x20, true); } void Initialize() @@ -598,6 +558,15 @@ class npc_halion_controller : public CreatureScript _twilightDamageTaken = 0; } + void JustRespawned() override + { + if (_instance->GetGuidData(DATA_HALION)) + return; + + Reset(); + me->GetMap()->SummonCreature(NPC_HALION, HalionRespawnPos); + } + void Reset() override { _summons.DespawnAll(); @@ -625,21 +594,36 @@ class npc_halion_controller : public CreatureScript _twilightDamageTaken = 0; _materialDamageTaken = 0; - _events.ScheduleEvent(EVENT_TRIGGER_BERSERK, 8 * MINUTE * IN_MILLISECONDS); + _events.ScheduleEvent(EVENT_TRIGGER_BERSERK, Minutes(8)); } - void JustReachedHome() override + void EnterEvadeMode(EvadeReason /*why*/) override { if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TWILIGHT_HALION))) + { twilightHalion->DespawnOrUnsummon(); + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, twilightHalion); + } if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION))) { - halion->AI()->SetData(DATA_EVADE_METHOD, 1); - halion->AI()->EnterEvadeMode(); + halion->DespawnOrUnsummon(); + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, halion); } _instance->SetBossState(DATA_HALION, FAIL); + _summons.DespawnAll(); + + uint32 corpseDelay = me->GetCorpseDelay(); + uint32 respawnDelay = me->GetRespawnDelay(); + + me->SetCorpseDelay(1); + me->SetRespawnDelay(30); + + me->DespawnOrUnsummon(); + + me->SetCorpseDelay(corpseDelay); + me->SetRespawnDelay(respawnDelay); } void DoAction(int32 action) override @@ -649,7 +633,16 @@ class npc_halion_controller : public CreatureScript case ACTION_INTRO_HALION: _events.Reset(); _events.SetPhase(PHASE_INTRO); - _events.ScheduleEvent(EVENT_START_INTRO, 2000); + _events.ScheduleEvent(EVENT_START_INTRO, Seconds(2)); + break; + case ACTION_INTRO_HALION_2: + if (_instance->GetGuidData(DATA_HALION)) + return; + + for (uint8 i = DATA_BURNING_TREE_1; i <= DATA_BURNING_TREE_4; ++i) + if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(i))) + _instance->HandleGameObject(_instance->GetGuidData(i), true, tree); + me->GetMap()->SummonCreature(NPC_HALION, HalionRespawnPos); break; case ACTION_MONITOR_CORPOREALITY: { @@ -677,8 +670,11 @@ class npc_halion_controller : public CreatureScript _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, 50); _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 50); - _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 7500); + _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, Seconds(7)); } + case ACTION_ACTIVATE_EMBERS: + _events.ScheduleEvent(EVENT_ACTIVATE_EMBERS, Seconds(6)); + break; default: break; } @@ -691,7 +687,7 @@ class npc_halion_controller : public CreatureScript // combat state. if (!_events.IsInPhase(PHASE_INTRO) && me->IsInCombat() && !UpdateVictim()) { - EnterEvadeMode(); + EnterEvadeMode(EVADE_REASON_NO_HOSTILES); return; } @@ -703,29 +699,31 @@ class npc_halion_controller : public CreatureScript { case EVENT_START_INTRO: DoCast(me, SPELL_COSMETIC_FIRE_PILLAR, true); - _events.ScheduleEvent(EVENT_INTRO_PROGRESS_1, 4000); + _events.ScheduleEvent(EVENT_INTRO_PROGRESS_1, Seconds(4)); break; case EVENT_INTRO_PROGRESS_1: for (uint8 i = DATA_BURNING_TREE_3; i <= DATA_BURNING_TREE_4; ++i) if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(i))) _instance->HandleGameObject(_instance->GetGuidData(i), true, tree); - _events.ScheduleEvent(EVENT_INTRO_PROGRESS_2, 4000); + _events.ScheduleEvent(EVENT_INTRO_PROGRESS_2, Seconds(4)); break; case EVENT_INTRO_PROGRESS_2: for (uint8 i = DATA_BURNING_TREE_1; i <= DATA_BURNING_TREE_2; ++i) if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(i))) _instance->HandleGameObject(_instance->GetGuidData(i), true, tree); - _events.ScheduleEvent(EVENT_INTRO_PROGRESS_3, 4000); + _events.ScheduleEvent(EVENT_INTRO_PROGRESS_3, Seconds(4)); break; case EVENT_INTRO_PROGRESS_3: DoCast(me, SPELL_FIERY_EXPLOSION); + if (_instance->GetGuidData(DATA_HALION)) + return; if (Creature* halion = me->GetMap()->SummonCreature(NPC_HALION, HalionSpawnPos)) halion->AI()->Talk(SAY_INTRO); break; case EVENT_TWILIGHT_MENDING: if (ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION))) // Just check if physical Halion is spawned if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TWILIGHT_HALION))) - twilightHalion->CastSpell((Unit*)NULL, SPELL_TWILIGHT_MENDING, true); + twilightHalion->CastSpell((Unit*)nullptr, SPELL_TWILIGHT_MENDING, true); break; case EVENT_TRIGGER_BERSERK: for (uint8 i = DATA_HALION; i <= DATA_TWILIGHT_HALION; i++) @@ -733,17 +731,16 @@ class npc_halion_controller : public CreatureScript halion->CastSpell(halion, SPELL_BERSERK, true); break; case EVENT_SHADOW_PULSARS_SHOOT: - if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TWILIGHT_HALION))) - twilightHalion->AI()->Talk(SAY_SPHERE_PULSE); - if (Creature* orbCarrier = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ORB_CARRIER))) - orbCarrier->AI()->DoAction(ACTION_SHOOT); - - _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 29000); + orbCarrier->AI()->DoAction(ACTION_WARNING_SHOOT); + _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, Seconds(30)); break; case EVENT_CHECK_CORPOREALITY: UpdateCorporeality(); - _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 5000); + _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, Seconds(5)); + break; + case EVENT_ACTIVATE_EMBERS: + _summons.DoZoneInCombat(NPC_LIVING_EMBER); break; default: break; @@ -769,7 +766,7 @@ class npc_halion_controller : public CreatureScript DoZoneInCombat(); break; case PHASE_TWO: - _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 29000); + _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, Seconds(35)); break; default: break; @@ -792,7 +789,7 @@ class npc_halion_controller : public CreatureScript uint8 oldValue = _materialCorporealityValue; if (_twilightDamageTaken == 0 || _materialDamageTaken == 0) { - _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, 100); + _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, Milliseconds(100)); _twilightDamageTaken = 0; _materialDamageTaken = 0; return; @@ -832,7 +829,7 @@ class npc_halion_controller : public CreatureScript } case CORPOREALITY_TWILIGHT_MENDING: { - _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, 100); + _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, Milliseconds(100)); _materialDamageTaken = 0; _twilightDamageTaken = 0; return; @@ -888,52 +885,73 @@ class npc_orb_carrier : public CreatureScript struct npc_orb_carrierAI : public ScriptedAI { npc_orb_carrierAI(Creature* creature) : ScriptedAI(creature), - instance(creature->GetInstanceScript()) + _instance(creature->GetInstanceScript()) { ASSERT(creature->GetVehicleKit()); } - void UpdateAI(uint32 /*diff*/) override + void UpdateAI(uint32 diff) override { /// According to sniffs this spell is cast every 1 or 2 seconds. /// However, refreshing it looks bad, so just cast the spell if /// we are not channeling it. if (!me->HasUnitState(UNIT_STATE_CASTING)) - me->CastSpell((Unit*)NULL, SPELL_TRACK_ROTATION, false); + me->CastSpell((Unit*)nullptr, SPELL_TRACK_ROTATION, false); + + scheduler.Update(diff); /// Workaround: This is here because even though the above spell has SPELL_ATTR1_CHANNEL_TRACK_TARGET, /// we are having two creatures involded here. This attribute is handled clientside, meaning the client /// sends orientation update itself. Here, no packet is sent, and the creature does not rotate. By /// forcing the carrier to always be facing the rotation focus, we ensure everything works as it should. - if (Creature* rotationFocus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ORB_ROTATION_FOCUS))) + if (Creature* rotationFocus = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ORB_ROTATION_FOCUS))) me->SetFacingToObject(rotationFocus); // setInFront } void DoAction(int32 action) override { - if (action == ACTION_SHOOT) + switch (action) { - Vehicle* vehicle = me->GetVehicleKit(); - Unit* southOrb = vehicle->GetPassenger(SEAT_SOUTH); - Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH); - if (southOrb && northOrb) + case ACTION_WARNING_SHOOT: { - if (northOrb->GetTypeId() == TYPEID_UNIT) + Vehicle* vehicle = me->GetVehicleKit(); + Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH); + if (northOrb && northOrb->GetTypeId() == TYPEID_UNIT) northOrb->ToCreature()->AI()->Talk(EMOTE_WARN_LASER); - TriggerCutter(northOrb, southOrb); + + scheduler.Schedule(Seconds(5), [this](TaskContext /*context*/) + { + DoAction(ACTION_SHOOT); + }); + break; } + case ACTION_SHOOT: + { + Vehicle* vehicle = me->GetVehicleKit(); + Unit* southOrb = vehicle->GetPassenger(SEAT_SOUTH); + Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH); + if (southOrb && northOrb) + TriggerCutter(northOrb, southOrb); - if (!IsHeroic()) - return; + if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TWILIGHT_HALION))) + twilightHalion->AI()->Talk(SAY_SPHERE_PULSE); + + if (!IsHeroic()) + return; - Unit* eastOrb = vehicle->GetPassenger(SEAT_EAST); - Unit* westOrb = vehicle->GetPassenger(SEAT_WEST); - if (eastOrb && westOrb) - TriggerCutter(eastOrb, westOrb); + Unit* eastOrb = vehicle->GetPassenger(SEAT_EAST); + Unit* westOrb = vehicle->GetPassenger(SEAT_WEST); + if (eastOrb && westOrb) + TriggerCutter(eastOrb, westOrb); + break; + } + default: + break; } } private: - InstanceScript* instance; + InstanceScript* _instance; + TaskScheduler scheduler; void TriggerCutter(Unit* caster, Unit* target) { @@ -986,12 +1004,12 @@ class npc_meteor_strike_initial : public CreatureScript controller->AI()->JustSummoned(me); DoCast(me, SPELL_METEOR_STRIKE_COUNTDOWN); - DoCast(me, SPELL_BIRTH_NO_VISUAL); // Unknown purpose + DoCast(me, SPELL_BIRTH_NO_VISUAL); if (HalionAI* halionAI = CAST_AI(HalionAI, owner->AI())) { Position const* ownerPos = halionAI->GetMeteorStrikePosition(); - float randomAdjustment = frand(0.0f, static_cast<float>(M_PI / 5.0f)); + float randomAdjustment = frand(static_cast<float>(M_PI / 5.0f), static_cast<float>(M_PI / 2.0f)); float angle[4]; angle[0] = me->GetAngle(ownerPos); angle[1] = angle[0] + randomAdjustment; @@ -1005,10 +1023,7 @@ class npc_meteor_strike_initial : public CreatureScript me->SetOrientation(angle[i]); Position newPos = me->GetNearPosition(10.0f, 0.0f); // Exact distance if (Creature* meteor = me->SummonCreature(NPC_METEOR_STRIKE_NORTH + i, newPos, TEMPSUMMON_TIMED_DESPAWN, 30000)) - { - meteor->SetOrientation(angle[i]); _meteorList.push_back(meteor); - } } } } @@ -1045,7 +1060,7 @@ class npc_meteor_strike : public CreatureScript { DoCast(me, SPELL_METEOR_STRIKE_FIRE_AURA_2, true); me->setActive(true); - _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 500); + _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, Milliseconds(500)); } } @@ -1109,7 +1124,7 @@ class npc_meteor_strike_flame : public CreatureScript void SetGUID(ObjectGuid guid, int32 /*id = 0 */) override { _rootOwnerGuid = guid; - _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 800); + _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, Milliseconds(800)); } void IsSummonedBy(Unit* /*summoner*/) override @@ -1201,7 +1216,7 @@ class npc_combustion_consumption : public CreatureScript if (type != DATA_STACKS_DISPELLED || !_damageSpell || !_explosionSpell || !summoner) return; - me->CastCustomSpell(SPELL_SCALE_AURA, SPELLVALUE_AURA_STACK, stackAmount, me); + me->CastCustomSpell(SPELL_SCALE_AURA, SPELLVALUE_AURA_STACK, stackAmount + 1, me); DoCast(me, _damageSpell); int32 damage = 1200 + (stackAmount * 1290); // Needs more research. @@ -1239,17 +1254,31 @@ class npc_living_inferno : public CreatureScript // SMSG_SPELL_GO for the living ember stuff isn't even sent to the client - Blizzard on drugs. if (me->GetMap()->GetDifficultyID() == DIFFICULTY_25_HC) - me->CastSpell(me, SPELL_SPAWN_LIVING_EMBERS, true); - + scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) + { + me->CastSpell(me, SPELL_SPAWN_LIVING_EMBERS, true); + }); if (InstanceScript* instance = me->GetInstanceScript()) if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER))) + { + controller->AI()->DoAction(ACTION_ACTIVATE_EMBERS); controller->AI()->JustSummoned(me); + } } void JustDied(Unit* /*killer*/) override { me->DespawnOrUnsummon(1); } + + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + ScriptedAI::UpdateAI(diff); + } + + private: + TaskScheduler scheduler; }; CreatureAI* GetAI(Creature* creature) const override @@ -1265,27 +1294,7 @@ class npc_living_ember : public CreatureScript struct npc_living_emberAI : public ScriptedAI { - npc_living_emberAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - _enrageTimer = 0; - } - - void Initialize() - { - _hasEnraged = false; - } - - void Reset() override - { - Initialize(); - } - - void EnterCombat(Unit* /*who*/) override - { - _enrageTimer = 20000; - _hasEnraged = false; - } + npc_living_emberAI(Creature* creature) : ScriptedAI(creature) { } void IsSummonedBy(Unit* /*summoner*/) override { @@ -1298,25 +1307,6 @@ class npc_living_ember : public CreatureScript { me->DespawnOrUnsummon(1); } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING)) - return; - - if (!_hasEnraged && _enrageTimer <= diff) - { - _hasEnraged = true; - DoCast(me, SPELL_BERSERK); - } - else _enrageTimer -= diff; - - DoMeleeAttackIfReady(); - } - - private: - uint32 _enrageTimer; - bool _hasEnraged; }; CreatureAI* GetAI(Creature* creature) const override @@ -1474,6 +1464,47 @@ class spell_halion_combustion_consumption : public SpellScriptLoader uint32 _spellID; }; +class spell_halion_combustion_consumption_periodic : public SpellScriptLoader +{ + public: + spell_halion_combustion_consumption_periodic() : SpellScriptLoader("spell_halion_combustion_consumption_periodic") { } + + class spell_halion_combustion_consumption_periodic_AuraScript : public AuraScript + { + PrepareAuraScript(spell_halion_combustion_consumption_periodic_AuraScript); + + bool Validate(SpellInfo const* spellInfo) override + { + if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell)) + return false; + return true; + } + + void HandleTick(AuraEffect const* aurEff) + { + PreventDefaultAction(); + Unit* caster = GetCaster(); + if (!caster) + return; + + uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; + int32 radius = caster->GetObjectScale() * M_PI * 10000 / 3; + + caster->CastCustomSpell(triggerSpell, SPELLVALUE_RADIUS_MOD, radius, (Unit*)nullptr, TRIGGERED_FULL_MASK, nullptr, aurEff, caster->GetGUID()); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_halion_combustion_consumption_periodic_AuraScript::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_halion_combustion_consumption_periodic_AuraScript(); + } +}; + class spell_halion_marks : public SpellScriptLoader { public: @@ -1512,7 +1543,7 @@ class spell_halion_marks : public SpellScriptLoader return; // Stacks marker - GetTarget()->CastCustomSpell(_summonSpellId, SPELLVALUE_BASE_POINT1, aurEff->GetBase()->GetStackAmount(), GetTarget(), TRIGGERED_FULL_MASK, NULL, NULL, GetCasterGUID()); + GetTarget()->CastCustomSpell(_summonSpellId, SPELLVALUE_BASE_POINT1, aurEff->GetBase()->GetStackAmount(), GetTarget(), TRIGGERED_FULL_MASK, nullptr, nullptr, GetCasterGUID()); } void Register() override @@ -1820,6 +1851,35 @@ class spell_halion_spawn_living_embers : public SpellScriptLoader } }; +class spell_halion_blazing_aura : public SpellScriptLoader +{ + public: + spell_halion_blazing_aura() : SpellScriptLoader("spell_halion_blazing_aura") { } + + class spell_halion_blazing_aura_SpellScript : public SpellScript + { + PrepareSpellScript(spell_halion_blazing_aura_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[EFFECT_1].TriggerSpell); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_halion_blazing_aura_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_FORCE_CAST); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_halion_blazing_aura_SpellScript(); + } +}; + + + void AddSC_boss_halion() { new boss_halion(); @@ -1841,6 +1901,7 @@ void AddSC_boss_halion() new spell_halion_combustion_consumption("spell_halion_fiery_combustion", SPELL_MARK_OF_COMBUSTION); new spell_halion_marks("spell_halion_mark_of_combustion", SPELL_FIERY_COMBUSTION_SUMMON, SPELL_FIERY_COMBUSTION); new spell_halion_marks("spell_halion_mark_of_consumption", SPELL_SOUL_CONSUMPTION_SUMMON, SPELL_SOUL_CONSUMPTION); + new spell_halion_combustion_consumption_periodic(); new spell_halion_damage_aoe_summon(); new spell_halion_twilight_realm_handlers("spell_halion_leave_twilight_realm", SPELL_SOUL_CONSUMPTION, false); new spell_halion_twilight_realm_handlers("spell_halion_enter_twilight_realm", SPELL_FIERY_COMBUSTION, true); @@ -1849,4 +1910,5 @@ void AddSC_boss_halion() new spell_halion_twilight_cutter(); new spell_halion_clear_debuffs(); new spell_halion_spawn_living_embers(); + new spell_halion_blazing_aura(); } diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp index 398d66009a0..52049a13962 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp @@ -53,11 +53,11 @@ class instance_ruby_sanctum : public InstanceMapScript void OnPlayerEnter(Player* /*player*/) override { - if (!GetGuidData(DATA_HALION_CONTROLLER) && GetBossState(DATA_HALION) != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE) + if (!GetGuidData(DATA_HALION) && GetBossState(DATA_HALION) != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE) { instance->LoadGrid(HalionControllerSpawnPos.GetPositionX(), HalionControllerSpawnPos.GetPositionY()); - if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos)) - halionController->AI()->DoAction(ACTION_INTRO_HALION); + if (Creature* halionController = instance->GetCreature(GetGuidData(DATA_HALION_CONTROLLER))) + halionController->AI()->DoAction(ACTION_INTRO_HALION_2); } } @@ -161,6 +161,12 @@ class instance_ruby_sanctum : public InstanceMapScript } } + void OnCreatureRemove(Creature* creature) override + { + if (creature->GetEntry() == NPC_HALION) + HalionGUID = ObjectGuid::Empty; + } + void OnUnitDeath(Unit* unit) override { Creature* creature = unit->ToCreature(); @@ -170,7 +176,7 @@ class instance_ruby_sanctum : public InstanceMapScript if (creature->GetEntry() == NPC_GENERAL_ZARITHRIAN && GetBossState(DATA_HALION) != DONE) { instance->LoadGrid(HalionControllerSpawnPos.GetPositionX(), HalionControllerSpawnPos.GetPositionY()); - if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos)) + if (Creature* halionController = instance->GetCreature(GetGuidData(DATA_HALION_CONTROLLER))) halionController->AI()->DoAction(ACTION_INTRO_HALION); } } diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h index e387fd63285..afd5dc3a0bd 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h @@ -56,6 +56,7 @@ enum RSSharedActions ACTION_INTRO_BALTHARUS = -3975101, ACTION_BALTHARUS_DEATH = -3975102, ACTION_INTRO_HALION = -4014601, + ACTION_INTRO_HALION_2 = -4014602, }; enum RSCreaturesIds |
