Scripts/Zul'Aman: Rewrite Nalorakk (#31490)

This commit is contained in:
offl
2026-01-16 22:36:44 +02:00
committed by GitHub
parent f2334b6500
commit 024331cd6f
4 changed files with 521 additions and 388 deletions

View File

@@ -0,0 +1,72 @@
--
SET @SPAWN_GROUP_ID := 329;
DELETE FROM `spawn_group` WHERE `spawnId` IN (86698,86699,86700,89259,89260,89261,89262,89263,89264,89268,89269,89270,89271) AND `spawnType` = 0;
INSERT INTO `spawn_group` (`groupId`, `spawnType`, `spawnId`) VALUES
(@SPAWN_GROUP_ID+0,0,86698),
(@SPAWN_GROUP_ID+0,0,86699),
(@SPAWN_GROUP_ID+0,0,86700),
(@SPAWN_GROUP_ID+1,0,89259),
(@SPAWN_GROUP_ID+1,0,89260),
(@SPAWN_GROUP_ID+1,0,89261),
(@SPAWN_GROUP_ID+1,0,89262),
(@SPAWN_GROUP_ID+2,0,89263),
(@SPAWN_GROUP_ID+2,0,89264),
(@SPAWN_GROUP_ID+3,0,89268),
(@SPAWN_GROUP_ID+3,0,89269),
(@SPAWN_GROUP_ID+3,0,89270),
(@SPAWN_GROUP_ID+3,0,89271);
DELETE FROM `spawn_group_template` WHERE `groupId` BETWEEN @SPAWN_GROUP_ID+0 AND @SPAWN_GROUP_ID+3;
INSERT INTO `spawn_group_template` (`groupId`, `groupName`, `groupFlags`) VALUES
(@SPAWN_GROUP_ID+0,"Zul'Aman - Nalorakk - Wave 1",4),
(@SPAWN_GROUP_ID+1,"Zul'Aman - Nalorakk - Wave 2",4),
(@SPAWN_GROUP_ID+2,"Zul'Aman - Nalorakk - Wave 3",4),
(@SPAWN_GROUP_ID+3,"Zul'Aman - Nalorakk - Wave 4",4);
UPDATE `creature` SET `StringId` = 'NalorakkWave1' WHERE `guid` IN (86698,86699,86700);
UPDATE `creature` SET `StringId` = 'NalorakkWave2' WHERE `guid` IN (89259,89260,89261,89262);
UPDATE `creature` SET `StringId` = 'NalorakkWave3' WHERE `guid` IN (89263,89264);
UPDATE `creature` SET `StringId` = 'NalorakkWave4' WHERE `guid` IN (89268,89269,89270,89271);
UPDATE `creature` SET `spawntimesecs` = 259200, `unit_flags` = 33600 WHERE `guid` IN (86698,86699,86700,89259,89260,89261,89262,89263,89264,89268,89269,89270,89271);
DELETE FROM `creature_text` WHERE `CreatureID` = 23576;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(23576,0,0,"Get da move on, guards! It be killin' time!",14,0,100,51,0,12066,22144,1,"Nalorakk - SAY_WAVE_1"),
(23576,1,0,"Guards, go already! Who you more afraid of, dem... or me?",14,0,100,51,0,12067,22146,1,"Nalorakk - SAY_WAVE_2"),
(23576,2,0,"Ride now! Ride out dere and bring me back some heads!",14,0,100,51,0,12068,22151,1,"Nalorakk - SAY_WAVE_3"),
(23576,3,0,"I be losin' me patience! Go on: make dem wish dey was never born!",14,0,100,51,0,12069,22155,1,"Nalorakk - SAY_WAVE_4"),
(23576,4,0,"Mua-ha-ha!",14,0,100,0,0,0,22145,1,"Nalorakk - SAY_WAVE_DONE"),
(23576,5,0,"You be dead soon enough!",14,0,100,0,0,12070,23166,1,"Nalorakk - SAY_AGGRO"),
(23576,6,0,"I bring da pain!",14,0,100,0,0,12071,23167,1,"Nalorakk - SAY_SURGE"),
(23576,7,0,"You call on da beast, you gonna get more dan you bargain for!",14,0,100,0,0,12072,23168,1,"Nalorakk - SAY_TO_BEAR "),
(23576,8,0,"Make way for da Nalorakk!",14,0,100,0,0,12073,23169,1,"Nalorakk - SAY_TO_TROLL"),
(23576,9,0,"You had your chance; now it be too late!",14,0,100,0,0,12074,23170,1,"Nalorakk - SAY_BERSERK"),
(23576,10,0,"Now whatchoo got to say?",14,0,100,0,0,12075,23171,1,"Nalorakk - SAY_SLAY_1"),
(23576,10,1,"Da Amani gonna rule again!",14,0,100,0,0,12076,23172,1,"Nalorakk - SAY_SLAY_2"),
(23576,11,0,"I... be waitin' on da udda side....",14,0,100,0,0,12077,23173,1,"Nalorakk - SAY_DEATH"),
(23576,12,0,"What could be better than servin' da bear spirit for eternity? Come closer now. Bring your souls to me!",14,0,100,0,0,12078,23305,1,"Nalorakk - SAY_EVENT_1"),
(23576,13,0,"I smell you, strangers. Don't be delayin' your fate. Come to me now. I make your sacrifice quick.",14,0,100,0,0,12079,23306,1,"Nalorakk - SAY_EVENT_2"),
(23576,14,0,"%s transforms into a bear!",41,0,100,0,0,0,24263,0,"Nalorakk - EMOTE_TRANSFORM");
DELETE FROM `waypoint_data` WHERE `id` IN (1,2,3);
INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES
(1,1,6.854601,1420.587,11.948586,NULL,0,1,0,100,0),
(1,2,-17.603733,1420.2533,12.702607,NULL,0,1,0,100,0),
(1,3,-52.46344,1419.6982,27.29911,0,1,1,0,100,0),
(2,1,-55.543488,1419.3763,27.303112,NULL,0,1,0,100,0),
(2,2,-78.06857,1419.0736,27.302307,NULL,0,1,0,100,0),
(2,3,-80.584625,1395.3932,27.132534,NULL,0,1,0,100,0),
(2,4,-80.22266,1375.8348,40.75975,1.570796370506286621,1,1,0,100,0),
(3,1,-80.03189,1315.3905,41.195145,NULL,0,1,0,100,0),
(3,2,-79.59927,1300.4309,48.532497,1.570796370506286621,1,1,0,100,0);
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_nalorakk_surge';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(44019, 'spell_nalorakk_surge');

