diff --git a/data/sql/updates/pending_db_world/rev_1684773536924402300.sql b/data/sql/updates/pending_db_world/rev_1684773536924402300.sql new file mode 100644 index 000000000..cebd5fdbe --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1684773536924402300.sql @@ -0,0 +1,10 @@ +-- +DELETE FROM `spell_script_names` WHERE `spell_id` = 30738 AND `ScriptName` = 'spell_blade_dance_targeting'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(30738, 'spell_blade_dance_targeting'); + +UPDATE `creature_template` SET `ScriptName` = 'npc_warchief_portal' WHERE `entry` = 17611; + +DELETE FROM `creature_text` WHERE `CreatureID` = 16808 AND `GroupID` = 5; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(16808, 5, 0, 'Cowards! You\'ll never draw me into the shadows!', 14, 0, 100, 0, 0, 0, 18367, 0, 'kargath SAY_EVADE'); diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp index 5c9a5c09a..71c2760f0 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp @@ -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 const summonSpells = { SPELL_SUMMON_HEATHEN, SPELL_SUMMON_REAVER, SPELL_SUMMON_SHARPSHOOTER }; +std::vector 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& 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 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); } diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp index 7ae1c3304..5df8630d0 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp @@ -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 } }; diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h index df137d902..089c0d2d2 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h @@ -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,