mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-16 02:20:27 +00:00
fix(Scripts/ShatteredHalls): fix some timers/mechanics of Grand Warlock Nethekurse (#16167)
This commit is contained in:
@@ -23,12 +23,14 @@
|
||||
enum eGrandWarlockNethekurse
|
||||
{
|
||||
SAY_INTRO = 0,
|
||||
SAY_PEON_ATTACKED = 1,
|
||||
SAY_PEON_DIES = 2,
|
||||
SAY_TAUNT = 3,
|
||||
SAY_AGGRO = 4,
|
||||
SAY_SLAY = 5,
|
||||
SAY_DIE = 6,
|
||||
SAY_INTRO_2 = 1,
|
||||
SAY_PEON_ATTACKED = 2,
|
||||
SAY_PEON_DIES = 3,
|
||||
SAY_SHADOW_SEAR = 4,
|
||||
SAY_SHADOW_FISSURE = 5,
|
||||
SAY_DEATH_COIL = 6,
|
||||
SAY_SLAY = 7,
|
||||
SAY_DIE = 8,
|
||||
|
||||
SPELL_DEATH_COIL_N = 30500,
|
||||
SPELL_DEATH_COIL_H = 35954,
|
||||
@@ -40,13 +42,10 @@ enum eGrandWarlockNethekurse
|
||||
// Spells used exclusively in RP
|
||||
SPELL_SHADOW_SEAR = 30735,
|
||||
SPELL_DEATH_COIL = 30741,
|
||||
SPELL_SHADOW_FISSURE_RP = 30745,
|
||||
|
||||
EVENT_INTRO = 1,
|
||||
EVENT_SPELL_DEATH_COIL = 2,
|
||||
EVENT_SPELL_SHADOW_FISSURE = 3,
|
||||
EVENT_SPELL_CLEAVE = 4,
|
||||
EVENT_CHECK_HEALTH = 5,
|
||||
EVENT_START_ATTACK = 6,
|
||||
EVENT_START_ATTACK = 2,
|
||||
|
||||
EVENT_STAGE_NONE = 0,
|
||||
EVENT_STAGE_INTRO = 1,
|
||||
@@ -55,13 +54,38 @@ enum eGrandWarlockNethekurse
|
||||
|
||||
SETDATA_DATA = 1,
|
||||
SETDATA_PEON_AGGRO = 1,
|
||||
SETDATA_PEON_DEATH = 2
|
||||
SETDATA_PEON_DEATH = 2,
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_PEON = 17083
|
||||
};
|
||||
|
||||
enum Groups
|
||||
{
|
||||
GROUP_RP = 0,
|
||||
};
|
||||
|
||||
enum Actions
|
||||
{
|
||||
ACTION_START_INTRO = 0,
|
||||
ACTION_CANCEL_INTRO = 1,
|
||||
ACTION_START_COMBAT = 2,
|
||||
};
|
||||
|
||||
// ########################################################
|
||||
// Grand Warlock Nethekurse
|
||||
// ########################################################
|
||||
|
||||
float NethekurseIntroPath[4][3] =
|
||||
{
|
||||
{184.78966f, 290.3699f, -8.18139f},
|
||||
{178.51125f, 278.779022f, -8.183065f},
|
||||
{171.82281f, 289.97687f, -8.185595f},
|
||||
{178.51125f, 287.97794f, -8.183065f}
|
||||
};
|
||||
|
||||
class boss_grand_warlock_nethekurse : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -69,7 +93,13 @@ public:
|
||||
|
||||
struct boss_grand_warlock_nethekurseAI : public BossAI
|
||||
{
|
||||
boss_grand_warlock_nethekurseAI(Creature* creature) : BossAI(creature, DATA_NETHEKURSE) { }
|
||||
boss_grand_warlock_nethekurseAI(Creature* creature) : BossAI(creature, DATA_NETHEKURSE)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
EventMap events2;
|
||||
void Reset() override
|
||||
@@ -77,6 +107,10 @@ public:
|
||||
EventStage = EVENT_STAGE_NONE;
|
||||
_Reset();
|
||||
events2.Reset();
|
||||
|
||||
ScheduleHealthCheckEvent(25, [&] {
|
||||
DoCastSelf(SPELL_DARK_SPIN);
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -97,21 +131,35 @@ public:
|
||||
return;
|
||||
|
||||
if (EventStage < EVENT_STAGE_TAUNT)
|
||||
{
|
||||
Talk(SAY_PEON_ATTACKED);
|
||||
}
|
||||
break;
|
||||
case SETDATA_PEON_DEATH:
|
||||
if (PeonKilledCount >= 4)
|
||||
return;
|
||||
|
||||
if (EventStage < EVENT_STAGE_TAUNT)
|
||||
Talk(SAY_PEON_DIES);
|
||||
|
||||
{
|
||||
PeonDieRP();
|
||||
}
|
||||
if (++PeonKilledCount == 4)
|
||||
events2.ScheduleEvent(EVENT_START_ATTACK, 5000);
|
||||
DoAction(ACTION_CANCEL_INTRO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PeonDieRP()
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->SetFacingTo(4.572762489318847656f);
|
||||
scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/)
|
||||
{
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_APPLAUD);
|
||||
Talk(SAY_PEON_DIES);
|
||||
});
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (EventStage < EVENT_STAGE_MAIN)
|
||||
@@ -120,40 +168,87 @@ public:
|
||||
if (me->Attack(who, true))
|
||||
{
|
||||
DoStartMovement(who);
|
||||
CombatEventScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
void CombatEventScheduler()
|
||||
{
|
||||
if (me->IsWithinDistInMap(who, 30.0f))
|
||||
scheduler.Schedule(12150ms, 19850ms, [this](TaskContext context)
|
||||
{
|
||||
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
if (EventStage == EVENT_STAGE_NONE && PeonKilledCount < 4)
|
||||
if (me->HealthBelowPct(90))
|
||||
{
|
||||
events2.ScheduleEvent(EVENT_INTRO, 90000);
|
||||
Talk(SAY_INTRO);
|
||||
EventStage = EVENT_STAGE_INTRO;
|
||||
instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
|
||||
me->SetInCombatWithZone();
|
||||
DoCastRandomTarget(DUNGEON_MODE(SPELL_DEATH_COIL_N, SPELL_DEATH_COIL_H), 0, 30.0f, true);
|
||||
}
|
||||
else if (PeonKilledCount >= 4)
|
||||
context.Repeat();
|
||||
}).Schedule(8100ms, 17300ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_SHADOW_FISSURE, 0, 60.0f, true);
|
||||
context.Repeat(8450ms, 9450ms);
|
||||
}).Schedule(10950ms, 21850ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(DUNGEON_MODE(SPELL_SHADOW_CLEAVE_N, SPELL_SHADOW_SLAM_H));
|
||||
context.Repeat(1200ms, 23900ms);
|
||||
});
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* /*who*/) override
|
||||
{
|
||||
if (EventStage == EVENT_STAGE_NONE)
|
||||
{
|
||||
if (me->SelectNearestPlayer(30.0f))
|
||||
{
|
||||
events2.ScheduleEvent(EVENT_START_ATTACK, 1000);
|
||||
instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
|
||||
me->SetInCombatWithZone();
|
||||
DoAction(ACTION_CANCEL_INTRO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EventStage < EVENT_STAGE_MAIN)
|
||||
return;
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
void IntroRP()
|
||||
{
|
||||
scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext context)
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/)
|
||||
{
|
||||
uint32 choicelocation = urand(1, 3);
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
me->GetMotionMaster()->MovePoint(0, NethekurseIntroPath[choicelocation][0], NethekurseIntroPath[choicelocation][1], NethekurseIntroPath[choicelocation][2]);
|
||||
scheduler.Schedule(2500ms, GROUP_RP, [this, choicelocation](TaskContext /*context*/)
|
||||
{
|
||||
CastRandomPeonSpell(choicelocation);
|
||||
});
|
||||
});
|
||||
context.Repeat(16400ms, 28500ms);
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
if (EventStage == EVENT_STAGE_NONE)
|
||||
{
|
||||
DoAction(ACTION_CANCEL_INTRO);
|
||||
CombatEventScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
void CastRandomPeonSpell(uint32 choice)
|
||||
{
|
||||
if (choice == 1)
|
||||
{
|
||||
Talk(SAY_DEATH_COIL);
|
||||
me->CastSpell(me, SPELL_DEATH_COIL, false);
|
||||
}
|
||||
else if (choice == 2)
|
||||
{
|
||||
Talk(SAY_SHADOW_FISSURE);
|
||||
me->CastSpell(me, SPELL_SHADOW_FISSURE_RP, false);
|
||||
}
|
||||
else if (choice == 3)
|
||||
{
|
||||
Talk(SAY_SHADOW_SEAR);
|
||||
me->CastSpell(me, SPELL_SHADOW_SEAR, false);
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
@@ -161,29 +256,59 @@ public:
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_CANCEL_INTRO)
|
||||
{
|
||||
introDone = true;
|
||||
scheduler.CancelGroup(GROUP_RP);
|
||||
events2.ScheduleEvent(EVENT_START_ATTACK, 1000);
|
||||
instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
|
||||
me->SetInCombatWithZone();
|
||||
Talk(SAY_INTRO_2);
|
||||
me->SetHomePosition(NethekurseIntroPath[3][0], NethekurseIntroPath[3][1], NethekurseIntroPath[3][2], 4.572762489318847656f);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action != ACTION_START_INTRO)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ATreached == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ATreached = true;
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1);
|
||||
events2.ScheduleEvent(EVENT_INTRO, 90000);
|
||||
Talk(SAY_INTRO);
|
||||
EventStage = EVENT_STAGE_INTRO;
|
||||
instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
|
||||
me->SetInCombatWithZone();
|
||||
IntroRP();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
scheduler.Update(diff);
|
||||
uint32 eventId = events2.ExecuteEvent();
|
||||
|
||||
if (EventStage < EVENT_STAGE_MAIN && instance->GetBossState(DATA_NETHEKURSE) == IN_PROGRESS)
|
||||
{
|
||||
if (eventId == EVENT_INTRO)
|
||||
{
|
||||
Talk(SAY_TAUNT);
|
||||
EventStage = EVENT_STAGE_TAUNT;
|
||||
me->CastSpell(me, SPELL_SHADOW_SEAR, false);
|
||||
}
|
||||
else if (eventId == EVENT_START_ATTACK)
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
EventStage = EVENT_STAGE_MAIN;
|
||||
if (Unit* target = me->SelectNearestPlayer(50.0f))
|
||||
AttackStart(target);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_DEATH_COIL, 20000);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_FISSURE, 8000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
DoAction(ACTION_CANCEL_INTRO);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -191,40 +316,10 @@ public:
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (EventStage < EVENT_STAGE_MAIN || me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_SHADOW_FISSURE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, SPELL_SHADOW_FISSURE, false);
|
||||
events.RescheduleEvent(EVENT_SPELL_SHADOW_FISSURE, urand(7500, 10000));
|
||||
break;
|
||||
case EVENT_SPELL_DEATH_COIL:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_DEATH_COIL_N, SPELL_DEATH_COIL_H), false);
|
||||
events.RescheduleEvent(EVENT_SPELL_DEATH_COIL, urand(15000, 20000));
|
||||
break;
|
||||
case EVENT_SPELL_CLEAVE:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_SHADOW_CLEAVE_N, SPELL_SHADOW_SLAM_H), false);
|
||||
events.RescheduleEvent(EVENT_SPELL_CLEAVE, urand(6000, 8000));
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(21))
|
||||
{
|
||||
events.Reset();
|
||||
me->CastSpell(me, SPELL_DARK_SPIN, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
events.RescheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!me->HealthBelowPct(21))
|
||||
if (!me->HealthBelowPct(25))
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
@@ -232,6 +327,8 @@ public:
|
||||
uint8 PeonEngagedCount = 0;
|
||||
uint8 PeonKilledCount = 0;
|
||||
uint8 EventStage;
|
||||
bool introDone;
|
||||
bool ATreached = false;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -251,7 +348,7 @@ public:
|
||||
|
||||
void CalculateDamageAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
amount = 1000;
|
||||
amount = 0;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
@@ -302,10 +399,36 @@ public:
|
||||
return new spell_tsh_shadow_bolt_SpellScript();
|
||||
}
|
||||
};
|
||||
class at_rp_nethekurse : public AreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_rp_nethekurse() : AreaTriggerScript
|
||||
("at_rp_nethekurse") { }
|
||||
|
||||
bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override
|
||||
{
|
||||
if (player->IsGameMaster())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
{
|
||||
if (instance->GetBossState(DATA_NETHEKURSE) != DONE && instance->GetBossState(DATA_NETHEKURSE) != IN_PROGRESS)
|
||||
{
|
||||
if (Creature* nethekurse = instance->GetCreature(DATA_NETHEKURSE))
|
||||
{
|
||||
nethekurse->AI()->DoAction(ACTION_START_INTRO);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_grand_warlock_nethekurse()
|
||||
{
|
||||
new boss_grand_warlock_nethekurse();
|
||||
new spell_tsh_shadow_sear();
|
||||
new spell_tsh_shadow_bolt();
|
||||
new at_rp_nethekurse();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "shattered_halls.h"
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_GRAND_WARLOCK_NETHEKURSE , DATA_NETHEKURSE },
|
||||
{ NPC_WARCHIEF_KARGATH , DATA_KARGATH },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
class instance_shattered_halls : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -37,6 +44,7 @@ public:
|
||||
void Initialize() override
|
||||
{
|
||||
SetBossNumber(ENCOUNTER_COUNT);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
|
||||
TeamIdInInstance = TEAM_NEUTRAL;
|
||||
RescueTimer = 100 * MINUTE * IN_MILLISECONDS;
|
||||
@@ -101,6 +109,7 @@ public:
|
||||
prisonerGUID[2] = creature->GetGUID();
|
||||
break;
|
||||
}
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
}
|
||||
|
||||
bool SetBossState(uint32 type, EncounterState state) override
|
||||
@@ -198,6 +207,7 @@ public:
|
||||
|
||||
protected:
|
||||
ObjectGuid warchiefKargathGUID;
|
||||
ObjectGuid grandWarlockNethekurseGUID;
|
||||
ObjectGuid nethekurseDoor1GUID;
|
||||
ObjectGuid nethekurseDoor2GUID;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user