aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/3.3.5/2025_12_20_01_world.sql95
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp602
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp13
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h1
4 files changed, 476 insertions, 235 deletions
diff --git a/sql/updates/world/3.3.5/2025_12_20_01_world.sql b/sql/updates/world/3.3.5/2025_12_20_01_world.sql
new file mode 100644
index 00000000000..5503c5f56d7
--- /dev/null
+++ b/sql/updates/world/3.3.5/2025_12_20_01_world.sql
@@ -0,0 +1,95 @@
+--
+UPDATE `creature_template` SET `ScriptName` = 'npc_wild_shadow_fissure' WHERE `entry` = 18370;
+UPDATE `creature_template` SET `minlevel` = 70, `maxlevel` = 70, `unit_flags` = 0x02000000 WHERE `entry` = 18370;
+UPDATE `creature_template` SET `minlevel` = 71, `maxlevel` = 71, `unit_flags` = 0x02000000 WHERE `entry` = 20598;
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` IN (30735,30741,32251,30745);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`ConditionStringValue1`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(13,1,30735,0,0,58,0,0,0,0,"FelOrcConvertNethekurseEvent",0,0,0,"","Group 0: Spell 'Shadow Sear' (Effect 0) targets creature 'Fel Orc Convert'"),
+(13,3,30741,0,0,58,0,0,0,0,"FelOrcConvertNethekurseEvent",0,0,0,"","Group 0: Spell 'Death Coil' (Effect 0, 1) targets creature 'Fel Orc Convert'"),
+(13,1,32251,0,0,58,0,0,0,0,"FelOrcConvertNethekurseEvent",0,0,0,"","Group 0: Spell 'Consumption' (Effect 0) targets creature 'Fel Orc Convert'"),
+(13,1,30745,0,0,58,0,0,0,0,"FelOrcConvertNethekurseEvent",0,0,0,"","Group 0: Spell 'Target Fissures' (Effect 0) targets creature 'Fel Orc Convert'");
+
+UPDATE `creature` SET `StringId` = 'FelOrcConvertNethekurseEvent' WHERE `guid` IN (59478,59479,59480,59481) AND `id` = 17083;
+
+UPDATE `creature` SET `position_x` = 164.71588134765625, `position_y` = 266.263031005859375, `position_z` = -13.1121978759765625, `orientation` = 1.047197580337524414, `VerifiedBuild` = 14007 WHERE `guid` = 59478 AND `id` = 17083;
+UPDATE `creature` SET `position_x` = 174.04949951171875, `position_y` = 269.132476806640625, `position_z` = -13.0549201965332031, `orientation` = 1.448623299598693847, `VerifiedBuild` = 14007 WHERE `guid` = 59479 AND `id` = 17083;
+UPDATE `creature` SET `position_x` = 184.4263458251953125, `position_y` = 269.293731689453125, `position_z` = -13.0555877685546875, `orientation` = 1.727875947952270507, `VerifiedBuild` = 14007 WHERE `guid` = 59480 AND `id` = 17083;
+UPDATE `creature` SET `position_x` = 194.48394775390625, `position_y` = 267.07208251953125, `position_z` = -13.1039943695068359, `orientation` = 2.181661605834960937, `VerifiedBuild` = 14007 WHERE `guid` = 59481 AND `id` = 17083;
+
+DELETE FROM `creature_text` WHERE `CreatureID` = 17083;
+INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(17083,0,0,"We are the true Horde!",12,0,100,0,0,0,16697,0,"Fel Orc Convert"),
+(17083,0,1,"For Kargath! For Victory!",12,0,100,0,0,0,16698,0,"Fel Orc Convert"),
+(17083,0,2,"Gakarah ma!",12,0,100,0,0,0,16699,0,"Fel Orc Convert"),
+(17083,0,3,"The blood is our power!",12,0,100,0,0,0,16700,0,"Fel Orc Convert"),
+(17083,0,4,"Lok'tar Illadari!
+",12,0,100,0,0,0,16701,0,"Fel Orc Convert"),
+(17083,0,5,"This world is OURS!",12,0,100,0,0,0,16702,0,"Fel Orc Convert"),
+(17083,0,6,"Lok narash!",12,0,100,0,0,0,16703,0,"Fel Orc Convert"),
+-- Not sure if these are grouped correctly, based on few sniffs
+-- By the way, language is correct, verified, not a typo
+-- Text 14143 seems to be unused, not added here
+(17083,1,0,"It hurt!",14,0,100,0,0,0,14136,0,"Fel Orc Convert - Shadow Sear"),
+(17083,1,1,"Augh! No more hurt!",14,0,100,0,0,0,14137,0,"Fel Orc Convert - Shadow Sear"),
+(17083,1,2,"This not good tickle!",14,0,100,0,0,0,14138,0,"Fel Orc Convert - Shadow Sear"),
+(17083,1,3,"Skin on fire!",14,0,100,0,0,0,14139,0,"Fel Orc Convert - Shadow Sear"),
+
+(17083,2,0,"It hurt!",14,1,100,0,0,0,14140,0,"Fel Orc Convert - Death Coil"),
+(17083,2,1,"Aahhh!",14,1,100,0,0,0,14141,0,"Fel Orc Convert - Death Coil"),
+(17083,2,2,"No more scary!",14,1,100,0,0,0,14142,0,"Fel Orc Convert - Death Coil"),
+(17083,2,3,"No more!",14,1,100,0,0,0,14144,0,"Fel Orc Convert - Death Coil"),
+
+(17083,3,0,"Pain!",14,1,100,0,0,0,14149,0,"Fel Orc Convert - Target Fissures"),
+(17083,3,1,"It hurts!",14,1,100,0,0,0,14150,0,"Fel Orc Convert - Target Fissures"),
+(17083,3,2,"Graaagggh!!",14,1,100,0,0,0,14151,0,"Fel Orc Convert - Target Fissures"),
+(17083,3,3,"No more!!",14,1,100,0,0,0,14152,0,"Fel Orc Convert - Target Fissures");
+
+DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_grand_warlock_nethekurse_target_fissures';
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(30745, 'spell_grand_warlock_nethekurse_target_fissures');
+
+DELETE FROM `areatrigger_scripts` WHERE `entry` = 4347;
+INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES
+(4347, 'at_shattered_halls_the_sewer');
+
+UPDATE `gameobject_template` SET `ScriptName` = 'go_grand_warlock_chamber_door' WHERE `entry` = 182539;
+
+DELETE FROM `creature_text` WHERE `CreatureID` = 16807;
+INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(16807,0,0,"Beg for your pitiful life!",14,0,100,11,0,10259,14130,0,"nethekurse SAY_TAUNT_SHADOW_SEAR"),
+(16807,1,0,"Run, coward, run! ",14,0,100,11,0,10260,14132,0,"nethekurse SAY_TAUNT_DEATH_COIL"),
+(16807,2,0,"Your pain amuses me!",14,0,100,11,0,10261,14148,0,"nethekurse SAY_TAUNT_SHADOW_FISSURE"),
+
+(16807,3,0,"You wish to fight us all at once? This should be amusing!
+",14,0,100,0,0,10262,15594,0,"nethekurse SAY_AGGRO_ALL_ALIVE"),
+(16807,4,0,"Come on, show me a real fight!",14,0,100,0,0,10272,15595,0,"nethekurse SAY_AGGRO_SOME_ALIVE"),
+(16807,5,0,"Thank you for saving me the trouble. Now it's my turn to have some fun!
+",14,0,100,0,0,10270,15589,0,"nethekurse SAY_AGGRO_ALL_DEAD"),
+
+(16807,6,0,"You can have that one, I no longer need him!",14,0,100,11,0,10263,15569,0,"nethekurse SAY_PEON_ENGAGED_1"),
+(16807,6,1,"Yes, beat him mercilessly! His skull is as thick as an ogre's!
+",14,0,100,11,0,10264,15575,0,"nethekurse SAY_PEON_ENGAGED_2"),
+(16807,6,2,"Don't waste your time on that one, he's weak!",14,0,100,11,0,10265,15573,0,"nethekurse SAY_PEON_ENGAGED_3"),
+(16807,6,3,"You want him? Very well, take him!",14,0,100,11,0,10266,15572,0,"nethekurse SAY_PEON_ENGAGED_4"),
+
+(16807,7,0,"One pitiful wretch down. Go on, take another one! ",14,0,100,0,0,10267,15579,0,"nethekurse SAY_PEON_DEFEATED_1"),
+(16807,7,1,"Ah, what a waste... next!",14,0,100,0,0,10268,15584,0,"nethekurse SAY_PEON_DEFEATED_2"),
+(16807,7,2,"I was going to kill him anyway!",14,0,100,0,0,10269,15582,0,"nethekurse SAY_PEON_DEFEATED_3"),
+
+(16807,8,0,"I'm already bored!",14,0,100,0,0,10271,16864,0,"nethekurse SAY_SLAY_1"),
+(16807,8,1,"I had more fun torturing the peons!",14,0,100,0,0,10273,16863,0,"nethekurse SAY_SLAY_2"),
+(16807,8,2,"You lose.",14,0,100,0,0,10274,16865,0,"nethekurse SAY_SLAY_3"),
+(16807,8,3,"Oh, just die!",14,0,100,0,0,10275,16866,0,"nethekurse SAY_SLAY_4"),
+
+(16807,9,0,"What... a shame.",14,0,100,0,0,10276,16862,0,"nethekurse SAY_DEATH");
+
+UPDATE `creature` SET `MovementType` = 2 WHERE `id` = 16807;
+UPDATE `creature_template_addon` SET `path_id` = 578530, `SheathState` = 1 WHERE `entry` IN (16807,20568);
+
+DELETE FROM `waypoint_data` WHERE `id` = 578530;
+INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `delay`, `action`, `orientation`, `move_type`, `action_chance`) VALUES
+(578530,1,178.51125,287.97794,-8.183065,0,0,NULL,0,100),
+(578530,2,171.82281,289.97687,-8.185595,0,0,NULL,0,100),
+(578530,3,178.51125,287.97794,-8.183065,0,0,NULL,0,100),
+(578530,4,184.78966,290.36990,-8.181390,0,0,NULL,0,100);
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
index c470c6a867e..f4816f8af10 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
@@ -15,349 +15,495 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Boss_Grand_Warlock_Nethekurse
-SD%Complete: 75
-SDComment: encounter not fully completed. missing part where boss kill minions.
-SDCategory: Hellfire Citadel, Shattered Halls
-EndScriptData */
-
-/* ContentData
-boss_grand_warlock_nethekurse
-npc_fel_orc_convert
-npc_lesser_shadow_fissure
-EndContentData */
+/*
+ * Combat timers requires to be revisited
+ * Clearly seen one peon died from Shadow Fissure, doesn't work because health regenerates,
+ it should regenerate in case of other spells, no sniffs with Wild Shadow Fissure
+ * Dark Spin gets interrupted after first tick
+ * Death Coil is a buff instead of a debuff
+ */
#include "ScriptMgr.h"
+#include "Containers.h"
+#include "GameObject.h"
+#include "GameObjectAI.h"
#include "InstanceScript.h"
-#include "ObjectAccessor.h"
+#include "Player.h"
#include "ScriptedCreature.h"
#include "shattered_halls.h"
+#include "SpellInfo.h"
+#include "SpellScript.h"
-enum Says
+enum NethekurseTexts
{
- SAY_INTRO = 0,
- SAY_PEON_ATTACKED = 1,
- SAY_PEON_DIES = 2,
- SAY_TAUNT = 3,
- SAY_AGGRO = 4,
- SAY_SLAY = 5,
- SAY_DIE = 6
+ SAY_TAUNT_SHADOW_SEAR = 0,
+ SAY_TAUNT_DEATH_COIL = 1,
+ SAY_TAUNT_SHADOW_FISSURE = 2,
+
+ SAY_AGGRO_ALL_ALIVE = 3,
+ SAY_AGGRO_SOME_ALIVE = 4,
+ SAY_AGGRO_ALL_DEAD = 5,
+
+ SAY_PEON_ENGAGED = 6,
+ SAY_PEON_DEFEATED = 7,
+
+ SAY_SLAY = 8,
+ SAY_DEATH = 9,
+
+ // Fel Orc Convert
+ SAY_PEON_AGGRO = 0,
+ SAY_PEON_SHADOW_SEAR = 1,
+ SAY_PEON_DEATH_COIL = 2,
+ SAY_PEON_SHADOW_FISSURE = 3
};
-enum Spells
+enum NethekurseSpells
{
- SPELL_DEATH_COIL = 30500, // 30741 heroic
- SPELL_DARK_SPIN = 30502, // core bug spell attack caster :D
- SPELL_SHADOW_FISSURE = 30496, // Summon the ShadowFissure NPC
+ // Combat
+ SPELL_SHADOW_FISSURE = 30496,
+ SPELL_DEATH_COIL = 30500,
SPELL_SHADOW_CLEAVE = 30495,
- H_SPELL_SHADOW_SLAM = 35953,
+ SPELL_SHADOW_SLAM = 35953,
+ SPELL_DARK_SPIN = 30502,
+
+ // Intro
+ SPELL_PEON_SHADOW_SEAR = 30735,
+ SPELL_PEON_DEATH_COIL = 30741,
+ SPELL_PEON_TARGET_FISSURES = 30745,
+
+ // Fel Orc Convert
SPELL_HEMORRHAGE = 30478,
+
+ // Lesser Shadow Fissure
SPELL_CONSUMPTION = 30497,
- SPELL_TEMPORARY_VISUAL = 39312, // this is wrong, a temporary solution. spell consumption already has the purple visual, but doesn't display as it should
+ SPELL_CONSUMPTION_H = 35952,
- SPELL_SHADOW_SEAR = 30735 // cast on entry 17083 which then makes sound 1343
- // 30948 cast on self by 17687
+ // Wild Shadow Fissure
+ SPELL_CONSUMPTION_WILD = 32250,
+
+ // Scripts
+ SPELL_SHADOW_FISSURE_2 = 30744
};
-enum SetData
+enum NethekurseEvents
{
- SETDATA_DATA = 1,
- SETDATA_PEON_AGGRO = 1,
- SETDATA_PEON_DEATH = 2
+ EVENT_TAUNT_PEONS = 1,
+ EVENT_INTERNAL_COOLDOWN,
+ EVENT_CLEAR_EMOTE_STATE,
+
+ EVENT_SHADOW_FISSURE,
+ EVENT_DEATH_COIL,
+ EVENT_SHADOW_CLEAVE,
+ EVENT_SHADOW_SLAM,
+ EVENT_DARK_SPIN
};
-enum Events
+enum NethekurseActions
{
- // Fel Orc Convert
- EVENT_HEMORRHAGE = 1
+ ACTION_START_INTRO = 0,
+ ACTION_PEON_ENGAGED = 1,
+ ACTION_PEON_KILLED = 2
};
-// ########################################################
-// Grand Warlock Nethekurse
-// ########################################################
+enum NethekurseMisc
+{
+ SOUND_ID_ROAR = 9110,
+ MAX_KILLED_PEONS = 4
+};
+// 16807 - Grand Warlock Nethekurse
struct boss_grand_warlock_nethekurse : 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;
- }
+ boss_grand_warlock_nethekurse(Creature* creature) : BossAI(creature, DATA_NETHEKURSE),
+ _peonKilledCount(0), _isEventOnCooldown(false), _isDarkSpinStarted(false) { }
void Reset() override
{
_Reset();
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- Initialize();
+ _isEventOnCooldown = false;
+ _isDarkSpinStarted = false;
}
- void JustDied(Unit* /*killer*/) override
+ void JustEngagedWith(Unit* who) override
{
- _JustDied();
- Talk(SAY_DIE);
+ BossAI::JustEngagedWith(who);
+
+ events.Reset();
+
+ events.ScheduleEvent(EVENT_SHADOW_FISSURE, 8s);
+ events.ScheduleEvent(EVENT_DEATH_COIL, 10s, 15s);
+
+ if (!IsHeroic())
+ events.ScheduleEvent(EVENT_SHADOW_CLEAVE, 15s, 20s);
+ else
+ events.ScheduleEvent(EVENT_SHADOW_SLAM, 15s, 20s);
+
+ switch (_peonKilledCount)
+ {
+ case 0:
+ Talk(SAY_AGGRO_ALL_ALIVE);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ Talk(SAY_AGGRO_SOME_ALIVE);
+ break;
+ case 4:
+ Talk(SAY_AGGRO_ALL_DEAD);
+ break;
+ default:
+ break;
+ }
}
- void SetData(uint32 data, uint32 value) override
+ void DoAction(int32 action) override
{
- if (data != SETDATA_DATA)
+ if (!me->IsAlive())
return;
- switch (value)
+ switch (action)
{
- case SETDATA_PEON_AGGRO:
- if (PeonEngagedCount >= 4)
- return;
+ case ACTION_START_INTRO:
+ if (!me->IsInCombat() && _peonKilledCount != MAX_KILLED_PEONS)
+ events.ScheduleEvent(EVENT_TAUNT_PEONS, 0s);
+ break;
+ case ACTION_PEON_ENGAGED:
+ if (!me->IsInCombat() && !_isEventOnCooldown)
+ {
+ Talk(SAY_PEON_ENGAGED);
+ me->PauseMovement(5000);
+ me->SetFacingTo(4.537856101989746093f);
+ _isEventOnCooldown = true;
- Talk(SAY_PEON_ATTACKED);
- ++PeonEngagedCount;
+ events.ScheduleEvent(EVENT_INTERNAL_COOLDOWN, 5s);
+ }
break;
- case SETDATA_PEON_DEATH:
- if (PeonKilledCount >= 4)
- return;
+ case ACTION_PEON_KILLED:
+ {
+ ++_peonKilledCount;
- Talk(SAY_PEON_DIES);
- ++PeonKilledCount;
+ if (!me->IsInCombat() && _peonKilledCount == MAX_KILLED_PEONS)
+ DoZoneInCombat();
- if (PeonKilledCount == 4)
+ if (!me->IsInCombat() && !_isEventOnCooldown && _peonKilledCount != MAX_KILLED_PEONS)
{
- IsIntroEvent = false;
- IsMainEvent = true;
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ Talk(SAY_PEON_DEFEATED);
+ me->PauseMovement(5000);
+ me->SetFacingTo(4.572762489318847656f);
+ me->SetEmoteState(EMOTE_STATE_APPLAUD);
+ _isEventOnCooldown = true;
+
+ events.ScheduleEvent(EVENT_INTERNAL_COOLDOWN, 5s);
+ events.ScheduleEvent(EVENT_CLEAR_EMOTE_STATE, 5s);
}
break;
+ }
default:
break;
}
}
- void DoTauntPeons()
+ void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
{
- Talk(SAY_TAUNT);
-
- /// @todo kill the peons first
- IsIntroEvent = false;
- PeonEngagedCount = 4;
- PeonKilledCount = 4;
- IsMainEvent = true;
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ if (!_isDarkSpinStarted && me->HealthBelowPctDamaged(25, damage))
+ {
+ _isDarkSpinStarted = true;
+ events.ScheduleEvent(EVENT_DARK_SPIN, 0s);
+ }
}
- void AttackStart(Unit* who) override
+ void KilledUnit(Unit* /*victim*/) override
{
- if (IsIntroEvent || !IsMainEvent)
- return;
+ Talk(SAY_SLAY);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_DEATH);
+ }
+
+ void UpdateOutOfCombatEvents(uint32 diff)
+ {
+ events.Update(diff);
- if (me->Attack(who, true))
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (Phase)
- DoStartNoMovement(who);
- else
- DoStartMovement(who);
+ switch (eventId)
+ {
+ // ... intro event starts every time player enters area trigger
+ case EVENT_TAUNT_PEONS:
+ {
+ switch (urand(0, 2))
+ {
+ case 0:
+ // This one targets two (?) peons
+ Talk(SAY_TAUNT_SHADOW_SEAR);
+ DoCastSelf(SPELL_PEON_SHADOW_SEAR, { SPELLVALUE_MAX_TARGETS, 2 });
+ break;
+ case 1:
+ // This one targets all four peons
+ Talk(SAY_TAUNT_DEATH_COIL);
+ DoCastSelf(SPELL_PEON_DEATH_COIL);
+ break;
+ case 2:
+ // This one targets one peon
+ Talk(SAY_TAUNT_SHADOW_FISSURE);
+ DoCastSelf(SPELL_PEON_TARGET_FISSURES);
+ break;
+ default:
+ break;
+ }
+
+ // ... cancel copies of event every time it is scheduled, then schedule new to repeat it, only one should be active
+ events.CancelEvent(EVENT_TAUNT_PEONS);
+ if (_peonKilledCount != MAX_KILLED_PEONS)
+ events.ScheduleEvent(EVENT_TAUNT_PEONS, 25s, 35s);
+ break;
+ }
+ case EVENT_INTERNAL_COOLDOWN:
+ _isEventOnCooldown = false;
+ break;
+ case EVENT_CLEAR_EMOTE_STATE:
+ me->SetEmoteState(EMOTE_ONESHOT_NONE);
+ break;
+ default:
+ break;
+ }
}
}
- void MoveInLineOfSight(Unit* who) override
+ void UpdateAI(uint32 diff) override
{
- if (!IntroOnce && me->IsWithinDistInMap(who, 30.0f))
+ if (!UpdateVictim())
{
- if (who->GetTypeId() != TYPEID_PLAYER)
- return;
+ UpdateOutOfCombatEvents(diff);
+ return;
+ }
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- Talk(SAY_INTRO);
- IntroOnce = true;
- IsIntroEvent = true;
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SHADOW_FISSURE:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
+ DoCast(target, SPELL_SHADOW_FISSURE);
+ events.Repeat(8s);
+ break;
+ case EVENT_DEATH_COIL:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random))
+ DoCast(target, SPELL_DEATH_COIL);
+ events.Repeat(10s, 20s);
+ break;
+ case EVENT_SHADOW_CLEAVE:
+ DoCastVictim(SPELL_SHADOW_CLEAVE);
+ events.Repeat(15s, 20s);
+ break;
+ case EVENT_SHADOW_SLAM:
+ DoCastVictim(SPELL_SHADOW_SLAM);
+ events.Repeat(15s, 20s);
+ break;
+ case EVENT_DARK_SPIN:
+ DoCastSelf(SPELL_DARK_SPIN);
+ break;
+ default:
+ break;
+ }
- instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
- if (IsIntroEvent || !IsMainEvent)
- return;
+ DoMeleeAttackIfReady();
+ }
+
+private:
+ uint32 _peonKilledCount;
+ bool _isEventOnCooldown;
+ bool _isDarkSpinStarted;
+};
+
+// 17083 - Fel Orc Convert
+struct npc_fel_orc_convert : public ScriptedAI
+{
+ npc_fel_orc_convert(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
- ScriptedAI::MoveInLineOfSight(who);
+ void Reset() override
+ {
+ _scheduler.CancelAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
- Talk(SAY_AGGRO);
+ if (roll_chance_i(15))
+ Talk(SAY_PEON_AGGRO);
+
+ _scheduler.Schedule(5s, 10s, [this](TaskContext task)
+ {
+ DoCastVictim(SPELL_HEMORRHAGE);
+ task.Repeat(5s, 10s);
+ });
+
+ if (!me->HasStringId("FelOrcConvertNethekurseEvent"))
+ return;
+
+ if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
+ nethekurse->AI()->DoAction(ACTION_PEON_ENGAGED);
}
- void JustSummoned(Creature* summoned) override
+ void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) 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()));
+ // Not sure if these are grouped correctly, based on few sniffs
+ // By the way, language is correct, verified, not a typo
+ // Text 14143 seems to be unused, not added here
+ switch (spellInfo->Id)
+ {
+ case SPELL_PEON_SHADOW_SEAR:
+ if (roll_chance_i(30))
+ Talk(SAY_PEON_SHADOW_SEAR);
+ break;
+ case SPELL_PEON_DEATH_COIL:
+ if (roll_chance_i(30))
+ {
+ Talk(SAY_PEON_DEATH_COIL);
+ DoPlaySoundToSet(me, SOUND_ID_ROAR);
+ }
+ break;
+ case SPELL_PEON_TARGET_FISSURES:
+ if (roll_chance_i(30))
+ Talk(SAY_PEON_SHADOW_FISSURE);
+ break;
+ default:
+ break;
+ }
}
- void KilledUnit(Unit* /*victim*/) override
+ void JustDied(Unit* /*killer*/) override
{
- Talk(SAY_SLAY);
+ if (!me->HasStringId("FelOrcConvertNethekurseEvent"))
+ return;
+
+ if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
+ nethekurse->AI()->DoAction(ACTION_PEON_KILLED);
}
void UpdateAI(uint32 diff) override
{
- 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 (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
+ _scheduler.Update(diff, [this]
{
- 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;
+ 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:
+ InstanceScript* _instance;
+ TaskScheduler _scheduler;
+};
- if (!HealthAbovePct(20))
- Phase = true;
+// 17471 - Lesser Shadow Fissure
+struct npc_lesser_shadow_fissure : public ScriptedAI
+{
+ npc_lesser_shadow_fissure(Creature* creature) : ScriptedAI(creature) { }
- DoMeleeAttackIfReady();
- }
+ void InitializeAI() override
+ {
+ me->SetReactState(REACT_PASSIVE);
}
- 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;
+ void JustAppeared() override
+ {
+ DoCastSelf(IsHeroic() ? SPELL_CONSUMPTION_H : SPELL_CONSUMPTION);
+ }
};
-// ########################################################
-// Fel Orc Convert
-// ########################################################
-
-struct npc_fel_orc_convert : public ScriptedAI
+// 18370 - Wild Shadow Fissure
+struct npc_wild_shadow_fissure : public ScriptedAI
{
- npc_fel_orc_convert(Creature* creature) : ScriptedAI(creature)
+ npc_wild_shadow_fissure(Creature* creature) : ScriptedAI(creature) { }
+
+ void InitializeAI() override
{
- instance = creature->GetInstanceScript();
+ me->SetReactState(REACT_PASSIVE);
}
- void Reset() override
+ void JustAppeared() override
{
- me->SetNoCallAssistance(true); //we don't want any assistance (WE R HEROZ!)
+ DoCastSelf(SPELL_CONSUMPTION_WILD);
}
+};
- void MoveInLineOfSight(Unit* /*who*/) override { }
+// 182539 - Grand Warlock Chamber Door
+struct go_grand_warlock_chamber_door : public GameObjectAI
+{
+ go_grand_warlock_chamber_door(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { }
- void JustEngagedWith(Unit* /*who*/) override
+ bool OnGossipHello(Player* /*player*/) override
{
- events.ScheduleEvent(EVENT_HEMORRHAGE, 3s);
+ if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
+ nethekurse->AI()->DoAction(ACTION_START_INTRO);
- 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);
+ return true;
}
- void JustDied(Unit* /*killer*/) override
- {
- if (instance->GetBossState(DATA_NETHEKURSE) != IN_PROGRESS)
- return;
+private:
+ InstanceScript* _instance;
+};
+
+// 30745 - Target Fissures
+class spell_grand_warlock_nethekurse_target_fissures : public SpellScript
+{
+ PrepareSpellScript(spell_grand_warlock_nethekurse_target_fissures);
- if (Creature* Kurse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GRAND_WARLOCK_NETHEKURSE)))
- Kurse->AI()->SetData(SETDATA_DATA, SETDATA_PEON_DEATH);
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_SHADOW_FISSURE_2 });
}
- void UpdateAI(uint32 diff) override
+ void FilterTargets(std::list<WorldObject*>& targets)
{
- if (!UpdateVictim())
+ if (targets.empty())
return;
- events.Update(diff);
-
- if (events.ExecuteEvent() == EVENT_HEMORRHAGE)
- {
- DoCastVictim(SPELL_HEMORRHAGE);
- events.ScheduleEvent(EVENT_HEMORRHAGE, 15s);
- }
+ WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
+ targets.clear();
+ targets.push_back(target);
+ }
- DoMeleeAttackIfReady();
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_SHADOW_FISSURE_2);
}
- private:
- InstanceScript* instance;
- EventMap events;
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_grand_warlock_nethekurse_target_fissures::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_grand_warlock_nethekurse_target_fissures::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
};
-// ########################################################
-// Lesser Shadow Fissure
-// ########################################################
-
-struct npc_lesser_shadow_fissure : public ScriptedAI
+// 4347
+class at_shattered_halls_the_sewer : public AreaTriggerScript
{
- npc_lesser_shadow_fissure(Creature* creature) : ScriptedAI(creature) { }
+public:
+ at_shattered_halls_the_sewer() : AreaTriggerScript("at_shattered_halls_the_sewer") { }
- void Reset() override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
- void AttackStart(Unit* /*who*/) override { }
- void JustEngagedWith(Unit* /*who*/) override { }
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* nethekurse = instance->GetCreature(DATA_NETHEKURSE))
+ nethekurse->AI()->DoAction(ACTION_START_INTRO);
+
+ return true;
+ }
};
void AddSC_boss_grand_warlock_nethekurse()
@@ -365,4 +511,8 @@ void AddSC_boss_grand_warlock_nethekurse()
RegisterShatteredHallsCreatureAI(boss_grand_warlock_nethekurse);
RegisterShatteredHallsCreatureAI(npc_fel_orc_convert);
RegisterShatteredHallsCreatureAI(npc_lesser_shadow_fissure);
+ RegisterShatteredHallsCreatureAI(npc_wild_shadow_fissure);
+ RegisterShatteredHallsGameObjectAI(go_grand_warlock_chamber_door);
+ RegisterSpellScript(spell_grand_warlock_nethekurse_target_fissures);
+ new at_shattered_halls_the_sewer();
}
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 13c990eeb34..e04b341b03c 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
@@ -42,9 +42,10 @@ DoorData const doorData[] =
ObjectData const creatureData[] =
{
- { NPC_LEFT_HEAD, DATA_LEFT_HEAD },
- { NPC_RIGHT_HEAD, DATA_RIGHT_HEAD },
- { 0, 0 } // END
+ { NPC_GRAND_WARLOCK_NETHEKURSE, DATA_NETHEKURSE },
+ { NPC_LEFT_HEAD, DATA_LEFT_HEAD },
+ { NPC_RIGHT_HEAD, DATA_RIGHT_HEAD },
+ { 0, 0 } // END
};
class instance_shattered_halls : public InstanceMapScript
@@ -115,9 +116,6 @@ class instance_shattered_halls : public InstanceMapScript
switch (creature->GetEntry())
{
- case NPC_GRAND_WARLOCK_NETHEKURSE:
- nethekurseGUID = creature->GetGUID();
- break;
case NPC_KARGATH_BLADEFIST:
kargathGUID = creature->GetGUID();
break;
@@ -181,8 +179,6 @@ class instance_shattered_halls : public InstanceMapScript
{
switch (data)
{
- case NPC_GRAND_WARLOCK_NETHEKURSE:
- return nethekurseGUID;
case NPC_KARGATH_BLADEFIST:
return kargathGUID;
case NPC_SHATTERED_EXECUTIONER:
@@ -285,7 +281,6 @@ class instance_shattered_halls : public InstanceMapScript
}
private:
- ObjectGuid nethekurseGUID;
ObjectGuid kargathGUID;
ObjectGuid executionerGUID;
ObjectGuid victimsGUID[3];
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
index 02044e4ca1d..52c69b4d60e 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
@@ -128,5 +128,6 @@ inline AI* GetShatteredHallsAI(T* obj)
}
#define RegisterShatteredHallsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetShatteredHallsAI)
+#define RegisterShatteredHallsGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetShatteredHallsAI)
#endif