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:
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_
|
||||
Reference in new issue
Block a user