diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp
index 5b8ac70..ce9a817 100644
--- a/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp
@@ -15,14 +15,23 @@
* with this program. If not, see .
*/
-// Nalorakk n'avait qu'une coquille de script : il frappait en melee et rien d'autre,
-// ni sorts ni changement de forme. Le combat est ici ecrit a partir du script amont
-// TrinityCore, en gardant NOTRE numerotation de creature_text (0-11).
-// Ce qui n'est pas porte : les quatre vagues de trolls qui l'annoncent dans la rampe.
-// L'amont les pilote par des spawn groups et des chemins de waypoints que ce core
-// n'a pas (pas de table spawn_group) -- cela demanderait de recreer les donnees.
+// Nalorakk n'avait qu'une coquille de script : ni sorts, ni formes, ni les quatre
+// vagues de trolls de la rampe.
+//
+// L'evenement suit AzerothCore, qui tient la meilleure version de ce contenu BC :
+// le boss attend au pied de la rampe, lance sur les joueurs le groupe de trolls
+// pose autour de lui, ATTEND QUE LA VAGUE SOIT MORTE, puis recule d'un palier en
+// lancant « Make way for da Nalorakk! ». Il n'est attaquable qu'apres la quatrieme.
+// Les deplacements passent par des positions en dur (reprises de l'ancien script
+// TrinityCore) : ni spawn groups ni chemins de waypoints n'existent sur ce core.
+//
+// Numerotation des textes : celle de NOTRE creature_text (verifiee ligne a ligne),
+// qui est l'ancienne numerotation BC et non celle des cores modernes.
#include "ScriptMgr.h"
+#include "Creature.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
#include "zulaman.h"
@@ -37,8 +46,8 @@ enum Says
SAY_SURGE = 6,
EMOTE_SURGE = 7,
EMOTE_BEAR = 8,
- SAY_BEAR = 9,
- SAY_TROLL = 10,
+ SAY_SHIFT_TO_BEAR = 9,
+ SAY_MAKE_WAY = 10, // « Make way for da Nalorakk! » : il recule d'un palier
SAY_DEATH = 11
};
@@ -47,7 +56,7 @@ enum Spells
// Forme troll
SPELL_BRUTAL_SWIPE = 42384,
SPELL_MANGLE = 42389,
- SPELL_SURGE = 44019,
+ SPELL_SURGE = 42402,
// Forme d'ours
SPELL_LACERATING_SLASH = 42395,
@@ -73,6 +82,29 @@ enum Events
EVENT_BERSERK
};
+enum WaveCreatures
+{
+ NPC_AMANISHI_AXE_THROWER = 23542,
+ NPC_AMANISHI_WARBRINGER = 23580,
+ NPC_AMANISHI_MEDICINE_MAN = 23581,
+ NPC_AMANISHI_TRIBESMAN = 23582
+};
+
+// Le chemin de la rampe. Les paliers ou il s'arrete pour lancer une vague sont
+// 0, 1, 5 et 8 ; les autres points ne sont que des etapes de trajet.
+static float const NalorakkWay[9][3] =
+{
+ { 18.569f, 1414.512f, 11.42f }, // palier 1
+ { -17.264f, 1419.551f, 12.62f }, // palier 2
+ { -52.642f, 1419.357f, 27.31f },
+ { -69.908f, 1419.721f, 27.31f },
+ { -79.929f, 1395.958f, 27.31f },
+ { -80.072f, 1374.555f, 40.87f }, // palier 3
+ { -80.072f, 1314.398f, 40.87f },
+ { -80.072f, 1295.775f, 48.60f },
+ { -80.072f, 1362.000f, 40.87f } // palier 4
+};
+
class boss_nalorakk : public CreatureScript
{
public:
@@ -81,13 +113,193 @@ class boss_nalorakk : public CreatureScript
struct boss_nalorakkAI : public BossAI
{
- boss_nalorakkAI(Creature* creature) : BossAI(creature, DATA_NALORAKK), _bearForm(false) { }
+ boss_nalorakkAI(Creature* creature) : BossAI(creature, DATA_NALORAKK),
+ _bearForm(false), _waveEvent(true), _waveInProgress(false), _inMove(false),
+ _wave(0), _currentPoint(0), _targetPoint(0), _checkTimer(0) { }
void Reset() override
{
_Reset();
_bearForm = false;
me->RemoveAurasDueToSpell(SPELL_SHAPE_OF_THE_BEAR);
+
+ if (!_waveEvent)
+ return;
+
+ // Une fois l'evenement joue, il ne recommence pas : sans cela un simple
+ // repli rendrait le boss intouchable pour de bon.
+ _waveInProgress = false;
+ _inMove = false;
+ _wave = 0;
+ _currentPoint = 0;
+ _targetPoint = 0;
+ _checkTimer = 0;
+ _waveGuids.clear();
+
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+ me->SetSpeedRate(MOVE_RUN, 2.0f);
+ me->SetWalk(false);
+
+ // Notre spawn est pose a la position finale du boss, en haut de la rampe :
+ // on le remet au pied, sinon l'evenement se deroulerait a l'envers.
+ me->NearTeleportTo(NalorakkWay[0][0], NalorakkWay[0][1], NalorakkWay[0][2], 3.14f);
+ me->SetHomePosition(NalorakkWay[0][0], NalorakkWay[0][1], NalorakkWay[0][2], 3.14f);
+ }
+
+ // Tant que les vagues durent, il ne repond pas aux provocations.
+ void AttackStart(Unit* who) override
+ {
+ if (!_waveEvent)
+ BossAI::AttackStart(who);
+ }
+
+ void GatherWave(uint32 entry, float radius)
+ {
+ std::list found;
+ me->GetCreatureListWithEntryInGrid(found, entry, radius);
+ for (Creature* creature : found)
+ if (creature->IsAlive())
+ _waveGuids.push_back(creature->GetGUID());
+ }
+
+ void LaunchWave(Unit* target)
+ {
+ _waveGuids.clear();
+
+ switch (_wave)
+ {
+ case 0:
+ GatherWave(NPC_AMANISHI_AXE_THROWER, 10.0f);
+ GatherWave(NPC_AMANISHI_TRIBESMAN, 10.0f);
+ break;
+ case 1:
+ GatherWave(NPC_AMANISHI_AXE_THROWER, 10.0f);
+ GatherWave(NPC_AMANISHI_TRIBESMAN, 10.0f);
+ GatherWave(NPC_AMANISHI_MEDICINE_MAN, 10.0f);
+ break;
+ case 2:
+ GatherWave(NPC_AMANISHI_WARBRINGER, 10.0f);
+ break;
+ case 3:
+ GatherWave(NPC_AMANISHI_WARBRINGER, 25.0f);
+ GatherWave(NPC_AMANISHI_MEDICINE_MAN, 25.0f);
+ break;
+ default:
+ break;
+ }
+
+ Talk(uint8(SAY_WAVE_1 + _wave));
+
+ for (ObjectGuid const& guid : _waveGuids)
+ if (Creature* member = ObjectAccessor::GetCreature(*me, guid))
+ {
+ member->SetNoCallAssistance(true);
+ member->AI()->AttackStart(target);
+ }
+
+ // La quatrieme vague est la derniere : il descend dans l'arene.
+ if (_wave == 3)
+ {
+ EndWaveEvent();
+ return;
+ }
+
+ _waveInProgress = true;
+ _checkTimer = 2000;
+ }
+
+ bool WaveIsDead() const
+ {
+ for (ObjectGuid const& guid : _waveGuids)
+ if (Creature* member = ObjectAccessor::GetCreature(*me, guid))
+ if (member->IsAlive())
+ return false;
+
+ return true;
+ }
+
+ // Fin de l'evenement : il redevient un boss ordinaire. Appele aussi en filet
+ // de securite si un joueur lui arrive au contact, parce qu'une immunite
+ // d'introduction qui ne se leve jamais rend un boss definitivement intuable.
+ void EndWaveEvent()
+ {
+ if (!_waveEvent)
+ return;
+
+ _waveEvent = false;
+ _waveInProgress = false;
+ _inMove = false;
+ _waveGuids.clear();
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+ me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!_waveEvent)
+ {
+ BossAI::MoveInLineOfSight(who);
+ return;
+ }
+
+ if (who->GetTypeId() != TYPEID_PLAYER || !me->IsHostileTo(who) || !who->IsAlive())
+ return;
+
+ if (me->IsWithinDistInMap(who, 8.0f))
+ {
+ EndWaveEvent();
+ return;
+ }
+
+ if (_waveInProgress || _inMove)
+ return;
+
+ float const range = (_wave == 0 || _wave == 3) ? 50.0f : 40.0f;
+ if (me->IsWithinDistInMap(who, range))
+ LaunchWave(who);
+ }
+
+ void MoveToNextStop()
+ {
+ Talk(SAY_MAKE_WAY);
+
+ _waveInProgress = false;
+ _inMove = true;
+ ++_wave;
+
+ switch (_wave)
+ {
+ case 1: _targetPoint = 1; break;
+ case 2: _targetPoint = 5; break;
+ case 3: _targetPoint = 8; break;
+ default: _targetPoint = _currentPoint; break;
+ }
+
+ AdvanceOnePoint();
+ }
+
+ void AdvanceOnePoint()
+ {
+ uint32 next = (_currentPoint < 7 && _targetPoint != 8) ? _currentPoint + 1
+ : (_targetPoint == 8 ? 8 : _targetPoint);
+
+ _currentPoint = next;
+ me->GetMotionMaster()->MovePoint(_currentPoint, NalorakkWay[_currentPoint][0], NalorakkWay[_currentPoint][1], NalorakkWay[_currentPoint][2]);
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (!_waveEvent || type != POINT_MOTION_TYPE || !_inMove || _currentPoint != id)
+ return;
+
+ if (_currentPoint == _targetPoint)
+ {
+ _inMove = false;
+ me->SetFacingTo(float(M_PI) * 0.5f);
+ return;
+ }
+
+ AdvanceOnePoint();
}
void EnterCombat(Unit* /*who*/) override
@@ -114,16 +326,16 @@ class boss_nalorakk : public CreatureScript
void ScheduleTrollEvents()
{
- events.ScheduleEvent(EVENT_BRUTAL_SWIPE, urand(10000, 20000));
- events.ScheduleEvent(EVENT_MANGLE, urand(15000, 20000));
- events.ScheduleEvent(EVENT_SURGE, urand(20000, 25000));
+ events.ScheduleEvent(EVENT_BRUTAL_SWIPE, urand(7000, 12000));
+ events.ScheduleEvent(EVENT_MANGLE, urand(10000, 15000));
+ events.ScheduleEvent(EVENT_SURGE, urand(15000, 20000));
}
void ScheduleBearEvents()
{
- events.ScheduleEvent(EVENT_LACERATING_SLASH, urand(10000, 15000));
- events.ScheduleEvent(EVENT_REND_FLESH, urand(12000, 18000));
- events.ScheduleEvent(EVENT_DEAFENING_ROAR, urand(20000, 25000));
+ events.ScheduleEvent(EVENT_LACERATING_SLASH, 2000);
+ events.ScheduleEvent(EVENT_REND_FLESH, 3000);
+ events.ScheduleEvent(EVENT_DEAFENING_ROAR, urand(5000, 10000));
}
void CancelFormEvents()
@@ -138,6 +350,20 @@ class boss_nalorakk : public CreatureScript
void UpdateAI(uint32 diff) override
{
+ // Deroulement des vagues : il ne recule qu'une fois la vague abattue.
+ if (_waveInProgress)
+ {
+ if (_checkTimer <= diff)
+ {
+ if (WaveIsDead())
+ MoveToNextStop();
+ else
+ _checkTimer = 2000;
+ }
+ else
+ _checkTimer -= diff;
+ }
+
if (!UpdateVictim())
return;
@@ -152,11 +378,11 @@ class boss_nalorakk : public CreatureScript
{
case EVENT_BRUTAL_SWIPE:
DoCastVictim(SPELL_BRUTAL_SWIPE);
- events.ScheduleEvent(EVENT_BRUTAL_SWIPE, urand(10000, 20000));
+ events.ScheduleEvent(EVENT_BRUTAL_SWIPE, urand(7000, 12000));
break;
case EVENT_MANGLE:
DoCastVictim(SPELL_MANGLE);
- events.ScheduleEvent(EVENT_MANGLE, urand(15000, 20000));
+ events.ScheduleEvent(EVENT_MANGLE, urand(10000, 15000));
break;
case EVENT_SURGE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me)))
@@ -165,19 +391,19 @@ class boss_nalorakk : public CreatureScript
Talk(EMOTE_SURGE, target);
DoCast(target, SPELL_SURGE);
}
- events.ScheduleEvent(EVENT_SURGE, urand(20000, 25000));
+ events.ScheduleEvent(EVENT_SURGE, urand(15000, 20000));
break;
case EVENT_LACERATING_SLASH:
DoCastVictim(SPELL_LACERATING_SLASH);
- events.ScheduleEvent(EVENT_LACERATING_SLASH, urand(10000, 15000));
+ events.ScheduleEvent(EVENT_LACERATING_SLASH, urand(18000, 22000));
break;
case EVENT_REND_FLESH:
DoCastVictim(SPELL_REND_FLESH);
- events.ScheduleEvent(EVENT_REND_FLESH, urand(12000, 18000));
+ events.ScheduleEvent(EVENT_REND_FLESH, urand(10000, 15000));
break;
case EVENT_DEAFENING_ROAR:
DoCast(me, SPELL_DEAFENING_ROAR);
- events.ScheduleEvent(EVENT_DEAFENING_ROAR, urand(20000, 25000));
+ events.ScheduleEvent(EVENT_DEAFENING_ROAR, urand(10000, 15000));
break;
case EVENT_SHAPESHIFT:
CancelFormEvents();
@@ -185,18 +411,17 @@ class boss_nalorakk : public CreatureScript
if (_bearForm)
{
- Talk(SAY_BEAR);
+ Talk(SAY_SHIFT_TO_BEAR);
Talk(EMOTE_BEAR);
DoCast(me, SPELL_SHAPE_OF_THE_BEAR);
ScheduleBearEvents();
- events.ScheduleEvent(EVENT_SHAPESHIFT, 45000);
+ events.ScheduleEvent(EVENT_SHAPESHIFT, urand(20000, 25000));
}
else
{
- Talk(SAY_TROLL);
me->RemoveAurasDueToSpell(SPELL_SHAPE_OF_THE_BEAR);
ScheduleTrollEvents();
- events.ScheduleEvent(EVENT_SHAPESHIFT, 45000);
+ events.ScheduleEvent(EVENT_SHAPESHIFT, urand(45000, 50000));
}
break;
case EVENT_BERSERK:
@@ -215,6 +440,14 @@ class boss_nalorakk : public CreatureScript
private:
bool _bearForm;
+ bool _waveEvent;
+ bool _waveInProgress;
+ bool _inMove;
+ uint32 _wave;
+ uint32 _currentPoint;
+ uint32 _targetPoint;
+ uint32 _checkTimer;
+ std::vector _waveGuids;
};
CreatureAI* GetAI(Creature* creature) const override