View File

@@ -15,419 +15,433 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Nalorakk
SD%Complete: 100
SDComment:
SDCategory: Zul'Aman
EndScriptData */
/*
* Creatures in waves should load waypoints, not engage immediately
* Surge implementation requires additional research
* Combat timers requires to be revisited
*/
#include "ScriptMgr.h"
#include "CellImpl.h"
#include "GridNotifiersImpl.h"
#include "Containers.h"
#include "Map.h"
#include "MotionMaster.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "SpellScript.h"
#include "zulaman.h"
enum Yells
enum NalorakkTexts
{
YELL_NALORAKK_WAVE1 = 0,
YELL_NALORAKK_WAVE2 = 1,
YELL_NALORAKK_WAVE3 = 2,
YELL_NALORAKK_WAVE4 = 3,
YELL_AGGRO = 4,
YELL_SURGE = 5,
YELL_SHIFTEDTOBEAR = 6,
YELL_SHIFTEDTOTROLL = 7,
YELL_BERSERK = 8,
YELL_KILL_ONE = 9,
YELL_KILL_TWO = 10,
YELL_DEATH = 11
// Not yet implemented
// YELL_NALORAKK_EVENT1 = 12,
// YELL_NALORAKK_EVENT2 = 13
SAY_WAVE_1 = 0,
SAY_WAVE_2 = 1,
SAY_WAVE_3 = 2,
SAY_WAVE_4 = 3,
SAY_WAVE_DONE = 4,
SAY_AGGRO = 5,
SAY_SURGE = 6,
SAY_TO_BEAR = 7,
SAY_TO_TROLL = 8,
SAY_BERSERK = 9,
SAY_SLAY = 10,
SAY_DEATH = 11,
SAY_EVENT_1 = 12, // NYI
SAY_EVENT_2 = 13, // NYI
EMOTE_TRANSFORM = 14
};
enum Spells
enum NalorakkSpells
{
// Troll form
SPELL_BRUTALSWIPE = 42384,
SPELL_MANGLE = 42389,
SPELL_MANGLEEFFECT = 44955,
SPELL_SURGE = 42402,
SPELL_BEARFORM = 42377,
SPELL_BRUTAL_SWIPE = 42384,
SPELL_MANGLE = 42389,
SPELL_SURGE = 44019,
// Bear form
SPELL_LACERATINGSLASH = 42395,
SPELL_RENDFLESH = 42397,
SPELL_DEAFENINGROAR = 42398,
SPELL_LACERATING_SLASH = 42395,
SPELL_REND_FLESH = 42397,
SPELL_DEAFENING_ROAR = 42398,
SPELL_BERSERK = 45078
// Shared
SPELL_SHAPE_OF_THE_BEAR = 42377,
SPELL_BERSERK = 45078,
// Scripts
SPELL_SURGE_CHARGE = 42402,
SPELL_SURGE_HASTE = 44960
};
// Trash Waves
float NalorakkWay[8][3] =
enum NalorakkEvents
{
{ 18.569f, 1414.512f, 11.42f}, // waypoint 1
{-17.264f, 1419.551f, 12.62f},
{-52.642f, 1419.357f, 27.31f}, // waypoint 2
{-69.908f, 1419.721f, 27.31f},
{-79.929f, 1395.958f, 27.31f},
{-80.072f, 1374.555f, 40.87f}, // waypoint 3
{-80.072f, 1314.398f, 40.87f},
{-80.072f, 1295.775f, 48.60f} // waypoint 4
// Waves
EVENT_WAVE_DONE_1 = 1,
EVENT_WAVE_DONE_2,
EVENT_WAVE_DONE_3,
EVENT_WAVE_DONE_4,
// Troll form
EVENT_BRUTAL_SWIPE,
EVENT_MANGLE,
EVENT_SURGE,
// Bear form
EVENT_LACERATING_SLASH,
EVENT_REND_FLESH,
EVENT_DEAFENING_ROAR,
// Shared
EVENT_SHAPESHIFT,
EVENT_BERSERK
};
class boss_nalorakk : public CreatureScript
enum NalorakkSpawnGroups
{
public:
boss_nalorakk() : CreatureScript("boss_nalorakk") { }
SPAWN_GROUP_NALORAKK_WAVE_1 = 329,
SPAWN_GROUP_NALORAKK_WAVE_2 = 330,
SPAWN_GROUP_NALORAKK_WAVE_3 = 331,
SPAWN_GROUP_NALORAKK_WAVE_4 = 332
};
struct boss_nalorakkAI : public BossAI
enum NalorakkPaths
{
PATH_WAVE_DONE_1 = 1,
PATH_WAVE_DONE_2 = 2,
PATH_WAVE_DONE_3 = 3
};
static constexpr std::array<uint8, 4> WaveTexts =
{
SAY_WAVE_1,
SAY_WAVE_2,
SAY_WAVE_3,
SAY_WAVE_4
};
static constexpr std::array<std::string_view, 4> NalorakkWave =
{
"NalorakkWave1",
"NalorakkWave2",
"NalorakkWave3",
"NalorakkWave4"
};
// 23576 - Nalorakk
struct boss_nalorakk : public BossAI
{
boss_nalorakk(Creature* creature) : BossAI(creature, BOSS_NALORAKK),
_waveEventInProgress(true), _isMovingToLocation(false), _isWaiting(false), _isInBearForm(false), _currentWaveCount(0) { }
void Reset() override
{
_Reset();
SetEquipmentSlots(true);
_isInBearForm = false;
if (_waveEventInProgress)
{
boss_nalorakkAI(Creature* creature) : BossAI(creature, BOSS_NALORAKK)
{
Initialize();
inMove = false;
MoveEvent = true;
MovePhase = 0;
waitTimer = 0;
LaceratingSlash_Timer = 0;
RendFlesh_Timer = 0;
DeafeningRoar_Timer = 0;
}
void Initialize()
{
Surge_Timer = urand(15000, 20000);
BrutalSwipe_Timer = urand(7000, 12000);
Mangle_Timer = urand(10000, 15000);
ShapeShift_Timer = urand(45000, 50000);
Berserk_Timer = 600000;
inBearForm = false;
}
uint32 BrutalSwipe_Timer;
uint32 Mangle_Timer;
uint32 Surge_Timer;
uint32 LaceratingSlash_Timer;
uint32 RendFlesh_Timer;
uint32 DeafeningRoar_Timer;
uint32 ShapeShift_Timer;
uint32 Berserk_Timer;
bool inBearForm;
bool MoveEvent;
bool inMove;
uint32 MovePhase;
uint32 waitTimer;
void Reset() override
{
_Reset();
if (MoveEvent)
{
me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
inMove = false;
waitTimer = 0;
me->SetSpeedRate(MOVE_RUN, 2);
me->SetWalk(false);
}
else
me->GetMotionMaster()->MovePoint(0, NalorakkWay[7][0], NalorakkWay[7][1], NalorakkWay[7][2]);
Initialize();
// me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 5122); /// @todo find the correct equipment id
}
void SendAttacker(Unit* target) const
{
std::vector<Creature*> tempList;
Trinity::AllFriendlyCreaturesInGrid check(me);
Trinity::CreatureListSearcher<Trinity::AllFriendlyCreaturesInGrid> searcher(me, tempList, check);
Cell::VisitGridObjects(me, searcher, 25.0f);
if (tempList.empty())
return;
for (Creature* creature : tempList)
{
creature->SetNoCallAssistance(true);
creature->AI()->AttackStart(target);
}
}
void AttackStart(Unit* who) override
{
if (!MoveEvent)
BossAI::AttackStart(who);
}
void MoveInLineOfSight(Unit* who) override
{
if (!MoveEvent)
BossAI::MoveInLineOfSight(who);
else
{
if (me->IsHostileTo(who))
{
if (!inMove)
{
switch (MovePhase)
{
case 0:
if (me->IsWithinDistInMap(who, 50))
{
Talk(YELL_NALORAKK_WAVE1);
me->GetMotionMaster()->MovePoint(1, NalorakkWay[1][0], NalorakkWay[1][1], NalorakkWay[1][2]);
++MovePhase;
inMove = true;
SendAttacker(who);
}
break;
case 2:
if (me->IsWithinDistInMap(who, 40))
{
Talk(YELL_NALORAKK_WAVE2);
me->GetMotionMaster()->MovePoint(3, NalorakkWay[3][0], NalorakkWay[3][1], NalorakkWay[3][2]);
++MovePhase;
inMove = true;
SendAttacker(who);
}
break;
case 5:
if (me->IsWithinDistInMap(who, 40))
{
Talk(YELL_NALORAKK_WAVE3);
me->GetMotionMaster()->MovePoint(6, NalorakkWay[6][0], NalorakkWay[6][1], NalorakkWay[6][2]);
++MovePhase;
inMove = true;
SendAttacker(who);
}
break;
case 7:
if (me->IsWithinDistInMap(who, 50))
{
SendAttacker(who);
Talk(YELL_NALORAKK_WAVE4);
me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
MoveEvent = false;
}
break;
}
}
}
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(YELL_AGGRO);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(YELL_DEATH);
}
void KilledUnit(Unit* /*victim*/) override
{
switch (urand(0, 1))
{
case 0:
Talk(YELL_KILL_ONE);
break;
case 1:
Talk(YELL_KILL_TWO);
break;
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (MoveEvent)
{
if (type != POINT_MOTION_TYPE)
return;
if (!inMove)
return;
if (MovePhase != id)
return;
switch (MovePhase)
{
case 2:
me->SetOrientation(3.1415f*2);
inMove = false;
return;
case 1:
case 3:
case 4:
case 6:
++MovePhase;
waitTimer = 1;
return;
case 5:
me->SetOrientation(3.1415f*0.5f);
inMove = false;
return;
case 7:
me->SetOrientation(3.1415f*0.5f);
inMove = false;
return;
}
}
}
void UpdateAI(uint32 diff) override
{
if (waitTimer && inMove)
{
if (waitTimer <= diff)
{
me->GetMotionMaster()->Clear(MOTION_PRIORITY_NORMAL);
me->GetMotionMaster()->MovePoint(MovePhase, NalorakkWay[MovePhase][0], NalorakkWay[MovePhase][1], NalorakkWay[MovePhase][2]);
waitTimer = 0;
}
else
waitTimer -= diff;
}
if (!UpdateVictim())
return;
if (Berserk_Timer <= diff)
{
DoCast(me, SPELL_BERSERK, true);
Talk(YELL_BERSERK);
Berserk_Timer = 600000;
}
else
Berserk_Timer -= diff;
if (ShapeShift_Timer <= diff)
{
if (inBearForm)
{
// me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 5122);
Talk(YELL_SHIFTEDTOTROLL);
me->RemoveAurasDueToSpell(SPELL_BEARFORM);
Surge_Timer = urand(15000, 20000);
BrutalSwipe_Timer = urand(7000, 12000);
Mangle_Timer = urand(10000, 15000);
ShapeShift_Timer = urand(45000, 50000);
inBearForm = false;
}
else
{
// me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 0);
Talk(YELL_SHIFTEDTOBEAR);
DoCast(me, SPELL_BEARFORM, true);
LaceratingSlash_Timer = 2000; // dur 18s
RendFlesh_Timer = 3000; // dur 5s
DeafeningRoar_Timer = urand(5000, 10000); // dur 2s
ShapeShift_Timer = urand(20000, 25000); // dur 30s
inBearForm = true;
}
}
else
ShapeShift_Timer -= diff;
if (!inBearForm)
{
if (BrutalSwipe_Timer <= diff)
{
DoCastVictim(SPELL_BRUTALSWIPE);
BrutalSwipe_Timer = urand(7000, 12000);
}
else
BrutalSwipe_Timer -= diff;
if (Mangle_Timer <= diff)
{
if (me->GetVictim() && !me->EnsureVictim()->HasAura(SPELL_MANGLEEFFECT))
{
DoCastVictim(SPELL_MANGLE);
Mangle_Timer = 1000;
}
else Mangle_Timer = urand(10000, 15000);
}
else
Mangle_Timer -= diff;
if (Surge_Timer <= diff)
{
Talk(YELL_SURGE);
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 45, true);
if (target)
DoCast(target, SPELL_SURGE);
Surge_Timer = urand(15000, 20000);
}
else
Surge_Timer -= diff;
}
else
{
if (LaceratingSlash_Timer <= diff)
{
DoCastVictim(SPELL_LACERATINGSLASH);
LaceratingSlash_Timer = urand(18000, 23000);
}
else
LaceratingSlash_Timer -= diff;
if (RendFlesh_Timer <= diff)
{
DoCastVictim(SPELL_RENDFLESH);
RendFlesh_Timer = urand(5000, 10000);
}
else
RendFlesh_Timer -= diff;
if (DeafeningRoar_Timer <= diff)
{
DoCastVictim(SPELL_DEAFENINGROAR);
DeafeningRoar_Timer = urand(15000, 20000);
}
else
DeafeningRoar_Timer -= diff;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulAmanAI<boss_nalorakkAI>(creature);
me->SetImmuneToAll(true);
me->GetMap()->SpawnGroupSpawn(SPAWN_GROUP_NALORAKK_WAVE_1, true);
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_BRUTAL_SWIPE, 10s, 20s);
events.ScheduleEvent(EVENT_MANGLE, 5s, 15s);
events.ScheduleEvent(EVENT_SURGE, 20s, 25s);
events.ScheduleEvent(EVENT_SHAPESHIFT, 45s);
events.ScheduleEvent(EVENT_BERSERK, 10min);
}
void OnSpellCast(SpellInfo const* spellInfo) override
{
switch (spellInfo->Id)
{
case SPELL_SHAPE_OF_THE_BEAR:
Talk(SAY_TO_BEAR);
Talk(EMOTE_TRANSFORM);
SetEquipmentSlots(false, EQUIP_NO_CHANGE, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
break;
case SPELL_SURGE:
Talk(SAY_SURGE);
break;
case SPELL_BERSERK:
Talk(SAY_BERSERK);
break;
default:
break;
}
}
void HandleWave(Unit* who)
{
Talk(WaveTexts[_currentWaveCount]);
std::vector<Creature*> waveCreatures;
GetCreatureListWithOptionsInGrid(waveCreatures, me, 50.0f, { .StringId = NalorakkWave[_currentWaveCount] });
for (Creature* waveCreature : waveCreatures)
{
waveCreature->SetImmuneToAll(false);
waveCreature->AI()->AttackStart(who);
}
++_currentWaveCount;
_isWaiting = true;
}
/// @todo: Handle this with GameObjects 186274, 186275, 186276, 186277
void MoveInLineOfSight(Unit* who) override
{
if (!_waveEventInProgress)
{
BossAI::MoveInLineOfSight(who);
return;
}
if (!me->IsHostileTo(who))
return;
if (_isMovingToLocation)
return;
if (_isWaiting)
return;
switch (_currentWaveCount)
{
case 0:
if (me->IsWithinDistInMap(who, 50))
HandleWave(who);
break;
case 1:
if (me->IsWithinDistInMap(who, 40))
HandleWave(who);
break;
case 2:
if (me->IsWithinDistInMap(who, 40))
HandleWave(who);
break;
case 3:
if (me->IsWithinDistInMap(who, 60))
HandleWave(who);
break;
default:
break;
}
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_WAVE_DONE_1:
Talk(SAY_WAVE_DONE);
_isMovingToLocation = true;
_isWaiting = false;
me->GetMap()->SpawnGroupSpawn(SPAWN_GROUP_NALORAKK_WAVE_2, true);
events.ScheduleEvent(EVENT_WAVE_DONE_1, 2s);
break;
case ACTION_WAVE_DONE_2:
Talk(SAY_WAVE_DONE);
_isMovingToLocation = true;
_isWaiting = false;
me->GetMap()->SpawnGroupSpawn(SPAWN_GROUP_NALORAKK_WAVE_3, true);
events.ScheduleEvent(EVENT_WAVE_DONE_2, 2s);
break;
case ACTION_WAVE_DONE_3:
Talk(SAY_WAVE_DONE);
_isMovingToLocation = true;
_isWaiting = false;
me->GetMap()->SpawnGroupSpawn(SPAWN_GROUP_NALORAKK_WAVE_4, true);
events.ScheduleEvent(EVENT_WAVE_DONE_3, 2s);
break;
case ACTION_WAVE_DONE_4:
events.ScheduleEvent(EVENT_WAVE_DONE_4, 0s);
break;
default:
break;
}
}
void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) override
{
_isMovingToLocation = false;
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
}
void UpdateOutOfCombatEvents(uint32 diff)
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_WAVE_DONE_1:
me->GetMotionMaster()->MovePath(PATH_WAVE_DONE_1, false);
break;
case EVENT_WAVE_DONE_2:
me->GetMotionMaster()->MovePath(PATH_WAVE_DONE_2, false);
break;
case EVENT_WAVE_DONE_3:
me->GetMotionMaster()->MovePath(PATH_WAVE_DONE_3, false);
break;
case EVENT_WAVE_DONE_4:
me->SetImmuneToAll(false);
_waveEventInProgress = false;
break;
default:
break;
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
UpdateOutOfCombatEvents(diff);
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BRUTAL_SWIPE:
DoCastVictim(SPELL_BRUTAL_SWIPE);
events.Repeat(10s, 20s);
break;
case EVENT_MANGLE:
DoCastVictim(SPELL_MANGLE);
events.Repeat(20s, 30s);
break;
case EVENT_SURGE:
DoCastSelf(SPELL_SURGE);
events.Repeat(15s, 20s);
break;
case EVENT_LACERATING_SLASH:
DoCastVictim(SPELL_LACERATING_SLASH);
events.Repeat(20s, 30s);
break;
case EVENT_REND_FLESH:
DoCastVictim(SPELL_REND_FLESH);
events.Repeat(10s, 15s);
break;
case EVENT_DEAFENING_ROAR:
DoCastSelf(SPELL_DEAFENING_ROAR);
events.Repeat(10s, 15s);
break;
case EVENT_SHAPESHIFT:
{
if (_isInBearForm)
{
Talk(SAY_TO_TROLL);
SetEquipmentSlots(true);
events.CancelEvent(EVENT_LACERATING_SLASH);
events.CancelEvent(EVENT_REND_FLESH);
events.CancelEvent(EVENT_DEAFENING_ROAR);
events.ScheduleEvent(EVENT_BRUTAL_SWIPE, 10s, 20s);
events.ScheduleEvent(EVENT_MANGLE, 5s, 15s);
events.ScheduleEvent(EVENT_SURGE, 20s, 25s);
events.Repeat(45s);
_isInBearForm = false;
}
else
{
DoCastSelf(SPELL_SHAPE_OF_THE_BEAR);
events.CancelEvent(EVENT_BRUTAL_SWIPE);
events.CancelEvent(EVENT_MANGLE);
events.CancelEvent(EVENT_SURGE);
events.ScheduleEvent(EVENT_LACERATING_SLASH, 5s, 10s);
events.ScheduleEvent(EVENT_REND_FLESH, 10s, 20s);
events.ScheduleEvent(EVENT_DEAFENING_ROAR, 15s, 20s);
events.Repeat(30s);
_isInBearForm = true;
}
break;
}
case EVENT_BERSERK:
DoCastSelf(SPELL_BERSERK);
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
DoMeleeAttackIfReady();
}
private:
bool _waveEventInProgress;
bool _isMovingToLocation;
bool _isWaiting;
bool _isInBearForm;
uint32 _currentWaveCount;
};
// 44019 - Surge
class spell_nalorakk_surge : public SpellScript
{
PrepareSpellScript(spell_nalorakk_surge);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SURGE_CHARGE, SPELL_SURGE_HASTE });
}
void FilterTargets(std::list<WorldObject*>& targets)
{
if (targets.empty())
return;
WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
targets.clear();
targets.push_back(target);
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
caster->CastSpell(target, SPELL_SURGE_CHARGE, true);
caster->CastSpell(caster, SPELL_SURGE_HASTE, true);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_nalorakk_surge::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_nalorakk_surge::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
void AddSC_boss_nalorakk()
{
new boss_nalorakk();
RegisterZulAmanCreatureAI(boss_nalorakk);
RegisterSpellScript(spell_nalorakk_surge);
}

View File

@@ -23,6 +23,7 @@ SDCategory: Zul'Aman
EndScriptData */
#include "ScriptMgr.h"
#include "CreatureAI.h"
#include "GameObject.h"
#include "InstanceScript.h"
#include "Log.h"
@@ -30,6 +31,7 @@ EndScriptData */
#include "Player.h"
#include "TemporarySummon.h"
#include "zulaman.h"
#include <algorithm>
enum Misc
{
@@ -38,6 +40,19 @@ enum Misc
WORLDSTATE_TIME_TO_SACRIFICE = 3106
};
struct NalorakkWaveDefinition
{
std::string_view StringId;
uint8 CreatureCount;
ZAActionIds ActionId;
} static constexpr NalorakkEventWaves[] =
{
{ .StringId = "NalorakkWave1", .CreatureCount = 3, .ActionId = ACTION_WAVE_DONE_1 },
{ .StringId = "NalorakkWave2", .CreatureCount = 4, .ActionId = ACTION_WAVE_DONE_2 },
{ .StringId = "NalorakkWave3", .CreatureCount = 2, .ActionId = ACTION_WAVE_DONE_3 },
{ .StringId = "NalorakkWave4", .CreatureCount = 4, .ActionId = ACTION_WAVE_DONE_4 },
};
// Chests spawn at bear/eagle/dragonhawk/lynx bosses
// The loots depend on how many bosses have been killed, but not the entries of the chests
// But we cannot add loots to gameobject, so we have to use the fixed loot_template
@@ -152,6 +167,27 @@ class instance_zulaman : public InstanceMapScript
}
}
void OnUnitDeath(Unit* unit) override
{
InstanceScript::OnUnitDeath(unit);
Creature* creature = unit->ToCreature();
if (!creature)
return;
auto nalorakkEventWave = std::ranges::find_if(NalorakkEventWaves,
[creature](std::string_view stringId) { return creature->HasStringId(stringId); }, &NalorakkWaveDefinition::StringId);
if (nalorakkEventWave != std::ranges::end(NalorakkEventWaves))
{
std::ptrdiff_t waveIndex = std::ranges::distance(std::ranges::begin(NalorakkEventWaves), nalorakkEventWave);
++killedUnitInWaveCounter[waveIndex];
if (killedUnitInWaveCounter[waveIndex] == nalorakkEventWave->CreatureCount)
if (Creature* nalorakk = GetCreature(BOSS_NALORAKK))
nalorakk->AI()->DoAction(nalorakkEventWave->ActionId);
}
}
void SummonHostage(uint8 num)
{
if (!QuestMinute)
@@ -310,6 +346,9 @@ class instance_zulaman : public InstanceMapScript
QuestTimer -= diff;
}
}
protected:
std::array<uint8, 4> killedUnitInWaveCounter = { };
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override

View File

@@ -77,6 +77,14 @@ enum ZAGameObjectIds
GO_STRANGE_GONG = 187359
};
enum ZAActionIds
{
ACTION_WAVE_DONE_1 = 0,
ACTION_WAVE_DONE_2 = 1,
ACTION_WAVE_DONE_3 = 2,
ACTION_WAVE_DONE_4 = 3
};
template <class AI, class T>
inline AI* GetZulAmanAI(T* obj)
{