TrinityCore
Loading...
Searching...
No Matches
boss_nethekurse.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
20 * Clearly seen one peon died from Shadow Fissure, doesn't work because health regenerates,
21 it should regenerate in case of other spells, no sniffs with Wild Shadow Fissure
22 * Dark Spin gets interrupted after first tick
23 * Death Coil is a buff instead of a debuff
24 */
25
26#include "ScriptMgr.h"
27#include "Containers.h"
28#include "GameObject.h"
29#include "GameObjectAI.h"
30#include "InstanceScript.h"
31#include "Player.h"
32#include "ScriptedCreature.h"
33#include "shattered_halls.h"
34#include "SpellInfo.h"
35#include "SpellScript.h"
36
59
61{
62 // Combat
68
69 // Intro
73
74 // Fel Orc Convert
76
77 // Lesser Shadow Fissure
80
81 // Wild Shadow Fissure
83
84 // Scripts
86};
87
100
107
113
114// 16807 - Grand Warlock Nethekurse
116{
119
120 void Reset() override
121 {
122 _Reset();
123
124 _isEventOnCooldown = false;
125 _isDarkSpinStarted = false;
126 }
127
128 void JustEngagedWith(Unit* who) override
129 {
131
132 events.Reset();
133
136
137 if (!IsHeroic())
139 else
141
142 switch (_peonKilledCount)
143 {
144 case 0:
146 break;
147 case 1:
148 case 2:
149 case 3:
151 break;
152 case 4:
154 break;
155 default:
156 break;
157 }
158 }
159
160 void DoAction(int32 action) override
161 {
162 if (!me->IsAlive())
163 return;
164
165 switch (action)
166 {
170 break;
172 if (!me->IsInCombat() && !_isEventOnCooldown)
173 {
175 me->PauseMovement(5000);
176 me->SetFacingTo(4.537856101989746093f);
177 _isEventOnCooldown = true;
178
180 }
181 break;
183 {
185
188
190 {
192 me->PauseMovement(5000);
193 me->SetFacingTo(4.572762489318847656f);
195 _isEventOnCooldown = true;
196
199 }
200 break;
201 }
202 default:
203 break;
204 }
205 }
206
207 void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
208 {
209 if (!_isDarkSpinStarted && me->HealthBelowPctDamaged(25, damage))
210 {
211 _isDarkSpinStarted = true;
213 }
214 }
215
216 void KilledUnit(Unit* /*victim*/) override
217 {
218 Talk(SAY_SLAY);
219 }
220
221 void JustDied(Unit* /*killer*/) override
222 {
223 _JustDied();
225 }
226
228 {
229 events.Update(diff);
230
231 while (uint32 eventId = events.ExecuteEvent())
232 {
233 switch (eventId)
234 {
235 // ... intro event starts every time player enters area trigger
237 {
238 switch (urand(0, 2))
239 {
240 case 0:
241 // This one targets two (?) peons
244 break;
245 case 1:
246 // This one targets all four peons
249 break;
250 case 2:
251 // This one targets one peon
254 break;
255 default:
256 break;
257 }
258
259 // ... cancel copies of event every time it is scheduled, then schedule new to repeat it, only one should be active
263 break;
264 }
266 _isEventOnCooldown = false;
267 break;
270 break;
271 default:
272 break;
273 }
274 }
275 }
276
277 void UpdateAI(uint32 diff) override
278 {
279 if (!UpdateVictim())
280 {
282 return;
283 }
284
285 events.Update(diff);
286
288 return;
289
290 while (uint32 eventId = events.ExecuteEvent())
291 {
292 switch (eventId)
293 {
295 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
297 events.Repeat(8s);
298 break;
299 case EVENT_DEATH_COIL:
301 DoCast(target, SPELL_DEATH_COIL);
302 events.Repeat(10s, 20s);
303 break;
306 events.Repeat(15s, 20s);
307 break;
310 events.Repeat(15s, 20s);
311 break;
312 case EVENT_DARK_SPIN:
314 break;
315 default:
316 break;
317 }
318
320 return;
321 }
322
324 }
325
326private:
330};
331
332// 17083 - Fel Orc Convert
334{
335 npc_fel_orc_convert(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
336
337 void Reset() override
338 {
340 }
341
342 void JustEngagedWith(Unit* /*who*/) override
343 {
344 if (roll_chance_i(15))
346
347 _scheduler.Schedule(5s, 10s, [this](TaskContext task)
348 {
350 task.Repeat(5s, 10s);
351 });
352
353 if (!me->HasStringId("FelOrcConvertNethekurseEvent"))
354 return;
355
356 if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
357 nethekurse->AI()->DoAction(ACTION_PEON_ENGAGED);
358 }
359
360 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
361 {
362 // Not sure if these are grouped correctly, based on few sniffs
363 // By the way, language is correct, verified, not a typo
364 // Text 14143 seems to be unused, not added here
365 switch (spellInfo->Id)
366 {
368 if (roll_chance_i(30))
370 break;
372 if (roll_chance_i(30))
373 {
376 }
377 break;
379 if (roll_chance_i(30))
381 break;
382 default:
383 break;
384 }
385 }
386
387 void JustDied(Unit* /*killer*/) override
388 {
389 if (!me->HasStringId("FelOrcConvertNethekurseEvent"))
390 return;
391
392 if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
393 nethekurse->AI()->DoAction(ACTION_PEON_KILLED);
394 }
395
396 void UpdateAI(uint32 diff) override
397 {
398 if (!UpdateVictim())
399 return;
400
401 _scheduler.Update(diff, [this]
402 {
404 });
405 }
406
407private:
410};
411
412// 17471 - Lesser Shadow Fissure
414{
416
417 void InitializeAI() override
418 {
420 }
421
426};
427
428// 18370 - Wild Shadow Fissure
430{
431 npc_wild_shadow_fissure(Creature* creature) : ScriptedAI(creature) { }
432
433 void InitializeAI() override
434 {
436 }
437
438 void JustAppeared() override
439 {
441 }
442};
443
444// 182539 - Grand Warlock Chamber Door
446{
447 go_grand_warlock_chamber_door(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { }
448
449 bool OnGossipHello(Player* /*player*/) override
450 {
451 if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
452 nethekurse->AI()->DoAction(ACTION_START_INTRO);
453
454 return true;
455 }
456
457private:
459};
460
461// 30745 - Target Fissures
492
493// 4347
495{
496public:
497 at_shattered_halls_the_sewer() : AreaTriggerScript("at_shattered_halls_the_sewer") { }
498
499 bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
500 {
501 if (InstanceScript* instance = player->GetInstanceScript())
502 if (Creature* nethekurse = instance->GetCreature(DATA_NETHEKURSE))
503 nethekurse->AI()->DoAction(ACTION_START_INTRO);
504
505 return true;
506 }
507};
508
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
bool roll_chance_i(int chance)
Definition Random.h:59
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1128
SpellEffIndex
@ EFFECT_0
@ SPELL_EFFECT_SCRIPT_EFFECT
@ TARGET_UNIT_SRC_AREA_ENTRY
@ EMOTE_STATE_APPLAUD
@ EMOTE_ONESHOT_NONE
@ SPELLVALUE_MAX_TARGETS
#define SpellEffectFn(F, I, N)
#define SpellObjectAreaTargetSelectFn(F, I, N)
@ REACT_PASSIVE
@ UNIT_STATE_CASTING
Definition Unit.h:235
DamageEffectType
Definition Unit.h:352
NethekurseTexts
@ SAY_PEON_DEFEATED
@ SAY_DEATH
@ SAY_AGGRO_ALL_DEAD
@ SAY_PEON_AGGRO
@ SAY_TAUNT_DEATH_COIL
@ SAY_PEON_DEATH_COIL
@ SAY_PEON_ENGAGED
@ SAY_PEON_SHADOW_SEAR
@ SAY_PEON_SHADOW_FISSURE
@ SAY_SLAY
@ SAY_AGGRO_ALL_ALIVE
@ SAY_AGGRO_SOME_ALIVE
@ SAY_TAUNT_SHADOW_FISSURE
@ SAY_TAUNT_SHADOW_SEAR
NethekurseSpells
@ SPELL_SHADOW_FISSURE
@ SPELL_DEATH_COIL
@ SPELL_CONSUMPTION_WILD
@ SPELL_PEON_TARGET_FISSURES
@ SPELL_SHADOW_FISSURE_2
@ SPELL_PEON_SHADOW_SEAR
@ SPELL_CONSUMPTION
@ SPELL_SHADOW_SLAM
@ SPELL_HEMORRHAGE
@ SPELL_DARK_SPIN
@ SPELL_SHADOW_CLEAVE
@ SPELL_CONSUMPTION_H
@ SPELL_PEON_DEATH_COIL
NethekurseMisc
@ MAX_KILLED_PEONS
@ SOUND_ID_ROAR
NethekurseEvents
@ EVENT_SHADOW_CLEAVE
@ EVENT_INTERNAL_COOLDOWN
@ EVENT_CLEAR_EMOTE_STATE
@ EVENT_DARK_SPIN
@ EVENT_SHADOW_FISSURE
@ EVENT_TAUNT_PEONS
@ EVENT_SHADOW_SLAM
@ EVENT_DEATH_COIL
NethekurseActions
@ ACTION_PEON_ENGAGED
@ ACTION_START_INTRO
@ ACTION_PEON_KILLED
void AddSC_boss_grand_warlock_nethekurse()
void JustEngagedWith(Unit *who) override
EventMap events
void DoZoneInCombat(Creature *creature=nullptr)
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:82
void SetReactState(ReactStates st)
Definition Creature.h:119
bool HasStringId(std::string_view id) const
void Update(uint32 time)
Definition EventMap.h:67
void Repeat(Milliseconds time)
Definition EventMap.cpp:63
EventId ExecuteEvent()
Definition EventMap.cpp:73
void CancelEvent(EventId eventId)
Definition EventMap.cpp:151
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:36
void Reset()
Definition EventMap.cpp:21
Creature * GetCreature(uint32 type)
uint32 Id
Definition SpellInfo.h:289
Unit * GetCaster() const
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
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
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
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition Unit.cpp:10327
bool IsAlive() const
Definition Unit.h:1234
void SetEmoteState(Emote emote)
Definition Unit.h:967
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
bool HealthBelowPctDamaged(int32 pct, uint32 damage) const
Definition Unit.h:918
bool IsInCombat() const
Definition Unit.h:1144
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)
bool OnTrigger(Player *player, AreaTriggerEntry const *) override
void FilterTargets(std::list< WorldObject * > &targets)
PrepareSpellScript(spell_grand_warlock_nethekurse_target_fissures)
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition Containers.h:108
@ DATA_NETHEKURSE
#define RegisterShatteredHallsGameObjectAI(ai_name)
#define RegisterShatteredHallsCreatureAI(ai_name)
bool IsHeroic() const
void DoPlaySoundToSet(WorldObject *source, uint32 soundId)
void UpdateOutOfCombatEvents(uint32 diff)
void JustEngagedWith(Unit *who) override
boss_grand_warlock_nethekurse(Creature *creature)
void DoAction(int32 action) override
void KilledUnit(Unit *) override
void UpdateAI(uint32 diff) override
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
bool OnGossipHello(Player *) override
go_grand_warlock_chamber_door(GameObject *go)
void JustDied(Unit *) override
npc_fel_orc_convert(Creature *creature)
void SpellHit(WorldObject *, SpellInfo const *spellInfo) override
void UpdateAI(uint32 diff) override
InstanceScript * _instance
void JustEngagedWith(Unit *) override
npc_lesser_shadow_fissure(Creature *creature)
npc_wild_shadow_fissure(Creature *creature)