Scripts/ScarletMonastry: reworked Interrogator Vishas and Bloodmage Thalnos scripts

* added missing Immolate proc aura to Interrogator Vishas and corrected his text health thresholds
* use correct spell id for Shadow Word: Pain
* corrected spell ids for Bloodmage Thalnos and implement a pseudo randomization event scheduler to come closer to sniff behaivior
This commit is contained in:
Ovahlord committed 2020-02-22 09:10:07 +01:00
1 parent 86c53ec031
commit b81ea0d288
5 files changed
+249 -189

No files matched your search

@@ -0,0 +1,6 @@
-- Interrogator Vishas
UPDATE `creature_template` SET `flags_extra`= `flags_extra` | 0x800;
UPDATE `creature_template_addon` SET `auras`= '8981' WHERE `entry`= 3983;
-- Bloodmage Thalnos
UPDATE `creature_template` SET `flags_extra`= 0 WHERE `entry`= 4543;
@@ -22,109 +22,163 @@
enum Yells
{
SAY_AGGRO = 0,
SAY_HEALTH = 1,
SAY_KILL = 2
SAY_HEALTH_BELOW_50 = 1,
SAY_SLAY = 2
};
enum Spells
{
SPELL_FLAMESHOCK = 8053,
SPELL_SHADOWBOLT = 1106,
SPELL_FLAMESPIKE = 8814,
SPELL_FIRENOVA = 16079
SPELL_SHADOW_BOLT = 20825,
SPELL_FIRE_NOVA = 12470,
SPELL_FLAME_SHOCK = 23038,
SPELL_FLAME_SPIKE = 8814
};
enum Events
{
EVENT_FLAME_SHOCK = 1,
EVENT_SHADOW_BOLT,
EVENT_FLAME_SPIKE,
EVENT_FIRE_NOVA
EVENT_SHADOW_BOLT = 1,
EVENT_FIRE_NOVA,
EVENT_FLAME_SHOCK,
EVENT_FLAME_SPIKE
};
class boss_bloodmage_thalnos : public CreatureScript
static constexpr uint8 const MaxChainedEvents = 4;
struct boss_bloodmage_thalnos : public BossAI
{
public:
boss_bloodmage_thalnos() : CreatureScript("boss_bloodmage_thalnos") { }
boss_bloodmage_thalnos(Creature* creature) : BossAI(creature, DATA_BLOODMAGE_THALNOS), _triggeredText(false)
{
InitializeEventCooldowns();
}
struct boss_bloodmage_thalnosAI : public BossAI
void Reset() override
{
_triggeredText = false;
InitializeEventCooldowns();
_Reset();
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
_JustEngagedWith();
events.ScheduleEvent(EVENT_FLAME_SPIKE, 8s, 10s);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 1ms);
}
void KilledUnit(Unit* victim) override
{
if (victim->IsPlayer())
Talk(SAY_SLAY);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (!_triggeredText && me->HealthBelowPctDamaged(50, damage))
{
boss_bloodmage_thalnosAI(Creature* creature) : BossAI(creature, DATA_BLOODMAGE_THALNOS)
{
_hpYell = false;
}
void Reset() override
{
_hpYell = false;
_Reset();
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_JustEngagedWith();
events.ScheduleEvent(EVENT_FLAME_SHOCK, 10000);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 2000);
events.ScheduleEvent(EVENT_FLAME_SPIKE, 8000);
events.ScheduleEvent(EVENT_FIRE_NOVA, 40000);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_KILL);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (!_hpYell && me->HealthBelowPctDamaged(35, damage))
{
Talk(SAY_HEALTH);
_hpYell = true;
}
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_FLAME_SHOCK:
DoCastVictim(SPELL_FLAMESHOCK);
events.ScheduleEvent(EVENT_FLAME_SHOCK, urand(10000, 15000));
break;
case EVENT_SHADOW_BOLT:
DoCastVictim(SPELL_SHADOWBOLT);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 2000);
break;
case EVENT_FLAME_SPIKE:
DoCastVictim(SPELL_FLAMESPIKE);
events.ScheduleEvent(EVENT_FLAME_SPIKE, 30000);
break;
case EVENT_FIRE_NOVA:
DoCastVictim(SPELL_FIRENOVA);
events.ScheduleEvent(EVENT_FIRE_NOVA, 40000);
break;
default:
break;
}
}
private:
bool _hpYell;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetScarletMonasteryAI<boss_bloodmage_thalnosAI>(creature);
Talk(SAY_HEALTH_BELOW_50);
_triggeredText = true;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHADOW_BOLT:
DoCastVictim(SPELL_SHADOW_BOLT);
ScheduleNextEvent();
break;
case EVENT_FLAME_SHOCK:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.f, true, -SPELL_FLAME_SHOCK))
DoCast(target, SPELL_FLAME_SHOCK);
else
DoCastVictim(SPELL_FLAME_SHOCK);
ScheduleNextEvent();
break;
case EVENT_FIRE_NOVA:
DoCastAOE(SPELL_FIRE_NOVA);
ScheduleNextEvent();
break;
case EVENT_FLAME_SPIKE:
DoCastVictim(SPELL_FLAME_SPIKE);
events.Repeat(3min);
break;
default:
break;
}
}
if (!me->HasSpellFocus())
DoMeleeAttackIfReady();
}
private:
bool _triggeredText;
int8 _remainingEventCycles[MaxChainedEvents];
void InitializeEventCooldowns()
{
_remainingEventCycles[EVENT_SHADOW_BOLT] = 0;
_remainingEventCycles[EVENT_FLAME_SHOCK] = 1;
_remainingEventCycles[EVENT_FIRE_NOVA] = 3;
}
void UpdateEventCooldowns()
{
for (uint8 i : { EVENT_FIRE_NOVA, EVENT_FLAME_SHOCK })
{
if (_remainingEventCycles[i] == 0)
{
if (i == EVENT_FLAME_SHOCK)
_remainingEventCycles[i] = 2;
else if (i == EVENT_FIRE_NOVA)
_remainingEventCycles[i] = 3;
}
else
_remainingEventCycles[i]--;
}
}
uint32 GetNextEventId() const
{
std::vector<uint32> possibleEventIds;
for (uint8 i : { EVENT_SHADOW_BOLT, EVENT_FIRE_NOVA, EVENT_FLAME_SHOCK })
{
// We have an long overdue event pending. Prioritize it.
if (_remainingEventCycles[i] <= -3)
return i;
// Otherwise pick a random event that's ready for execution
if (_remainingEventCycles[i] == 0)
possibleEventIds.push_back(i);
}
if (!possibleEventIds.empty())
return Trinity::Containers::SelectRandomContainerElement(possibleEventIds);
return 0;
}
void ScheduleNextEvent()
{
UpdateEventCooldowns();
events.ScheduleEvent(GetNextEventId(), 3s);
}
};
void AddSC_boss_bloodmage_thalnos()
{
new boss_bloodmage_thalnos();
RegisterScarletMonastryCreatureAI(boss_bloodmage_thalnos);
}
@@ -24,15 +24,14 @@
enum Says
{
SAY_AGGRO = 0,
SAY_HEALTH1 = 1,
SAY_HEALTH2 = 2,
SAY_KILL = 3,
SAY_TRIGGER_VORREL = 0
SAY_HEALTH_BELOW_75 = 1,
SAY_HEALTH_BELOW_25 = 2,
SAY_KILL = 3
};
enum Spells
{
SPELL_SHADOW_WORD_PAIN = 2767
SPELL_SHADOW_WORD_PAIN = 14032
};
enum Events
@@ -40,88 +39,74 @@ enum Events
EVENT_SHADOW_WORD_PAIN = 1
};
class boss_interrogator_vishas : public CreatureScript
struct boss_interrogator_vishas : public BossAI
{
public:
boss_interrogator_vishas() : CreatureScript("boss_interrogator_vishas") { }
boss_interrogator_vishas(Creature* creature) : BossAI(creature, DATA_INTERROGATOR_VISHAS), _textCount(0) { }
struct boss_interrogator_vishasAI : public BossAI
void Reset() override
{
_textCount = 0;
_Reset();
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_JustEngagedWith();
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 6s, 8s);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_KILL);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (me->HealthBelowPctDamaged(75, damage) && _textCount == 0)
{
boss_interrogator_vishasAI(Creature* creature) : BossAI(creature, DATA_INTERROGATOR_VISHAS)
{
Initialize();
}
void Initialize()
{
_yellCount = 0;
}
void Reset() override
{
Initialize();
_Reset();
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_JustEngagedWith();
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 5000);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_KILL);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
if (Creature* vorrel = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VORREL)))
vorrel->AI()->Talk(SAY_TRIGGER_VORREL);
}
void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
{
if (me->HealthBelowPctDamaged(60, damage) && _yellCount < 1)
{
Talk(SAY_HEALTH1);
++_yellCount;
}
if (me->HealthBelowPctDamaged(30, damage) && _yellCount < 2)
{
Talk(SAY_HEALTH2);
++_yellCount;
}
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_SHADOW_WORD_PAIN:
DoCastVictim(SPELL_SHADOW_WORD_PAIN);
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(5000, 15000));
break;
default:
break;
}
}
private:
uint8 _yellCount;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetScarletMonasteryAI<boss_interrogator_vishasAI>(creature);
Talk(SAY_HEALTH_BELOW_75);
++_textCount;
}
if (me->HealthBelowPctDamaged(25, damage) && _textCount == 1)
{
Talk(SAY_HEALTH_BELOW_25);
++_textCount;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHADOW_WORD_PAIN:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.f, true, -SPELL_SHADOW_WORD_PAIN))
DoCast(target, SPELL_SHADOW_WORD_PAIN);
events.Repeat(7s, 11s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
uint8 _textCount;
};
void AddSC_boss_interrogator_vishas()
{
new boss_interrogator_vishas();
RegisterScarletMonastryCreatureAI(boss_interrogator_vishas);
}
@@ -22,6 +22,13 @@
#include "Map.h"
#include "scarlet_monastery.h"
ObjectData const creatureData[] =
{
{ BOSS_INTERROGATOR_VISHAS, DATA_INTERROGATOR_VISHAS },
{ BOSS_BLOODMAGE_THALNOS, DATA_BLOODMAGE_THALNOS },
{ 0, 0 } // END
};
DoorData const doorData[] =
{
{ GO_HIGH_INQUISITORS_DOOR, DATA_MOGRAINE_AND_WHITE_EVENT, DOOR_TYPE_ROOM },
@@ -39,6 +46,7 @@ class instance_scarlet_monastery : public InstanceMapScript
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
HorsemanAdds.clear();
@@ -27,33 +27,37 @@ uint32 const EncounterCount = 10;
enum SMDataTypes
{
DATA_MOGRAINE_AND_WHITE_EVENT = 1,
DATA_MOGRAINE = 2,
DATA_WHITEMANE = 3,
// Bosses
DATA_INTERROGATOR_VISHAS = 1,
DATA_BLOODMAGE_THALNOS = 2,
DATA_HORSEMAN_EVENT = 4,
DATA_PUMPKIN_SHRINE = 5,
DATA_VORREL = 6,
DATA_ARCANIST_DOAN = 7,
DATA_AZSHIR = 8,
DATA_BLOODMAGE_THALNOS = 9,
DATA_HEROD = 10,
DATA_HIGH_INQUISITOR_FAIRBANKS = 11,
DATA_HOUNDMASTER_LOKSEY = 12,
DATA_INTERROGATOR_VISHAS = 13,
DATA_SCORN = 14
DATA_MOGRAINE_AND_WHITE_EVENT,
DATA_MOGRAINE,
DATA_WHITEMANE,
DATA_HORSEMAN_EVENT,
DATA_PUMPKIN_SHRINE,
DATA_VORREL,
DATA_ARCANIST_DOAN,
DATA_AZSHIR,
DATA_HEROD,
DATA_HIGH_INQUISITOR_FAIRBANKS,
DATA_HOUNDMASTER_LOKSEY,
DATA_SCORN
};
enum SMCreatureIds
{
NPC_MOGRAINE = 3976,
NPC_WHITEMANE = 3977,
NPC_VORREL = 3981,
// Bosses
BOSS_INTERROGATOR_VISHAS = 3983,
BOSS_BLOODMAGE_THALNOS = 4543,
NPC_HORSEMAN = 23682,
NPC_HEAD = 23775,
NPC_PUMPKIN = 23694
NPC_MOGRAINE = 3976,
NPC_WHITEMANE = 3977,
NPC_VORREL = 3981,
NPC_HORSEMAN = 23682,
NPC_HEAD = 23775,
NPC_PUMPKIN = 23694
};
enum SMGameObjectIds
@@ -68,4 +72,7 @@ inline AI* GetScarletMonasteryAI(T* obj)
return GetInstanceAI<AI>(obj, SMScriptName);
}
#define RegisterScarletMonastryCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetScarletMonasteryAI)
#endif // SCARLET_M_