TrinityCore
Loading...
Searching...
No Matches
boss_lurker_below.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Combat timers requires to be revisited, seems like emerge and spout timers are randomized
20 * Everything related to emerge and submerge requires sniff verification
21 * SPELL_LURKER_SPAWN_TRIGGER interrupts fishing, this closes loot window
22 * Verify if Lurker should emerge if all nagas are killed
23 */
24
25#include "ScriptMgr.h"
26#include "GameObject.h"
27#include "GameObjectAI.h"
28#include "InstanceScript.h"
29#include "Map.h"
30#include "MotionMaster.h"
31#include "Player.h"
32#include "ScriptedCreature.h"
33#include "serpent_shrine.h"
34#include "SpellAuraEffects.h"
35#include "SpellInfo.h"
36#include "SpellScript.h"
37
43
45{
46 // Combat
47 SPELL_GEYSER = 37478,
48 SPELL_WHIRL = 37660,
49 SPELL_SPOUT = 37431,
51
52 // Submerge
55
56 // World Trigger (Not Immune PC)
58
59 // Coilfang Ambusher
60 SPELL_SHOOT = 37770,
62
63 // Coilfang Guardian
66
67 // Scripts
69 SPELL_SPOUT_RIGHT = 37430
70};
71
86
99
112
118
119static Position const LurkerSpawnPosition = { 38.4567f, -417.324f, -18.9167f, 2.94961f };
120
133
134// 21217 - The Lurker Below
136{
138
139 void InitializeAI() override
140 {
143 }
144
145 void JustAppeared() override
146 {
149 }
150
161
162 void OnSpellStart(SpellInfo const* spellInfo) override
163 {
165 if (spellInfo->Id == SPELL_SPOUT)
166 {
169 }
170 }
171
172 void DoAction(int32 action) override
173 {
174 if (action == ACTION_SPOUT_STARTED)
176 }
177
178 void EnterEvadeMode(EvadeReason /*why*/) override
179 {
181 me->GetMap()->SpawnGroupDespawn(group);
182
185 }
186
187 void JustDied(Unit* /*killer*/) override
188 {
189 _JustDied();
190
192 me->GetMap()->SpawnGroupDespawn(group);
193 }
194
195 void UpdateAI(uint32 diff) override
196 {
197 if (!UpdateVictim())
198 return;
199
200 events.Update(diff);
201
203 return;
204
205 while (uint32 eventId = events.ExecuteEvent())
206 {
207 switch (eventId)
208 {
211 break;
212 case EVENT_GEYSER:
214 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f))
215 DoCast(target, SPELL_GEYSER);
216 events.Repeat(10s, 15s);
217 break;
218 case EVENT_WHIRL:
221 events.Repeat(15s, 20s);
222 break;
223 case EVENT_SPOUT:
225 events.Repeat(55s);
226 break;
231 break;
235 break;
236 case EVENT_WATER_BOLT:
240 events.Repeat(1200ms);
241 break;
242 case EVENT_SUBMERGE:
247
249 me->GetMap()->SpawnGroupSpawn(group, true, true);
250
254
260 break;
261 case EVENT_EMERGE:
265 break;
266 case EVENT_EMERGE_2:
269 break;
270 case EVENT_EMERGE_3:
276 break;
277 default:
278 break;
279 }
280
282 return;
283 }
284
286 }
287};
288
289// 21865 - Coilfang Ambusher
291{
293
294 void JustAppeared() override
295 {
296 me->GetMotionMaster()->MovePath(GetPathId(), false);
297 }
298
299 void Reset() override
300 {
302 }
303
305 {
306 if (me->HasStringId("CoilfangAmbusher1"))
308 else if (me->HasStringId("CoilfangAmbusher2"))
310 else if (me->HasStringId("CoilfangAmbusher3"))
312 else if (me->HasStringId("CoilfangAmbusher4"))
314 else if (me->HasStringId("CoilfangAmbusher5"))
316 else if (me->HasStringId("CoilfangAmbusher6"))
318 return 0;
319 }
320
321 void JustEngagedWith(Unit* /*who*/) override
322 {
323 if (roll_chance_i(25))
325
327 .Schedule(0s, [this](TaskContext task)
328 {
329 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f))
330 DoCast(target, SPELL_SHOOT);
331 task.Repeat(3600ms, 7200ms);
332 })
333 .Schedule(10s, 15s, [this](TaskContext task)
334 {
336 task.Repeat(10s, 20s);
337 });
338 }
339
340 void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) override
341 {
342 me->SetImmuneToPC(false);
343 SetCombatMovement(false);
345 }
346
347 void UpdateAI(uint32 diff) override
348 {
349 if (!UpdateVictim())
350 return;
351
352 _scheduler.Update(diff);
353
355 }
356
357private:
359};
360
361// 21873 - Coilfang Guardian
363{
365
366 void JustAppeared() override
367 {
368 me->GetMotionMaster()->MovePath(GetPathId(), false);
369 }
370
371 void Reset() override
372 {
374 }
375
377 {
378 if (me->HasStringId("CoilfangGuardian1"))
380 else if (me->HasStringId("CoilfangGuardian2"))
382 else if (me->HasStringId("CoilfangGuardian3"))
384 return 0;
385 }
386
387 void JustEngagedWith(Unit* /*who*/) override
388 {
389 if (roll_chance_i(25))
391
393 .Schedule(10s, 15s, [this](TaskContext task)
394 {
396 task.Repeat(15s, 20s);
397 })
398 .Schedule(5s, 10s, [this](TaskContext task)
399 {
401 task.Repeat(10s, 15s);
402 });
403 }
404
405 void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) override
406 {
407 me->SetImmuneToPC(false);
409 }
410
411 void UpdateAI(uint32 diff) override
412 {
413 if (!UpdateVictim())
414 return;
415
416 _scheduler.Update(diff);
417
419 }
420
421private:
423};
424
425// 184956 - Strange Pool
427{
429
430 bool OnGossipHello(Player* player) override
431 {
432 if (roll_chance_i(25))
433 {
435 trigger->CastSpell(player, SPELL_LURKER_SPAWN_TRIGGER);
436
438
440 if (InstanceScript* instance = me->GetInstanceScript())
441 instance->SetBossState(BOSS_THE_LURKER_BELOW, SPECIAL);
442 }
443
444 return false;
445 }
446};
447
448// 37431 - Spout
450{
452
453 bool Validate(SpellInfo const* /*spellInfo*/) override
454 {
456 }
457
458 void HandleScript(SpellEffIndex /*effIndex*/)
459 {
460 if (Creature* creature = GetCaster()->ToCreature())
461 {
462 creature->CastSpell(creature, RAND(SPELL_SPOUT_LEFT, SPELL_SPOUT_RIGHT), true);
463 creature->AI()->DoAction(ACTION_SPOUT_STARTED);
464 }
465 }
466
471};
472
473// 37429 - Spout
474// 37430 - Spout
476{
478
479 bool Validate(SpellInfo const* spellInfo) override
480 {
481 return ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0).CalcValue()) });
482 }
483
484 void OnPeriodic(AuraEffect const* aurEff)
485 {
486 Unit* target = GetTarget();
487
488 float orientation = target->GetOrientation();
489
490 switch (GetId())
491 {
492 case SPELL_SPOUT_LEFT:
493 orientation += 5 * float(M_PI) / 180;
494 break;
496 orientation -= 5 * float(M_PI) / 180;
497 break;
498 default:
499 break;
500 }
501
502 target->SetFacingTo(orientation);
503
504 target->CastSpell(target, aurEff->GetAmount(), true);
505 }
506
511};
512
513// 37433 - Spout
515{
517
518 void FilterTargets(std::list<WorldObject*>& targets)
519 {
520 targets.remove_if([](WorldObject* target)
521 {
522 return !target->IsUnit() || target->ToUnit()->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
523 });
524 }
525
530};
531
#define M_PI
Definition Common.h:72
First const & RAND(First const &first, Second const &second, Rest const &... rest)
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
GameObjectActions
@ FAIL
@ SPECIAL
bool roll_chance_i(int chance)
Definition Random.h:59
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1128
Creature * GetClosestCreatureWithEntry(WorldObject *source, uint32 entry, float maxSearchRange, bool alive=true)
SpellEffIndex
@ EFFECT_0
@ SPELL_EFFECT_SCRIPT_EFFECT
@ TARGET_UNIT_CONE_ENEMY_24
#define EFFECT_ALL
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
@ SPELLVALUE_MAX_TARGETS
#define SpellEffectFn(F, I, N)
#define SpellObjectAreaTargetSelectFn(F, I, N)
#define AuraEffectPeriodicFn(F, I, N)
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ UNIT_STAND_STATE_SUBMERGED
Definition UnitDefines.h:43
@ UNIT_STAND_STATE_STAND
Definition UnitDefines.h:34
@ MOVEMENTFLAG_SWIMMING
@ UNIT_FLAG_UNINTERACTIBLE
@ UNIT_STATE_CASTING
Definition Unit.h:235
static Position const LurkerSpawnPosition
@ EVENT_SPOUT
@ EVENT_EMERGE_2
@ EVENT_EMERGE
@ EVENT_WATER_BOLT
@ EVENT_SPOUT_END_1
@ EVENT_WHIRL
@ EVENT_SPOUT_END_2
@ EVENT_EMERGE_3
@ EVENT_SUBMERGE
@ EVENT_GEYSER
@ EVENT_AGGRO_DELAY
static constexpr std::array< uint32, 9 > CoilfangNagaSpawnGroupsData
void AddSC_boss_the_lurker_below()
LurkerSpawnGroups
@ SPAWN_GROUP_COILFANG_AMBUSHER_5
@ SPAWN_GROUP_COILFANG_AMBUSHER_6
@ SPAWN_GROUP_COILFANG_GUARDIAN_3
@ SPAWN_GROUP_COILFANG_GUARDIAN_2
@ SPAWN_GROUP_COILFANG_AMBUSHER_2
@ SPAWN_GROUP_COILFANG_AMBUSHER_4
@ SPAWN_GROUP_COILFANG_GUARDIAN_1
@ SPAWN_GROUP_COILFANG_AMBUSHER_3
@ SPAWN_GROUP_COILFANG_AMBUSHER_1
@ PATH_COILFANG_AMBUSHER_5
@ PATH_COILFANG_AMBUSHER_4
@ PATH_COILFANG_AMBUSHER_6
@ PATH_COILFANG_GUARDIAN_2
@ PATH_COILFANG_AMBUSHER_2
@ PATH_COILFANG_AMBUSHER_1
@ PATH_COILFANG_GUARDIAN_3
@ PATH_COILFANG_GUARDIAN_1
@ PATH_COILFANG_AMBUSHER_3
@ SPELL_SPREAD_SHOT
@ SPELL_HAMSTRING
@ SPELL_CLEAR_ALL_DEBUFFS
@ SPELL_SHOOT
@ SPELL_WATER_BOLT
@ SPELL_SPOUT_RIGHT
@ SPELL_SPOUT
@ SPELL_SUBMERGE_VISUAL
@ SPELL_ARCING_SMASH
@ SPELL_SPOUT_LEFT
@ SPELL_WHIRL
@ SPELL_LURKER_SPAWN_TRIGGER
@ SPELL_GEYSER
@ ACTION_SPOUT_STARTED
@ NPC_WORLD_TRIGGER_NOT_IMMUNE_PC
@ SAY_AGGRO
@ EMOTE_SPOUT
int32 GetAmount() const
HookList< EffectPeriodicHandler > OnEffectPeriodic
Unit * GetTarget() const
uint32 GetId() const
InstanceScript *const instance
void JustEngagedWith(Unit *who) override
EventMap events
void DoZoneInCombat(Creature *creature=nullptr)
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:82
void SetImmuneToPC(bool apply) override
Definition Creature.h:129
void SetReactState(ReactStates st)
Definition Creature.h:119
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
bool HasStringId(std::string_view id) const
ReactStates GetReactState() const
Definition Creature.h:120
void Update(uint32 time)
Definition EventMap.h:67
void Repeat(Milliseconds time)
Definition EventMap.cpp:63
EventId ExecuteEvent()
Definition EventMap.cpp:73
void RescheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:52
void CancelEvent(EventId eventId)
Definition EventMap.cpp:151
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:36
GameObject *const me
GameObjectAI(GameObject *go)
void ActivateObject(GameObjectActions action, WorldObject *spellCaster=nullptr, uint32 spellId=0, int32 effectIndex=-1)
virtual bool SetBossState(uint32 id, EncounterState state)
bool SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn=false, bool force=false, std::vector< WorldObject * > *spawnedObjects=nullptr)
Definition Map.cpp:3382
bool SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes=false, size_t *count=nullptr)
Definition Map.cpp:3458
TempSummon * SummonCreature(uint32 entry, Position const &pos, SummonPropertiesEntry const *properties=nullptr, uint32 duration=0, WorldObject *summoner=nullptr, uint32 spellId=0, uint32 vehId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Definition Object.cpp:1852
void MovePath(uint32 pathId, bool repeatable)
static Unit * ToUnit(Object *o)
Definition Object.h:192
bool IsUnit() const
Definition Object.h:191
int32 CalcValue(WorldObject const *caster=nullptr, int32 const *basePoints=nullptr) const
uint32 Id
Definition SpellInfo.h:289
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:483
Unit * GetCaster() const
HookList< EffectHandler > OnEffectHit
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
TaskContext & Repeat(std::chrono::duration< _Rep, _Period > const &duration)
TaskScheduler & CancelAll()
TaskScheduler & Schedule(std::chrono::duration< _Rep, _Period > const &time, task_handler_t const &task)
TaskScheduler & Update(success_t const &callback=EmptyCallback)
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:54
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:241
virtual void InitializeAI()
Definition UnitAI.cpp:36
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:166
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:96
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:106
Definition Unit.h:769
bool IsWithinMeleeRange(Unit const *obj) const
Definition Unit.h:844
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
bool HasUnitMovementFlag(uint32 f) const
Definition Unit.h:1678
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3784
Unit * GetVictim() const
Definition Unit.h:859
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
void SetFacingTo(float ori, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13250
void SetStandState(UnitStandStateType state)
Definition Unit.cpp:10363
void RemoveAllAuras()
Definition Unit.cpp:4157
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:954
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:955
Map * GetMap() const
Definition Object.h:449
InstanceScript * GetInstanceScript() const
Definition Object.cpp:1087
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
PrepareSpellScript(spell_the_lurker_below_spout_damage)
void FilterTargets(std::list< WorldObject * > &targets)
PrepareAuraScript(spell_the_lurker_below_spout_periodic)
bool Validate(SpellInfo const *spellInfo) override
void OnPeriodic(AuraEffect const *aurEff)
PrepareSpellScript(spell_the_lurker_below_spout)
bool Validate(SpellInfo const *) override
#define RegisterSerpentshrineCavernGameObjectAI(ai_name)
@ NPC_THE_LURKER_BELOW
@ BOSS_THE_LURKER_BELOW
#define RegisterSerpentshrineCavernCreatureAI(ai_name)
float GetOrientation() const
Definition Position.h:82
void SetCombatMovement(bool allowMovement)
ScriptedAI(Creature *creature)
void DoAction(int32 action) override
void EnterEvadeMode(EvadeReason) override
void UpdateAI(uint32 diff) override
void JustDied(Unit *) override
void JustEngagedWith(Unit *who) override
void OnSpellStart(SpellInfo const *spellInfo) override
boss_the_lurker_below(Creature *creature)
bool OnGossipHello(Player *player) override
void WaypointPathEnded(uint32, uint32) override
void UpdateAI(uint32 diff) override
void JustEngagedWith(Unit *) override
void WaypointPathEnded(uint32, uint32) override
void JustEngagedWith(Unit *) override
void UpdateAI(uint32 diff) override