Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_lord_marrowgar.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "ObjectMgr.h"
7#include "ScriptMgr.h"
8#include "ScriptedCreature.h"
9#include "SpellAuras.h"
10#include "MoveSplineInit.h"
11#include "Player.h"
12#include "icecrown_citadel.h"
13
25
27{
28 // Lord Marrowgar
34
35 // Bone Spike
38
39 // Coldflame
42};
43
44uint32 const BoneSpikeSummonId[3] = {69062, 72669, 72670};
45
62
68
70{
72
73 // Manual marking for targets hit by Bone Slice as no aura exists for this purpose
74 // These units are the tanks in this encounter
75 // and should be immune to Bone Spike Graveyard
77 //DATA_SPIKE_IMMUNE_1, = 2, // Reserved & used
78 //DATA_SPIKE_IMMUNE_2, = 3, // Reserved & used
79
81
83};
84
85class BoneSpikeTargetSelector : public SF_UNARY_FUNCTION<Unit*, bool>
86{
87 public:
89
90 bool operator()(Unit* unit) const
91 {
92 if (unit->GetTypeId() != TypeID::TYPEID_PLAYER)
93 return false;
94
95 if (unit->HasAura(SPELL_IMPALED))
96 return false;
97
98 // Check if it is one of the tanks soaking Bone Slice
99 for (uint32 i = 0; i < MAX_BONE_SPIKE_IMMUNE; ++i)
100 if (unit->GetGUID() == _ai->GetGUID(DATA_SPIKE_IMMUNE + i))
101 return false;
102
103 return true;
104 }
105
106 private:
108};
109
111{
112 public:
113 boss_lord_marrowgar() : CreatureScript("boss_lord_marrowgar") { }
114
116 {
118 {
119 _boneStormDuration = RAID_MODE<uint32>(20000, 30000, 20000, 30000);
120 _baseSpeed = creature->GetSpeedRate(MOVE_RUN);
121 _coldflameLastPos.Relocate(creature);
122 _introDone = false;
123 _boneSlice = false;
124 }
125
127 {
128 _Reset();
129 me->SetSpeed(MOVE_RUN, _baseSpeed, true);
130 me->RemoveAurasDueToSpell(SPELL_BONE_STORM);
131 me->RemoveAurasDueToSpell(SPELL_BERSERK);
132 events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000);
134 events.ScheduleEvent(EVENT_COLDFLAME, 5000, EVENT_GROUP_SPECIAL);
135 events.ScheduleEvent(EVENT_WARN_BONE_STORM, std::rand() % 50000 + 45000);
136 events.ScheduleEvent(EVENT_ENRAGE, 600000);
137 _boneSlice = false;
138 _boneSpikeImmune.clear();
139 }
140
141 void EnterCombat(Unit* /*who*/) OVERRIDE
142 {
144
145 me->setActive(true);
148 }
149
150 void JustDied(Unit* /*killer*/) OVERRIDE
151 {
153
154 _JustDied();
155 }
156
158 {
160 instance->SetBossState(DATA_LORD_MARROWGAR, FAIL);
161 instance->SetData(DATA_BONED_ACHIEVEMENT, uint32(true)); // reset
162 }
163
165 {
166 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER)
167 Talk(SAY_KILL);
168 }
169
171
172 {
173 if (!_introDone && me->IsWithinDistInMap(who, 70.0f))
174 {
176 _introDone = true;
177 }
178 }
179
181 {
182 if (!UpdateVictim() || !CheckInRoom())
183 return;
184
185 events.Update(diff);
186
187 if (me->HasUnitState(UNIT_STATE_CASTING))
188 return;
189
190 while (uint32 eventId = events.ExecuteEvent())
191 {
192 switch (eventId)
193 {
195 if (IsHeroic() || !me->HasAura(SPELL_BONE_STORM))
197 events.ScheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, std::rand() % 20000 + 15000, EVENT_GROUP_SPECIAL);
198 break;
199 case EVENT_COLDFLAME:
200 _coldflameLastPos.Relocate(me);
201 _coldflameTarget = 0LL;
202 if (!me->HasAura(SPELL_BONE_STORM))
204 else
206 events.ScheduleEvent(EVENT_COLDFLAME, 5000, EVENT_GROUP_SPECIAL);
207 break;
209 _boneSlice = false;
211 me->FinishSpell(CURRENT_MELEE_SPELL, false);
213 events.DelayEvents(3000, EVENT_GROUP_SPECIAL);
214 events.ScheduleEvent(EVENT_BONE_STORM_BEGIN, 3050);
215 events.ScheduleEvent(EVENT_WARN_BONE_STORM, std::rand() % 95000 + 90000);
216 break;
218 if (Aura* pStorm = me->GetAura(SPELL_BONE_STORM))
219 pStorm->SetDuration(int32(_boneStormDuration));
220 me->SetSpeed(MOVE_RUN, _baseSpeed*3.0f, true);
223 // no break here
225 {
228 if (!unit)
229 unit = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true);
230 if (unit)
231 me->GetMotionMaster()->MovePoint(POINT_TARGET_BONESTORM_PLAYER, *unit);
232 break;
233 }
235 if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
236 me->GetMotionMaster()->MovementExpired();
237 me->GetMotionMaster()->MoveChase(me->GetVictim());
238 me->SetSpeed(MOVE_RUN, _baseSpeed, true);
239 events.CancelEvent(EVENT_BONE_STORM_MOVE);
240 events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000);
241 if (!IsHeroic())
243 break;
245 _boneSlice = true;
246 break;
247 case EVENT_ENRAGE:
248 DoCast(me, SPELL_BERSERK, true);
250 break;
251 }
252 }
253
254 // We should not melee attack when storming
255 if (me->HasAura(SPELL_BONE_STORM))
256 return;
257
258 // 10 seconds since encounter start Bone Slice replaces melee attacks
259 if (_boneSlice && !me->GetCurrentSpell(CURRENT_MELEE_SPELL))
261
263 }
264
266 {
268 return;
269
270 // lock movement
271 me->GetMotionMaster()->MoveIdle();
272 }
273
275 {
276 return &_coldflameLastPos;
277 }
278
279 uint64 GetGUID(int32 type /*= 0 */) const OVERRIDE
280 {
281 switch (type)
282 {
284 return _coldflameTarget;
285 case DATA_SPIKE_IMMUNE + 0:
286 case DATA_SPIKE_IMMUNE + 1:
287 case DATA_SPIKE_IMMUNE + 2:
288 {
289 uint32 index = uint32(type - DATA_SPIKE_IMMUNE);
290 if (index < _boneSpikeImmune.size())
291 return _boneSpikeImmune[index];
292
293 break;
294 }
295 }
296
297 return 0LL;
298 }
299
300 void SetGUID(uint64 guid, int32 type /*= 0 */) OVERRIDE
301 {
302 switch (type)
303 {
305 _coldflameTarget = guid;
306 break;
308 _boneSpikeImmune.push_back(guid);
309 break;
310 }
311 }
312
314 {
315 if (action != ACTION_CLEAR_SPIKE_IMMUNITIES)
316 return;
317
318 _boneSpikeImmune.clear();
319 }
320
321 private:
323 std::vector<uint64> _boneSpikeImmune;
329 };
330
332 {
334 }
335};
336
338
340{
341 public:
342 npc_coldflame() : CreatureScript("npc_coldflame") { }
343
345 {
346 npc_coldflameAI(Creature* creature) : ScriptedAI(creature)
347 {
348 }
349
351 {
352 if (owner->GetTypeId() != TypeID::TYPEID_UNIT)
353 return;
354
355 Position pos;
356 if (MarrowgarAI* marrowgarAI = CAST_AI(MarrowgarAI, owner->GetAI()))
357 pos.Relocate(marrowgarAI->GetLastColdflamePosition());
358 else
359 pos.Relocate(owner);
360
361 if (owner->HasAura(SPELL_BONE_STORM))
362 {
364 me->SetOrientation(ang);
365 owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 5.0f - owner->GetObjectSize(), ang);
366 }
367 else
368 {
369 Player* target = ObjectAccessor::GetPlayer(*owner, owner->GetAI()->GetGUID(DATA_COLDFLAME_GUID));
370 if (!target)
371 {
372 me->DespawnOrUnsummon();
373 return;
374 }
375
376 float ang = Position::NormalizeOrientation(pos.GetAngle(target));
377 me->SetOrientation(ang);
378 owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 15.0f - owner->GetObjectSize(), ang);
379 }
380
381 me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), me->GetPositionZ(), me->GetOrientation());
383 _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 500);
384 }
385
387 {
388 _events.Update(diff);
389
390 if (_events.ExecuteEvent() == EVENT_COLDFLAME_TRIGGER)
391 {
392 Position newPos;
393 me->GetNearPosition(newPos, 5.0f, 0.0f);
394 me->NearTeleportTo(newPos.GetPositionX(), newPos.GetPositionY(), me->GetPositionZ(), me->GetOrientation());
396 _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 500);
397 }
398 }
399
400 private:
402 };
403
405 {
407 }
408};
409
411{
412 public:
413 npc_bone_spike() : CreatureScript("npc_bone_spike") { }
414
416 {
418 {
419 ASSERT(creature->GetVehicleKit());
420
421 SetCombatMovement(false);
422 }
423
424 void JustDied(Unit* /*killer*/) OVERRIDE
425 {
426 if (TempSummon* summ = me->ToTempSummon())
427 if (Unit* trapped = summ->GetSummoner())
428 trapped->RemoveAurasDueToSpell(SPELL_IMPALED);
429
430 me->DespawnOrUnsummon();
431 }
432
434 {
435 me->DespawnOrUnsummon();
436 victim->RemoveAurasDueToSpell(SPELL_IMPALED);
437 }
438
439 void IsSummonedBy(Unit* summoner) OVERRIDE
440 {
441 DoCast(summoner, SPELL_IMPALED);
442 summoner->CastSpell(me, SPELL_RIDE_VEHICLE, true);
443 _events.ScheduleEvent(EVENT_FAIL_BONED, 8000);
444 _hasTrappedUnit = true;
445 }
446
447 void PassengerBoarded(Unit* passenger, int8 /*seat*/, bool apply) OVERRIDE
448 {
449 if (!apply)
450 return;
451
455 Movement::MoveSplineInit init(passenger);
457 init.MoveTo(-0.02206125f, -0.02132235f, 5.514783f, false);
458 init.Launch();
459 }
460
462 {
463 if (!_hasTrappedUnit)
464 return;
465
466 _events.Update(diff);
467
468 if (_events.ExecuteEvent() == EVENT_FAIL_BONED)
469 if (InstanceScript* instance = me->GetInstanceScript())
470 instance->SetData(DATA_BONED_ACHIEVEMENT, uint32(false));
471 }
472
473 private:
476 };
477
479 {
481 }
482};
483
485{
486 public:
487 spell_marrowgar_coldflame() : SpellScriptLoader("spell_marrowgar_coldflame") { }
488
490 {
492
493 void SelectTarget(std::list<WorldObject*>& targets)
494 {
495 targets.clear();
496 // select any unit but not the tank (by owners threatlist)
497 Unit* target = GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 1, -GetCaster()->GetObjectSize(), true, -SPELL_IMPALED);
498 if (!target)
499 target = GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true); // or the tank if its solo
500 if (!target)
501 return;
502
504 targets.push_back(target);
505 }
506
508 {
509 PreventHitDefaultEffect(effIndex);
511 }
512
518 };
519
524};
525
553
555{
556 public:
557 spell_marrowgar_coldflame_damage() : SpellScriptLoader("spell_marrowgar_coldflame_damage") { }
558
560 {
562
563 bool CanBeAppliedOn(Unit* target)
564 {
565 if (target->HasAura(SPELL_IMPALED))
566 return false;
567
568 if (target->GetExactDist2d(GetOwner()) > GetSpellInfo()->Effects[EFFECT_0].CalcRadius())
569 return false;
570
571 if (Aura* aur = target->GetAura(GetId()))
572 if (aur->GetOwner() != GetOwner())
573 return false;
574
575 return true;
576 }
577
582 };
583
588};
589
591{
592 public:
593 spell_marrowgar_bone_spike_graveyard() : SpellScriptLoader("spell_marrowgar_bone_spike_graveyard") { }
594
596 {
598
599 bool Validate(SpellInfo const* /*spell*/) OVERRIDE
600 {
601 for (uint32 i = 0; i < 3; ++i)
602 if (!sSpellMgr->GetSpellInfo(BoneSpikeSummonId[i]))
603 return false;
604
605 return true;
606 }
607
609 {
611 }
612
617
619 {
620 PreventHitDefaultEffect(effIndex);
621 if (Creature* marrowgar = GetCaster()->ToCreature())
622 {
623 CreatureAI* marrowgarAI = marrowgar->AI();
624 uint8 boneSpikeCount = uint8(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 3 : 1);
625
626 std::list<Unit*> targets;
627 marrowgarAI->SelectTargetList(targets, BoneSpikeTargetSelector(marrowgarAI), boneSpikeCount, SELECT_TARGET_RANDOM);
628 if (targets.empty())
629 return;
630
631 uint32 i = 0;
632 for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr, ++i)
633 {
634 Unit* target = *itr;
635 target->CastCustomSpell(BoneSpikeSummonId[i], SPELLVALUE_BASE_POINT0, 0, target, true);
636 }
637
638 marrowgarAI->Talk(SAY_BONESPIKE);
639 }
640 }
641
647 };
648
653};
654
680
682{
683 public:
684 spell_marrowgar_bone_slice() : SpellScriptLoader("spell_marrowgar_bone_slice") { }
685
687 {
689
691 {
692 _targetCount = 0;
693 return true;
694 }
695
700
701 void CountTargets(std::list<WorldObject*>& targets)
702 {
703 _targetCount = std::min<uint32>(targets.size(), GetSpellInfo()->MaxAffectedTargets);
704 }
705
707 {
708 // Mark the unit as hit, even if the spell missed or was dodged/parried
710
711 if (!_targetCount)
712 return; // This spell can miss all targets
713
715 }
716
723
725 };
726
731};
732
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::int8_t int8
Definition Define.h:75
#define OVERRIDE
Definition Define.h:60
std::uint64_t uint64
Definition Define.h:76
#define ASSERT
Definition Errors.h:29
@ IN_PROGRESS
@ FAIL
@ POINT_MOTION_TYPE
@ TYPEID_PLAYER
Definition Object.h:55
@ TYPEID_UNIT
Definition Object.h:54
#define CAST_AI(a, b)
SpellEffIndex
@ EFFECT_1
@ EFFECT_0
@ SPELL_EFFECT_SCRIPT_EFFECT
@ SPELL_EFFECT_APPLY_AURA
@ TARGET_UNIT_DEST_AREA_ENEMY
SpellCastResult
#define sSpellMgr
Definition SpellMgr.h:744
#define SpellCheckCastFn(F)
#define SpellEffectFn(F, I, N)
#define SpellObjectAreaTargetSelectFn(F, I, N)
#define SpellCastFn(F)
#define SpellHitFn(F)
#define AuraCheckAreaTargetFn(F)
#define SF_UNARY_FUNCTION
@ SPELLVALUE_BASE_POINT0
Definition Unit.h:114
@ CURRENT_MELEE_SPELL
Definition Unit.h:1108
@ UNIT_STATE_CASTING
Definition Unit.h:527
@ MOVE_RUN
Definition Unit.h:556
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
@ EVENT_ENRAGE
@ SAY_BERSERK
#define SAY_DEATH
#define SAY_AGGRO
#define SAY_KILL
#define SPELL_BERSERK
@ SPELL_COLDFLAME_BONE_STORM
@ SPELL_RIDE_VEHICLE
@ SPELL_COLDFLAME_SUMMON
@ SPELL_COLDFLAME_PASSIVE
@ SPELL_COLDFLAME_NORMAL
@ SPELL_BONE_SPIKE_GRAVEYARD
@ SPELL_IMPALED
@ SPELL_BONE_STORM
@ SPELL_BONE_SLICE
void AddSC_boss_lord_marrowgar()
boss_lord_marrowgar::boss_lord_marrowgarAI MarrowgarAI
@ POINT_TARGET_BONESTORM_PLAYER
@ POINT_TARGET_COLDFLAME
uint32 const BoneSpikeSummonId[3]
@ ACTION_CLEAR_SPIKE_IMMUNITIES
@ MAX_BONE_SPIKE_IMMUNE
@ DATA_COLDFLAME_GUID
@ DATA_SPIKE_IMMUNE
@ SAY_ENTER_ZONE
@ SAY_BONESPIKE
@ SAY_BONE_STORM
@ EMOTE_BONE_STORM
@ EVENT_COLDFLAME_TRIGGER
@ EVENT_FAIL_BONED
@ EVENT_WARN_BONE_STORM
@ EVENT_GROUP_SPECIAL
@ EVENT_BONE_STORM_END
@ EVENT_BONE_STORM_MOVE
@ EVENT_COLDFLAME
@ EVENT_BONE_SPIKE_GRAVEYARD
@ EVENT_BONE_STORM_BEGIN
@ EVENT_ENABLE_BONE_SLICE
SpellInfo const * GetSpellInfo() const
WorldObject * GetOwner() const
HookList< CheckAreaTargetHandler > DoCheckAreaTarget
uint32 GetId() const
bool operator()(Unit *unit) const
InstanceScript *const instance
void _JustReachedHome()
bool CheckInRoom()
EventMap events
BossAI(Creature *creature, uint32 bossId)
void DoZoneInCombat(Creature *creature=NULL, float maxRangeToNearestTarget=50.0f)
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
CreatureScript(const char *name)
void MoveTo(const Vector3 &destination, bool generatePath=true, bool forceDestination=false)
static Player * GetPlayer(WorldObject const &, uint64 guid)
uint64 GetGUID() const
Definition Object.h:119
TypeID GetTypeId() const
Definition Object.h:131
HookList< CheckCastHandler > OnCheckCast
SpellInfo const * GetSpellInfo()
HookList< HitHandler > OnHit
void PreventHitDefaultEffect(SpellEffIndex effIndex)
HookList< EffectHandler > OnEffectHitTarget
Unit * GetHitUnit()
int32 GetEffectValue()
HookList< CastHandler > BeforeCast
void SetHitDamage(int32 damage)
Unit * GetCaster()
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
int32 GetHitDamage()
SpellScriptLoader(const char *name)
virtual void DoAction(int32)
Definition UnitAI.h:126
virtual void SetGUID(uint64, int32=0)
Definition UnitAI.h:129
void SelectTargetList(std::list< Unit * > &targetList, uint32 num, SelectAggroTarget targetType, float dist=0.0f, bool playerOnly=false, int32 aura=0)
Definition UnitAI.cpp:71
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:28
void DoCast(uint32 spellId)
Definition UnitAI.cpp:110
Unit * SelectTarget(SelectAggroTarget targetType, uint32 position=0, float dist=0.0f, bool playerOnly=false, int32 aura=0)
Definition UnitAI.cpp:66
void DoCastVictim(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:168
void DoCastAOE(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:176
Definition Unit.h:1367
void CastSpell(SpellCastTargets const &targets, SpellInfo const *spellInfo, CustomSpellValues const *value, TriggerCastFlags triggerFlags=TRIGGERED_NONE, Item *castItem=NULL, AuraEffect const *triggeredByAura=NULL, uint64 originalCaster=0)
Aura * GetAura(uint32 spellId, uint64 casterGUID=0, uint64 itemCasterGUID=0, uint32 reqEffMask=0) const
bool HasAura(uint32 spellId, uint64 casterGUID=0, uint64 itemCasterGUID=0, uint32 reqEffMask=0) const
float GetSpeedRate(UnitMoveType mtype) const
Definition Unit.h:2581
bool IsAIEnabled
Definition Unit.h:2735
void CastCustomSpell(Unit *victim, uint32 spellId, int32 const *bp0, int32 const *bp1, int32 const *bp2, bool triggered, Item *castItem=NULL, AuraEffect const *triggeredByAura=NULL, uint64 originalCaster=0)
UnitAI * GetAI()
Definition Unit.h:1393
Vehicle * GetVehicleKit() const
Definition Unit.h:2739
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
PrepareSpellScript(spell_marrowgar_bone_slice_SpellScript)
SpellScript * GetSpellScript() const OVERRIDE
SpellScript * GetSpellScript() const OVERRIDE
PrepareSpellScript(spell_marrowgar_bone_storm_SpellScript)
SpellScript * GetSpellScript() const OVERRIDE
PrepareSpellScript(spell_marrowgar_coldflame_SpellScript)
SpellScript * GetSpellScript() const OVERRIDE
AuraScript * GetAuraScript() const OVERRIDE
SpellScript * GetSpellScript() const OVERRIDE
CreatureAI * GetIcecrownCitadelAI(Creature *creature)
@ DATA_LORD_MARROWGAR
@ DATA_BONED_ACHIEVEMENT
float GetAngle(Position const *pos) const
Definition Object.cpp:1860
float GetExactDist2d(const float x, const float y) const
Definition Object.h:366
static float NormalizeOrientation(float o)
Definition Object.h:427
float m_positionX
Definition Object.h:287
float m_positionY
Definition Object.h:288
float GetPositionX() const
Definition Object.h:328
float GetPositionY() const
Definition Object.h:329
void Relocate(float x, float y)
Definition Object.h:302
bool IsHeroic() const
void SetCombatMovement(bool allowMovement)
Creature * me
const T & RAID_MODE(const T &normal10, const T &normal25) const
ScriptedAI(Creature *creature)
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void MovementInform(uint32 type, uint32 id) OVERRIDE
void SetGUID(uint64 guid, int32 type) OVERRIDE
uint64 GetGUID(int32 type) const OVERRIDE
void KilledUnit(Unit *victim) OVERRIDE
void IsSummonedBy(Unit *summoner) OVERRIDE
void PassengerBoarded(Unit *passenger, int8, bool apply) OVERRIDE
== Fields =======================================
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void IsSummonedBy(Unit *owner) OVERRIDE