mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-16 02:20:27 +00:00
fix(Scripts/ShatteredHalls): Rewrite Warchief Kargath Bladefist (#16355)
This commit is contained in:
@@ -17,41 +17,53 @@
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "shattered_halls.h"
|
||||
|
||||
enum Says
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_DEATH = 2
|
||||
SAY_DEATH = 2,
|
||||
SAY_EVADE = 5
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_BLADE_DANCE = 30739,
|
||||
SPELL_CHARGE = 25821,
|
||||
SPELL_SPRINT = 32720
|
||||
// Blade dance
|
||||
SPELL_BLADE_DANCE_TARGETING = 30738,
|
||||
SPELL_BLADE_DANCE_DMG = 30739,
|
||||
SPELL_BLADE_DANCE_CHARGE = 30751,
|
||||
|
||||
// Warchief portal
|
||||
SPELL_SUMMON_HEATHEN = 30737,
|
||||
SPELL_SUMMON_REAVER = 30785,
|
||||
SPELL_SUMMON_SHARPSHOOTER = 30786
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_SHATTERED_ASSASSIN = 17695,
|
||||
NPC_HEARTHEN_GUARD = 17621,
|
||||
NPC_SHARPSHOOTER_GUARD = 17622,
|
||||
NPC_REAVER_GUARD = 17623
|
||||
NPC_BLADE_DANCE_TARGET = 20709
|
||||
};
|
||||
|
||||
enum Misc
|
||||
enum PortalData
|
||||
{
|
||||
EVENT_SPELL_CHARGE = 1,
|
||||
EVENT_MOVE_TO_NEXT_POINT = 2,
|
||||
EVENT_BLADE_DANCE = 3,
|
||||
EVENT_FINISH_BLADE_DANCE = 4
|
||||
DATA_START_FIGHT = 1,
|
||||
DATA_RESET_FIGHT = 2
|
||||
};
|
||||
|
||||
float AssassEntrance[3] = { 275.136f, -84.29f, 2.3f }; // y -8
|
||||
float AssassExit[3] = { 184.233f, -84.29f, 2.3f }; // y -8
|
||||
float AddsEntrance[3] = { 306.036f, -84.29f, 1.93f };
|
||||
std::array<uint32, 3> const summonSpells = { SPELL_SUMMON_HEATHEN, SPELL_SUMMON_REAVER, SPELL_SUMMON_SHARPSHOOTER };
|
||||
std::vector<Position> const assassinsPos =
|
||||
{
|
||||
{ 172.68164f, -80.65692f, 2.0834563f, 5.4279f },
|
||||
{ 167.8295f, -86.55783f, 1.9949634f, 0.8118f },
|
||||
{ 287.0375f, -88.17879f, 2.0663502f, 3.2490f },
|
||||
{ 292.1491f, -82.25267f, 1.9973913f, 5.8568f }
|
||||
};
|
||||
|
||||
Position const kargathRespawnPos = { 231.25f, -83.6449f, 5.02341f };
|
||||
|
||||
struct boss_warchief_kargath_bladefist : public BossAI
|
||||
{
|
||||
@@ -75,10 +87,45 @@ struct boss_warchief_kargath_bladefist : public BossAI
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
|
||||
{
|
||||
if (summon)
|
||||
{
|
||||
summon->SetVisible(false);
|
||||
scheduler.Schedule(20s, [summon](TaskContext /*context*/)
|
||||
{
|
||||
if (summon)
|
||||
{
|
||||
summon->Respawn(true);
|
||||
summon->SetVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RespawnAssassins()
|
||||
{
|
||||
for (Position const& summonPos : assassinsPos)
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, summonPos);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
if (Creature* warchiefPortal = instance->GetCreature(DATA_WARCHIEF_PORTAL))
|
||||
warchiefPortal->AI()->SetData(DATA_RESET_FIGHT, 0);
|
||||
_danceCount = 0;
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
_JustDied();
|
||||
BossAI::JustDied(killer);
|
||||
if (instance)
|
||||
{
|
||||
if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER)))
|
||||
@@ -88,79 +135,58 @@ struct boss_warchief_kargath_bladefist : public BossAI
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
_JustEngagedWith();
|
||||
scheduler.Schedule(5s, [this](TaskContext /*context*/)
|
||||
{
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] + 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] - 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] + 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] - 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
}).Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
for (uint8 i = 0; i < 2; ++i)
|
||||
{
|
||||
me->SummonCreature(NPC_HEARTHEN_GUARD + urand(0, 2), AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
}
|
||||
context.Repeat(30s);
|
||||
}).Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
scheduler.DelayAll(10001ms);
|
||||
context.Repeat(40s);
|
||||
scheduler.Schedule(1ms, [this](TaskContext /*context*/)
|
||||
{
|
||||
float x = 210 + frand(0.0f, 35.0f);
|
||||
float y = -65.0f - frand(0.0f, 35.0f);
|
||||
me->GetMotionMaster()->MovePoint(1, x, y, me->GetPositionZ());
|
||||
}).Schedule(10s, [this](TaskContext /*context*/)
|
||||
{
|
||||
//events.SetPhase(0); howToMigrate?
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
if (IsHeroic())
|
||||
BossAI::JustEngagedWith(who);
|
||||
if (Creature* warchiefPortal = instance->GetCreature(DATA_WARCHIEF_PORTAL))
|
||||
warchiefPortal->AI()->SetData(DATA_START_FIGHT, 0);
|
||||
RespawnAssassins();
|
||||
scheduler
|
||||
.Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
scheduler.Schedule(3s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_CHARGE);
|
||||
context.Repeat(30s);
|
||||
});
|
||||
}
|
||||
});
|
||||
//events.SetPhase(1); howToMigrate?
|
||||
DoCastSelf(SPELL_SPRINT, true);
|
||||
});
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
if (summon->GetEntry() != NPC_SHATTERED_ASSASSIN)
|
||||
{
|
||||
summon->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random, 0));
|
||||
}
|
||||
summons.Summon(summon);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
_danceCount = 0;
|
||||
DoCastAOE(SPELL_BLADE_DANCE_TARGETING);
|
||||
context.Repeat(32850ms, 41350ms);
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
if (victim && victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
void MovementInform(uint32 type, uint32 /*id*/) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE || id != 1)
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
me->CastSpell(me, SPELL_BLADE_DANCE, true);
|
||||
events.ScheduleEvent(EVENT_MOVE_TO_NEXT_POINT, 0);
|
||||
if (_danceCount < 8)
|
||||
{
|
||||
_danceCount++;
|
||||
scheduler.Schedule(100ms, [this](TaskContext /*context*/)
|
||||
{
|
||||
DoCastAOE(SPELL_BLADE_DANCE_TARGETING);
|
||||
});
|
||||
}
|
||||
else
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
|
||||
bool IsInRoom()
|
||||
{
|
||||
if (me->GetExactDist2d(kargathRespawnPos) >= 42.f)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (me->GetPositionX() > 255 || me->GetPositionX() < 205)
|
||||
if (!IsInRoom())
|
||||
{
|
||||
Talk(SAY_EVADE);
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
@@ -168,14 +194,128 @@ struct boss_warchief_kargath_bladefist : public BossAI
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
scheduler.Update(diff, [this]
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
|
||||
if (!events.IsInPhase(1)) // howToMigrate?
|
||||
DoMeleeAttackIfReady();
|
||||
protected:
|
||||
uint8 _danceCount;
|
||||
};
|
||||
|
||||
struct npc_warchief_portal : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
npc_warchief_portal(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* creature) override
|
||||
{
|
||||
InstanceScript* instance = me->GetInstanceScript();
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
if (Creature* kargath = instance->GetCreature(DATA_KARGATH))
|
||||
kargath->AI()->JustSummoned(creature);
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 /*data*/) override
|
||||
{
|
||||
if (type == DATA_START_FIGHT)
|
||||
{
|
||||
_scheduler.Schedule(20600ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(summonSpells[context.GetRepeatCounter() % 3]);
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
if (type == DATA_RESET_FIGHT)
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
class spell_blade_dance_targeting : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_blade_dance_targeting);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_BLADE_DANCE_CHARGE, SPELL_BLADE_DANCE_DMG });
|
||||
}
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
targets.remove_if([&](WorldObject* target) -> bool
|
||||
{
|
||||
float dist = caster->GetDistance2d(target);
|
||||
// Do not target dummies that are too close or too far away
|
||||
if (dist < 5.f || dist > 16.f)
|
||||
return true;
|
||||
// Do not target anything that is not a target dummy
|
||||
if (target->GetEntry() != NPC_BLADE_DANCE_TARGET)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
std::list<WorldObject*> targets2 = targets;
|
||||
|
||||
targets.remove_if([&](WorldObject* target) -> bool
|
||||
{
|
||||
if (target->SelectNearestPlayer(15.f))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
Acore::Containers::RandomResize(targets2, 1);
|
||||
|
||||
if (urand(0, 2))
|
||||
{
|
||||
if (targets.empty())
|
||||
targets = targets2;
|
||||
else
|
||||
Acore::Containers::RandomResize(targets, 1);
|
||||
}
|
||||
else
|
||||
targets = targets2;
|
||||
}
|
||||
|
||||
void HandleOnHit()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetHitUnit();
|
||||
if (!caster || !target)
|
||||
return;
|
||||
|
||||
caster->CastSpell(target, SPELL_BLADE_DANCE_CHARGE, true);
|
||||
caster->CastSpell(target, SPELL_BLADE_DANCE_DMG, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_blade_dance_targeting::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
|
||||
OnHit += SpellHitFn(spell_blade_dance_targeting::HandleOnHit);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_warchief_kargath_bladefist()
|
||||
{
|
||||
RegisterShatteredHallsCreatureAI(boss_warchief_kargath_bladefist);
|
||||
RegisterShatteredHallsCreatureAI(npc_warchief_portal);
|
||||
RegisterSpellScript(spell_blade_dance_targeting);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ ObjectData const creatureData[] =
|
||||
{ NPC_WARCHIEF_KARGATH , DATA_KARGATH },
|
||||
{ NPC_OMROGG_LEFT_HEAD , DATA_OMROGG_LEFT_HEAD },
|
||||
{ NPC_OMROGG_RIGHT_HEAD , DATA_OMROGG_RIGHT_HEAD },
|
||||
{ NPC_WARCHIEF_PORTAL , DATA_WARCHIEF_PORTAL },
|
||||
{ 0 , 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -37,14 +37,17 @@ enum DataTypes
|
||||
DATA_PRISONER_3 = 13,
|
||||
DATA_EXECUTIONER = 14,
|
||||
DATA_OMROGG_LEFT_HEAD = 15,
|
||||
DATA_OMROGG_RIGHT_HEAD = 16
|
||||
DATA_OMROGG_RIGHT_HEAD = 16,
|
||||
DATA_WARCHIEF_PORTAL = 17
|
||||
};
|
||||
|
||||
enum CreatureIds
|
||||
{
|
||||
NPC_GRAND_WARLOCK_NETHEKURSE = 16807,
|
||||
NPC_WARCHIEF_KARGATH = 16808,
|
||||
NPC_FEL_ORC_CONVERT = 17083,
|
||||
// Warchief Kargath
|
||||
NPC_WARCHIEF_KARGATH = 16808,
|
||||
NPC_WARCHIEF_PORTAL = 17611,
|
||||
|
||||
// O'MROGG
|
||||
NPC_OMROGG_LEFT_HEAD = 19523,
|
||||
|
||||
Reference in New Issue
Block a user