TrinityCore
boss_sjonnir.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#include "ScriptMgr.h"
19#include "halls_of_stone.h"
20#include "InstanceScript.h"
21#include "MotionMaster.h"
22#include "ObjectAccessor.h"
23#include "ScriptedCreature.h"
24#include "SpellInfo.h"
25#include "SpellScript.h"
26
28{
32 EMOTE_FRENZY = 3
33};
34
36{
37 SPELL_FRENZY = 28747,
38
39 SPELL_SUMMON_IRON_DWARF_PERIODIC = 50789, // 59860 not used
49
50 // Malformed Ooze
54
55 // Iron Sludge
57};
58
59#define SPELL_LIGHTNING_RING_1 DUNGEON_MODE<uint32>(50840,59848)
60#define SPELL_LIGHTNING_RING_2 DUNGEON_MODE<uint32>(51849,59861)
61#define SPELL_STATIC_CHARGE DUNGEON_MODE<uint32>(50834,59861)
62#define SPELL_CHAIN_LIGHTNING DUNGEON_MODE<uint32>(50830,59844)
63#define SPELL_LIGHTNING_SHIELD DUNGEON_MODE<uint32>(50831,59845)
64#define SPELL_SUMMON_IRON_TROGG_PERIODIC DUNGEON_MODE<uint32>(50792,59859)
65#define SPELL_SUMMON_MALFORMED_OOZE_PERIODIC DUNGEON_MODE<uint32>(50801,59858)
66#define SPELL_TOXIC_VOLLEY DUNGEON_MODE<uint32>(50838,59853)
67
69{
72 NPC_EARTHEN_DWARF = 27980
73};
74
75enum Misc
76{
79
82};
83
85{
92};
93
94Position const CenterPoint = { 1293.8799f, 666.942f, 189.60754f, 0.0f };
95
96struct boss_sjonnir : public BossAI
97{
99 _sludgesKilled(0), _summonsTroggs(false), _summonsOozes(false), _summonsDwarfs(false), _frenzied(false) { }
100
101 void JustEngagedWith(Unit* who) override
102 {
104 {
106 return;
107 }
108
112
118 }
119
120 void JustSummoned(Creature* summoned) override
121 {
122 switch (summoned->GetEntry())
123 {
126 // AttackStart(me->GetVictim()) does not work in case of very first spawn
128 summoned->AI()->AttackStart(target);
129 break;
131 summoned->AI()->AttackStart(me);
132 break;
133 }
134 summons.Summon(summoned);
135 }
136
137 void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
138 {
139 if (me->HealthBelowPctDamaged(75, damage) && !_summonsTroggs)
140 {
141 _summonsTroggs = true;
144 }
145
146 if (me->HealthBelowPctDamaged(50, damage) && !_summonsOozes)
147 {
148 _summonsOozes = true;
151 }
152
153 if (me->HealthBelowPctDamaged(25, damage) && !_summonsDwarfs)
154 {
155 _summonsDwarfs = true;
158 }
159
160 if (me->HealthBelowPctDamaged(20, damage) && !_frenzied)
161 {
162 _frenzied = true;
163 // Old removed, more powerful added
167 }
168 }
169
170 void EnterEvadeMode(EvadeReason /*why*/) override
171 {
175 }
176
177 void JustDied(Unit* /*killer*/) override
178 {
179 _JustDied();
181 }
182
183 void KilledUnit(Unit* who) override
184 {
185 if (who->GetTypeId() == TYPEID_PLAYER)
186 Talk(SAY_SLAY);
187 }
188
189 void DoAction(int32 action) override
190 {
191 if (action == ACTION_SLUDGE_DEAD)
193 }
194
195 uint32 GetData(uint32 type) const override
196 {
197 if (type == DATA_ABUSE_THE_OOZE)
198 return _sludgesKilled;
199
200 return 0;
201 }
202
203 void UpdateAI(uint32 diff) override
204 {
205 if (!UpdateVictim())
206 return;
207
208 events.Update(diff);
209
211 return;
212
213 while (uint32 eventId = events.ExecuteEvent())
214 {
215 switch (eventId)
216 {
219 events.Repeat(10s, 15s);
220 break;
224 events.Repeat(5s, 15s);
225 break;
227 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true, true))
229 events.Repeat(20s, 27s);
230 break;
233 events.Repeat(50s);
234 break;
237 events.Repeat(15s);
238 break;
239 case EVENT_FRENZY:
242 break;
243 default:
244 break;
245 }
246
248 return;
249 }
250 }
251
252private:
258};
259
261{
262 npc_malformed_ooze(Creature* creature) : ScriptedAI(creature) { }
263
264 void InitializeAI() override
265 {
266 me->SetCorpseDelay(5, true);
268 }
269
270 void JustAppeared() override
271 {
273 }
274
275 void MovementInform(uint32 type, uint32 id) override
276 {
277 if (type == POINT_MOTION_TYPE && id == POINT_CENTER)
278 {
281 }
282 }
283
284 /* This is far from correct implementation. Once ooze reaches center point, it casts periodic aura. When spell hits another ooze, both
285 caster and target removes periodic aura and caster starts moving to target. Target does not stop random movement. Once caster is close
286 enough to target, caster casts a spell to combine with target. Target despawns instantly, caster despawns after 1sec.
287
288 Since target does not stop random movement, that causes problems because combine spell is used when oozes are close enough to each other
289 but with current implementation it takes too much time to reach target, as result there may be too much oozes trying to combine at
290 the same time.
291 Increasing radius at which combine spell can be used or trying to change the way oozes chases target only creates more problems because
292 combine spell may target not required target but just ooze which was closer to caster. That leaves multiple spawns which can't combine
293 anymore since combining process was started(auras were removed) but wasn't finished sucessfully
294
295 Currently target is forced to stop random movement and caster just casts spell when is close enough to target. Spells has additional
296 conditions in DB. That makes oozes combine every time sucessfully but not too fast and give players more time too kill sludges
297 Ideally both spells should be scripted, filtering targets(if possible) and casting spell on target which was stored previously may look
298 overcomplicated but saves from casting spell on wrong target. Or maybe solving the problem with moving to stored target will be enough */
299 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
300 {
301 Creature* creatureTarget = target->ToCreature();
302 if (!creatureTarget)
303 return;
304
305 switch (spellInfo->Id)
306 {
308 _combineTarget = creatureTarget->GetGUID();
311 creatureTarget->GetMotionMaster()->MoveIdle();
313 me->GetMotionMaster()->MovePoint(POINT_COMBINE, creatureTarget->GetPosition());
314
315 _scheduler.Schedule(1s, [this](TaskContext task)
316 {
318 // Completely unclear what should happen in this case or in case when caster dies
319 if (!combineTarget || !combineTarget->IsAlive())
320 {
322 return;
323 }
324
325 if (me->GetExactDist2d(combineTarget) <= 0.1f)
326 DoCast(combineTarget, SPELL_SUMMON_IRON_SLUDGE);
327 else
328 {
330 task.Repeat();
331 }
332 });
333 break;
335 creatureTarget->DespawnOrUnsummon();
337 break;
338 }
339 }
340
341 void UpdateAI(uint32 diff) override
342 {
343 _scheduler.Update(diff);
344 }
345
346private:
349};
350
352{
353 npc_iron_sludge(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
354
355 void JustAppeared() override
356 {
357 me->SetCorpseDelay(4, true);
359
361 if (CreatureAI* ai = sjonnir->AI())
362 ai->JustSummoned(me);
363 }
364
365 void JustEngagedWith(Unit* /*who*/) override
366 {
367 _scheduler.Schedule(3s, 6s, [this](TaskContext task)
368 {
370 task.Repeat(3s, 6s);
371 });
372 }
373
374 void JustDied(Unit* /*killer*/) override
375 {
377 if (CreatureAI* ai = sjonnir->AI())
378 ai->DoAction(ACTION_SLUDGE_DEAD);
379 }
380
381 void UpdateAI(uint32 diff) override
382 {
383 if (!UpdateVictim())
384 return;
385
386 _scheduler.Update(diff);
387 }
388
389private:
392};
393
394/* 50789 - Summon Iron Dwarf
395 50792 - Summon Iron Trogg
396 59859 - Summon Iron Trogg
397 50801 - Summon Malformed Ooze
398 59858 - Summon Malformed Ooze
399 50824 - Summon Earthen Dwarf */
401{
402public:
403 spell_sjonnir_periodic_summon(uint32 leftPipeSpell, uint32 rightPipeSpell)
404 : AuraScript(), _leftPipeSpell(leftPipeSpell), _rightPipeSpell(rightPipeSpell) { }
405
406private:
407 bool Validate(SpellInfo const* /*spellInfo*/) override
408 {
410 }
411
412 void AfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
413 {
415 }
416
417 void OnPeriodic(AuraEffect const* /*aurEff*/)
418 {
420 }
421
422 void Register() override
423 {
426 }
427
430};
431
432// 50777 - Iron Sludge Spawn Visual
434{
435 void AfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
436 {
437 // They're indeed passive but I'm not sure enough if it's handled by this aura or directly in script
438 if (Creature* creature = GetTarget()->ToCreature())
439 creature->SetReactState(REACT_PASSIVE);
440 }
441
442 void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
443 {
444 if (Creature* creature = GetTarget()->ToCreature())
445 {
446 creature->SetReactState(REACT_AGGRESSIVE);
447 if (creature->IsAIEnabled() && creature->IsAlive())
448 creature->AI()->DoZoneInCombat();
449 }
450 }
451
452 void Register() override
453 {
456 }
457};
458
460{
461 public:
463 {
464 }
465
466 bool OnCheck(Player* /*player*/, Unit* target) override
467 {
468 if (!target)
469 return false;
470
471 if (Creature* Sjonnir = target->ToCreature())
472 if (Sjonnir->AI()->GetData(DATA_ABUSE_THE_OOZE) >= 5)
473 return true;
474
475 return false;
476 }
477};
478
480{
490}
Texts
First const & RAND(First const &first, Second const &second, Rest const &... rest)
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
@ POINT_MOTION_TYPE
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
Spells
Definition: PlayerAI.cpp:32
#define RegisterSpellScript(spell_script)
Definition: ScriptMgr.h:1369
#define RegisterSpellScriptWithArgs(spell_script, script_name,...)
Definition: ScriptMgr.h:1368
@ EFFECT_0
Definition: SharedDefines.h:30
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
@ SPELL_AURA_DUMMY
@ SPELL_AURA_PERIODIC_DUMMY
#define AuraEffectPeriodicFn(F, I, N)
Definition: SpellScript.h:2046
#define AuraEffectApplyFn(F, I, N, M)
Definition: SpellScript.h:2029
#define AuraEffectRemoveFn(F, I, N, M)
Definition: SpellScript.h:2040
EvadeReason
Definition: UnitAICommon.h:30
@ REACT_PASSIVE
Definition: UnitDefines.h:506
@ REACT_AGGRESSIVE
Definition: UnitDefines.h:508
DamageEffectType
Definition: UnitDefines.h:131
@ UNIT_STATE_CASTING
Definition: Unit.h:270
@ NPC_FORGED_IRON_DWARF
@ NPC_FORGED_IRON_TROGG
@ NPC_EARTHEN_DWARF
#define SPELL_LIGHTNING_RING_2
void AddSC_boss_sjonnir()
@ POINT_CENTER
@ ACTION_SLUDGE_DEAD
@ DATA_ABUSE_THE_OOZE
@ POINT_COMBINE
Position const CenterPoint
#define SPELL_SUMMON_IRON_TROGG_PERIODIC
@ SPELL_OOZE_COMBINE_EFFECT
@ SPELL_SUMMON_IRON_DWARF_2
@ SPELL_IRON_SLUDGE_SPAWN_VISUAL
@ SPELL_SUMMON_IRON_TROGG_2
@ SPELL_SUMMON_EARTHEN_DWARF_2
@ SPELL_SUMMON_IRON_DWARF_PERIODIC
@ SPELL_SUMMON_MALFORMED_OOZE_1
@ SPELL_OOZE_COMBINE_PERIODIC
@ SPELL_SUMMON_MALFORMED_OOZE_2
@ SPELL_SUMMON_IRON_TROGG_1
@ SPELL_SUMMON_EARTHEN_DWARF_1
@ SPELL_SUMMON_IRON_SLUDGE
@ SPELL_SUMMON_EARTHEN_DWARF_PERIODIC
@ SPELL_FRENZY
@ SPELL_SUMMON_IRON_DWARF_1
#define SPELL_CHAIN_LIGHTNING
#define SPELL_LIGHTNING_RING_1
#define SPELL_LIGHTNING_SHIELD
#define SPELL_TOXIC_VOLLEY
#define SPELL_SUMMON_MALFORMED_OOZE_PERIODIC
@ SAY_DEATH
@ SAY_AGGRO
@ EMOTE_FRENZY
@ SAY_SLAY
#define SPELL_STATIC_CHARGE
@ EVENT_CHAIN_LIGHTNING
@ EVENT_STATIC_CHARGE
@ EVENT_LIGHTNING_SHIELD
@ EVENT_LIGHTNING_RING_2
@ EVENT_FRENZY
@ EVENT_LIGHTNING_RING_1
HookList< EffectApplyHandler > AfterEffectRemove
Definition: SpellScript.h:2039
HookList< EffectPeriodicHandler > OnEffectPeriodic
Definition: SpellScript.h:2045
HookList< EffectApplyHandler > AfterEffectApply
Definition: SpellScript.h:2028
Unit * GetTarget() const
InstanceScript *const instance
void JustEngagedWith(Unit *who) override
void _DespawnAtEvade(Seconds delayToRespawn=30s, Creature *who=nullptr)
SummonList summons
EventMap events
void _JustDied()
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
Definition: CreatureAI.cpp:56
bool UpdateVictim()
Definition: CreatureAI.cpp:245
void AttackStart(Unit *victim) override
== Triggered Actions Requested ==================
Definition: CreatureAI.cpp:328
Creature *const me
Definition: CreatureAI.h:61
void SetReactState(ReactStates st)
Definition: Creature.h:160
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
Definition: Creature.cpp:2415
void SetCorpseDelay(uint32 delay, bool ignoreCorpseDecayRatio=false)
Definition: Creature.h:104
CreatureAI * AI() const
Definition: Creature.h:214
uint32 ExecuteEvent()
Definition: EventMap.cpp:73
void Update(uint32 time)
Definition: EventMap.h:56
void Repeat(Milliseconds time)
Definition: EventMap.cpp:63
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition: EventMap.cpp:36
void CancelEvent(uint32 eventId)
Definition: EventMap.cpp:131
Creature * GetCreature(uint32 type)
virtual bool CheckRequiredBosses(uint32, Player const *=nullptr) const
void MoveRandom(float wanderDistance=0.0f, Optional< Milliseconds > duration={}, MovementSlot slot=MOTION_SLOT_DEFAULT)
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< float > closeEnoughDistance={})
static Creature * ToCreature(Object *o)
Definition: Object.h:219
TypeID GetTypeId() const
Definition: Object.h:173
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
static Player * ToPlayer(Object *o)
Definition: Object.h:213
uint32 const Id
Definition: SpellInfo.h:325
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
Definition: SpellScript.h:162
void Summon(Creature const *summon)
TaskContext & Repeat(std::chrono::duration< Rep, Period > duration)
TaskScheduler & Schedule(std::chrono::duration< Rep, Period > time, task_handler_t task)
TaskScheduler & Update(success_t const &callback=nullptr)
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.h:159
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.cpp:180
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition: UnitAI.cpp:79
SpellCastResult DoCast(uint32 spellId)
Definition: UnitAI.cpp:89
Definition: Unit.h:627
MotionMaster * GetMotionMaster()
Definition: Unit.h:1652
bool IsAlive() const
Definition: Unit.h:1164
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
bool HealthBelowPctDamaged(int32 pct, uint32 damage) const
Definition: Unit.h:781
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
bool OnCheck(Player *, Unit *target) override
void AfterRemove(AuraEffect const *, AuraEffectHandleModes)
void AfterApply(AuraEffect const *, AuraEffectHandleModes)
bool Validate(SpellInfo const *) override
spell_sjonnir_periodic_summon(uint32 leftPipeSpell, uint32 rightPipeSpell)
void OnPeriodic(AuraEffect const *)
void AfterApply(AuraEffect const *, AuraEffectHandleModes)
@ DATA_SJONNIR_THE_IRONSHAPER
#define RegisterHallsOfStoneCreatureAI(ai_name)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
float GetExactDist2d(const float x, const float y) const
Definition: Position.h:106
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
void JustSummoned(Creature *summoned) override
void JustEngagedWith(Unit *who) override
void UpdateAI(uint32 diff) override
void KilledUnit(Unit *who) override
uint8 _sludgesKilled
void JustDied(Unit *) override
boss_sjonnir(Creature *creature)
void DoAction(int32 action) override
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
uint32 GetData(uint32 type) const override
void EnterEvadeMode(EvadeReason) override
npc_iron_sludge(Creature *creature)
TaskScheduler _scheduler
void JustDied(Unit *) override
void JustEngagedWith(Unit *) override
InstanceScript * _instance
void JustAppeared() override
void UpdateAI(uint32 diff) override
TaskScheduler _scheduler
void JustAppeared() override
void SpellHitTarget(WorldObject *target, SpellInfo const *spellInfo) override
void UpdateAI(uint32 diff) override
ObjectGuid _combineTarget
npc_malformed_ooze(Creature *creature)
void InitializeAI() override
void MovementInform(uint32 type, uint32 id) override