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.
This commit is contained in:
Gustavo
2016-07-05 05:54:31 -03:00
committed by Aokromes
parent b67e304c88
commit 58aaccb8af
5 changed files with 364 additions and 265 deletions

View File

@@ -0,0 +1,21 @@
SET @CGUID := 600009;
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`, `phaseMask`, `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, 15, 33, 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');

View File

@@ -3718,9 +3718,17 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
break;
case 75888: // Awaken Flames
case 75889: // Awaken Flames
spellInfo->AttributesEx |= SPELL_ATTR1_CANT_TARGET_SELF;
case 75875: // Combustion and Consumption Heroic versions lacks radius data
spellInfo->Effects[EFFECT_0].Mechanic = MECHANIC_NONE;
spellInfo->Effects[EFFECT_1].Mechanic = MECHANIC_SNARE;
spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
break;
case 75884:
spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
// No break
case 75883:
case 75876:
spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
break;
// ENDOF RUBY SANCTUM SPELLS
//

View File

@@ -137,7 +137,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
@@ -150,7 +151,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
@@ -168,8 +171,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
@@ -189,6 +191,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;
@@ -212,132 +215,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);
@@ -388,58 +298,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))
me->CastSpell(target, SPELL_FIERY_COMBUSTION, TRIGGERED_IGNORE_SET_FACING);
events.ScheduleEvent(EVENT_FIERY_COMBUSTION, Seconds(25));
break;
}
default:
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;
}
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:
@@ -459,9 +387,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)
@@ -470,26 +398,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
@@ -522,6 +453,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);
@@ -542,7 +477,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)
{
@@ -550,25 +485,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();
}
};
@@ -589,7 +550,6 @@ class npc_halion_controller : public CreatureScript
_instance(creature->GetInstanceScript()), _summons(me)
{
Initialize();
me->SetPhaseMask(me->GetPhaseMask() | 0x20, true);
}
void Initialize()
@@ -599,6 +559,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();
@@ -626,21 +595,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
@@ -650,7 +634,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:
{
@@ -678,8 +671,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;
}
@@ -692,7 +688,7 @@ class npc_halion_controller : public CreatureScript
// combat state.
if (!_events.IsInPhase(PHASE_INTRO) && me->IsInCombat() && !UpdateVictim())
{
EnterEvadeMode();
EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
return;
}
@@ -704,29 +700,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++)
@@ -734,17 +732,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;
@@ -770,7 +767,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;
@@ -793,7 +790,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;
@@ -833,7 +830,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;
@@ -889,52 +886,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);
Unit* eastOrb = vehicle->GetPassenger(SEAT_EAST);
Unit* westOrb = vehicle->GetPassenger(SEAT_WEST);
if (eastOrb && westOrb)
TriggerCutter(eastOrb, westOrb);
if (!IsHeroic())
return;
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)
{
@@ -987,12 +1005,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;
@@ -1006,10 +1024,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);
}
}
}
}
@@ -1046,7 +1061,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));
}
}
@@ -1110,7 +1125,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
@@ -1202,7 +1217,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.
@@ -1240,17 +1255,32 @@ 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()->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC)
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
@@ -1266,27 +1296,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
{
@@ -1299,25 +1309,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
@@ -1473,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:
@@ -1511,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
@@ -1819,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();
@@ -1840,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);
@@ -1848,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();
}

View File

@@ -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);
}
}

View File

@@ -56,6 +56,7 @@ enum SharedActions
ACTION_INTRO_BALTHARUS = -3975101,
ACTION_BALTHARUS_DEATH = -3975102,
ACTION_INTRO_HALION = -4014601,
ACTION_INTRO_HALION_2 = -4014602,
};
enum CreaturesIds