diff options
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 |