fix(Scripts/MoltenCore): Ragnaros rewrite (#8935)

This commit is contained in:
Andrius Peleckas
2021-11-22 17:17:32 +02:00
committed by GitHub
parent dc9c3a5fe4
commit edf7b54315
3 changed files with 211 additions and 111 deletions

View File

@@ -0,0 +1,12 @@
INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1635972083556511200');
-- Majordomo texts
DELETE FROM `creature_text` WHERE `CreatureID`=12018 AND `GroupID`=11 AND `ID`=0;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(12018, 11, 0, 'My flame... Please, don\'t take away my flame...', 14, 0, 100, 0, 0, 8042, 0, 0, 'majordomo SAY_DEATH');
-- Ragnaros auras
UPDATE `creature_template_addon` SET `auras`='20563 21387' WHERE `entry`=11502;
-- Ragnaros Texts
UPDATE `creature_text` SET `comment`='ragnaros SAY_KNOCKBACK' WHERE `CreatureID`=11502 AND `GroupID`=7 AND `ID`=0;

View File

@@ -40,6 +40,7 @@ enum Texts
// Majordomo
SAY_RAG_SUM_1 = 9,
SAY_RAG_SUM_2 = 10,
SAY_DEATH = 11,
// Ragnaros
SAY_ARRIVAL1_RAG = 1,
@@ -130,8 +131,11 @@ public:
{
boss_majordomoAI(Creature* creature) : BossAI(creature, DATA_MAJORDOMO_EXECUTUS), spawnInTextTimer(0) {}
// Disabled events
void JustDied(Unit* /*killer*/) override {}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
me->DespawnOrUnsummon(10s, 0s);
}
void JustSummoned(Creature* summon) override
{

View File

@@ -28,52 +28,64 @@ enum Texts
SAY_ARRIVAL5_RAG = 4,
SAY_REINFORCEMENTS1 = 5,
SAY_REINFORCEMENTS2 = 6,
SAY_HAND = 7,
SAY_KNOCKBACK = 7, // Text is used for SPELL_HAND_OF_RAGNAROS & SPELL_MIGHT_OF_RAGNAROS. "By fire be purged!"
SAY_WRATH = 8,
SAY_KILL = 9,
SAY_MAGMABURST = 10
SAY_MAGMABURST = 10,
};
enum Spells
{
SPELL_HAND_OF_RAGNAROS = 19780,
SPELL_WRATH_OF_RAGNAROS = 20566,
SPELL_LAVA_BURST = 21158,
SPELL_MAGMA_BLAST = 20565, // Ranged attack
SPELL_SONS_OF_FLAME_DUMMY = 21108, // Server side effect
SPELL_RAGSUBMERGE = 21107, // Stealth aura
SPELL_RAGNA_SUBMERGE_VISUAL = 20567, // Visual for submerging into lava
SPELL_LAVA_BURST = 21908, // Randomly trigger one of server side spells (21886, 21900 - 21907) which summons Go 178088 (TODO)
SPELL_MAGMA_BLAST = 20565, // Ranged attack
SPELL_SONS_OF_FLAME_DUMMY = 21108, // Server side effect
SPELL_RAGSUBMERGE = 21107, // Stealth aura
SPELL_RAGNA_SUBMERGE_VISUAL = 20567, // Visual for submerging into lava
SPELL_RAGEMERGE = 20568,
SPELL_MELT_WEAPON = 21387,
SPELL_ELEMENTAL_FIRE = 20563,
SPELL_ERRUPTION = 17731,
SPELL_RAGNAROS_SUBMERGE_EFFECT = 21859, // Applies pacify state and applies all schools immunity
SPELL_RAGNAROS_SUBMERGE_EFFECT = 21859, // Applies pacify state and applies all schools immunity (server side)
SPELL_ELEMENTAL_FIRE_KILL = 19773, // Spell is used only on Majordomo
SPELL_MIGHT_OF_RAGNAROS = 21154,
SPELL_INTENSE_HEAT = 21155,
SPELL_SUMMON_SONS_FLAME = 21108, // Trigger the eight spells summoning the Son of Flame adds (TODO)
};
enum Events
{
EVENT_ERUPTION = 1,
EVENT_ERUPTION = 1,
EVENT_WRATH_OF_RAGNAROS,
EVENT_HAND_OF_RAGNAROS,
EVENT_MIGHT_OF_RAGNAROS,
EVENT_LAVA_BURST,
EVENT_MAGMA_BLAST,
EVENT_SUBMERGE,
EVENT_INTRO_1,
EVENT_INTRO_2,
EVENT_INTRO_3,
EVENT_INTRO_4,
EVENT_INTRO_5,
// Submerge
EVENT_EMERGE,
// Intro
EVENT_INTRO_SAY,
EVENT_INTRO_MAKE_ATTACKABLE,
// Misc
EVENT_RESET_KNOCKBACK_EMOTE,
};
enum Creatures
{
NPC_SON_OF_FLAME = 12143,
NPC_SON_OF_FLAME = 12143,
NPC_FLAME_OF_RAGNAROS = 13148,
};
enum Misc
{
MAX_SON_OF_FLAME_COUNT = 8,
MAX_SON_OF_FLAME_COUNT = 8,
// Event phase
PHASE_INTRO = 1, // Intro events with Majordomu
PHASE_EMERGED = 2, // events which are executed while Ragnaros is visible
PHASE_SUBMERGED = 3, // events which are executed while Ragnaros is submerged (not visible)
};
constexpr float DEATH_ORIENTATION = 4.0f;
@@ -86,61 +98,78 @@ public:
struct boss_ragnarosAI : public BossAI
{
boss_ragnarosAI(Creature* creature) : BossAI(creature, DATA_RAGNAROS),
attackableTImer(0),
_emergeTimer(90000),
_isIntroDone(false),
_hasYelledMagmaBurst(false),
_hasSubmergedOnce(false),
_isBanished(false)
_isKnockbackEmoteAllowed(true)
{
creature->SetReactState(REACT_PASSIVE);
creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
}
void Reset() override
{
_Reset();
_emergeTimer = 90000;
// Never reset intro events!
if (_isIntroDone && !(extraEvents.GetPhaseMask() & (1 << (PHASE_INTRO - 1))))
{
extraEvents.Reset();
extraEvents.SetPhase(PHASE_EMERGED);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
}
_hasYelledMagmaBurst = false;
_hasSubmergedOnce = false;
_isBanished = false;
_isKnockbackEmoteAllowed = true;
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
DoCastSelf(SPELL_MELT_WEAPON, true);
DoCastSelf(SPELL_ELEMENTAL_FIRE, true);
}
void DoAction(int32 action) override
{
if (action == ACTION_FINISH_RAGNAROS_INTRO)
{
attackableTImer = 10000;
extraEvents.SetPhase(PHASE_INTRO);
extraEvents.ScheduleEvent(EVENT_INTRO_SAY, 5000, 0, PHASE_INTRO);
}
}
void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
if (summon->GetEntry() == NPC_FLAME_OF_RAGNAROS)
{
summon->CastSpell((Unit*)nullptr, SPELL_INTENSE_HEAT, true, nullptr, nullptr, me->GetGUID());
}
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
summons.Despawn(summon);
if (events.IsInPhase(PHASE_SUBMERGED) && !summons.HasEntry(NPC_SON_OF_FLAME))
{
HandleEmerge();
}
}
void EnterCombat(Unit* /*victim*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_ERUPTION, 15000);
events.ScheduleEvent(EVENT_WRATH_OF_RAGNAROS, 30000);
events.ScheduleEvent(EVENT_HAND_OF_RAGNAROS, 25000);
events.ScheduleEvent(EVENT_LAVA_BURST, 10000);
events.ScheduleEvent(EVENT_MAGMA_BLAST, 2000);
events.ScheduleEvent(EVENT_SUBMERGE, 180000);
events.SetPhase(PHASE_EMERGED);
ScheduleCombatEvents();
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
extraEvents.Reset();
me->SetFacingTo(DEATH_ORIENTATION);
}
void KilledUnit(Unit* victim) override
{
if (roll_chance_i(25) && victim->GetTypeId() == TYPEID_PLAYER)
if (roll_chance_i(25) && victim->IsPlayer())
{
Talk(SAY_KILL);
}
@@ -156,41 +185,44 @@ public:
void UpdateAI(uint32 diff) override
{
if (attackableTImer)
if (!extraEvents.Empty())
{
if (attackableTImer <= diff)
{
me->RemoveAurasDueToSpell(SPELL_RAGNAROS_SUBMERGE_EFFECT);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NON_ATTACKABLE);
me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat();
attackableTImer = 0;
}
else
{
attackableTImer -= diff;
}
}
extraEvents.Update(diff);
if (_isBanished && (_emergeTimer <= diff || !summons.HasEntry(NPC_SON_OF_FLAME)))
{
//Become unbanished again
me->SetReactState(REACT_AGGRESSIVE);
me->SetFaction(14);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
while (uint32 const eventId = extraEvents.ExecuteEvent())
{
AttackStart(target);
switch (eventId)
{
// Intro events
case EVENT_INTRO_SAY:
{
Talk(SAY_ARRIVAL5_RAG);
extraEvents.ScheduleEvent(EVENT_INTRO_MAKE_ATTACKABLE, 2500, 0, PHASE_INTRO);
break;
}
case EVENT_INTRO_MAKE_ATTACKABLE:
{
_isIntroDone = true;
extraEvents.SetPhase(PHASE_EMERGED);
me->RemoveAurasDueToSpell(SPELL_RAGNAROS_SUBMERGE_EFFECT);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NON_ATTACKABLE);
me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat();
break;
}
// Submerge events
case EVENT_EMERGE:
{
HandleEmerge();
break;
}
case EVENT_RESET_KNOCKBACK_EMOTE:
{
_isKnockbackEmoteAllowed = true;
break;
}
}
}
_isBanished = false;
}
else if (_isBanished)
{
_emergeTimer -= diff;
return;
}
if (!UpdateVictim())
@@ -204,16 +236,12 @@ public:
{
return;
}
// Base combat events - (mainly emerge phase)
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ERUPTION:
{
DoCastVictim(SPELL_ERRUPTION);
events.RepeatEvent(urand(20000, 45000));
break;
}
case EVENT_WRATH_OF_RAGNAROS:
{
DoCastVictim(SPELL_WRATH_OF_RAGNAROS);
@@ -227,50 +255,95 @@ public:
case EVENT_HAND_OF_RAGNAROS:
{
DoCastSelf(SPELL_HAND_OF_RAGNAROS);
if (urand(0, 1))
if (_isKnockbackEmoteAllowed)
{
Talk(SAY_HAND);
Talk(SAY_KNOCKBACK);
_isKnockbackEmoteAllowed = false;
extraEvents.RescheduleEvent(EVENT_RESET_KNOCKBACK_EMOTE, 5000);
}
events.RepeatEvent(20000);
break;
}
case EVENT_LAVA_BURST:
{
DoCastVictim(SPELL_LAVA_BURST);
DoCastAOE(SPELL_LAVA_BURST);
events.RepeatEvent(10000);
break;
}
case EVENT_MAGMA_BLAST:
{
Unit* victim = me->GetVictim();
Unit const* victim = me->GetVictim();
if (victim && !me->IsWithinMeleeRange(victim))
{
DoCast(victim, SPELL_MAGMA_BLAST);
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
DoCast(target, SPELL_MAGMA_BLAST);
}
if (!_hasYelledMagmaBurst)
{
Talk(SAY_MAGMABURST);
_hasYelledMagmaBurst = true;
}
}
events.RepeatEvent(2500);
else if (_hasYelledMagmaBurst)
{
_hasYelledMagmaBurst = false;
}
events.RepeatEvent(500);
break;
}
case EVENT_MIGHT_OF_RAGNAROS:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, [](Unit const* target)
{
return target->IsPlayer() && target->getPowerType() == POWER_MANA;
}))
{
if (me->CastSpell(target, SPELL_MIGHT_OF_RAGNAROS) == SPELL_CAST_OK && _isKnockbackEmoteAllowed)
{
Talk(SAY_KNOCKBACK, me);
_isKnockbackEmoteAllowed = false;
extraEvents.RescheduleEvent(EVENT_RESET_KNOCKBACK_EMOTE, 5000);
}
}
events.RepeatEvent(urand(11000, 30000));
break;
}
case EVENT_SUBMERGE:
{
if (!_isBanished)
events.CancelEventGroup(PHASE_EMERGED);
events.SetPhase(PHASE_SUBMERGED);
extraEvents.SetPhase(PHASE_SUBMERGED);
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(false);
me->AttackStop();
DoResetThreat();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED);
DoCastSelf(SPELL_RAGNA_SUBMERGE_VISUAL, true);
//me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE);
Talk(_hasSubmergedOnce ? SAY_REINFORCEMENTS2 : SAY_REINFORCEMENTS1);
for (uint8 i = 0; i < MAX_SON_OF_FLAME_COUNT; ++i)
{
me->InterruptNonMeleeSpells(false);
me->AttackStop();
DoResetThreat();
me->SetReactState(REACT_PASSIVE);
me->SetFaction(35);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED);
DoCastSelf(SPELL_RAGNA_SUBMERGE_VISUAL, true);
//me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE);
SummonMinions();
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
if (Creature* summoned = me->SummonCreature(NPC_SON_OF_FLAME, target->GetPosition(), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 900000))
{
summoned->AI()->AttackStart(target);
}
}
}
events.ScheduleEvent(EVENT_SUBMERGE, 180000);
if (!_hasSubmergedOnce)
{
_hasSubmergedOnce = true;
}
extraEvents.ScheduleEvent(EVENT_EMERGE, 90000, PHASE_SUBMERGED, PHASE_SUBMERGED);
break;
}
}
@@ -285,34 +358,45 @@ public:
}
private:
uint32 attackableTImer; // used after intro
uint32 _emergeTimer;
EventMap extraEvents;
bool _isIntroDone;
bool _hasYelledMagmaBurst;
bool _hasSubmergedOnce;
bool _isBanished;
bool _isKnockbackEmoteAllowed; // Prevents possible text overlap
void SummonMinions()
void HandleEmerge()
{
Talk(_hasSubmergedOnce ? SAY_REINFORCEMENTS2 : SAY_REINFORCEMENTS1);
for (uint8 i = 0; i < MAX_SON_OF_FLAME_COUNT; ++i)
if (events.IsInPhase(PHASE_EMERGED))
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
if (Creature* summoned = me->SummonCreature(NPC_SON_OF_FLAME, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 900000))
{
summoned->AI()->AttackStart(target);
}
}
return;
}
_isBanished = true;
_emergeTimer = 90000;
if (!_hasSubmergedOnce)
events.SetPhase(PHASE_EMERGED);
ScheduleCombatEvents();
extraEvents.CancelEventGroup(PHASE_SUBMERGED);
extraEvents.SetPhase(PHASE_EMERGED);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
_hasSubmergedOnce = true;
AttackStart(target);
}
}
void ScheduleCombatEvents()
{
events.RescheduleEvent(EVENT_ERUPTION, 15000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_WRATH_OF_RAGNAROS, 30000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_HAND_OF_RAGNAROS, 25000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_LAVA_BURST, 10000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_MAGMA_BLAST, 500, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_SUBMERGE, 180000, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_MIGHT_OF_RAGNAROS, 11000, PHASE_EMERGED, PHASE_EMERGED);
}
};
CreatureAI* GetAI(Creature* creature) const override