fix(Scripts/HellfireRamparts): modernise boss scripts for Hellfire Ramparts (#16250)

* first two bosses

* add vazruden+nazan

* dumb mistake fix

* remove double summon say from Omor

* new attempt at scheduling talking

* fix boolean condition for speaking

* debug

* revert debug

* initial

* diff comment
This commit is contained in:
Dan
2023-05-13 19:50:46 +02:00
committed by GitHub
parent dfa5da00b1
commit 8e28b64ccf
3 changed files with 161 additions and 170 deletions

View File

@@ -34,16 +34,7 @@ enum Spells
SPELL_SHADOW_BOLT = 30686, SPELL_SHADOW_BOLT = 30686,
SPELL_SUMMON_FIENDISH_HOUND = 30707, SPELL_SUMMON_FIENDISH_HOUND = 30707,
SPELL_TREACHEROUS_AURA = 30695, SPELL_TREACHEROUS_AURA = 30695,
SPELL_DEMONIC_SHIELD = 31901, SPELL_DEMONIC_SHIELD = 31901
};
enum Misc
{
EVENT_SUMMON1 = 1,
EVENT_SUMMON2 = 2,
EVENT_TREACHEROUS_AURA = 3,
EVENT_DEMONIC_SHIELD = 4,
EVENT_KILL_TALK = 5
}; };
class boss_omor_the_unscarred : public CreatureScript class boss_omor_the_unscarred : public CreatureScript
@@ -56,33 +47,63 @@ public:
boss_omor_the_unscarredAI(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED) boss_omor_the_unscarredAI(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED)
{ {
SetCombatMovement(false); SetCombatMovement(false);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
} }
void Reset() override void Reset() override
{ {
Talk(SAY_WIPE); Talk(SAY_WIPE);
BossAI::Reset(); _Reset();
_targetGUID.Clear(); _targetGUID.Clear();
ScheduleHealthCheckEvent(21, [&]{
DoCastSelf(SPELL_DEMONIC_SHIELD);
scheduler.Schedule(15s, [this](TaskContext context)
{
DoCastSelf(SPELL_DEMONIC_SHIELD);
context.Repeat(15s);
});
});
} }
void JustEngagedWith(Unit* who) override void JustEngagedWith(Unit* /*who*/) override
{ {
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who); _JustEngagedWith();
events.ScheduleEvent(EVENT_SUMMON1, 10000); scheduler.Schedule(6s, [this](TaskContext context)
events.ScheduleEvent(EVENT_SUMMON2, 25000); {
events.ScheduleEvent(EVENT_TREACHEROUS_AURA, 6000); if (roll_chance_i(33))
events.ScheduleEvent(EVENT_DEMONIC_SHIELD, 1000); {
Talk(SAY_CURSE);
}
DoCastRandomTarget(SPELL_TREACHEROUS_AURA);
context.Repeat(12s, 18s);
}).Schedule(10s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND);
}).Schedule(25s, [this](TaskContext context)
{
DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND);
context.Repeat(15s);
});
} }
void KilledUnit(Unit*) override void KilledUnit(Unit*) override
{ {
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0) if(!_hasSpoken)
{ {
_hasSpoken = true;
Talk(SAY_KILL); Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
} }
scheduler.Schedule(6s, [this](TaskContext /*context*/)
{
_hasSpoken = false;
});
} }
void JustSummoned(Creature* summon) override void JustSummoned(Creature* summon) override
@@ -92,49 +113,20 @@ public:
summon->SetInCombatWithZone(); summon->SetInCombatWithZone();
} }
void JustDied(Unit* killer) override void JustDied(Unit* /*killer*/) override
{ {
Talk(SAY_DIE); Talk(SAY_DIE);
BossAI::JustDied(killer); _JustDied();
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 /*diff*/) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
switch (events.ExecuteEvent())
{
case EVENT_SUMMON1:
Talk(SAY_SUMMON);
me->CastSpell(me, SPELL_SUMMON_FIENDISH_HOUND, false);
break;
case EVENT_SUMMON2:
me->CastSpell(me, SPELL_SUMMON_FIENDISH_HOUND, false);
events.ScheduleEvent(EVENT_SUMMON2, 15000);
break;
case EVENT_TREACHEROUS_AURA:
if (roll_chance_i(33))
Talk(SAY_CURSE);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_TREACHEROUS_AURA, false);
events.ScheduleEvent(EVENT_TREACHEROUS_AURA, urand(12000, 18000));
break;
case EVENT_DEMONIC_SHIELD:
if (me->HealthBelowPct(21))
{
me->CastSpell(me, SPELL_DEMONIC_SHIELD, false);
events.ScheduleEvent(EVENT_DEMONIC_SHIELD, 15000);
}
else
events.ScheduleEvent(EVENT_DEMONIC_SHIELD, 1000);
break;
}
if (!me->GetVictim() || !me->isAttackReady()) if (!me->GetVictim() || !me->isAttackReady())
return; return;
@@ -153,6 +145,7 @@ public:
private: private:
ObjectGuid _targetGUID; ObjectGuid _targetGUID;
bool _hasSpoken;
}; };
CreatureAI* GetAI(Creature* creature) const override CreatureAI* GetAI(Creature* creature) const override

