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

(cherry picked from commit 024331cd6fb70490bd2e61752f78f613df813b03)
This commit is contained in:
offl
2026-06-29 22:35:52 +02:00
committed by Shauren
parent 0a99511f5c
commit cf9c07d9c8
10 changed files with 672 additions and 176 deletions
@@ -0,0 +1,94 @@
--
DELETE FROM `creature_addon` WHERE `guid` IN (291934,291825,291826,291827,291795,291796,291797,291800,291791,291792,291787,291788,291789,291790);
DELETE FROM `creature` WHERE `guid` IN (291934,291825,291826,291827,291795,291796,291797,291800,291791,291792,291787,291788,291789,291790);
DELETE FROM `creature` WHERE `guid` IN (86609,86698,86699,86700,89259,89260,89261,89262,89263,89264,89268,89269,89270,89271);
INSERT INTO `creature` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnDifficulties`, `PhaseId`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `curHealthPct`, `MovementType`, `npcflag`, `unit_flags`, `ScriptName`, `StringId`, `VerifiedBuild`) VALUES
(86609, 23576, 568, 0, 0, '2', 0, 0, 1, 16.9616, 1414.6, 11.9265, 6.23082, 259200, 0, 100, 0, NULL, NULL, '', NULL, 0),
(86698, 23582, 568, 0, 0, '2', 0, 22272, 1, 19.0948, 1420.57, 11.973, 5.8294, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave1', 0),
(86699, 23542, 568, 0, 0, '2', 0, 22274, 1, 17.3455, 1418.6, 11.9475, 6.02139, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave1', 0),
(86700, 23582, 568, 0, 0, '2', 0, 22271, 1, 14.5413, 1411.64, 11.982, 0.017453, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave1', 0),
(89259, 23581, 568, 0, 0, '2', 0, 22275, 1, -50.7096, 1423.47, 27.4899, 6.17846, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave2', 0),
(89260, 23582, 568, 0, 0, '2', 0, 22271, 1, -53.3283, 1416.59, 27.3666, 0.017453, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave2', 0),
(89261, 23542, 568, 0, 0, '2', 0, 22273, 1, -53.39, 1422.76, 27.367, 6.17846, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave2', 0),
(89262, 23582, 568, 0, 0, '2', 0, 22272, 1, -50.7764, 1415.72, 27.4538, 0, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave2', 0),
(89263, 23580, 568, 0, 0, '2', 0, 22277, 1, -84.733, 1375.83, 40.8849, 1.41372, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave3', 0),
(89264, 23580, 568, 0, 0, '2', 0, 22278, 1, -76.1125, 1375.98, 40.8471, 1.67552, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave3', 0),
(89268, 23580, 568, 0, 0, '2', 0, 22277, 1, -84.5659, 1315.04, 41.201, 4.85202, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave4', 0),
(89269, 23581, 568, 0, 0, '2', 0, 22276, 1, -71.6538, 1315.07, 41.3016, 4.4855, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave4', 0),
(89270, 23581, 568, 0, 0, '2', 0, 22276, 1, -88.9147, 1314.97, 41.1013, 4.97419, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave4', 0),
(89271, 23580, 568, 0, 0, '2', 0, 22278, 1, -75.9265, 1315.24, 41.3016, 4.60767, 259200, 0, 100, 0, NULL, 0x8340, '', 'NalorakkWave4', 0);
INSERT INTO `creature_addon` (`guid`, `PathId`, `mount`, `MountCreatureID`, `StandState`, `AnimTier`, `VisFlags`, `SheathState`, `PvPFlags`, `emote`, `visibilityDistanceType`, `auras`) VALUES
(86609, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3, NULL);
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);
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_path` WHERE `PathId` IN (1,2,3);
INSERT INTO `waypoint_path` (`PathId`, `MoveType`, `Flags`, `Velocity`, `Comment`) VALUES
(1,1,0,NULL,'Nalorakk - move to 2nd trash pack'),
(2,1,0,NULL,'Nalorakk - move to 3rd trash pack'),
(3,1,0,NULL,'Nalorakk - move to final pos');
DELETE FROM `waypoint_path_node` WHERE `PathId` IN (1,2,3);
INSERT INTO `waypoint_path_node` (`PathId`, `NodeId`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `Delay`) VALUES
(1,1,6.854601,1420.587,11.948586,NULL,0),
(1,2,-17.603733,1420.2533,12.702607,NULL,0),
(1,3,-52.46344,1419.6982,27.29911,0,1),
(2,1,-55.543488,1419.3763,27.303112,NULL,0),
(2,2,-78.06857,1419.0736,27.302307,NULL,0),
(2,3,-80.584625,1395.3932,27.132534,NULL,0),
(2,4,-80.22266,1375.8348,40.75975,1.570796370506286621,1),
(3,1,-80.03189,1315.3905,41.195145,NULL,0),
(3,2,-79.59927,1300.4309,48.532497,1.570796370506286621,1);
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_nalorakk_surge';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(44019, 'spell_nalorakk_surge');
@@ -61,7 +61,7 @@ class boss_akilzon : public CreatureScript
struct boss_akilzonAI : public BossAI
{
boss_akilzonAI(Creature* creature) : BossAI(creature, DATA_AKILZON) { }
boss_akilzonAI(Creature* creature) : BossAI(creature, BOSS_AKILZON) { }
void Reset() override
{
@@ -52,7 +52,7 @@ class boss_daakara : public CreatureScript
struct boss_daakaraAI : public BossAI
{
boss_daakaraAI(Creature* creature) : BossAI(creature, DATA_DAAKARA) { }
boss_daakaraAI(Creature* creature) : BossAI(creature, BOSS_DAAKARA) { }
void Reset() override
{
@@ -45,7 +45,7 @@ class boss_halazzi : public CreatureScript
struct boss_halazziAI : public BossAI
{
boss_halazziAI(Creature* creature) : BossAI(creature, DATA_HALAZZI) { }
boss_halazziAI(Creature* creature) : BossAI(creature, BOSS_HALAZZI) { }
void Reset() override
{
@@ -49,7 +49,7 @@ class boss_hexlord_malacrass : public CreatureScript
struct boss_hex_lord_malacrassAI : public BossAI
{
boss_hex_lord_malacrassAI(Creature* creature) : BossAI(creature, DATA_HEXLORD) { }
boss_hex_lord_malacrassAI(Creature* creature) : BossAI(creature, BOSS_HEXLORD) { }
void Reset() override
{
@@ -46,7 +46,7 @@ class boss_janalai : public CreatureScript
struct boss_janalaiAI : public BossAI
{
boss_janalaiAI(Creature* creature) : BossAI(creature, DATA_JANALAI) { }
boss_janalaiAI(Creature* creature) : BossAI(creature, BOSS_JANALAI) { }
void Reset() override
{
@@ -1,4 +1,4 @@
/*
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
@@ -15,96 +15,420 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Creatures in waves should load waypoints, not engage immediately
* Surge implementation requires additional research
* Combat timers requires to be revisited
*/
#include "ScriptMgr.h"
#include "Containers.h"
#include "Map.h"
#include "MotionMaster.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "SpellScript.h"
#include "zulaman.h"
enum Says
enum NalorakkTexts
{
SAY_WAVE_1 = 0,
SAY_WAVE_2 = 1,
SAY_WAVE_3 = 2,
SAY_WAVE_4 = 3,
SAY_AGGRO = 4,
SAY_PLAYER_KILL = 5,
SAY_SURGE = 6,
EMOTE_SURGE = 7,
EMOTE_BEAR = 8,
SAY_BEAR = 9,
SAY_TROLL = 10,
SAY_DEATH = 11
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_BRUTAL_SWIPE = 42384,
SPELL_SURGE = 44019,
// Bear form
SPELL_LACERATING_SLASH = 42395,
SPELL_REND_FLESH = 42397,
SPELL_DEAFENING_ROAR = 42398,
// Shared
SPELL_SHAPE_OF_THE_BEAR = 42377,
SPELL_BERSERK = 45078,
// Scripts
SPELL_SURGE_CHARGE = 42402,
SPELL_SURGE_HASTE = 44960
};
enum Events
enum NalorakkEvents
{
// Waves
EVENT_WAVE_DONE_1 = 1,
EVENT_WAVE_DONE_2,
EVENT_WAVE_DONE_3,
EVENT_WAVE_DONE_4,
// Troll form
EVENT_BRUTAL_SWIPE,
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:
SPAWN_GROUP_NALORAKK_WAVE_1 = 329,
SPAWN_GROUP_NALORAKK_WAVE_2 = 330,
SPAWN_GROUP_NALORAKK_WAVE_3 = 331,
SPAWN_GROUP_NALORAKK_WAVE_4 = 332
};
boss_nalorakk() : CreatureScript("boss_nalorakk") { }
enum NalorakkPaths
{
PATH_WAVE_DONE_1 = 1,
PATH_WAVE_DONE_2 = 2,
PATH_WAVE_DONE_3 = 3
};
struct boss_nalorakkAI : public BossAI
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, DATA_NALORAKK) { }
void Reset() override
{
_Reset();
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
_JustDied();
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_PLAYER_KILL);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
/*
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
default:
break;
}
}
*/
}
};
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_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_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_SURGE, 20s, 25s);
events.Repeat(45s);
_isInBearForm = false;
}
else
{
DoCastSelf(SPELL_SHAPE_OF_THE_BEAR);
events.CancelEvent(EVENT_BRUTAL_SWIPE);
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;
}
}
private:
bool _waveEventInProgress;
bool _isMovingToLocation;
bool _isWaiting;
bool _isInBearForm;
uint32 _currentWaveCount;
};
// 44019 - Surge
class spell_nalorakk_surge : public SpellScript
{
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);
}
@@ -16,21 +16,93 @@
*/
#include "ScriptMgr.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "GameObject.h"
#include "InstanceScript.h"
#include "Map.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "TemporarySummon.h"
#include "zulaman.h"
#include <algorithm>
DungeonEncounterData const encounters[] =
struct NalorakkWaveDefinition
{
{ DATA_AKILZON, {{ 1189 }} },
{ DATA_NALORAKK, {{ 1190 }} },
{ DATA_JANALAI, {{ 1191 }} },
{ DATA_HALAZZI, {{ 1192 }} },
{ DATA_HEXLORD, {{ 1193 }} },
{ DATA_DAAKARA, {{ 1194 }} }
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
struct SHostageInfo
{
uint32 npc, go; // FIXME go Not used
Position pos;
};
static SHostageInfo const HostageInfo[] =
{
{ 23790, 186648, { -57.f, 1343.f, 40.77f, 3.2f } }, // bear
{ 23999, 187021, { 400.f, 1414.f, 74.36f, 3.3f } }, // eagle
{ 24001, 186672, { -35.f, 1134.f, 18.71f, 1.9f } }, // dragonhawk
{ 24024, 186667, { 413.f, 1117.f, 6.32f, 3.1f } } // lynx
};
static constexpr DoorData doorData[] =
{
{ GO_HEXLORD_ENTRANCE, BOSS_NALORAKK, EncounterDoorBehavior::OpenWhenDone },
{ GO_HEXLORD_ENTRANCE, BOSS_AKILZON, EncounterDoorBehavior::OpenWhenDone },
{ GO_HEXLORD_ENTRANCE, BOSS_JANALAI, EncounterDoorBehavior::OpenWhenDone },
{ GO_HEXLORD_ENTRANCE, BOSS_HALAZZI, EncounterDoorBehavior::OpenWhenDone },
{ GO_DOOR_AKILZON, BOSS_AKILZON, EncounterDoorBehavior::OpenWhenNotInProgress },
{ GO_LYNX_TEMPLE_ENTRANCE, BOSS_HALAZZI, EncounterDoorBehavior::OpenWhenNotInProgress },
{ GO_LYNX_TEMPLE_EXIT, BOSS_HALAZZI, EncounterDoorBehavior::OpenWhenDone },
{ GO_HEXLORD_ENTRANCE, BOSS_HEXLORD, EncounterDoorBehavior::OpenWhenNotInProgress },
{ GO_WOODEN_DOOR, BOSS_HEXLORD, EncounterDoorBehavior::OpenWhenDone },
{ GO_DOOR_DAAKARA, BOSS_DAAKARA, EncounterDoorBehavior::OpenWhenNotInProgress }
};
static constexpr ObjectData creatureData[] =
{
{ NPC_NALORAKK, BOSS_NALORAKK },
{ NPC_AKILZON, BOSS_AKILZON },
{ NPC_JANALAI, BOSS_JANALAI },
{ NPC_HALAZZI, BOSS_HALAZZI },
{ NPC_HEXLORD, BOSS_HEXLORD },
{ NPC_HEXLORD_TRIGGER, DATA_HEXLORD_TRIGGER },
{ NPC_DAAKARA, BOSS_DAAKARA },
{ NPC_BEAR_SPIRIT, DATA_BEAR_SPIRIT },
{ NPC_EAGLE_SPIRIT, DATA_EAGLE_SPIRIT },
{ NPC_LYNX_SPIRIT, DATA_LYNX_SPIRIT },
{ NPC_DRAGONHAWK_SPIRIT, DATA_DRAGONHAWK_SPIRIT }
};
static constexpr ObjectData gameObjectData[] =
{
{ GO_MASSIVE_GATE, GO_MASSIVE_GATE },
{ GO_BAKKALZUS_SATCHEL, GO_BAKKALZUS_SATCHEL },
{ GO_HAZLEKS_TRUNK, GO_HAZLEKS_TRUNK },
{ GO_KASHAS_BAG, GO_KASHAS_BAG },
{ GO_NORKANIS_PACKAGE, GO_NORKANIS_PACKAGE },
{ GO_STRANGE_GONG, GO_STRANGE_GONG }
};
static constexpr DungeonEncounterData encounters[] =
{
{ BOSS_AKILZON, {{ 1189 }} },
{ BOSS_NALORAKK, {{ 1190 }} },
{ BOSS_JANALAI, {{ 1191 }} },
{ BOSS_HALAZZI, {{ 1192 }} },
{ BOSS_HEXLORD, {{ 1193 }} },
{ BOSS_DAAKARA, {{ 1194 }} }
};
class instance_zulaman : public InstanceMapScript
@@ -44,7 +116,9 @@ class instance_zulaman : public InstanceMapScript
ZulAmanState(*this, "TimedRunState", NOT_STARTED)
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
SetBossNumber(MAX_ENCOUNTER);
LoadDoorData(doorData);
LoadObjectData(creatureData, gameObjectData);
LoadDungeonEncounterData(encounters);
SpeedRunTimer = 15;
@@ -53,32 +127,13 @@ class instance_zulaman : public InstanceMapScript
void OnCreatureCreate(Creature* creature) override
{
InstanceScript::OnCreatureCreate(creature);
switch (creature->GetEntry())
{
case NPC_AKILZON:
AkilzonGUID = creature->GetGUID();
break;
case NPC_NALORAKK:
NalorakkGUID = creature->GetGUID();
break;
case NPC_JANALAI:
JanalaiGUID = creature->GetGUID();
break;
case NPC_HALAZZI:
HalazziGUID = creature->GetGUID();
break;
case NPC_HEXLORD:
HexLordMalacrassGUID = creature->GetGUID();
break;
case NPC_DAAKARA:
DaakaraGUID = creature->GetGUID();
break;
case NPC_VOLJIN:
VoljinGUID = creature->GetGUID();
break;
case NPC_HEXLORD_TRIGGER:
HexLordTriggerGUID = creature->GetGUID();
break;
default:
break;
}
@@ -86,14 +141,11 @@ class instance_zulaman : public InstanceMapScript
void OnGameObjectCreate(GameObject* go) override
{
InstanceScript::OnGameObjectCreate(go);
switch (go->GetEntry())
{
case GO_STRANGE_GONG:
StrangeGongGUID = go->GetGUID();
break;
case GO_MASSIVE_GATE:
MasiveGateGUID = go->GetGUID();
AddDoor(go, true);
if (ZulAmanState != NOT_STARTED)
go->SetGoState(GO_STATE_ACTIVE);
break;
@@ -102,45 +154,44 @@ class instance_zulaman : public InstanceMapScript
}
}
void OnGameObjectRemove(GameObject* go) override
void OnUnitDeath(Unit* unit) override
{
switch (go->GetEntry())
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))
{
case GO_MASSIVE_GATE:
AddDoor(go, false);
break;
default:
break;
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);
}
}
ObjectGuid GetGuidData(uint32 type) const override
void SummonHostage(uint8 num)
{
switch (type)
{
case DATA_AKILZON:
return AkilzonGUID;
case DATA_NALORAKK:
return NalorakkGUID;
case DATA_JANALAI:
return JanalaiGUID;
case DATA_HALAZZI:
return HalazziGUID;
case DATA_HEXLORD:
return HexLordMalacrassGUID;
case DATA_DAAKARA:
return DaakaraGUID;
case DATA_HEXLORD_TRIGGER:
return HexLordTriggerGUID;
case DATA_STRANGE_GONG:
return StrangeGongGUID;
case DATA_MASSIVE_GATE:
return MasiveGateGUID;
default:
break;
}
if (ZulAmanState != IN_PROGRESS)
return;
return ObjectGuid::Empty;
Map::PlayerList const& playerList = instance->GetPlayers();
if (playerList.empty())
return;
if (Player* player = playerList.front()->GetSource())
{
if (Unit* hostage = player->SummonCreature(HostageInfo[num].npc, HostageInfo[num].pos, TEMPSUMMON_DEAD_DESPAWN))
{
hostage->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
hostage->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
}
}
void SetData(uint32 type, uint32 data) override
@@ -204,16 +255,24 @@ class instance_zulaman : public InstanceMapScript
switch (type)
{
case DATA_AKILZON:
case BOSS_NALORAKK:
if (state == DONE)
SummonHostage(0);
break;
case DATA_NALORAKK:
case BOSS_AKILZON:
if (state == DONE)
SummonHostage(1);
break;
case DATA_JANALAI:
case BOSS_JANALAI:
if (state == DONE)
SummonHostage(2);
break;
case DATA_HALAZZI:
case DATA_HEXLORD:
case DATA_DAAKARA:
case BOSS_HALAZZI:
if (state == DONE)
SummonHostage(3);
break;
case BOSS_HEXLORD:
case BOSS_DAAKARA:
default:
break;
}
@@ -277,19 +336,11 @@ class instance_zulaman : public InstanceMapScript
protected:
EventMap events;
ObjectGuid AkilzonGUID;
ObjectGuid NalorakkGUID;
ObjectGuid JanalaiGUID;
ObjectGuid HalazziGUID;
ObjectGuid HexLordMalacrassGUID;
ObjectGuid DaakaraGUID;
ObjectGuid VoljinGUID;
ObjectGuid HexLordTriggerGUID;
ObjectGuid StrangeGongGUID;
ObjectGuid MasiveGateGUID;
uint32 SpeedRunTimer;
PersistentInstanceScriptValue<uint32> ZulAmanState;
uint32 ZulAmanBossCount;
std::array<uint8, 4> killedUnitInWaveCounter = { };
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
@@ -149,7 +149,7 @@ class npc_voljin_zulaman : public CreatureScript
break;
case EVENT_BANGING_THE_GONG:
DoCast(me, SPELL_BANGING_THE_GONG);
if (GameObject* strangeGong = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(DATA_STRANGE_GONG)))
if (GameObject* strangeGong = _instance->GetGameObject(GO_STRANGE_GONG))
strangeGong->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
me->SetVirtualItem(0, uint32(ITEM_VIRTUAL_ITEM));
break;
@@ -159,7 +159,7 @@ class npc_voljin_zulaman : public CreatureScript
break;
case EVENT_START_DOOR_OPENING_2:
me->SetVirtualItem(0, uint32(0));
if (GameObject* strangeGong = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(DATA_STRANGE_GONG)))
if (GameObject* strangeGong = _instance->GetGameObject(GO_STRANGE_GONG))
strangeGong->SetFlag(GO_FLAG_NOT_SELECTABLE);
_events.ScheduleEvent(EVENT_START_DOOR_OPENING_3, 500ms);
break;
@@ -168,7 +168,7 @@ class npc_voljin_zulaman : public CreatureScript
break;
case EVENT_START_DOOR_OPENING_4:
_instance->SetData(DATA_ZULAMAN_STATE, IN_PROGRESS);
if (GameObject* masiveGate = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(DATA_MASSIVE_GATE)))
if (GameObject* masiveGate = _instance->GetGameObject(GO_MASSIVE_GATE))
masiveGate->SetGoState(GO_STATE_ACTIVE);
_events.ScheduleEvent(EVENT_START_DOOR_OPENING_5, 3s);
break;
@@ -197,7 +197,7 @@ class npc_voljin_zulaman : public CreatureScript
switch (pointId)
{
case POINT_STRANGE_GONG:
if (GameObject* strangeGong = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(DATA_STRANGE_GONG)))
if (GameObject* strangeGong = _instance->GetGameObject(GO_STRANGE_GONG))
me->SetFacingToObject(strangeGong); // setInFront
break;
case POINT_START_DOOR_OPENING_1:
@@ -20,28 +20,29 @@
#include "CreatureAIImpl.h"
uint32 const EncounterCount = 6;
#define ZulamanScriptName "instance_zulaman"
#define DataHeader "ZA"
enum ZADataTypes
{
// BossState
DATA_AKILZON = 0,
DATA_NALORAKK = 1,
DATA_JANALAI = 2,
DATA_HALAZZI = 3,
DATA_HEXLORD = 4,
DATA_DAAKARA = 5,
BOSS_AKILZON = 0,
BOSS_NALORAKK = 1,
BOSS_JANALAI = 2,
BOSS_HALAZZI = 3,
BOSS_HEXLORD = 4,
BOSS_DAAKARA = 5,
MAX_ENCOUNTER,
// Data64
DATA_HEXLORD_TRIGGER,
DATA_STRANGE_GONG,
DATA_MASSIVE_GATE,
// SetData
DATA_ZULAMAN_STATE
DATA_ZULAMAN_STATE,
DATA_BEAR_SPIRIT,
DATA_EAGLE_SPIRIT,
DATA_LYNX_SPIRIT,
DATA_DRAGONHAWK_SPIRIT
};
enum ZACreatureIds
@@ -54,13 +55,29 @@ enum ZACreatureIds
NPC_DAAKARA = 23863,
NPC_VOLJIN = 52924,
NPC_HEXLORD_TRIGGER = 24363
NPC_HEXLORD_TRIGGER = 24363,
// Daakara
NPC_BEAR_SPIRIT = 23878,
NPC_EAGLE_SPIRIT = 23880,
NPC_LYNX_SPIRIT = 23877,
NPC_DRAGONHAWK_SPIRIT = 23879
};
enum ZAGameObjectIds
{
GO_STRANGE_GONG = 187359,
GO_LYNX_TEMPLE_EXIT = 186303,
GO_LYNX_TEMPLE_ENTRANCE = 186304,
GO_HEXLORD_ENTRANCE = 186305,
GO_WOODEN_DOOR = 186306,
GO_MASSIVE_GATE = 186728,
GO_DOOR_AKILZON = 186858,
GO_DOOR_DAAKARA = 186859,
GO_BAKKALZUS_SATCHEL = 187021,
GO_HAZLEKS_TRUNK = 186648,
GO_KASHAS_BAG = 186672,
GO_NORKANIS_PACKAGE = 186667,
GO_STRANGE_GONG = 187359,
};
enum ZAEvents
@@ -80,10 +97,20 @@ enum ZAWorldStates
WORLD_STATE_ZULAMAN_TIMER = 3106,
};
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)
{
return GetInstanceAI<AI>(obj, ZulamanScriptName);
}
#define RegisterZulAmanCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetZulAmanAI)
#endif