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 }
323
324private:
328};
329
330// 17083 - Fel Orc Convert
332{
333 npc_fel_orc_convert(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
334
335 void Reset() override
336 {
338 }
339
340 void JustEngagedWith(Unit* /*who*/) override
341 {
342 if (roll_chance(15))
344
345 _scheduler.Schedule(5s, 10s, [this](TaskContext& task)
346 {
348 task.Repeat(5s, 10s);
349 });
350
351 if (!me->HasStringId("FelOrcConvertNethekurseEvent"))
352 return;
353
354 if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
355 nethekurse->AI()->DoAction(ACTION_PEON_ENGAGED);
356 }
357
358 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
359 {
360 // Not sure if these are grouped correctly, based on few sniffs
361 // By the way, language is correct, verified, not a typo
362 // Text 14143 seems to be unused, not added here
363 switch (spellInfo->Id)
364 {
366 if (roll_chance(30))
368 break;
370 if (roll_chance(30))
371 {
374 }
375 break;
377 if (roll_chance(30))
379 break;
380 default:
381 break;
382 }
383 }
384
385 void JustDied(Unit* /*killer*/) override
386 {
387 if (!me->HasStringId("FelOrcConvertNethekurseEvent"))
388 return;
389
390 if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
391 nethekurse->AI()->DoAction(ACTION_PEON_KILLED);
392 }
393
394 void UpdateAI(uint32 diff) override
395 {
396 if (!UpdateVictim())
397 return;
398
399 _scheduler.Update(diff);
400 }
401
402private:
405};
406
407// 17471 - Lesser Shadow Fissure
409{
411
412 void InitializeAI() override
413 {
415 }
416
421};
422
423// 18370 - Wild Shadow Fissure
425{
426 npc_wild_shadow_fissure(Creature* creature) : ScriptedAI(creature) { }
427
428 void InitializeAI() override
429 {
431 }
432
433 void JustAppeared() override
434 {
436 }
437};
438
439// 182539 - Grand Warlock Chamber Door
441{
442 go_grand_warlock_chamber_door(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { }
443
444 bool OnGossipHello(Player* /*player*/) override
445 {
446 if (Creature* nethekurse = _instance->GetCreature(DATA_NETHEKURSE))
447 nethekurse->AI()->DoAction(ACTION_START_INTRO);
448
449 return true;
450 }
451
452private:
454};
455
456// 30745 - Target Fissures
458{
459 bool Validate(SpellInfo const* /*spellInfo*/) override
460 {
462 }
463
464 void FilterTargets(std::list<WorldObject*>& targets)
465 {
466 if (targets.empty())
467 return;
468
470 targets.clear();
471 targets.push_back(target);
472 }
473
478
484};
485
486// 4347
488{
489public:
490 at_shattered_halls_the_sewer() : AreaTriggerScript("at_shattered_halls_the_sewer") { }
491
492 bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
493 {
494 if (InstanceScript* instance = player->GetInstanceScript())
495 if (Creature* nethekurse = instance->GetCreature(DATA_NETHEKURSE))
496 nethekurse->AI()->DoAction(ACTION_START_INTRO);
497
498 return true;
499 }
500};
501
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
bool roll_chance(float chance, PseudoRandomDistributionState &state)
Definition Random.cpp:131
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:43
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1383
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
DamageEffectType
@ UNIT_STATE_CASTING
Definition Unit.h:290
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()
Definition CreatureAI.h:169
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:63
void SetReactState(ReactStates st)
Definition Creature.h:180
bool HasStringId(std::string_view id) const
void Update(uint32 time)
Definition EventMap.h:77
void Repeat(Milliseconds time)
Definition EventMap.cpp:67
EventId ExecuteEvent()
Definition EventMap.cpp:77
void CancelEvent(EventId eventId)
Definition EventMap.cpp:156
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:40
void Reset()
Definition EventMap.cpp:25
Creature * GetCreature(uint32 type)
uint32 const Id
Definition SpellInfo.h:328
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
Unit * GetCaster() const
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
TaskContext & Repeat(TaskScheduler::duration_t duration)
TaskScheduler & CancelAll()
TaskScheduler & Schedule(duration_t time, task_handler_t task)
TaskScheduler & Update()
Update the scheduler to the current time.
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:160
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:172
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:71
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:81
Definition Unit.h:647
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition Unit.cpp:10768
bool IsAlive() const
Definition Unit.h:1205
void SetEmoteState(Emote emote)
Definition Unit.h:880
bool HealthBelowPctDamaged(float pct, uint32 damage) const
Definition Unit.h:805
bool HasUnitState(const uint32 f) const
Definition Unit.h:755
void SetFacingTo(float ori, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13385
bool IsInCombat() const
Definition Unit.h:1073
InstanceScript * GetInstanceScript() const
Definition Object.cpp:394
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2222
bool OnTrigger(Player *player, AreaTriggerEntry const *) override
void FilterTargets(std::list< WorldObject * > &targets)
auto SelectRandomContainerElement(C const &container) -> std::add_const_t< decltype(*std::ranges::begin(container))> &
Definition Containers.h:110
@ 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)