View File

@@ -43,18 +43,14 @@ enum Spells
enum Misc enum Misc
{ {
ACTION_FLY_DOWN = 0, ACTION_FLY_DOWN = 0,
POINT_MIDDLE = 0, POINT_MIDDLE = 0,
POINT_FLIGHT = 1, POINT_FLIGHT = 1
};
EVENT_SPELL_REVENGE = 1, enum GroupPhase
EVENT_KILL_TALK = 2, {
EVENT_AGGRO_TALK = 3, GROUP_PHASE_1 = 0,
EVENT_SPELL_FIREBALL = 4, GROUP_PHASE_2 = 1
EVENT_SPELL_CONE_OF_FIRE = 5,
EVENT_SPELL_BELLOWING_ROAR = 6,
EVENT_CHANGE_POS = 7,
EVENT_RESTORE_COMBAT = 8
}; };
const Position NazanPos[3] = const Position NazanPos[3] =
@@ -158,10 +154,14 @@ class boss_nazan : public CreatureScript
public: public:
boss_nazan() : CreatureScript("boss_nazan") { } boss_nazan() : CreatureScript("boss_nazan") { }
struct boss_nazanAI : public ScriptedAI struct boss_nazanAI : public BossAI
{ {
boss_nazanAI(Creature* creature) : ScriptedAI(creature) boss_nazanAI(Creature* creature) : BossAI(creature, DATA_VAZRUDEN)
{ {
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
} }
void Reset() override void Reset() override
@@ -178,8 +178,17 @@ public:
void JustEngagedWith(Unit*) override void JustEngagedWith(Unit*) override
{ {
events.ScheduleEvent(EVENT_CHANGE_POS, 0); scheduler.CancelGroup(GROUP_PHASE_2);
events.ScheduleEvent(EVENT_SPELL_FIREBALL, 5000); scheduler.Schedule(5ms, GROUP_PHASE_1, [this](TaskContext context)
{
me->GetMotionMaster()->MovePoint(POINT_FLIGHT, NazanPos[urand(0, 2)], false);
scheduler.DelayAll(7s);
context.Repeat(30s);
}).Schedule(5s, GROUP_PHASE_1, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_FIREBALL);
context.Repeat(4s, 6s);
});
} }
void AttackStart(Unit* who) override void AttackStart(Unit* who) override
@@ -209,48 +218,37 @@ public:
me->SetCanFly(false); me->SetCanFly(false);
me->SetDisableGravity(false); me->SetDisableGravity(false);
me->SetReactState(REACT_AGGRESSIVE); me->SetReactState(REACT_AGGRESSIVE);
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 1); scheduler.CancelGroup(GROUP_PHASE_1);
events.ScheduleEvent(EVENT_SPELL_CONE_OF_FIRE, 5000); me->GetMotionMaster()->MoveChase(me->GetVictim());
events.ScheduleEvent(EVENT_SPELL_FIREBALL, 6000);
scheduler.Schedule(5s, GROUP_PHASE_2, [this](TaskContext context)
{
DoCastVictim(SPELL_CONE_OF_FIRE);
context.Repeat(12s);
}).Schedule(6s, GROUP_PHASE_2, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_FIREBALL);
context.Repeat(4s, 6s);
});
if (IsHeroic()) if (IsHeroic())
events.ScheduleEvent(EVENT_SPELL_BELLOWING_ROAR, 10000); {
scheduler.Schedule(10s, GROUP_PHASE_2, [this](TaskContext context)
{
DoCastSelf(SPELL_BELLOWING_ROAR);
context.Repeat(30s);
});
}
} }
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 /*diff*/) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_FIREBALL:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_FIREBALL, false);
events.ScheduleEvent(EVENT_SPELL_FIREBALL, urand(4000, 6000));
break;
case EVENT_CHANGE_POS:
me->GetMotionMaster()->MovePoint(POINT_FLIGHT, NazanPos[urand(0, 2)], false);
events.DelayEvents(7000);
events.ScheduleEvent(EVENT_CHANGE_POS, 30000);
break;
case EVENT_RESTORE_COMBAT:
me->GetMotionMaster()->MoveChase(me->GetVictim());
break;
case EVENT_SPELL_CONE_OF_FIRE:
me->CastSpell(me->GetVictim(), SPELL_CONE_OF_FIRE, false);
events.ScheduleEvent(EVENT_SPELL_CONE_OF_FIRE, 12000);
break;
case EVENT_SPELL_BELLOWING_ROAR:
me->CastSpell(me, SPELL_BELLOWING_ROAR, false);
events.ScheduleEvent(EVENT_SPELL_BELLOWING_ROAR, 30000);
break;
}
if (!me->IsLevitating()) if (!me->IsLevitating())
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
@@ -270,9 +268,15 @@ class boss_vazruden : public CreatureScript
public: public:
boss_vazruden() : CreatureScript("boss_vazruden") { } boss_vazruden() : CreatureScript("boss_vazruden") { }
struct boss_vazrudenAI : public ScriptedAI struct boss_vazrudenAI : public BossAI
{ {
boss_vazrudenAI(Creature* creature) : ScriptedAI(creature) { } boss_vazrudenAI(Creature* creature) : BossAI(creature, DATA_VAZRUDEN)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override void Reset() override
{ {
@@ -288,17 +292,27 @@ public:
void JustEngagedWith(Unit*) override void JustEngagedWith(Unit*) override
{ {
events.ScheduleEvent(EVENT_AGGRO_TALK, 5000); scheduler.Schedule(5s, [this](TaskContext /*context*/)
events.ScheduleEvent(EVENT_SPELL_REVENGE, 4000); {
Talk(SAY_AGGRO);
}).Schedule(4s, [this](TaskContext context)
{
DoCastVictim(DUNGEON_MODE(SPELL_REVENGE, SPELL_REVENGE_H));
context.Repeat(6s);
});
} }
void KilledUnit(Unit*) override void KilledUnit(Unit*) override
{ {
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0) if (!_hasSpoken)
{ {
_hasSpoken = true;
Talk(SAY_KILL); Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
} }
scheduler.Schedule(6s, [this](TaskContext /*context*/)
{
_hasSpoken = false;
});
} }
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
@@ -315,28 +329,17 @@ public:
Talk(SAY_DIE); Talk(SAY_DIE);
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 /*diff*/) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_AGGRO_TALK:
Talk(SAY_AGGRO);
break;
case EVENT_SPELL_REVENGE:
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_REVENGE, SPELL_REVENGE_H), false);
events.ScheduleEvent(EVENT_SPELL_REVENGE, 6000);
break;
}
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
private: private:
EventMap events; EventMap events;
bool _hasSpoken;
bool _nazanCalled; bool _nazanCalled;
}; };

