aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/3.3.5/2025_07_22_00_world.sql121
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp491
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp718
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp470
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp10
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp283
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h11
7 files changed, 1048 insertions, 1056 deletions
diff --git a/sql/updates/world/3.3.5/2025_07_22_00_world.sql b/sql/updates/world/3.3.5/2025_07_22_00_world.sql
new file mode 100644
index 00000000000..d4491e15235
--- /dev/null
+++ b/sql/updates/world/3.3.5/2025_07_22_00_world.sql
@@ -0,0 +1,121 @@
+-- Warchief Kargath Bladefist
+UPDATE `creature_template` SET `unit_flags` = 33554432, `ScriptName` = 'npc_warchiefs_portal' WHERE `entry` = 17611;
+DELETE FROM `creature` WHERE `id` = 17611;
+
+DELETE FROM `waypoints` WHERE `entry` = 17621;
+INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `point_comment`) VALUES
+(17621,1,312.5911,-84.185234,1.9369955,NULL,0,'Heathen Guard'),
+(17621,2,301.18335,-83.94184,1.9370384,NULL,0,'Heathen Guard'),
+(17621,3,289.016,-83.993065,1.9303827,NULL,0,'Heathen Guard'),
+(17621,4,279.15543,-84.08081,2.189514,NULL,0,'Heathen Guard'),
+(17621,5,274.1177,-84.06761,2.3095038,NULL,0,'Heathen Guard');
+
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 17621 AND `source_type` = 0 AND `id` IN (3,4);
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 17622 AND `source_type` = 0 AND `id` IN (5,6);
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 17623 AND `source_type` = 0 AND `id` IN (5,6);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(17621,0,3,0,54,0,100,0,0,0,0,0,0,53,1,17621,0,0,0,0,1,0,0,0,0,0,0,0,0,"Heathen Guard - On Just Summoned - Start Waypoint"),
+(17621,0,4,0,40,0,100,0,5,17621,0,0,0,38,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Heathen Guard - On Waypoint 5 Reached - Set In Combat With Zone"),
+
+(17622,0,5,0,54,0,100,0,0,0,0,0,0,53,1,17621,0,0,0,0,1,0,0,0,0,0,0,0,0,"Sharpshooter Guard - On Just Summoned - Start Waypoint"),
+(17622,0,6,0,40,0,100,0,5,17621,0,0,0,38,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Sharpshooter Guard - On Waypoint 5 Reached - Set In Combat With Zone"),
+
+(17623,0,5,0,54,0,100,0,0,0,0,0,0,53,1,17621,0,0,0,0,1,0,0,0,0,0,0,0,0,"Reaver Guard - On Just Summoned - Start Waypoint"),
+(17623,0,6,0,40,0,100,0,5,17621,0,0,0,38,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Reaver Guard - On Waypoint 5 Reached - Set In Combat With Zone");
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` IN (30751,30738);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(13,1,30751,0,0,31,0,3,20709,0,0,0,0,"","Group 0: Spell 'Blade Dance Charge' (Effect 0) targets creature 'Blade Dance Target'"),
+(13,1,30738,0,0,31,0,3,20709,0,0,0,0,"","Group 0: Spell 'Blade Dance Targeting' (Effect 0) targets creature 'Blade Dance Target'");
+
+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_LEASH");
+
+DELETE FROM `creature_summon_groups` WHERE `summonerId` = 16808;
+INSERT INTO `creature_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `summonType`, `summonTime`, `Comment`) VALUES
+(16808,0,0,17611,336.707,-84.0521,1.99244,3.124140,8,0,"Warchief Kargath Bladefist - Group 0 - Warchief's Portal"),
+
+(16808,0,1,17695,287.038,-88.1788,2.06635,2.443460,7,300000,"Warchief Kargath Bladefist - Group 1 - Shattered Hand Assassin"),
+(16808,0,1,17695,167.829,-86.5578,1.99496,0.890118,7,300000,"Warchief Kargath Bladefist - Group 1 - Shattered Hand Assassin"),
+(16808,0,1,17695,292.149,-82.2527,1.99739,2.932150,7,300000,"Warchief Kargath Bladefist - Group 1 - Shattered Hand Assassin"),
+(16808,0,1,17695,172.682,-80.6569,2.08346,5.427970,7,300000,"Warchief Kargath Bladefist - Group 1 - Shattered Hand Assassin");
+
+UPDATE `creature_template_addon` SET `auras` = '19818' WHERE `entry` = 16808;
+
+DELETE FROM `creature` WHERE `guid` IN (86464,86465,86466);
+DELETE FROM `spawn_group` WHERE `spawnType` = 0 AND `spawnId` IN (86464,86465,86466);
+
+-- Warbringer O'mrogg
+DELETE FROM `creature` WHERE `guid` IN (130847,130848) AND `id` IN (19523,19524);
+INSERT INTO `creature` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `VerifiedBuild`) VALUES
+(130847, 19523, 540, 0, 0, 3, 1, 0, 0, 374.378570556640625, 51.28566360473632812, 30.643890380859375, 0.03490658476948738, 86400, 0, 0, 74, 0, 0, 0, 0, 0, 14007),
+(130848, 19524, 540, 0, 0, 3, 1, 0, 0, 374.356475830078125, 64.50481414794921875, 31.22058868408203125, 6.0737457275390625, 86400, 0, 0, 74, 0, 0, 0, 0, 0, 14007);
+
+UPDATE `creature_template` SET `flags_extra` = `flags_extra`|128 WHERE `entry` IN (19523,19524,20572,20573);
+
+DELETE FROM `creature_equip_template` WHERE `CreatureID`=16809 AND `ID`=2;
+INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`, `VerifiedBuild`) VALUES
+(16809, 2, 29479, 0, 0, 61967);
+
+DELETE FROM `creature_template_movement` WHERE `CreatureId` IN (19523,19524,20572,20573);
+INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
+(19523,1,1,1,1,0,0,NULL),
+(20572,1,1,1,1,0,0,NULL),
+(19524,1,1,1,1,0,0,NULL),
+(20573,1,1,1,1,0,0,NULL);
+
+DELETE FROM `creature_text` WHERE `CreatureID` IN (19523,19524,16809);
+INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(16809,0,0,"%s roars!",16,0,100,0,0,0,14029,0,"omrogg EMOTE_ROAR"),
+
+-- Smash! 15:26:08.000 -- Why don't you let me do the talking? 15:26:11.000 -- Hey! 15:26:14.000
+-- https://youtu.be/9aHROEXiVSA?t=1548
+/* L */ (19523,0,0,"Smash!", 14,0,100,0,0,10306,14046,0,"omrogg SAY_AGGRO_1"),
+/* R */ (19524,0,0,"Why don't you let me do the talking?", 14,0,100,0,0,10317,14047,0,"omrogg SAY_AGGRO_1_1"),
+/* L */ (19523,1,0,"Hey!", 14,0,100,0,0,10307,16917,0,"omrogg SAY_AGGRO_1_2"),
+
+-- https://youtu.be/cmZMZFc09oM?t=26
+/* L */ (19523,2,0,"If you nice me let you live.", 14,0,100,0,0,10308,14048,0,"omrogg SAY_AGGRO_2"),
+/* R */ (19524,1,0,"No, we will NOT let you live.", 14,0,100,0,0,10318,16916,0,"omrogg SAY_AGGRO_2_1"),
+
+-- https://youtu.be/c7anPGIo9pA?t=5
+/* L */ (19523,3,0,"Me hungry.", 14,0,100,0,0,10309,16918,0,"omrogg SAY_AGGRO_3"),
+/* R */ (19524,2,0,"You're always hungry. That's why we so fat!", 14,0,100,0,0,10319,16919,0,"omrogg SAY_AGGRO_3_1"),
+
+-- Me not like this one... 15:26:36.000 -- Hey, you numbskull! 15:26:39.000 -- We kill his friend! 15:26:41.000
+-- https://youtu.be/FfjIPe1F7v4?t=1810
+/* L */ (19523,4,0,"Me not like this one...", 14,0,100,0,0,10300,14043,0,"omrogg SAY_ATTACK_1"),
+/* R */ (19524,3,0,"Hey, you numbskull!", 14,0,100,0,0,10312,14044,0,"omrogg SAY_ATTACK_1_1"),
+/* L */ (19523,5,0,"We kill his friend!", 14,0,100,0,0,10301,14045,0,"omrogg SAY_ATTACK_1_2"),
+
+-- https://youtu.be/H4hvmeYjIYI?t=3130
+/* L */ (19523,6,0,"We kill someone else!", 14,0,100,0,0,10302,16895,0,"omrogg SAY_ATTACK_2"),
+/* R */ (19524,4,0,"I'm not done yet, idiot!", 14,0,100,0,0,10313,16896,0,"omrogg SAY_ATTACK_2_1"),
+
+-- https://youtu.be/H4hvmeYjIYI?t=3197
+/* L */ (19523,7,0,"You stay here. Me go kill someone else!", 14,0,100,0,0,10303,16898,0,"omrogg SAY_ATTACK_3"),
+/* R */ (19524,5,0,"That's not funny!", 14,0,100,0,0,10314,16899,0,"omrogg SAY_ATTACK_3_1"),
+/* L */ (19523,8,0,"Ha ha ha.", 14,0,100,0,0,10304,16900,0,"omrogg SAY_ATTACK_3_2"),
+
+-- https://youtu.be/0phkTyrfzpo?t=484
+/* R */ (19524,6,0,"What are you doing?", 14,0,100,0,0,10315,16901,0,"omrogg SAY_ATTACK_4"),
+/* L */ (19523,9,0,"Me get bored.", 14,0,100,0,0,10305,16902,0,"omrogg SAY_ATTACK_4_1"),
+/* R */ (19524,7,0,"Bored? He was almost dead!", 14,0,100,0,0,10316,16903,0,"omrogg SAY_ATTACK_4_2"),
+
+-- https://wowpedia.fandom.com/wiki/Warbringer_O%27mrogg
+/* R */ (19524,8,0,"I'm tired. You kill next one!", 14,0,100,0,0,10320,16921,0,"omrogg SAY_SLAY_1"),
+
+-- https://wowpedia.fandom.com/wiki/Warbringer_O%27mrogg
+/* L */ (19523,10,0,"This one die easy!", 14,0,100,0,0,10310,16922,0,"omrogg SAY_SLAY_2"),
+/* R */ (19524,9,0,"That's because I do all the hard work!", 14,0,100,0,0,10321,16923,0,"omrogg SAY_SLAY_2_1"),
+
+-- This all... your fault! 15:26:57.000 -- I... hate... you. 15:27:00.000
+-- https://youtu.be/FfjIPe1F7v4?t=1830
+/* L */ (19523,11,0,"This all... your fault!", 14,0,100,0,0,10311,16924,0,"omrogg SAY_DEATH_1"),
+/* R */ (19524,10,0,"I... hate... you.", 14,0,100,0,0,10322,16925,0,"omrogg SAY_DEATH_1_1");
+
+DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_omrogg_burning_maul';
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(30598, 'spell_omrogg_burning_maul'),
+(36056, 'spell_omrogg_burning_maul');
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
index 24529fbef8a..c470c6a867e 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
@@ -77,325 +77,292 @@ enum Events
// Grand Warlock Nethekurse
// ########################################################
-class boss_grand_warlock_nethekurse : public CreatureScript
+struct boss_grand_warlock_nethekurse : public BossAI
{
- public:
- boss_grand_warlock_nethekurse() : CreatureScript("boss_grand_warlock_nethekurse") { }
-
- struct boss_grand_warlock_nethekurseAI : public BossAI
+ boss_grand_warlock_nethekurse(Creature* creature) : BossAI(creature, DATA_NETHEKURSE)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ IsIntroEvent = false;
+ IntroOnce = false;
+ IsMainEvent = false;
+ //HasTaunted = false;
+ SpinOnce = false;
+ Phase = false;
+
+ PeonEngagedCount = 0;
+ PeonKilledCount = 0;
+
+ IntroEvent_Timer = 90000; // how long before getting bored and kills his minions?
+ DeathCoil_Timer = 20000;
+ ShadowFissure_Timer = 8000;
+ Cleave_Timer = 5000;
+ }
+
+ void Reset() override
+ {
+ _Reset();
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+
+ Initialize();
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_DIE);
+ }
+
+ void SetData(uint32 data, uint32 value) override
+ {
+ if (data != SETDATA_DATA)
+ return;
+
+ switch (value)
{
- boss_grand_warlock_nethekurseAI(Creature* creature) : BossAI(creature, DATA_NETHEKURSE)
- {
- Initialize();
- }
-
- void Initialize()
- {
- IsIntroEvent = false;
- IntroOnce = false;
- IsMainEvent = false;
- //HasTaunted = false;
- SpinOnce = false;
- Phase = false;
-
- PeonEngagedCount = 0;
- PeonKilledCount = 0;
-
- IntroEvent_Timer = 90000; // how long before getting bored and kills his minions?
- DeathCoil_Timer = 20000;
- ShadowFissure_Timer = 8000;
- Cleave_Timer = 5000;
- }
-
- void Reset() override
- {
- _Reset();
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
-
- Initialize();
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- _JustDied();
- Talk(SAY_DIE);
- }
+ case SETDATA_PEON_AGGRO:
+ if (PeonEngagedCount >= 4)
+ return;
- void SetData(uint32 data, uint32 value) override
- {
- if (data != SETDATA_DATA)
+ Talk(SAY_PEON_ATTACKED);
+ ++PeonEngagedCount;
+ break;
+ case SETDATA_PEON_DEATH:
+ if (PeonKilledCount >= 4)
return;
- switch (value)
+ Talk(SAY_PEON_DIES);
+ ++PeonKilledCount;
+
+ if (PeonKilledCount == 4)
{
- case SETDATA_PEON_AGGRO:
- if (PeonEngagedCount >= 4)
- return;
-
- Talk(SAY_PEON_ATTACKED);
- ++PeonEngagedCount;
- break;
- case SETDATA_PEON_DEATH:
- if (PeonKilledCount >= 4)
- return;
-
- Talk(SAY_PEON_DIES);
- ++PeonKilledCount;
-
- if (PeonKilledCount == 4)
- {
- IsIntroEvent = false;
- IsMainEvent = true;
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- }
- break;
- default:
- break;
+ IsIntroEvent = false;
+ IsMainEvent = true;
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
}
- }
+ break;
+ default:
+ break;
+ }
+ }
+
+ void DoTauntPeons()
+ {
+ Talk(SAY_TAUNT);
+
+ /// @todo kill the peons first
+ IsIntroEvent = false;
+ PeonEngagedCount = 4;
+ PeonKilledCount = 4;
+ IsMainEvent = true;
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ if (IsIntroEvent || !IsMainEvent)
+ return;
+
+ if (me->Attack(who, true))
+ {
+ if (Phase)
+ DoStartNoMovement(who);
+ else
+ DoStartMovement(who);
+ }
+ }
- void DoTauntPeons()
- {
- Talk(SAY_TAUNT);
-
- /// @todo kill the peons first
- IsIntroEvent = false;
- PeonEngagedCount = 4;
- PeonKilledCount = 4;
- IsMainEvent = true;
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- }
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!IntroOnce && me->IsWithinDistInMap(who, 30.0f))
+ {
+ if (who->GetTypeId() != TYPEID_PLAYER)
+ return;
- void AttackStart(Unit* who) override
- {
- if (IsIntroEvent || !IsMainEvent)
- return;
+ Talk(SAY_INTRO);
+ IntroOnce = true;
+ IsIntroEvent = true;
- if (me->Attack(who, true))
- {
- if (Phase)
- DoStartNoMovement(who);
- else
- DoStartMovement(who);
- }
- }
+ instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
+ }
- void MoveInLineOfSight(Unit* who) override
- {
- if (!IntroOnce && me->IsWithinDistInMap(who, 30.0f))
- {
- if (who->GetTypeId() != TYPEID_PLAYER)
- return;
+ if (IsIntroEvent || !IsMainEvent)
+ return;
- Talk(SAY_INTRO);
- IntroOnce = true;
- IsIntroEvent = true;
+ ScriptedAI::MoveInLineOfSight(who);
+ }
- instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
- }
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ Talk(SAY_AGGRO);
+ }
- if (IsIntroEvent || !IsMainEvent)
- return;
+ void JustSummoned(Creature* summoned) override
+ {
+ //triggered spell of consumption does not properly show it's SpellVisual, wrong spellid?
+ summoned->CastSpell(summoned, SPELL_TEMPORARY_VISUAL, true);
+ summoned->CastSpell(summoned, SPELL_CONSUMPTION, CastSpellExtraArgs().SetOriginalCaster(me->GetGUID()));
+ }
- ScriptedAI::MoveInLineOfSight(who);
- }
+ void KilledUnit(Unit* /*victim*/) override
+ {
+ Talk(SAY_SLAY);
+ }
- void JustEngagedWith(Unit* /*who*/) override
+ void UpdateAI(uint32 diff) override
+ {
+ if (IsIntroEvent)
+ {
+ if (instance->GetBossState(DATA_NETHEKURSE) == IN_PROGRESS)
{
- Talk(SAY_AGGRO);
+ if (IntroEvent_Timer <= diff)
+ DoTauntPeons();
+ else
+ IntroEvent_Timer -= diff;
}
+ }
- void JustSummoned(Creature* summoned) override
+ if (!UpdateVictim())
+ return;
+
+ if (!IsMainEvent)
+ return;
+
+ if (Phase)
+ {
+ if (!SpinOnce)
{
- //triggered spell of consumption does not properly show it's SpellVisual, wrong spellid?
- summoned->CastSpell(summoned, SPELL_TEMPORARY_VISUAL, true);
- summoned->CastSpell(summoned, SPELL_CONSUMPTION, CastSpellExtraArgs().SetOriginalCaster(me->GetGUID()));
+ DoCastVictim(SPELL_DARK_SPIN);
+ SpinOnce = true;
}
- void KilledUnit(Unit* /*victim*/) override
+ if (Cleave_Timer <= diff)
{
- Talk(SAY_SLAY);
+ DoCastVictim(SPELL_SHADOW_CLEAVE);
+ Cleave_Timer = 6000 + rand32() % 2500;
}
-
- void UpdateAI(uint32 diff) override
+ else
+ Cleave_Timer -= diff;
+ }
+ else
+ {
+ if (ShadowFissure_Timer <= diff)
{
- if (IsIntroEvent)
- {
- if (instance->GetBossState(DATA_NETHEKURSE) == IN_PROGRESS)
- {
- if (IntroEvent_Timer <= diff)
- DoTauntPeons();
- else
- IntroEvent_Timer -= diff;
- }
- }
-
- if (!UpdateVictim())
- return;
-
- if (!IsMainEvent)
- return;
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_SHADOW_FISSURE);
+ ShadowFissure_Timer = urand(7500, 15000);
+ }
+ else
+ ShadowFissure_Timer -= diff;
- if (Phase)
- {
- if (!SpinOnce)
- {
- DoCastVictim(SPELL_DARK_SPIN);
- SpinOnce = true;
- }
-
- if (Cleave_Timer <= diff)
- {
- DoCastVictim(SPELL_SHADOW_CLEAVE);
- Cleave_Timer = 6000 + rand32() % 2500;
- }
- else
- Cleave_Timer -= diff;
- }
- else
- {
- if (ShadowFissure_Timer <= diff)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- DoCast(target, SPELL_SHADOW_FISSURE);
- ShadowFissure_Timer = urand(7500, 15000);
- }
- else
- ShadowFissure_Timer -= diff;
-
- if (DeathCoil_Timer <= diff)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- DoCast(target, SPELL_DEATH_COIL);
- DeathCoil_Timer = urand(15000, 20000);
- }
- else
- DeathCoil_Timer -= diff;
-
- if (!HealthAbovePct(20))
- Phase = true;
-
- DoMeleeAttackIfReady();
- }
+ if (DeathCoil_Timer <= diff)
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_DEATH_COIL);
+ DeathCoil_Timer = urand(15000, 20000);
}
+ else
+ DeathCoil_Timer -= diff;
- private:
- uint32 PeonEngagedCount;
- uint32 PeonKilledCount;
- uint32 IntroEvent_Timer;
- uint32 DeathCoil_Timer;
- uint32 ShadowFissure_Timer;
- uint32 Cleave_Timer;
- bool IntroOnce;
- bool IsIntroEvent;
- bool IsMainEvent;
- bool SpinOnce;
- //bool HasTaunted;
- bool Phase;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetShatteredHallsAI<boss_grand_warlock_nethekurseAI>(creature);
+ if (!HealthAbovePct(20))
+ Phase = true;
+
+ DoMeleeAttackIfReady();
}
+ }
+
+ private:
+ uint32 PeonEngagedCount;
+ uint32 PeonKilledCount;
+ uint32 IntroEvent_Timer;
+ uint32 DeathCoil_Timer;
+ uint32 ShadowFissure_Timer;
+ uint32 Cleave_Timer;
+ bool IntroOnce;
+ bool IsIntroEvent;
+ bool IsMainEvent;
+ bool SpinOnce;
+ //bool HasTaunted;
+ bool Phase;
};
// ########################################################
// Fel Orc Convert
// ########################################################
-class npc_fel_orc_convert : public CreatureScript
+struct npc_fel_orc_convert : public ScriptedAI
{
- public:
- npc_fel_orc_convert() : CreatureScript("npc_fel_orc_convert") { }
-
- struct npc_fel_orc_convertAI : public ScriptedAI
- {
- npc_fel_orc_convertAI(Creature* creature) : ScriptedAI(creature)
- {
- instance = creature->GetInstanceScript();
- }
-
- void Reset() override
- {
- me->SetNoCallAssistance(true); //we don't want any assistance (WE R HEROZ!)
- }
+ npc_fel_orc_convert(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = creature->GetInstanceScript();
+ }
- void MoveInLineOfSight(Unit* /*who*/) override { }
+ void Reset() override
+ {
+ me->SetNoCallAssistance(true); //we don't want any assistance (WE R HEROZ!)
+ }
- void JustEngagedWith(Unit* /*who*/) override
- {
- events.ScheduleEvent(EVENT_HEMORRHAGE, 3s);
+ void MoveInLineOfSight(Unit* /*who*/) override { }
- if (Creature* Kurse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GRAND_WARLOCK_NETHEKURSE)))
- if (me->IsWithinDist(Kurse, 45.0f))
- Kurse->AI()->SetData(SETDATA_DATA, SETDATA_PEON_AGGRO);
- }
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ events.ScheduleEvent(EVENT_HEMORRHAGE, 3s);
- void JustDied(Unit* /*killer*/) override
- {
- if (instance->GetBossState(DATA_NETHEKURSE) != IN_PROGRESS)
- return;
+ if (Creature* Kurse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GRAND_WARLOCK_NETHEKURSE)))
+ if (me->IsWithinDist(Kurse, 45.0f))
+ Kurse->AI()->SetData(SETDATA_DATA, SETDATA_PEON_AGGRO);
+ }
- if (Creature* Kurse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GRAND_WARLOCK_NETHEKURSE)))
- Kurse->AI()->SetData(SETDATA_DATA, SETDATA_PEON_DEATH);
- }
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (instance->GetBossState(DATA_NETHEKURSE) != IN_PROGRESS)
+ return;
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ if (Creature* Kurse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GRAND_WARLOCK_NETHEKURSE)))
+ Kurse->AI()->SetData(SETDATA_DATA, SETDATA_PEON_DEATH);
+ }
- events.Update(diff);
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- if (events.ExecuteEvent() == EVENT_HEMORRHAGE)
- {
- DoCastVictim(SPELL_HEMORRHAGE);
- events.ScheduleEvent(EVENT_HEMORRHAGE, 15s);
- }
+ events.Update(diff);
- DoMeleeAttackIfReady();
- }
-
- private:
- InstanceScript* instance;
- EventMap events;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
+ if (events.ExecuteEvent() == EVENT_HEMORRHAGE)
{
- return GetShatteredHallsAI<npc_fel_orc_convertAI>(creature);
+ DoCastVictim(SPELL_HEMORRHAGE);
+ events.ScheduleEvent(EVENT_HEMORRHAGE, 15s);
}
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ InstanceScript* instance;
+ EventMap events;
};
// ########################################################
// Lesser Shadow Fissure
// ########################################################
-class npc_lesser_shadow_fissure : public CreatureScript
+struct npc_lesser_shadow_fissure : public ScriptedAI
{
- public:
- npc_lesser_shadow_fissure() : CreatureScript("npc_lesser_shadow_fissure") { }
+ npc_lesser_shadow_fissure(Creature* creature) : ScriptedAI(creature) { }
- struct npc_lesser_shadow_fissureAI : public ScriptedAI
- {
- npc_lesser_shadow_fissureAI(Creature* creature) : ScriptedAI(creature) { }
-
- void Reset() override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
- void AttackStart(Unit* /*who*/) override { }
- void JustEngagedWith(Unit* /*who*/) override { }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetShatteredHallsAI<npc_lesser_shadow_fissureAI>(creature);
- }
+ void Reset() override { }
+ void MoveInLineOfSight(Unit* /*who*/) override { }
+ void AttackStart(Unit* /*who*/) override { }
+ void JustEngagedWith(Unit* /*who*/) override { }
};
void AddSC_boss_grand_warlock_nethekurse()
{
- new boss_grand_warlock_nethekurse();
- new npc_fel_orc_convert();
- new npc_lesser_shadow_fissure();
+ RegisterShatteredHallsCreatureAI(boss_grand_warlock_nethekurse);
+ RegisterShatteredHallsCreatureAI(npc_fel_orc_convert);
+ RegisterShatteredHallsCreatureAI(npc_lesser_shadow_fissure);
}
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp
index bbd3f2c454d..bdf49566426 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp
@@ -15,441 +15,433 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Boss_Warbringer_Omrogg
-SD%Complete: 85
-SDComment: Heroic enabled. Spell timing may need additional tweaks
-SDCategory: Hellfire Citadel, Shattered Halls
-EndScriptData */
-
-/* ContentData
-npc_omrogg_heads
-boss_warbringer_omrogg
-EndContentData */
+/* Timers requires to be revisited */
#include "ScriptMgr.h"
#include "InstanceScript.h"
-#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
+#include "SpellInfo.h"
+#include "SpellMgr.h"
+#include "SpellScript.h"
#include "shattered_halls.h"
-enum Yells
+enum OmroggTexts
{
- YELL_DIE_L = 0,
- YELL_DIE_R = 1,
- EMOTE_ENRAGE = 2,
-};
+ EMOTE_ROAR = 0,
-enum Spells
-{
- SPELL_BLAST_WAVE = 30600,
- SPELL_FEAR = 30584,
- SPELL_THUNDERCLAP = 30633,
+ SAY_AGGRO_1 = 0,
+ SAY_AGGRO_1_1 = 0,
+ SAY_AGGRO_1_2 = 1,
- SPELL_BURNING_MAUL = 30598,
- H_SPELL_BURNING_MAUL = 36056,
-};
+ SAY_AGGRO_2 = 2,
+ SAY_AGGRO_2_1 = 1,
-enum Creatures
-{
- NPC_LEFT_HEAD = 19523,
- NPC_RIGHT_HEAD = 19524
-};
+ SAY_AGGRO_3 = 3,
+ SAY_AGGRO_3_1 = 2,
-enum SetData
-{
- SETDATA_DATA = 1,
- SETDATA_YELL = 1
-};
+ SAY_ATTACK_1 = 4,
+ SAY_ATTACK_1_1 = 3,
+ SAY_ATTACK_1_2 = 5,
-enum Events
-{
- // Omrogg Heads
- EVENT_DEATH_YELL = 1
-};
+ SAY_ATTACK_2 = 6,
+ SAY_ATTACK_2_1 = 4,
-struct Yell
-{
- int32 id;
- uint32 creature;
-};
+ SAY_ATTACK_3 = 7,
+ SAY_ATTACK_3_1 = 5,
+ SAY_ATTACK_3_2 = 8,
-static Yell GoCombat[]=
-{
- {0, NPC_LEFT_HEAD},
- {1, NPC_LEFT_HEAD},
- {2, NPC_LEFT_HEAD},
-};
+ SAY_ATTACK_4 = 6,
+ SAY_ATTACK_4_1 = 9,
+ SAY_ATTACK_4_2 = 7,
-static Yell GoCombatDelay[]=
-{
- {0, NPC_RIGHT_HEAD},
- {1, NPC_RIGHT_HEAD},
- {2, NPC_RIGHT_HEAD},
-};
+ SAY_SLAY_1 = 8,
-static Yell Threat[]=
-{
- {3, NPC_LEFT_HEAD},
- {3, NPC_RIGHT_HEAD},
- {4, NPC_LEFT_HEAD},
- {5, NPC_LEFT_HEAD},
+ SAY_SLAY_2 = 10,
+ SAY_SLAY_2_1 = 9,
+
+ SAY_DEATH_1 = 11,
+ SAY_DEATH_1_1 = 10
};
-static Yell ThreatDelay1[]=
+enum OmroggSpells
{
- {4, NPC_RIGHT_HEAD},
- {6, NPC_LEFT_HEAD},
- {5, NPC_RIGHT_HEAD},
- {6, NPC_RIGHT_HEAD},
+ SPELL_FEAR = 30584,
+ SPELL_THUNDERCLAP = 30633,
+ SPELL_BEATDOWN = 30618,
+ SPELL_BURNING_MAUL = 30598, // Triggers 30620, what it does? (no, it doesn't trigger 30600)
+
+ SPELL_BLAST_WAVE = 30600
};
-static Yell ThreatDelay2[]=
+enum OmroggEvents
{
- {7, NPC_LEFT_HEAD},
- {7, NPC_RIGHT_HEAD},
- {8, NPC_LEFT_HEAD},
- {9, NPC_LEFT_HEAD},
+ EVENT_FEAR = 1,
+ EVENT_THUNDERCLAP,
+ EVENT_BEATDOWN,
+ EVENT_BURNING_MAUL
};
-static Yell Killing[]=
+enum OmroggActions
{
- {10, NPC_LEFT_HEAD},
- {8, NPC_RIGHT_HEAD},
+ ACTION_AGGRO_1 = 1,
+ ACTION_AGGRO_2 = 2,
+ ACTION_AGGRO_3 = 3,
+ ACTION_ATTACK_1 = 4,
+ ACTION_ATTACK_2 = 5,
+ ACTION_ATTACK_3 = 6,
+ ACTION_ATTACK_4 = 7,
+ ACTION_SLAY_1 = 8,
+ ACTION_SLAY_2 = 9,
+ ACTION_DEATH = 10
};
-static Yell KillingDelay[]=
+enum OmroggEquips
{
- {9, NPC_RIGHT_HEAD},
- {11, NPC_LEFT_HEAD},
+ EQUIP_ID_BURNING_MAUL = 2
};
-// ########################################################
-// Warbringer_Omrogg
-// ########################################################
-
-class boss_warbringer_omrogg : public CreatureScript
+// 16809 - Warbringer O'mrogg
+struct boss_warbringer_omrogg : public BossAI
{
- public:
- boss_warbringer_omrogg() : CreatureScript("boss_warbringer_omrogg") { }
-
- struct boss_warbringer_omroggAI : public BossAI
+ boss_warbringer_omrogg(Creature* creature) : BossAI(creature, DATA_OMROGG) { }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ events.ScheduleEvent(EVENT_FEAR, 20s, 30s);
+ events.ScheduleEvent(EVENT_THUNDERCLAP, 15s, 25s);
+ events.ScheduleEvent(EVENT_BEATDOWN, 25s, 30s);
+ events.ScheduleEvent(EVENT_BURNING_MAUL, 50s, 60s);
+
+ if (Creature* leftHead = instance->GetCreature(DATA_LEFT_HEAD))
+ leftHead->AI()->DoAction(RAND(ACTION_AGGRO_1, ACTION_AGGRO_2, ACTION_AGGRO_3));
+ }
+
+ void OnSpellCast(SpellInfo const* spell) override
+ {
+ /// @todo: Threat reset and AttackStart should be in spell script
+ if (spell->Id == SPELL_BEATDOWN)
{
- boss_warbringer_omroggAI(Creature* creature) : BossAI(creature, DATA_OMROGG)
- {
- Initialize();
- iaggro = 0;
- ithreat = 0;
- ikilling = 0;
- }
-
- void Initialize()
- {
- AggroYell = false;
- ThreatYell = false;
- ThreatYell2 = false;
- KillingYell = false;
-
- Delay_Timer = 4000;
- BlastWave_Timer = 0;
- BlastCount = 0;
- Fear_Timer = 8000;
- BurningMaul_Timer = 25000;
- ThunderClap_Timer = 15000;
- ResetThreat_Timer = 30000;
- }
+ ResetThreatList();
- void Reset() override
- {
- _Reset();
- if (Unit* LeftHead = ObjectAccessor::GetUnit(*me, LeftHeadGUID))
- {
- LeftHead->setDeathState(JUST_DIED);
- LeftHeadGUID.Clear();
- }
-
- if (Unit* RightHead = ObjectAccessor::GetUnit(*me, RightHeadGUID))
- {
- RightHead->setDeathState(JUST_DIED);
- RightHeadGUID.Clear();
- }
-
- Initialize();
-
- instance->SetData(DATA_OMROGG, NOT_STARTED); //End boss can use this later. O'mrogg must be defeated(DONE) or he will come to aid.
- }
-
- void DoYellForThreat()
- {
- Creature* LeftHead = ObjectAccessor::GetCreature(*me, LeftHeadGUID);
- Creature* RightHead = ObjectAccessor::GetCreature(*me, RightHeadGUID);
-
- if (!LeftHead || !RightHead)
- return;
-
- ithreat = rand32() % 4;
-
- Creature* source = (LeftHead->GetEntry() == Threat[ithreat].creature ? LeftHead : RightHead);
-
- source->AI()->Talk(Threat[ithreat].id);
-
- Delay_Timer = 3500;
- ThreatYell = true;
- }
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ AttackStart(target);
- void JustEngagedWith(Unit* /*who*/) override
- {
- me->SummonCreature(NPC_LEFT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN);
- me->SummonCreature(NPC_RIGHT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN);
+ // Apparently this and all other are handled by GameEvents since this spell sends GameEvent
+ if (Creature* leftHead = instance->GetCreature(DATA_LEFT_HEAD))
+ leftHead->AI()->DoAction(RAND(ACTION_ATTACK_1, ACTION_ATTACK_2, ACTION_ATTACK_3, ACTION_ATTACK_4));
+ }
- if (Creature* LeftHead = ObjectAccessor::GetCreature(*me, LeftHeadGUID))
- {
- iaggro = rand32() % 3;
+ if (spell->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_BURNING_MAUL, me))
+ Talk(EMOTE_ROAR);
+ }
- LeftHead->AI()->Talk(GoCombat[iaggro].id);
+ void KilledUnit(Unit* /*victim*/) override
+ {
+ if (Creature* leftHead = instance->GetCreature(DATA_LEFT_HEAD))
+ leftHead->AI()->DoAction(RAND(ACTION_SLAY_1, ACTION_SLAY_2));
+ }
- Delay_Timer = 3500;
- AggroYell = true;
- }
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
- instance->SetBossState(DATA_OMROGG, IN_PROGRESS);
- }
+ if (Creature* leftHead = instance->GetCreature(DATA_LEFT_HEAD))
+ leftHead->AI()->DoAction(ACTION_DEATH);
+ }
- void JustSummoned(Creature* summoned) override
- {
- if (summoned->GetEntry() == NPC_LEFT_HEAD)
- LeftHeadGUID = summoned->GetGUID();
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- if (summoned->GetEntry() == NPC_RIGHT_HEAD)
- RightHeadGUID = summoned->GetGUID();
+ events.Update(diff);
- //summoned->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- //summoned->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
- summoned->SetVisible(false);
- }
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- void KilledUnit(Unit* /*victim*/) override
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
{
- Creature* LeftHead = ObjectAccessor::GetCreature(*me, LeftHeadGUID);
- Creature* RightHead = ObjectAccessor::GetCreature(*me, RightHeadGUID);
-
- if (!LeftHead || !RightHead)
- return;
-
- ikilling = rand32() % 2;
-
- Creature* source = (LeftHead->GetEntry() == Killing[ikilling].creature ? LeftHead : RightHead);
-
- switch (ikilling)
- {
- case 0:
- source->AI()->Talk(Killing[ikilling].id);
- Delay_Timer = 3500;
- KillingYell = true;
- break;
- case 1:
- source->AI()->Talk(Killing[ikilling].id);
- KillingYell = false;
- break;
- }
+ case EVENT_FEAR:
+ DoCastSelf(SPELL_FEAR);
+ events.Repeat(15s, 35s);
+ break;
+ case EVENT_THUNDERCLAP:
+ DoCastSelf(SPELL_THUNDERCLAP);
+ events.Repeat(15s, 30s);
+ break;
+ case EVENT_BEATDOWN:
+ DoCastSelf(SPELL_BEATDOWN);
+ events.Repeat(25s, 40s);
+ break;
+ case EVENT_BURNING_MAUL:
+ DoCastSelf(SPELL_BURNING_MAUL);
+ events.Repeat(60s, 70s);
+ break;
+ default:
+ break;
}
- void JustDied(Unit* /*killer*/) override
- {
- Creature* LeftHead = ObjectAccessor::GetCreature(*me, LeftHeadGUID);
- Creature* RightHead = ObjectAccessor::GetCreature(*me, RightHeadGUID);
-
- _JustDied();
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
- if (!LeftHead || !RightHead)
- return;
+ DoMeleeAttackIfReady();
+ }
+};
- LeftHead->AI()->Talk(YELL_DIE_L);
+// 19523 - O'mrogg's Left Head
+// 19524 - O'mrogg's Right Head
+struct npc_omrogg_heads : public ScriptedAI
+{
+ npc_omrogg_heads(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
- RightHead->AI()->SetData(SETDATA_DATA, SETDATA_YELL);
- }
+ void RightHeadTalk(uint32 text)
+ {
+ if (Creature* rightHead = _instance->GetCreature(DATA_RIGHT_HEAD))
+ rightHead->AI()->Talk(text);
+ }
- void UpdateAI(uint32 diff) override
- {
- if (Delay_Timer <= diff)
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_AGGRO_1:
+ _scheduler.Schedule(0s, [this](TaskContext task)
{
- Delay_Timer = 3500;
-
- Creature* LeftHead = ObjectAccessor::GetCreature(*me, LeftHeadGUID);
- Creature* RightHead = ObjectAccessor::GetCreature(*me, RightHeadGUID);
-
- if (!LeftHead || !RightHead)
- return;
-
- if (AggroYell)
+ switch (task.GetRepeatCounter())
{
- RightHead->AI()->Talk(GoCombatDelay[iaggro].id);
- AggroYell = false;
+ case 0:
+ Talk(SAY_AGGRO_1);
+ task.Repeat(3s);
+ break;
+ case 1:
+ RightHeadTalk(SAY_AGGRO_1_1);
+ task.Repeat(3s);
+ break;
+ case 2:
+ Talk(SAY_AGGRO_1_2);
+ break;
+ default:
+ break;
}
-
- if (ThreatYell2)
+ });
+ break;
+ case ACTION_AGGRO_2:
+ _scheduler.Schedule(0s, [this](TaskContext task)
+ {
+ switch (task.GetRepeatCounter())
{
- Creature* source = (LeftHead->GetEntry() == ThreatDelay2[ithreat].creature ? LeftHead : RightHead);
-
- source->AI()->Talk(ThreatDelay2[ithreat].id);
- ThreatYell2 = false;
+ case 0:
+ Talk(SAY_AGGRO_2);
+ task.Repeat(3s);
+ break;
+ case 1:
+ RightHeadTalk(SAY_AGGRO_2_1);
+ break;
+ default:
+ break;
}
-
- if (ThreatYell)
+ });
+ break;
+ case ACTION_AGGRO_3:
+ _scheduler.Schedule(0s, [this](TaskContext task)
+ {
+ switch (task.GetRepeatCounter())
{
- Creature* source = (LeftHead->GetEntry() == ThreatDelay1[ithreat].creature ? LeftHead : RightHead);
-
- source->AI()->Talk(ThreatDelay1[ithreat].id);
- ThreatYell = false;
- ThreatYell2 = true;
+ case 0:
+ Talk(SAY_AGGRO_3);
+ task.Repeat(3s);
+ break;
+ case 1:
+ RightHeadTalk(SAY_AGGRO_3_1);
+ break;
+ default:
+ break;
}
-
- if (KillingYell)
+ });
+ break;
+ case ACTION_ATTACK_1:
+ _scheduler.Schedule(0s, [this](TaskContext task)
+ {
+ switch (task.GetRepeatCounter())
{
- Creature* source = (LeftHead->GetEntry() == KillingDelay[ikilling].creature ? LeftHead : RightHead);
-
- source->AI()->Talk(KillingDelay[ikilling].id);
- KillingYell = false;
+ case 0:
+ Talk(SAY_ATTACK_1);
+ task.Repeat(3s);
+ break;
+ case 1:
+ RightHeadTalk(SAY_ATTACK_1_1);
+ task.Repeat(3s);
+ break;
+ case 2:
+ Talk(SAY_ATTACK_1_2);
+ break;
+ default:
+ break;
}
- } else Delay_Timer -= diff;
-
- if (!UpdateVictim())
- return;
-
- if (BlastCount && BlastWave_Timer <= diff)
+ });
+ break;
+ case ACTION_ATTACK_2:
+ _scheduler.Schedule(0s, [this](TaskContext task)
{
- DoCast(me, SPELL_BLAST_WAVE);
- BlastWave_Timer = 5000;
- ++BlastCount;
-
- if (BlastCount == 3)
- BlastCount = 0;
- }
- else
- BlastWave_Timer -= diff;
-
- if (BurningMaul_Timer <= diff)
+ switch (task.GetRepeatCounter())
+ {
+ case 0:
+ Talk(SAY_ATTACK_2);
+ task.Repeat(3s);
+ break;
+ case 1:
+ RightHeadTalk(SAY_ATTACK_2_1);
+ break;
+ default:
+ break;
+ }
+ });
+ break;
+ case ACTION_ATTACK_3:
+ _scheduler.Schedule(0s, [this](TaskContext task)
{
- Talk(EMOTE_ENRAGE);
- DoCast(me, SPELL_BURNING_MAUL);
- BurningMaul_Timer = 40000;
- BlastWave_Timer = 16000;
- BlastCount = 1;
- }
- else
- BurningMaul_Timer -= diff;
-
- if (ResetThreat_Timer <= diff)
+ switch (task.GetRepeatCounter())
+ {
+ case 0:
+ Talk(SAY_ATTACK_3);
+ task.Repeat(3s);
+ break;
+ case 1:
+ RightHeadTalk(SAY_ATTACK_3_1);
+ task.Repeat(3s);
+ break;
+ case 2:
+ Talk(SAY_ATTACK_3_2);
+ break;
+ default:
+ break;
+ }
+ });
+ break;
+ case ACTION_ATTACK_4:
+ _scheduler.Schedule(0s, [this](TaskContext task)
{
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ switch (task.GetRepeatCounter())
{
- DoYellForThreat();
- ResetThreatList();
- AddThreat(target, 0.0f);
+ case 0:
+ RightHeadTalk(SAY_ATTACK_4);
+ task.Repeat(2s);
+ break;
+ case 1:
+ Talk(SAY_ATTACK_4_1);
+ task.Repeat(2s);
+ break;
+ case 2:
+ RightHeadTalk(SAY_ATTACK_4_2);
+ break;
+ default:
+ break;
}
- ResetThreat_Timer = 25000 + rand32() % 15000;
- }
- else
- ResetThreat_Timer -= diff;
-
- if (Fear_Timer <= diff)
+ });
+ break;
+ case ACTION_SLAY_1:
+ _scheduler.Schedule(0s, [this](TaskContext /*task*/)
{
- DoCast(me, SPELL_FEAR);
- Fear_Timer = 15000 + rand32() % 20000;
- }
- else
- Fear_Timer -= diff;
-
- if (ThunderClap_Timer <= diff)
+ RightHeadTalk(SAY_SLAY_1);
+ });
+ break;
+ case ACTION_SLAY_2:
+ _scheduler.Schedule(0s, [this](TaskContext task)
{
- DoCast(me, SPELL_THUNDERCLAP);
- ThunderClap_Timer = 15000 + rand32() % 15000;
- }
- else
- ThunderClap_Timer -= diff;
+ switch (task.GetRepeatCounter())
+ {
+ case 0:
+ Talk(SAY_SLAY_2);
+ task.Repeat(3s);
+ break;
+ case 1:
+ RightHeadTalk(SAY_SLAY_2_1);
+ break;
+ default:
+ break;
+ }
+ });
+ break;
+ case ACTION_DEATH:
+ _scheduler.Schedule(0s, [this](TaskContext task)
+ {
+ switch (task.GetRepeatCounter())
+ {
+ case 0:
+ Talk(SAY_DEATH_1);
+ task.Repeat(3s);
+ break;
+ case 1:
+ RightHeadTalk(SAY_DEATH_1_1);
+ me->DespawnOrUnsummon(4s);
+ if (Creature* rightHead = _instance->GetCreature(DATA_RIGHT_HEAD))
+ rightHead->DespawnOrUnsummon(4s);
+ break;
+ default:
+ break;
+ }
+ });
+ break;
+ default:
+ break;
+ }
+ }
- DoMeleeAttackIfReady();
- }
+ void UpdateAI(uint32 diff) override
+ {
+ _scheduler.Update(diff);
+ }
- private:
- ObjectGuid LeftHeadGUID;
- ObjectGuid RightHeadGUID;
- int iaggro;
- int ithreat;
- int ikilling;
-
- bool AggroYell;
- bool ThreatYell;
- bool ThreatYell2;
- bool KillingYell;
-
- uint32 Delay_Timer;
- uint32 BlastWave_Timer;
- uint32 BlastCount;
- uint32 Fear_Timer;
- uint32 BurningMaul_Timer;
- uint32 ThunderClap_Timer;
- uint32 ResetThreat_Timer;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetShatteredHallsAI<boss_warbringer_omroggAI>(creature);
- }
+private:
+ TaskScheduler _scheduler;
+ InstanceScript* _instance;
};
-// ########################################################
-// Omrogg Heads
-// ########################################################
-
-class npc_omrogg_heads : public CreatureScript
+/// @todo: This requires additional research. Is it handled correctly? Isn't it too over-powered?
+// That's a lot of damage if all melee attacks are successful so we cast it not always for now. No ProcCategoryRecovery for both spells
+// 30598, 36056 - Burning Maul
+class spell_omrogg_burning_maul : public AuraScript
{
- public:
- npc_omrogg_heads() : CreatureScript("npc_omrogg_heads") { }
-
- struct npc_omrogg_headsAI : public ScriptedAI
- {
- npc_omrogg_headsAI(Creature* creature) : ScriptedAI(creature)
- {
- instance = creature->GetInstanceScript();
- }
-
- void Reset() override { }
-
- void JustEngagedWith(Unit* /*who*/) override { }
-
- void SetData(uint32 data, uint32 value) override
- {
- if (data == SETDATA_DATA && value == SETDATA_YELL)
- {
- events.ScheduleEvent(EVENT_DEATH_YELL, 4s);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- events.Update(diff);
-
- if (events.ExecuteEvent() == EVENT_DEATH_YELL)
- {
- Talk(YELL_DIE_R);
- me->setDeathState(JUST_DIED);
- }
- }
-
- private:
- InstanceScript* instance;
- EventMap events;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetShatteredHallsAI<npc_omrogg_headsAI>(creature);
- }
+ PrepareAuraScript(spell_omrogg_burning_maul);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_BLAST_WAVE });
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Creature* creature = GetTarget()->ToCreature())
+ creature->LoadEquipment(EQUIP_ID_BURNING_MAUL);
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Creature* creature = GetTarget()->ToCreature())
+ creature->LoadEquipment(creature->GetOriginalEquipmentId());
+ }
+
+ void OnProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ if (roll_chance_i(50))
+ GetTarget()->CastSpell(GetTarget(), SPELL_BLAST_WAVE);
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_omrogg_burning_maul::OnApply, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
+ OnEffectRemove += AuraEffectRemoveFn(spell_omrogg_burning_maul::OnRemove, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
+ OnEffectProc += AuraEffectProcFn(spell_omrogg_burning_maul::OnProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
};
void AddSC_boss_warbringer_omrogg()
{
- new boss_warbringer_omrogg();
- new npc_omrogg_heads();
+ RegisterShatteredHallsCreatureAI(boss_warbringer_omrogg);
+ RegisterShatteredHallsCreatureAI(npc_omrogg_heads);
+ RegisterSpellScript(spell_omrogg_burning_maul);
}
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 eced2630e10..dc8e59b54f5 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
@@ -15,329 +15,255 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Boss_Warchief_Kargath_Bladefist
-SD%Complete: 90
-SDComment:
-SDCategory: Hellfire Citadel, Shattered Halls
-EndScriptData */
-
-/* ContentData
-boss_warchief_kargath_bladefist
-EndContentData */
+/* Blade Dance implementation requires recheck. Apparently SPELL_BLADE_DANCE_CHARGE can miss, as result handling half of Blade Dance sequence
+ in SpellHitTarget will stop sequence */
#include "ScriptMgr.h"
+#include "Containers.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
+#include "SpellInfo.h"
#include "shattered_halls.h"
-enum Says
+enum KargathTexts
{
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2,
SAY_CALL_EXECUTIONER_A = 3,
- SAY_CALL_EXECUTIONER_H = 4
+ SAY_CALL_EXECUTIONER_H = 4,
+
+ SAY_LEASH = 5
};
-enum Spells
+enum KargathSpells
{
- SPELL_BLADE_DANCE = 30739,
- H_SPELL_CHARGE = 25821
+ // Kargath
+ SPELL_BLADE_DANCE_TARGETING = 30738,
+ SPELL_BLADE_DANCE = 30739,
+ SPELL_BLADE_DANCE_CHARGE = 30751,
+ SPELL_CHARGE_H = 25821,
+
+ // Warchief's Portal
+ SPELL_SUMMON_HEATHEN = 30737,
+ SPELL_SUMMON_REAVER = 30785,
+ SPELL_SUMMON_SHARPSHOOTER = 30786
};
-enum Creatures
+enum KargathEvents
{
- NPC_SHATTERED_ASSASSIN = 17695,
- NPC_HEARTHEN_GUARD = 17621,
- NPC_SHARPSHOOTER_GUARD = 17622,
- NPC_REAVER_GUARD = 17623
+ EVENT_BLADE_DANCE = 1,
+ EVENT_CHARGE_H,
+ EVENT_SUMMON_PORTAL,
+ EVENT_SUMMON_ASSASSINS,
+ EVENT_LEASH
};
-#define TARGET_NUM 5
-
-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 };
-
-class boss_warchief_kargath_bladefist : public CreatureScript
+enum KargathMisc
{
- public:
- boss_warchief_kargath_bladefist() : CreatureScript("boss_warchief_kargath_bladefist") { }
+ NPC_SHATTERED_ASSASSIN = 17695,
+ MAX_BLADE_DANCE_COUNT = 8,
+ SUMMON_GROUP_PORTAL = 0,
+ SUMMON_GROUP_ASSASSINS = 1
+};
- struct boss_warchief_kargath_bladefistAI : public BossAI
+// 16808 - Warchief Kargath Bladefist
+struct boss_warchief_kargath_bladefist : public BossAI
+{
+ boss_warchief_kargath_bladefist(Creature* creature) : BossAI(creature, DATA_KARGATH), _bladeDanceCount(0) { }
+
+ void Reset() override
+ {
+ _Reset();
+ _bladeDanceTargets.clear();
+ _bladeDanceTargetGUID.Clear();
+ _bladeDanceCount = 0;
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ Talk(SAY_AGGRO);
+ BossAI::JustEngagedWith(who);
+ events.ScheduleEvent(EVENT_BLADE_DANCE, 30s, 35s);
+ events.ScheduleEvent(EVENT_SUMMON_PORTAL, 1s);
+ events.ScheduleEvent(EVENT_SUMMON_ASSASSINS, 3s);
+ events.ScheduleEvent(EVENT_LEASH, 1s);
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_EXECUTIONER_TAUNT)
{
- boss_warchief_kargath_bladefistAI(Creature* creature) : BossAI(creature, DATA_KARGATH)
- {
- Initialize();
- target_num = 0;
- }
-
- void Initialize()
+ switch (instance->GetData(DATA_TEAM_IN_INSTANCE))
{
- summoned = 2;
- InBlade = false;
- Wait_Timer = 0;
-
- Charge_timer = 0;
- Blade_Dance_Timer = 45000;
- Summon_Assistant_Timer = 30000;
- Assassins_Timer = 5000;
- resetcheck_timer = 5000;
+ case ALLIANCE:
+ Talk(SAY_CALL_EXECUTIONER_A);
+ break;
+ case HORDE:
+ Talk(SAY_CALL_EXECUTIONER_H);
+ break;
+ default:
+ break;
}
-
- void DoAction(int32 action) override
+ }
+ }
+
+ void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_BLADE_DANCE_TARGETING)
+ _bladeDanceTargets.push_back(target->GetGUID());
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ if (summon->GetEntry() == NPC_SHATTERED_ASSASSIN)
+ summon->GetMotionMaster()->MoveRandom(5.0f);
+
+ // Allow despawn but do not engage all summons (assassins shouldn't be engaged)
+ summons.Summon(summon);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_DEATH);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
{
- if (action == ACTION_EXECUTIONER_TAUNT)
+ case EVENT_BLADE_DANCE:
{
- switch (instance->GetData(DATA_TEAM_IN_INSTANCE))
+ if (_bladeDanceCount < MAX_BLADE_DANCE_COUNT)
{
- case ALLIANCE:
- Talk(SAY_CALL_EXECUTIONER_A);
- break;
- case HORDE:
- Talk(SAY_CALL_EXECUTIONER_H);
- break;
- default:
- break;
- }
- }
- }
-
- void Reset() override
- {
- removeAdds();
- _Reset();
- me->SetSpeedRate(MOVE_RUN, 2);
- me->SetWalk(false);
-
- Initialize();
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- _JustDied();
- Talk(SAY_DEATH);
- removeAdds();
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
- }
-
- void JustSummoned(Creature* summon) override
- {
- switch (summon->GetEntry())
- {
- case NPC_HEARTHEN_GUARD:
- case NPC_SHARPSHOOTER_GUARD:
- case NPC_REAVER_GUARD:
- summon->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random, 0));
- adds.push_back(summon->GetGUID());
- break;
- case NPC_SHATTERED_ASSASSIN:
- assassins.push_back(summon->GetGUID());
- break;
- }
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (victim->GetTypeId() == TYPEID_PLAYER)
- {
- Talk(SAY_SLAY);
- }
- }
+ _bladeDanceTargets.clear();
- void MovementInform(uint32 type, uint32 id) override
- {
- if (InBlade)
- {
- if (type != POINT_MOTION_TYPE)
- return;
+ DoCastSelf(SPELL_BLADE_DANCE_TARGETING);
- if (id != 1)
- return;
-
- if (target_num > 0) // to prevent loops
- {
- Wait_Timer = 1;
- DoCast(me, SPELL_BLADE_DANCE, true);
- target_num--;
- }
- }
- }
+ if (!_bladeDanceTargets.empty())
+ {
+ _bladeDanceTargetGUID.Clear();
- void removeAdds()
- {
- for (GuidVector::const_iterator itr = adds.begin(); itr!= adds.end(); ++itr)
- {
- Creature* creature = ObjectAccessor::GetCreature(*me, *itr);
- if (creature && creature->IsAlive())
- creature->DespawnOrUnsummon();
- }
- adds.clear();
+ _bladeDanceTargetGUID = Trinity::Containers::SelectRandomContainerElement(_bladeDanceTargets);
- for (GuidVector::const_iterator itr = assassins.begin(); itr!= assassins.end(); ++itr)
- {
- Creature* creature = ObjectAccessor::GetCreature(*me, *itr);
- if (creature && creature->IsAlive())
- creature->DespawnOrUnsummon();
- }
- assassins.clear();
- }
- void SpawnAssassin()
- {
- me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1]+8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30s);
- me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1]-8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30s);
- me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1]+8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30s);
- me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1]-8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30s);
- }
+ Creature* target = ObjectAccessor::GetCreature(*me, _bladeDanceTargetGUID);
+ if (target)
+ DoCast(target, SPELL_BLADE_DANCE_CHARGE);
- void UpdateAI(uint32 diff) override
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
+ DoCastSelf(SPELL_BLADE_DANCE);
+ }
- if (Assassins_Timer)
- {
- if (Assassins_Timer <= diff)
- {
- SpawnAssassin();
- Assassins_Timer = 0;
+ events.ScheduleEvent(EVENT_BLADE_DANCE, 500ms);
+ ++_bladeDanceCount;
}
else
- Assassins_Timer -= diff;
- }
-
- if (InBlade)
- {
- if (Wait_Timer)
{
- if (Wait_Timer <= diff)
- {
- if (target_num <= 0)
- {
- // stop bladedance
- InBlade = false;
- me->SetSpeedRate(MOVE_RUN, 2);
- me->GetMotionMaster()->MoveChase(me->GetVictim());
- Blade_Dance_Timer = 30000;
- Wait_Timer = 0;
- if (IsHeroic())
- Charge_timer = 5000;
- }
- else
- {
- //move in bladedance
- float x, y, randx, randy;
- randx = 0.0f + rand32() % 40;
- randy = 0.0f + rand32() % 40;
- x = 210+ randx;
- y = -60- randy;
- me->GetMotionMaster()->MovePoint(1, x, y, me->GetPositionZ());
- Wait_Timer = 0;
- }
- }
- else
- Wait_Timer -= diff;
+ if (IsHeroic())
+ events.ScheduleEvent(EVENT_CHARGE_H, 500ms);
+ events.ScheduleEvent(EVENT_BLADE_DANCE, 45s, 50s);
+ _bladeDanceCount = 0;
}
+ break;
}
- else
- {
- if (Blade_Dance_Timer)
+ case EVENT_CHARGE_H:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_CHARGE_H);
+ break;
+ case EVENT_SUMMON_PORTAL:
+ me->SummonCreatureGroup(SUMMON_GROUP_PORTAL);
+ break;
+ case EVENT_SUMMON_ASSASSINS:
+ me->SummonCreatureGroup(SUMMON_GROUP_ASSASSINS);
+ break;
+ case EVENT_LEASH:
+ // He CAN evade during Blade Dance on retail, however with this distance he will not
+ if (me->GetDistance(me->GetHomePosition()) > 40.0f)
{
- if (Blade_Dance_Timer <= diff)
- {
- target_num = TARGET_NUM;
- Wait_Timer = 1;
- InBlade = true;
- Blade_Dance_Timer = 0;
- me->SetSpeedRate(MOVE_RUN, 4);
- return;
- }
- else
- Blade_Dance_Timer -= diff;
+ Talk(SAY_LEASH);
+ EnterEvadeMode(EVADE_REASON_BOUNDARY);
}
+ events.Repeat(1s);
+ break;
+ default:
+ break;
+ }
+ }
- if (Charge_timer)
- {
- if (Charge_timer <= diff)
- {
- DoCast(SelectTarget(SelectTargetMethod::Random, 0), H_SPELL_CHARGE);
- Charge_timer = 0;
- }
- else
- Charge_timer -= diff;
- }
+ DoMeleeAttackIfReady();
+ }
- if (Summon_Assistant_Timer <= diff)
- {
- for (uint8 i = 0; i < summoned; ++i)
- {
- switch (urand(0, 2))
- {
- case 0:
- me->SummonCreature(NPC_HEARTHEN_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30s);
- break;
- case 1:
- me->SummonCreature(NPC_SHARPSHOOTER_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30s);
- break;
- case 2:
- me->SummonCreature(NPC_REAVER_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30s);
- break;
- }
- }
- if (urand(0, 9) < 2)
- ++summoned;
- Summon_Assistant_Timer = urand(25000, 35000);
- }
- else
- Summon_Assistant_Timer -= diff;
+private:
+ GuidList _bladeDanceTargets;
+ ObjectGuid _bladeDanceTargetGUID;
+ uint8 _bladeDanceCount;
+};
- DoMeleeAttackIfReady();
- }
+// 17611 - Warchief's Portal
+struct npc_warchiefs_portal : public ScriptedAI
+{
+ npc_warchiefs_portal(Creature* creature) : ScriptedAI(creature), _summonCount(0), _instance(creature->GetInstanceScript()) { }
- if (resetcheck_timer <= diff)
- {
- uint32 tempx = uint32(me->GetPositionX());
- if (tempx > 255 || tempx < 205)
- {
- EnterEvadeMode();
- return;
- }
- resetcheck_timer = 5000;
- }
- else
- resetcheck_timer -= diff;
- }
+ void JustAppeared() override
+ {
+ _summonCount = 1;
- private:
- GuidVector adds;
- GuidVector assassins;
- uint32 Charge_timer;
- uint32 Blade_Dance_Timer;
- uint32 Summon_Assistant_Timer;
- uint32 resetcheck_timer;
- uint32 Wait_Timer;
- uint32 Assassins_Timer;
- uint32 summoned;
- uint32 target_num;
- bool InBlade;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
+ _scheduler.Schedule(20s, [this](TaskContext task)
{
- return GetShatteredHallsAI<boss_warchief_kargath_bladefistAI>(creature);
- }
+ switch (_summonCount)
+ {
+ // In this exact order and repeat again
+ case 1: DoCastSelf(SPELL_SUMMON_HEATHEN); break;
+ case 2: DoCastSelf(SPELL_SUMMON_REAVER); break;
+ case 3: DoCastSelf(SPELL_SUMMON_SHARPSHOOTER); break;
+ default: break;
+ }
+
+ if (_summonCount >= 3)
+ _summonCount = 1;
+ else
+ ++_summonCount;
+
+ task.Repeat(20s);
+ });
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ // Not correct to despawn them after encounter is finished, originally they become passive and start path and despawn on reaching last waypoint
+ if (Creature* kargath = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(NPC_KARGATH_BLADEFIST)))
+ kargath->AI()->JustSummoned(summon);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _scheduler.Update(diff);
+ }
+
+private:
+ uint8 _summonCount;
+ TaskScheduler _scheduler;
+ InstanceScript* _instance;
};
void AddSC_boss_warchief_kargath_bladefist()
{
- new boss_warchief_kargath_bladefist();
+ RegisterShatteredHallsCreatureAI(boss_warchief_kargath_bladefist);
+ RegisterShatteredHallsCreatureAI(npc_warchiefs_portal);
}
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 03e6547c3cf..13c990eeb34 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
@@ -40,6 +40,13 @@ DoorData const doorData[] =
{ 0, 0, DOOR_TYPE_ROOM }
};
+ObjectData const creatureData[] =
+{
+ { NPC_LEFT_HEAD, DATA_LEFT_HEAD },
+ { NPC_RIGHT_HEAD, DATA_RIGHT_HEAD },
+ { 0, 0 } // END
+};
+
class instance_shattered_halls : public InstanceMapScript
{
public:
@@ -57,6 +64,7 @@ class instance_shattered_halls : public InstanceMapScript
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
+ LoadObjectData(creatureData, nullptr);
executionTimer = 0;
executed = 0;
_team = 0;
@@ -95,6 +103,8 @@ class instance_shattered_halls : public InstanceMapScript
void OnCreatureCreate(Creature* creature) override
{
+ InstanceScript::OnCreatureCreate(creature);
+
if (!_team)
{
Map::PlayerList const& players = instance->GetPlayers();
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
index e1da5cc09bd..084f43cbe95 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
@@ -65,199 +65,166 @@ enum Spells
SPELL_CLEAVE = 15284
};
-class boss_shattered_executioner : public CreatureScript
+struct boss_shattered_executioner : public BossAI
{
- public:
- boss_shattered_executioner() : CreatureScript("boss_shattered_executioner") { }
-
- struct boss_shattered_executionerAI : public BossAI
+ boss_shattered_executioner(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER)
+ {
+ Initialize();
+ };
+
+ void Initialize()
+ {
+ cleaveTimer = 500;
+ }
+
+ void Reset() override
+ {
+ _Reset();
+
+ // _Reset() resets the loot mode, so we add them again, if any
+ uint32 prisonersExecuted = instance->GetData(DATA_PRISONERS_EXECUTED);
+ if (prisonersExecuted == 0)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_3);
+ if (prisonersExecuted <= 1)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_2);
+ if (prisonersExecuted <= 2)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_1);
+
+ if (instance->GetBossState(DATA_KARGATH) == DONE)
+ me->SetImmuneToPC(false);
+ else
+ me->SetImmuneToPC(true);
+
+ Initialize();
+ }
+
+ void JustSummoned(Creature*) override { } // avoid despawn of prisoners on death/reset
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+
+ if (instance->GetData(DATA_PRISONERS_EXECUTED) > 0)
+ return;
+
+ Map::PlayerList const& players = instance->instance->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{
- boss_shattered_executionerAI(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER)
- {
- Initialize();
- };
-
- void Initialize()
- {
- cleaveTimer = 500;
- }
-
- void Reset() override
- {
- _Reset();
-
- // _Reset() resets the loot mode, so we add them again, if any
- uint32 prisonersExecuted = instance->GetData(DATA_PRISONERS_EXECUTED);
- if (prisonersExecuted == 0)
- me->AddLootMode(LOOT_MODE_HARD_MODE_3);
- if (prisonersExecuted <= 1)
- me->AddLootMode(LOOT_MODE_HARD_MODE_2);
- if (prisonersExecuted <= 2)
- me->AddLootMode(LOOT_MODE_HARD_MODE_1);
-
- if (instance->GetBossState(DATA_KARGATH) == DONE)
- me->SetImmuneToPC(false);
- else
- me->SetImmuneToPC(true);
-
- Initialize();
- }
+ Player* pl = itr->GetSource();
+ uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
+ if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
+ pl->CompleteQuest(qId);
+ }
+ }
- void JustSummoned(Creature*) override { } // avoid despawn of prisoners on death/reset
+ void SetData(uint32 type, uint32 data) override
+ {
+ if (type == DATA_PRISONERS_EXECUTED && data <= 3)
+ {
+ if (Creature* victim = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FIRST_PRISONER + data - 1)))
+ Unit::Kill(me, victim);
- void JustDied(Unit* /*killer*/) override
+ if (data == 1)
{
- _JustDied();
-
- if (instance->GetData(DATA_PRISONERS_EXECUTED) > 0)
- return;
-
Map::PlayerList const& players = instance->instance->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{
Player* pl = itr->GetSource();
uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
- pl->CompleteQuest(qId);
+ pl->FailQuest(qId);
}
}
- void SetData(uint32 type, uint32 data) override
+ switch (data)
{
- if (type == DATA_PRISONERS_EXECUTED && data <= 3)
- {
- if (Creature* victim = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FIRST_PRISONER + data - 1)))
- Unit::Kill(me, victim);
-
- if (data == 1)
- {
- Map::PlayerList const& players = instance->instance->GetPlayers();
- for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
- {
- Player* pl = itr->GetSource();
- uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
- if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
- pl->FailQuest(qId);
- }
- }
-
- switch (data)
- {
- case 3:
- me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
- [[fallthrough]];
- case 2:
- me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
- [[fallthrough]];
- case 1:
- me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
- [[fallthrough]];
- default:
- break;
- }
- }
+ case 3:
+ me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
+ [[fallthrough]];
+ case 2:
+ me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
+ [[fallthrough]];
+ case 1:
+ me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
+ [[fallthrough]];
+ default:
+ break;
}
+ }
+ }
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- if (cleaveTimer <= diff)
- {
- DoCast(SPELL_CLEAVE);
- cleaveTimer = urand(5000, 7000);
- }
- else
- cleaveTimer -= diff;
-
- DoMeleeAttackIfReady();
- }
- private:
- uint32 cleaveTimer;
- };
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- CreatureAI* GetAI(Creature* creature) const override
+ if (cleaveTimer <= diff)
{
- return GetShatteredHallsAI<boss_shattered_executionerAI>(creature);
+ DoCast(SPELL_CLEAVE);
+ cleaveTimer = urand(5000, 7000);
}
+ else
+ cleaveTimer -= diff;
+
+ DoMeleeAttackIfReady();
+ }
+private:
+ uint32 cleaveTimer;
};
// 39288, 39289, 39290 - Kargath's Executioner
-class spell_kargath_executioner : public SpellScriptLoader
+class spell_kargath_executioner : public AuraScript
{
- public:
- spell_kargath_executioner() : SpellScriptLoader("spell_kargath_executioner") { }
+ PrepareAuraScript(spell_kargath_executioner);
- class spell_kargath_executioner_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_kargath_executioner_AuraScript);
+ bool AreaCheck(Unit* target)
+ {
+ if (target->GetMap()->GetId() != 540)
+ return false;
- bool AreaCheck(Unit* target)
- {
- if (target->GetMap()->GetId() != 540)
- return false;
+ return true;
+ }
- return true;
- }
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
- bool Load() override
- {
- return GetCaster()->GetTypeId() == TYPEID_PLAYER;
- }
-
- void Register() override
- {
- DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner_AuraScript::AreaCheck);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_kargath_executioner_AuraScript();
- }
+ void Register() override
+ {
+ DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner::AreaCheck);
+ }
};
// 39291 - Remove Kargath's Executioner
-class spell_remove_kargath_executioner : public SpellScriptLoader
+class spell_remove_kargath_executioner : public SpellScript
{
- public:
- spell_remove_kargath_executioner() : SpellScriptLoader("spell_remove_kargath_executioner") { }
-
- class spell_remove_kargath_executioner_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_remove_kargath_executioner_SpellScript);
-
- void HandleScript(SpellEffIndex /*effIndex*/)
- {
- Unit* target = GetCaster();
-
- target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_1);
- target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_2);
- target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_3);
- }
-
- bool Load() override
- {
- return GetCaster()->GetTypeId() == TYPEID_PLAYER;
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_remove_kargath_executioner_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_remove_kargath_executioner_SpellScript();
- }
+ PrepareSpellScript(spell_remove_kargath_executioner);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetCaster();
+
+ target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_1);
+ target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_2);
+ target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_3);
+ }
+
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_remove_kargath_executioner::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
};
void AddSC_shattered_halls()
{
new at_nethekurse_exit();
- new boss_shattered_executioner();
- new spell_kargath_executioner();
- new spell_remove_kargath_executioner();
+ RegisterShatteredHallsCreatureAI(boss_shattered_executioner);
+ RegisterSpellScript(spell_kargath_executioner);
+ RegisterSpellScript(spell_remove_kargath_executioner);
}
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
index f0994dac7c0..02044e4ca1d 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
@@ -40,7 +40,10 @@ enum SHDataTypes
DATA_FIRST_PRISONER,
DATA_SECOND_PRISONER,
- DATA_THIRD_PRISONER
+ DATA_THIRD_PRISONER,
+
+ DATA_LEFT_HEAD,
+ DATA_RIGHT_HEAD
};
enum SHCreatureIds
@@ -49,6 +52,10 @@ enum SHCreatureIds
NPC_BLOOD_GUARD_PORUNG = 20923,
NPC_KARGATH_BLADEFIST = 16808,
+ // Warbringer O'mrogg
+ NPC_LEFT_HEAD = 19523,
+ NPC_RIGHT_HEAD = 19524,
+
NPC_SHATTERED_EXECUTIONER = 17301,
// Alliance Ids
@@ -120,4 +127,6 @@ inline AI* GetShatteredHallsAI(T* obj)
return GetInstanceAI<AI>(obj, SHScriptName);
}
+#define RegisterShatteredHallsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetShatteredHallsAI)
+
#endif