refactor(Scripts/ZulAman): Nalorakk refactored (#19010)

* init

* update movement

* updates and debug

* stuck :/

scheduler doesn't seem to update when at the end of wp movement???

* fix wps and implement fight

* finalise

* unused

* Update boss_nalorakk.cpp

* keep oprientation

* ran_intro
This commit is contained in:
Dan
2024-07-04 20:13:41 +02:00
committed by GitHub
parent 65eb900c55
commit b959d5cc87
4 changed files with 286 additions and 380 deletions
@@ -0,0 +1,14 @@
--
DELETE FROM `waypoint_data` WHERE `id` IN (2357601, 2357602, 2357603);
INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES
(2357601, 1, -52.642, 1419.357, 27.31, NULL, 0, 1, 0, 100, 0),
(2357602, 1, -69.908, 1419.721, 27.31, NULL, 0, 1, 0, 100, 0),
(2357602, 2, -79.929, 1395.958, 27.31, NULL, 0, 1, 0, 100, 0),
(2357602, 3, -80.072, 1374.555, 40.87, NULL, 0, 1, 0, 100, 0),
(2357603, 1, -80.072, 1314.398, 40.87, NULL, 0, 1, 0, 100, 0),
(2357603, 2, -80.072, 1295.775, 48.60, NULL, 0, 1, 0, 100, 0);
DELETE FROM `creature_text` WHERE `CreatureID` = 23576 AND `GroupID` IN (14, 15);
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(23576, 14, 0, 'Mua-ha-ha!', 14, 0, 100, 0, 0, 0, 22145, 1, 'Nalorakk - RUN AWAY'),
(23576, 15, 0, '%s transforms into a bear!', 16, 0, 100, 0, 0, 0, 24263, 1, 'Nalorakk - EMOTE BEAR');
@@ -46,19 +46,6 @@ enum Spells
SPELL_DEAFENINGROAR = 42398 SPELL_DEAFENINGROAR = 42398
}; };
// Trash Waves
float NalorakkWay[8][3] =
{
{ 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
};
enum Talks enum Talks
{ {
SAY_WAVE1 = 0, SAY_WAVE1 = 0,
@@ -74,399 +61,300 @@ enum Talks
SAY_KILL_TWO, SAY_KILL_TWO,
SAY_DEATH, SAY_DEATH,
SAY_NALORAKK_EVENT1, // Not implemented SAY_NALORAKK_EVENT1, // Not implemented
SAY_NALORAKK_EVENT2 // Not implemented SAY_NALORAKK_EVENT2, // Not implemented
SAY_RUN_AWAY,
EMOTE_BEAR
}; };
class boss_nalorakk : public CreatureScript enum Phases
{ {
public: PHASE_SEND_GUARDS_1 = 0,
boss_nalorakk() PHASE_SEND_GUARDS_2 = 1,
: CreatureScript("boss_nalorakk") PHASE_SEND_GUARDS_3 = 2,
PHASE_SEND_GUARDS_4 = 3,
PHASE_SEND_GUARDS_5 = 4,
PHASE_START_COMBAT = 5
};
enum NalorakkGroups
{
GROUP_CHECK_DEAD = 1,
GROUP_MOVE = 2,
GROUP_BERSERK = 3,
GROUP_HUMAN = 4,
GROUP_BEAR = 5
};
struct boss_nalorakk : public BossAI
{
boss_nalorakk(Creature* creature) : BossAI(creature, DATA_NALORAKKEVENT)
{ {
_ranIntro = false;
_active = true;
creature->SetReactState(REACT_PASSIVE);
me->SetImmuneToAll(true);
} }
struct boss_nalorakkAI : public ScriptedAI
{
boss_nalorakkAI(Creature* creature) : ScriptedAI(creature)
{
MoveEvent = true;
MovePhase = 0;
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
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 void Reset() override
{ {
if (MoveEvent) BossAI::Reset();
_waveList.clear();
_introScheduler.CancelAll();
if (_bearForm)
{ {
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->RemoveAurasDueToSpell(SPELL_BEARFORM);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); _bearForm = false;
inMove = false;
waitTimer = 0;
me->SetSpeed(MOVE_RUN, 2);
me->SetWalk(false);
ResetMobs();
} }
else if (_ranIntro)
{ {
(*me).GetMotionMaster()->MovePoint(0, NalorakkWay[7][0], NalorakkWay[7][1], NalorakkWay[7][2]); _phase = PHASE_START_COMBAT;
me->SetReactState(REACT_AGGRESSIVE);
_active = false;
} }
if (instance)
{
instance->SetData(DATA_NALORAKKEVENT, NOT_STARTED);
}
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;
// me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 5122); /// @todo find the correct equipment id
}
void ResetMobs()
{
std::list<Creature*> templist;
float x, y, z;
me->GetPosition(x, y, z);
{
CellCoord pair(Acore::ComputeCellCoord(x, y));
Cell cell(pair);
cell.SetNoCreate();
Acore::AllFriendlyCreaturesInGrid check(me);
Acore::CreatureListSearcher<Acore::AllFriendlyCreaturesInGrid> searcher(me, templist, check);
TypeContainerVisitor<Acore::CreatureListSearcher<Acore::AllFriendlyCreaturesInGrid>, GridTypeMapContainer> cSearcher(searcher);
cell.Visit(pair, cSearcher, *(me->GetMap()), *me, me->GetGridActivationRange());
}
if (templist.empty())
return;
for (std::list<Creature*>::const_iterator i = templist.begin(); i != templist.end(); ++i)
if ((*i) && me->GetGUID() != (*i)->GetGUID() && me->IsWithinDistInMap((*i), 25))
(*i)->AI()->Reset();
}
void SendAttacker(Unit* target)
{
std::list<Creature*> templist;
float x, y, z;
me->GetPosition(x, y, z);
{
CellCoord pair(Acore::ComputeCellCoord(x, y));
Cell cell(pair);
cell.SetNoCreate();
Acore::AllFriendlyCreaturesInGrid check(me);
Acore::CreatureListSearcher<Acore::AllFriendlyCreaturesInGrid> searcher(me, templist, check);
TypeContainerVisitor<Acore::CreatureListSearcher<Acore::AllFriendlyCreaturesInGrid>, GridTypeMapContainer> cSearcher(searcher);
cell.Visit(pair, cSearcher, *(me->GetMap()), *me, me->GetGridActivationRange());
}
if (templist.empty())
return;
for (std::list<Creature*>::const_iterator i = templist.begin(); i != templist.end(); ++i)
{
if ((*i) && me->IsWithinDistInMap((*i), 25))
{
(*i)->SetNoCallAssistance(true);
(*i)->AI()->AttackStart(target);
}
}
}
void AttackStart(Unit* who) override
{
if (!MoveEvent)
ScriptedAI::AttackStart(who);
} }
void MoveInLineOfSight(Unit* who) override void MoveInLineOfSight(Unit* who) override
{
if (who->IsPlayer() && _phase < PHASE_START_COMBAT && _active)
{
_active = false;
switch (_phase)
{
case PHASE_SEND_GUARDS_1:
me->GetCreaturesWithEntryInRange(_waveList, 10.0f, NPC_AMANISHI_AXE_THROWER);
me->GetCreaturesWithEntryInRange(_waveList, 10.0f, NPC_AMANISHI_TRIBESMAN);
GroupedAttack(_waveList);
Talk(SAY_WAVE1);
_introScheduler.Schedule(5s, GROUP_CHECK_DEAD, [this](TaskContext context)
{
if (CheckFullyDeadGroup(_waveList))
{
if (_phase == PHASE_SEND_GUARDS_1)
{
_introScheduler.CancelGroup(GROUP_CHECK_DEAD);
_waveList.clear();
me->GetMotionMaster()->MovePath(me->GetEntry()*100+1, false);
Talk(SAY_RUN_AWAY);
_introScheduler.Schedule(5s, [this](TaskContext)
{
me->SetFacingTo(6.25f);
_active = true;
});
_phase = PHASE_SEND_GUARDS_2;
}
}
context.Repeat(5s);
});
break;
case PHASE_SEND_GUARDS_2:
me->GetCreaturesWithEntryInRange(_waveList, 10.0f, NPC_AMANISHI_AXE_THROWER);
me->GetCreaturesWithEntryInRange(_waveList, 10.0f, NPC_AMANISHI_TRIBESMAN);
me->GetCreaturesWithEntryInRange(_waveList, 10.0f, NPC_AMANISHI_MEDICINE_MAN);
GroupedAttack(_waveList);
Talk(SAY_WAVE2);
_introScheduler.Schedule(5s, GROUP_CHECK_DEAD, [this](TaskContext context)
{
if (CheckFullyDeadGroup(_waveList))
{
if (_phase == PHASE_SEND_GUARDS_2)
{
_introScheduler.CancelGroup(GROUP_CHECK_DEAD);
_waveList.clear();
Talk(SAY_RUN_AWAY);
me->GetMotionMaster()->MovePath(me->GetEntry()*100+2, false);
_introScheduler.Schedule(6s, [this](TaskContext)
{
me->SetFacingTo(1.54f);
_active = true;
});
_phase = PHASE_SEND_GUARDS_3;
}
}
context.Repeat(5s);
});
break;
case PHASE_SEND_GUARDS_3:
me->GetCreaturesWithEntryInRange(_waveList, 10.0f, NPC_AMANISHI_WARBRINGER);
GroupedAttack(_waveList);
Talk(SAY_WAVE3);
_introScheduler.Schedule(5s, GROUP_CHECK_DEAD, [this](TaskContext context)
{ {
if (!MoveEvent) if (CheckFullyDeadGroup(_waveList))
{ {
ScriptedAI::MoveInLineOfSight(who); if (_phase == PHASE_SEND_GUARDS_3)
{
_introScheduler.CancelGroup(GROUP_CHECK_DEAD);
_waveList.clear();
Talk(SAY_RUN_AWAY);
me->GetMotionMaster()->MovePath(me->GetEntry()*100+3, false);
_introScheduler.Schedule(6s, [this](TaskContext)
{
me->SetFacingTo(1.54f);
_active = true;
});
_phase = PHASE_SEND_GUARDS_4;
}
}
context.Repeat(5s);
});
break;
case PHASE_SEND_GUARDS_4:
me->GetCreaturesWithEntryInRange(_waveList, 25.0f, NPC_AMANISHI_WARBRINGER);
me->GetCreaturesWithEntryInRange(_waveList, 25.0f, NPC_AMANISHI_MEDICINE_MAN);
GroupedAttack(_waveList);
Talk(SAY_WAVE4);
_introScheduler.Schedule(5s, GROUP_CHECK_DEAD, [this](TaskContext context)
{
if (CheckFullyDeadGroup(_waveList))
{
if (_phase == PHASE_SEND_GUARDS_4)
{
_introScheduler.CancelGroup(GROUP_CHECK_DEAD);
me->SetHomePosition(me->GetPosition());
me->SetImmuneToAll(false);
me->SetReactState(REACT_AGGRESSIVE);
me->SetInCombatWithZone();
_waveList.clear();
_phase = PHASE_START_COMBAT;
_ranIntro = true;
}
}
context.Repeat(5s);
});
break;
}
}
BossAI::MoveInLineOfSight(who);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
scheduler.Schedule(15s, 20s, GROUP_HUMAN, [this](TaskContext context)
{
Talk(SAY_SURGE);
DoCastRandomTarget(SPELL_SURGE, 0, 45.0f, false, false, false);
context.Repeat();
}).Schedule(7s, 12s, GROUP_HUMAN, [this](TaskContext context)
{
DoCastVictim(SPELL_BRUTALSWIPE);
context.Repeat();
}).Schedule(10s, 15s, GROUP_HUMAN, [this](TaskContext context)
{
if (!me->GetVictim()->HasAura(SPELL_MANGLEEFFECT))
{
DoCastVictim(SPELL_MANGLE);
context.Repeat(1s);
} }
else else
{ {
if (me->IsHostileTo(who)) context.Repeat();
}
}).Schedule(10min, GROUP_BERSERK, [this](TaskContext)
{ {
if (!inMove) Talk(SAY_BERSERK);
DoCastSelf(SPELL_BERSERK, true);
}).Schedule(45s, 50s, GROUP_HUMAN, [this](TaskContext)
{ {
switch (MovePhase) ShapeShift(_bearForm);
{ });
case 0:
if (me->IsWithinDistInMap(who, 50))
{
Talk(SAY_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(SAY_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(SAY_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(SAY_WAVE4);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
MoveEvent = false;
}
break;
}
}
}
}
} }
void JustEngagedWith(Unit* /*who*/) override void ShapeShift(bool currentlyInBearForm)
{ {
if (instance) if (currentlyInBearForm)
instance->SetData(DATA_NALORAKKEVENT, IN_PROGRESS); {
Talk(SAY_SHIFTEDTOTROLL);
Talk(SAY_AGGRO); me->RemoveAurasDueToSpell(SPELL_BEARFORM);
DoZoneInCombat(); scheduler.CancelGroup(GROUP_BEAR);
_bearForm = false;
scheduler.Schedule(15s, 20s, GROUP_HUMAN, [this](TaskContext context)
{
Talk(SAY_SURGE);
DoCastRandomTarget(SPELL_SURGE, 0, 45.0f, false, false, false);
context.Repeat();
}).Schedule(7s, 12s, GROUP_HUMAN, [this](TaskContext context)
{
DoCastVictim(SPELL_BRUTALSWIPE);
context.Repeat();
}).Schedule(10s, 15s, GROUP_HUMAN, [this](TaskContext context)
{
DoCastVictim(SPELL_MANGLE);
context.Repeat();
}).Schedule(10min, GROUP_BERSERK, [this](TaskContext)
{
Talk(SAY_BERSERK);
DoCastSelf(SPELL_BERSERK, true);
}).Schedule(45s, 50s, GROUP_HUMAN, [this](TaskContext)
{
ShapeShift(_bearForm);
});
} }
else
void JustDied(Unit* /*killer*/) override
{ {
ResetMobs(); Talk(SAY_SHIFTEDTOBEAR);
Talk(EMOTE_BEAR);
if (instance) DoCastSelf(SPELL_BEARFORM, true);
instance->SetData(DATA_NALORAKKEVENT, DONE); scheduler.CancelGroup(GROUP_HUMAN);
_bearForm = true;
Talk(SAY_DEATH); scheduler.Schedule(2s, GROUP_BEAR, [this](TaskContext context)
}
void KilledUnit(Unit* /*victim*/) override
{ {
switch (urand(0, 1)) DoCastVictim(SPELL_LACERATINGSLASH);
context.Repeat(18s, 23s);
}).Schedule(3s, GROUP_BEAR, [this](TaskContext context)
{ {
case 0: DoCastVictim(SPELL_RENDFLESH);
Talk(SAY_KILL_ONE); context.Repeat(5s, 10s);
break; }).Schedule(5s, 10s, GROUP_BEAR, [this](TaskContext context)
case 1: {
Talk(SAY_KILL_TWO); DoCastSelf(SPELL_DEAFENINGROAR);
break; context.Repeat(15s, 20s);
}).Schedule(25s, 30s, GROUP_BEAR, [this](TaskContext context)
{
ShapeShift(_bearForm);
context.Repeat();
});
} }
} }
void MovementInform(uint32 type, uint32 id) override void GroupedAttack(std::list<Creature* > attackerList)
{ {
if (MoveEvent) for (Creature* attacker : attackerList)
{ {
if (type != POINT_MOTION_TYPE) attacker->SetInCombatWithZone();
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;
inMove = true;
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 void UpdateAI(uint32 diff) override
{ {
if (waitTimer && inMove) _introScheduler.Update(diff);
{ BossAI::UpdateAI(diff);
if (waitTimer <= diff)
{
(*me).GetMotionMaster()->MovementExpired();
(*me).GetMotionMaster()->MovePoint(MovePhase, NalorakkWay[MovePhase][0], NalorakkWay[MovePhase][1], NalorakkWay[MovePhase][2]);
waitTimer = 0;
}
else waitTimer -= diff;
} }
if (!UpdateVictim()) bool CheckFullyDeadGroup(std::list<Creature* > groupToCheck)
return;
if (Berserk_Timer <= diff)
{ {
DoCast(me, SPELL_BERSERK, true); for (Creature* member : groupToCheck)
Talk(SAY_BERSERK);
Berserk_Timer = 600000;
}
else Berserk_Timer -= diff;
if (ShapeShift_Timer <= diff)
{ {
if (inBearForm) if (member->IsAlive())
{ {
// me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 5122); return false;
Talk(SAY_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(SAY_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; return true;
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->GetVictim()->HasAura(SPELL_MANGLEEFFECT))
{
DoCastVictim(SPELL_MANGLE);
Mangle_Timer = 1000;
}
else Mangle_Timer = urand(10000, 15000);
}
else Mangle_Timer -= diff;
if (Surge_Timer <= diff)
{
Talk(SAY_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);
} }
private:
uint8 _phase;
bool _ranIntro;
bool _active;
bool _bearForm;
TaskScheduler _introScheduler;
std::list<Creature *> _waveList;
}; };
void AddSC_boss_nalorakk() void AddSC_boss_nalorakk()
{ {
new boss_nalorakk(); RegisterZulAmanCreatureAI(boss_nalorakk);
} }
@@ -46,7 +46,11 @@ enum CreatureIds
NPC_HEXLORD = 24239, NPC_HEXLORD = 24239,
NPC_HALAZZI = 23577, NPC_HALAZZI = 23577,
NPC_NALORAKK = 23576, NPC_NALORAKK = 23576,
NPC_SPIRIT_LYNX = 24143 NPC_SPIRIT_LYNX = 24143,
NPC_AMANISHI_WARBRINGER = 23580,
NPC_AMANISHI_TRIBESMAN = 23582,
NPC_AMANISHI_MEDICINE_MAN = 23581,
NPC_AMANISHI_AXE_THROWER = 23542
}; };
enum GameobjectIds enum GameobjectIds