View File

@@ -38,13 +38,7 @@ enum Spells
enum Misc enum Misc
{ {
NPC_HELLFIRE_WATCHER = 17309, NPC_HELLFIRE_WATCHER = 17309
EVENT_MORTAL_WOUND = 1,
EVENT_SURGE = 2,
EVENT_RETALIATION = 3,
EVENT_KILL_TALK = 4,
EVENT_CHECK_HEALTH = 5
}; };
class boss_watchkeeper_gargolmar : public CreatureScript class boss_watchkeeper_gargolmar : public CreatureScript
@@ -57,21 +51,53 @@ public:
boss_watchkeeper_gargolmarAI(Creature* creature) : BossAI(creature, DATA_WATCHKEEPER_GARGOLMAR) boss_watchkeeper_gargolmarAI(Creature* creature) : BossAI(creature, DATA_WATCHKEEPER_GARGOLMAR)
{ {
_taunted = false; _taunted = false;
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
} }
void Reset() override void Reset() override
{ {
BossAI::Reset(); _Reset();
ScheduleHealthCheckEvent(50, [&]{
Talk(SAY_HEAL);
std::list<Creature*> clist;
me->GetCreaturesWithEntryInRange(clist, 100.0f, NPC_HELLFIRE_WATCHER);
for (std::list<Creature*>::const_iterator itr = clist.begin(); itr != clist.end(); ++itr)
(*itr)->AI()->SetData(NPC_HELLFIRE_WATCHER, 0);
});
ScheduleHealthCheckEvent(20, [&]{
DoCastSelf(SPELL_RETALIATION);
scheduler.Schedule(30s, [this](TaskContext context)
{
DoCastSelf(SPELL_RETALIATION);
context.Repeat(30s);
});
});
} }
void JustEngagedWith(Unit* who) override void JustEngagedWith(Unit* /*who*/) override
{ {
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who); _JustEngagedWith();
events.ScheduleEvent(EVENT_MORTAL_WOUND, 5000);
events.ScheduleEvent(EVENT_SURGE, 3000); scheduler.Schedule(5s, [this] (TaskContext context)
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000); {
events.ScheduleEvent(EVENT_RETALIATION, 1000); DoCastVictim(SPELL_MORTAL_WOUND);
context.Repeat(8s);
}).Schedule(3s, [this](TaskContext context)
{
Talk(SAY_SURGE);
if(Unit* target = SelectTarget((SelectTargetMethod::MinDistance), 0))
{
me->CastSpell(target, SPELL_SURGE);
}
context.Repeat(11s);
});
} }
void MoveInLineOfSight(Unit* who) override void MoveInLineOfSight(Unit* who) override
@@ -90,68 +116,37 @@ public:
void KilledUnit(Unit*) override void KilledUnit(Unit*) override
{ {
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0) if (!_hasSpoken)
{ {
_hasSpoken = true;
Talk(SAY_KILL); Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
} }
scheduler.Schedule(6s, [this](TaskContext /*context*/)
{
_hasSpoken = false;
});
} }
void JustDied(Unit* killer) override void JustDied(Unit* /*killer*/) override
{ {
Talk(SAY_DIE); Talk(SAY_DIE);
BossAI::JustDied(killer); _JustDied();
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 /*diff*/) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
switch (events.ExecuteEvent())
{
case EVENT_MORTAL_WOUND:
me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
events.ScheduleEvent(EVENT_MORTAL_WOUND, 8000);
break;
case EVENT_SURGE:
Talk(SAY_SURGE);
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0))
me->CastSpell(target, SPELL_SURGE, false);
events.ScheduleEvent(EVENT_SURGE, 11000);
break;
case EVENT_RETALIATION:
if (me->HealthBelowPct(20))
{
me->CastSpell(me, SPELL_RETALIATION, false);
events.ScheduleEvent(EVENT_RETALIATION, 30000);
}
else
events.ScheduleEvent(EVENT_RETALIATION, 500);
break;
case EVENT_CHECK_HEALTH:
if (me->HealthBelowPct(50))
{
Talk(SAY_HEAL);
std::list<Creature*> clist;
me->GetCreaturesWithEntryInRange(clist, 100.0f, NPC_HELLFIRE_WATCHER);
for (std::list<Creature*>::const_iterator itr = clist.begin(); itr != clist.end(); ++itr)
(*itr)->AI()->SetData(NPC_HELLFIRE_WATCHER, 0);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH, 500);
break;
}
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
private: private:
bool _taunted; bool _taunted;
bool _hasSpoken;
}; };
CreatureAI* GetAI(Creature* creature) const override CreatureAI* GetAI(Creature* creature) const override