Scripts/Shattered Halls: Rewrite Nethekurse (#31426)

This commit is contained in:
offl
2025-12-20 02:26:04 +02:00
committed by GitHub
parent a26ace1cd5
commit 37284e759f
4 changed files with 516 additions and 275 deletions

View File

@@ -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);

View File

@@ -15,196 +15,202 @@
* 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,
enum Spells
{
SPELL_DEATH_COIL = 30500, // 30741 heroic
SPELL_DARK_SPIN = 30502, // core bug spell attack caster :D
SPELL_SHADOW_FISSURE = 30496, // Summon the ShadowFissure NPC
SPELL_SHADOW_CLEAVE = 30495,
H_SPELL_SHADOW_SLAM = 35953,
SPELL_HEMORRHAGE = 30478,
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
SAY_AGGRO_ALL_ALIVE = 3,
SAY_AGGRO_SOME_ALIVE = 4,
SAY_AGGRO_ALL_DEAD = 5,
SPELL_SHADOW_SEAR = 30735 // cast on entry 17083 which then makes sound 1343
// 30948 cast on self by 17687
};
SAY_PEON_ENGAGED = 6,
SAY_PEON_DEFEATED = 7,
enum SetData
{
SETDATA_DATA = 1,
SETDATA_PEON_AGGRO = 1,
SETDATA_PEON_DEATH = 2
};
SAY_SLAY = 8,
SAY_DEATH = 9,
enum Events
{
// Fel Orc Convert
EVENT_HEMORRHAGE = 1
SAY_PEON_AGGRO = 0,
SAY_PEON_SHADOW_SEAR = 1,
SAY_PEON_DEATH_COIL = 2,
SAY_PEON_SHADOW_FISSURE = 3
};
// ########################################################
// Grand Warlock Nethekurse
// ########################################################
enum NethekurseSpells
{
// Combat
SPELL_SHADOW_FISSURE = 30496,
SPELL_DEATH_COIL = 30500,
SPELL_SHADOW_CLEAVE = 30495,
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_CONSUMPTION_H = 35952,
// Wild Shadow Fissure
SPELL_CONSUMPTION_WILD = 32250,
// Scripts
SPELL_SHADOW_FISSURE_2 = 30744
};
enum NethekurseEvents
{
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 NethekurseActions
{
ACTION_START_INTRO = 0,
ACTION_PEON_ENGAGED = 1,
ACTION_PEON_KILLED = 2
};
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);
void SetData(uint32 data, uint32 value) override
{
if (data != SETDATA_DATA)
return;
events.Reset();
switch (value)
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 SETDATA_PEON_AGGRO:
if (PeonEngagedCount >= 4)
return;
Talk(SAY_PEON_ATTACKED);
++PeonEngagedCount;
case 0:
Talk(SAY_AGGRO_ALL_ALIVE);
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);
}
case 1:
case 2:
case 3:
Talk(SAY_AGGRO_SOME_ALIVE);
break;
case 4:
Talk(SAY_AGGRO_ALL_DEAD);
break;
default:
break;
}
}
void DoTauntPeons()
void DoAction(int32 action) override
{
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)
if (!me->IsAlive())
return;
if (me->Attack(who, true))
switch (action)
{
if (Phase)
DoStartNoMovement(who);
else
DoStartMovement(who);
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;
events.ScheduleEvent(EVENT_INTERNAL_COOLDOWN, 5s);
}
break;
case ACTION_PEON_KILLED:
{
++_peonKilledCount;
if (!me->IsInCombat() && _peonKilledCount == MAX_KILLED_PEONS)
DoZoneInCombat();
if (!me->IsInCombat() && !_isEventOnCooldown && _peonKilledCount != MAX_KILLED_PEONS)
{
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 MoveInLineOfSight(Unit* who) override
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
{
if (!IntroOnce && me->IsWithinDistInMap(who, 30.0f))
if (!_isDarkSpinStarted && me->HealthBelowPctDamaged(25, damage))
{
if (who->GetTypeId() != TYPEID_PLAYER)
return;
Talk(SAY_INTRO);
IntroOnce = true;
IsIntroEvent = true;
instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
_isDarkSpinStarted = true;
events.ScheduleEvent(EVENT_DARK_SPIN, 0s);
}
if (IsIntroEvent || !IsMainEvent)
return;
ScriptedAI::MoveInLineOfSight(who);
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
}
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()));
}
void KilledUnit(Unit* /*victim*/) override
@@ -212,152 +218,292 @@ struct boss_grand_warlock_nethekurse : public BossAI
Talk(SAY_SLAY);
}
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
{
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();
}
}
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
// ########################################################
struct npc_fel_orc_convert : public ScriptedAI
{
npc_fel_orc_convert(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
void Reset() override
{
me->SetNoCallAssistance(true); //we don't want any assistance (WE R HEROZ!)
}
void MoveInLineOfSight(Unit* /*who*/) override { }
void JustEngagedWith(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_HEMORRHAGE, 3s);
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 JustDied(Unit* /*killer*/) override
{
if (instance->GetBossState(DATA_NETHEKURSE) != IN_PROGRESS)
return;
_JustDied();
Talk(SAY_DEATH);
}
if (Creature* Kurse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_GRAND_WARLOCK_NETHEKURSE)))
Kurse->AI()->SetData(SETDATA_DATA, SETDATA_PEON_DEATH);
void UpdateOutOfCombatEvents(uint32 diff)
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
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 UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
UpdateOutOfCombatEvents(diff);
return;
}
events.Update(diff);
if (events.ExecuteEvent() == EVENT_HEMORRHAGE)
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
DoCastVictim(SPELL_HEMORRHAGE);
events.ScheduleEvent(EVENT_HEMORRHAGE, 15s);
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;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
EventMap events;
private:
uint32 _peonKilledCount;
bool _isEventOnCooldown;
bool _isDarkSpinStarted;
};
// ########################################################
// Lesser Shadow Fissure
// ########################################################
// 17083 - Fel Orc Convert
struct npc_fel_orc_convert : public ScriptedAI
{
npc_fel_orc_convert(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void Reset() override
{
_scheduler.CancelAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
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 SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
{
// 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 JustDied(Unit* /*killer*/) override
{
if (!me->HasStringId("FelOrcConvertNethekurseEvent"))
return;
if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
nethekurse->AI()->DoAction(ACTION_PEON_KILLED);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_scheduler.Update(diff, [this]
{
DoMeleeAttackIfReady();
});
}
private:
InstanceScript* _instance;
TaskScheduler _scheduler;
};
// 17471 - Lesser Shadow Fissure
struct npc_lesser_shadow_fissure : public ScriptedAI
{
npc_lesser_shadow_fissure(Creature* creature) : ScriptedAI(creature) { }
void Reset() override { }
void MoveInLineOfSight(Unit* /*who*/) override { }
void AttackStart(Unit* /*who*/) override { }
void JustEngagedWith(Unit* /*who*/) override { }
void InitializeAI() override
{
me->SetReactState(REACT_PASSIVE);
}
void JustAppeared() override
{
DoCastSelf(IsHeroic() ? SPELL_CONSUMPTION_H : SPELL_CONSUMPTION);
}
};
// 18370 - Wild Shadow Fissure
struct npc_wild_shadow_fissure : public ScriptedAI
{
npc_wild_shadow_fissure(Creature* creature) : ScriptedAI(creature) { }
void InitializeAI() override
{
me->SetReactState(REACT_PASSIVE);
}
void JustAppeared() override
{
DoCastSelf(SPELL_CONSUMPTION_WILD);
}
};
// 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()) { }
bool OnGossipHello(Player* /*player*/) override
{
if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
nethekurse->AI()->DoAction(ACTION_START_INTRO);
return true;
}
private:
InstanceScript* _instance;
};
// 30745 - Target Fissures
class spell_grand_warlock_nethekurse_target_fissures : public SpellScript
{
PrepareSpellScript(spell_grand_warlock_nethekurse_target_fissures);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SHADOW_FISSURE_2 });
}
void FilterTargets(std::list<WorldObject*>& targets)
{
if (targets.empty())
return;
WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
targets.clear();
targets.push_back(target);
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_SHADOW_FISSURE_2);
}
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);
}
};
// 4347
class at_shattered_halls_the_sewer : public AreaTriggerScript
{
public:
at_shattered_halls_the_sewer() : AreaTriggerScript("at_shattered_halls_the_sewer") { }
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();
}

View File

@@ -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];

View File

@@ -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