TrinityCore
Loading...
Searching...
No Matches
boss_shade_of_medivh.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 "AreaTrigger.h"
19#include "AreaTriggerAI.h"
20#include "Containers.h"
21#include "Creature.h"
22#include "InstanceScript.h"
23#include "ObjectAccessor.h"
24#include "Player.h"
25#include "Position.h"
26#include "ScriptedCreature.h"
27#include "ScriptMgr.h"
28#include "Spell.h"
29#include "SpellAuras.h"
30#include "SpellAuraEffects.h"
31#include "SpellScript.h"
32#include "return_to_karazhan.h"
33
63
74
76{
77 SAY_INTRO = 0, // Implement later
91 SAY_SPECIAL = 14 // Used if players have the item Atiesh, Greatstaff of the Guardian
92};
93
100
105
110
111static constexpr Position GuardiansImageMedivhPosition = { -4599.3f, -2517.86f, 2876.59f };
112static constexpr Position GuardiansImagePosition[3] =
113{
114 { -4599.8057f, -2494.7551f, 2876.6255f, 4.694935f },
115 { -4618.8994f, -2526.8315f, 2876.6252f, 0.663225f },
116 { -4581.1006f, -2526.6892f, 2876.6257f, 2.460914f }
117};
118
120{
121 { -4573.2363f, -2517.875f, 2903.3594f },
122 { -4617.39f, -2499.2f, 2886.25f },
123 { -4620.2275f, -2535.092f, 2903.4875f },
124 { -4573.2363f, -2517.875f, 2885.7869f },
125 { -4617.3906f, -2499.1997f, 2902.f },
126 { -4598.722f, -2555.3784f, 2906.814f },
127 { -4580.137f, -2499.736f, 2887.0764f },
128 { -4624.4116f, -2517.2588f, 2886.9016f },
129 { -4624.4116f, -2517.2588f, 2904.4302f },
130 { -4580.137f, -2499.736f, 2902.3f },
131 { -4620.2275f, -2535.092f, 2887.8333f },
132 { -4577.932f, -2535.927f, 2902.615f },
133 { -4573.2363f, -2517.875f, 2903.3594f },
134 { -4577.932f, -2535.927f, 2885.7869f }
135};
136
137// 114350 - Shade of Medivh
139{
141
142 void JustAppeared() override
143 {
148
149 scheduler.Schedule(2s, [this](TaskContext& task)
150 {
151 static constexpr uint8 VisualCount = 5;
152 static constexpr float TravelSpeed = 8.0f;
153
154 std::vector<Position> positions(std::begin(MedivhVisualSpellsPositions), std::end(MedivhVisualSpellsPositions));
156
157 for (uint8 i = 0; i < VisualCount; i++)
158 {
159 me->SendPlaySpellVisual(positions[i], SPELLVISUAL_ARCANE_MISSILE, 0, 0, TravelSpeed);
160 }
161 task.Repeat(1200ms);
162 });
163 }
164
165 void JustDied(Unit* /*killer*/) override
166 {
168 _JustDied();
170 Talk(SAY_DEAD);
171 }
172
183
184 void KilledUnit(Unit* victim) override
185 {
186 if (!victim->IsPlayer())
187 return;
188
189 Talk(SAY_SLAY);
190 }
191
192 void Reset() override
193 {
194 events.Reset();
195 _triggeredSplit = false;
198 }
199
229
230 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
231 {
232 switch (spellInfo->Id)
233 {
235 {
237
240 else if (_guardiansImageDefeatedCount == 2)
242 else if (_guardiansImageDefeatedCount == 3)
244
245 break;
246 }
248 {
249 if (!_triggeredSplit)
250 {
251 _triggeredSplit = true;
253 }
254 break;
255 }
256 default:
257 break;
258 }
259 }
260
261 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
262 {
263 if (!target->IsPlayer())
264 return;
265
266 switch (spellInfo->Id)
267 {
269 {
271 break;
272 }
274 {
276 break;
277 }
278 default:
279 break;
280 }
281 }
282
283 void OnSpellStart(SpellInfo const* spellInfo) override
284 {
285 switch (spellInfo->Id)
286 {
288 {
290 break;
291 }
293 {
296 break;
297 }
299 {
301 break;
302 }
303 default:
304 break;
305 }
306 }
307
308 void OnSpellFailed(SpellInfo const* spellInfo) override
309 {
310 switch (spellInfo->Id)
311 {
314 case SPELL_FROSTBITE:
315 {
317 break;
318 }
319 default:
320 break;
321 }
322 }
323
338
339 void UpdateAI(uint32 diff) override
340 {
341 scheduler.Update(diff);
342
343 if (!UpdateVictim())
344 return;
345
346 events.Update(diff);
347
349 return;
350
351 while (uint32 eventId = events.ExecuteEvent())
352 {
353 switch (eventId)
354 {
356 {
358 events.Repeat(6s);
359 break;
360 }
361 case EVENT_CHECK_MANA:
362 {
363 if (me->GetPowerPct(POWER_MANA) >= 100)
365 events.Repeat(500ms);
366 break;
367 }
368 case EVENT_TELEPORT:
369 {
371 break;
372 }
374 {
376 me->SetUninteractible(false);
380 break;
381 }
382 default:
383 break;
384 }
385
387 return;
388 }
389 }
390
391 uint32 GetData(uint32 id) const override
392 {
393 if (id == DATA_INFERNO_BOLT_NEXT)
395 return 0;
396 }
397
398 void SetData(uint32 id, uint32 value) override
399 {
400 if (id == DATA_INFERNO_BOLT_NEXT)
401 _castInfernoBoltNext = value;
402 }
403
404private:
408};
409
410// 114675 - Guardian's Image
412{
414
415 void JustAppeared() override
416 {
419 }
420
421 void JustDied(Unit* /*killer*/) override
422 {
425
427 }
428
429 void EnterEvadeMode(EvadeReason why) override
430 {
432 shadeOfMedivh->AI()->EnterEvadeMode(why);
433 }
434
441
442 void UpdateAI(uint32 diff) override
443 {
444 if (!UpdateVictim())
445 return;
446
447 events.Update(diff);
448
450 return;
451
452 while (uint32 eventId = events.ExecuteEvent())
453 {
454 switch (eventId)
455 {
457 {
459 events.Repeat(3s);
460 break;
461 }
462 default:
463 break;
464 }
465
467 return;
468 }
469 }
470
471private:
473};
474
475// 228582 - Mana Regen
477{
478 static constexpr std::array<uint8, 3> ShadeOfMedivhEnergizeCycle = { 3, 4, 3 };
479
480 void PeriodicTick(AuraEffect const* aurEff) const
481 {
482 uint8 cycleIdx = (aurEff->GetTickNumber() - 1) % ShadeOfMedivhEnergizeCycle.size();
483 int32 amount = ShadeOfMedivhEnergizeCycle[cycleIdx] * GetTarget()->GetMaxPower(POWER_MANA) / 100;
484 GetTarget()->ModifyPower(POWER_MANA, amount);
485 }
486
491};
492
493// 227599 - Basic Primer
495{
496 bool Validate(SpellInfo const* /*spellInfo*/) override
497 {
499 }
500
502 {
503 Creature* creatureCaster = GetCaster()->ToCreature();
504 if (!creatureCaster)
505 return;
506
507 Unit* target = creatureCaster->AI()->SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true);
509
510 if (creatureCaster->AI()->GetData(DATA_INFERNO_BOLT_NEXT) == 1)
511 {
513 creatureCaster->AI()->SetData(DATA_INFERNO_BOLT_NEXT, 0);
514 }
515 else if (spellId == SPELL_FROSTBITE)
516 creatureCaster->AI()->SetData(DATA_INFERNO_BOLT_NEXT, 1);
517
518 creatureCaster->CastSpell(target, spellId, CastSpellExtraArgsInit{
520 .TriggeringSpell = GetSpell()
521 });
522 }
523
528};
529
530// 228237 - Signature Primer
532{
533 bool Validate(SpellInfo const* /*spellInfo*/) override
534 {
536 }
537
538 void HandleHit() const
539 {
540 Creature* creatureCaster = GetCaster()->ToCreature();
541 if (!creatureCaster)
542 return;
543
545 creatureCaster->CastSpell(creatureCaster, spellId, CastSpellExtraArgsInit{
547 .TriggeringSpell = GetSpell()
548 });
549 }
550
551 void HandleAfterCast() const
552 {
554 }
555
561};
562
563// 228249 - Inferno Bolt
584
585// 227628 - Piercing Missiles
606
607// 228269 - Flame Wreath
628
629// 228222 - Ceaseless Winter
651
652// 228334 - Guardian's Image
654{
655 bool Validate(SpellInfo const* /*spellInfo*/) override
656 {
658 }
659
660 void HandleHit() const
661 {
662 for (uint8 i = 0; i < 3; i++)
663 {
666 .TriggeringSpell = GetSpell()
667 });
668 }
669 }
670
675};
676
677// 228992 - Arcane Bolt
693
694// 232314 - V.O Controller
696{
697 void HandleScript(SpellEffIndex /*effIndex*/) const
698 {
699 uint8 text = 0;
700 ObjectGuid originalCast = GetSpell()->m_originalCastId;
701
702 if (!originalCast.IsEmpty())
703 {
704 switch (originalCast.GetEntry())
705 {
706 case SPELL_FROSTBITE:
707 {
708 text = SAY_FROSTBITE;
709 break;
710 }
712 {
713 text = SAY_INFERNO_BOLT;
714 break;
715 }
716 default:
717 break;
718 }
719 }
720 else
721 text = SAY_AGGRO;
722
723 if (Creature* shadeOfMedivh = GetHitUnit()->ToCreature())
724 shadeOfMedivh->AI()->Talk(text);
725 }
726
731};
732
733// 232314 - V.O Controller (attached to 227592 - Frostbite and 227615 - Inferno Bolt)
735{
736 bool Validate(SpellInfo const* /*spellInfo*/) override
737 {
739 }
740
741 void HandleAfterCast() const
742 {
743 Unit* caster = GetCaster();
744 if (caster->HasAura(SPELL_VO_CONTROLLER))
745 return;
746
749 .TriggeringSpell = GetSpell(),
750 });
751 }
752
757};
758
759// 227779 - Ceaseless Winter
760// Id - 8848
782
783// 227779 - Ceaseless Winter
784// Id - 8809
794
795// 228257 - Flame Wreath
797{
799
801 {
802 return std::ranges::count_if(at->GetInsideUnits(), [this](ObjectGuid const& guid)
803 {
804 Player* player = ObjectAccessor::GetPlayer(*at, guid);
805 if (!player || !player->IsAlive() || player->IsGameMaster())
806 return false;
807 return true;
808 });
809 }
810
811 void OnUnitEnter(Unit* unit) override
812 {
813 Unit* caster = at->GetCaster();
814 if (!caster)
815 return;
816
817 if (!unit->IsPlayer())
818 return;
819
820 if (GetInsidePlayersCount() >= 2)
821 {
823 at->Remove();
824 }
825 else
827
828 }
829
830 void OnUnitExit(Unit* unit, AreaTriggerExitReason /*reason*/) override
831 {
832 Unit* caster = at->GetCaster();
833 if (!caster)
834 return;
835
836 if (!unit->IsPlayer())
837 return;
838
840 {
843 at->Remove();
844 }
845 }
846};
847
AreaTriggerExitReason
Definition AreaTrigger.h:69
First const & RAND(First const &first, Second const &second, Rest const &... rest)
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
@ ENCOUNTER_FRAME_DISENGAGE
@ ENCOUNTER_FRAME_UPDATE_PRIORITY
@ ENCOUNTER_FRAME_ENGAGE
#define RegisterAreaTriggerAI(ai_name)
Definition ScriptMgr.h:1428
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1383
SpellEffIndex
@ EFFECT_0
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_APPLY_AURA
@ POWER_MANA
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
@ AURA_REMOVE_BY_EXPIRE
@ SPELL_AURA_PERIODIC_DUMMY
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
@ TRIGGERED_IGNORE_CAST_IN_PROGRESS
Will not check if a current cast is in progress.
@ TRIGGERED_DONT_REPORT_CAST_ERROR
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
#define SpellEffectFn(F, I, N)
#define AuraEffectPeriodicFn(F, I, N)
#define SpellCastFn(F)
#define SpellHitFn(F)
#define AuraEffectRemoveFn(F, I, N, M)
EvadeReason
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ UNIT_STATE_CASTING
Definition Unit.h:276
static constexpr Position MedivhVisualSpellsPositions[14]
@ SAY_INFERNO_BOLT_WARNING
@ SAY_CEASELESS_WINTER
@ SAY_FLAME_WREATH
@ SAY_INFERNO_BOLT
@ SAY_FLAME_WREATH_WARNING
@ SAY_GUARDIANS_IMAGE
@ SAY_PIERCING_MISSILES
@ ACTION_START_VISUALS
@ ACTION_DISSOLVE
@ ACTION_FINISH_SPLIT
@ SPELL_SIGNATURE_PRIMER
@ SPELL_INFERNO_BOLT_MARKER
@ SPELL_REFORM_VISUAL_STATE_1
@ SPELL_FLAME_WREATH_AREA_DAMAGE
@ SPELL_ARCANE_BOLT_SELECTOR
@ SPELL_FROSTBITE
@ SPELL_REFORM_VISUAL_STATE_2
@ SPELL_FLAME_WREATH_AREATRIGGER
@ SPELL_FLAME_WREATH_PERIODIC_DAMAGE
@ SPELL_GUARDIANS_IMAGE
@ SPELL_VO_CONTROLLER
@ SPELL_MANA_REGEN
@ SPELL_ARCANE_CHANNEL
@ SPELL_BASIC_PRIMER
@ SPELL_PIERCING_MISSILES
@ SPELL_REFORM_VISUAL
@ SPELL_ARCANE_DISSOLVE_IN
@ SPELL_CEASELESS_WINTER_PERIODIC
@ SPELL_INFERNO_BOLT
@ SPELL_CEASELESS_WINTER
@ SPELL_FLAME_WREATH_SELECTOR
@ SPELL_GUARDIANS_IMAGE_MISSILE
@ SPELL_CEASELESS_WINTER_DAMAGE
@ SPELL_PIERCING_MISSILES_DEBUFF
@ SPELLVISUAL_ARCANE_MISSILE
@ DATA_INFERNO_BOLT_NEXT
static constexpr Position GuardiansImagePosition[3]
@ EVENT_ARCANE_BOLT
@ EVENT_BASIC_PRIMER
@ EVENT_CHECK_MANA
@ EVENT_BACK_TO_COMBAT
static constexpr Position GuardiansImageMedivhPosition
void AddSC_boss_shade_of_medivh()
AreaTrigger *const at
AreaTriggerAI(AreaTrigger *a, uint32 scriptId={}) noexcept
GuidUnorderedSet const & GetInsideUnits() const
Unit * GetCaster() const
uint32 GetTickNumber() const
AuraApplication const * GetTargetApplication() const
HookList< EffectApplyHandler > AfterEffectRemove
HookList< EffectPeriodicHandler > OnEffectPeriodic
Unit * GetCaster() const
Unit * GetTarget() const
bool IsPlayer() const
Definition BaseEntity.h:173
InstanceScript *const instance
void JustEngagedWith(Unit *who) override
void _DespawnAtEvade(Seconds delayToRespawn=30s, Creature *who=nullptr)
TaskScheduler scheduler
SummonList summons
EventMap events
void DoZoneInCombat()
Definition CreatureAI.h:169
bool _EnterEvadeMode(EvadeReason why=EvadeReason::Other)
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:63
void SetReactState(ReactStates st)
Definition Creature.h:174
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
CreatureAI * AI() const
Definition Creature.h:228
uint32 ExecuteEvent()
Definition EventMap.cpp:77
void Update(uint32 time)
Definition EventMap.h:61
void Repeat(Milliseconds time)
Definition EventMap.cpp:67
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition EventMap.cpp:40
void CancelEvent(uint32 eventId)
Definition EventMap.cpp:135
void Reset()
Definition EventMap.cpp:25
Creature * GetCreature(uint32 type)
void SendEncounterUnit(EncounterFrameType type, Unit const *unit, Optional< int32 > param1={}, Optional< int32 > param2={})
bool IsEmpty() const
Definition ObjectGuid.h:362
uint32 GetEntry() const
Definition ObjectGuid.h:334
Creature * ToCreature()
Definition Object.h:121
uint32 const Id
Definition SpellInfo.h:328
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
HookList< CastHandler > AfterCast
Unit * GetCaster() const
int32 GetEffectValueAsInt() const
HookList< HitHandler > OnHit
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
Spell * GetSpell() const
ObjectGuid m_originalCastId
Definition Spell.h:605
TaskContext & Repeat(TaskScheduler::duration_t duration)
TaskScheduler & CancelAll()
TaskScheduler & Schedule(duration_t time, task_handler_t task)
TaskScheduler & ClearValidator()
Clears the validator which is asked if tasks are allowed to be executed.
TaskScheduler & Update()
Update the scheduler to the current time.
virtual void SetData(uint32 id, uint32 value)
Definition UnitAI.h:75
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:160
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:79
virtual uint32 GetData(uint32 id) const
Definition UnitAI.h:74
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:89
Definition Unit.h:635
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8697
void SendPlaySpellVisual(Unit *target, uint32 spellVisualId, uint8 missReason, uint8 reflectStatus, float travelSpeed, bool speedAsTime=false, float launchDelay=0.0f)
Definition Unit.cpp:12305
void SetPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:10046
int32 GetMaxPower(Powers power) const
Definition Unit.cpp:10037
void SetUninteractible(bool apply)
Definition Unit.cpp:8564
bool isMoving() const
Definition Unit.h:1804
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint16 num=1)
Definition Unit.cpp:3990
void NearTeleportTo(TeleportLocation const &target, bool casting=false)
Definition Unit.cpp:12958
bool HasUnitState(const uint32 f) const
Definition Unit.h:743
float GetPowerPct(Powers power) const
Definition Unit.h:820
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4804
void RemoveAllAreaTriggers(AreaTriggerRemoveReason reason=AreaTriggerRemoveReason::Default)
Definition Unit.cpp:5512
bool AttackStop()
Definition Unit.cpp:5965
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3974
void SetPowerType(Powers power, bool sendUpdate=true, bool onInit=false)
Definition Unit.cpp:5697
InstanceScript * GetInstanceScript() const
Definition Object.cpp:396
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
static constexpr std::array< uint8, 3 > ShadeOfMedivhEnergizeCycle
void PeriodicTick(AuraEffect const *aurEff) const
void OnRemove(AuraEffect const *, AuraEffectHandleModes) const
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
void RandomShuffle(Iterator begin, Iterator end)
Reorder the elements of the iterator range randomly.
Definition Containers.h:171
#define RegisterReturnToKarazhanCreatureAI(ai_name)
@ DATA_SHADE_OF_MEDIVH
TriggerCastFlags TriggerFlags
void OnUnitExit(Unit *unit, AreaTriggerExitReason) override
void OnUnitExit(Unit *unit, AreaTriggerExitReason) override
void OnUnitEnter(Unit *unit) override
void OnUnitExit(Unit *unit, AreaTriggerExitReason) override
void EnterEvadeMode(EvadeReason why) override
void JustDied(Unit *) override
void SpellHitTarget(WorldObject *target, SpellInfo const *spellInfo) override
void SpellHit(WorldObject *, SpellInfo const *spellInfo) override
boss_shade_of_medivh(Creature *creature)
void KilledUnit(Unit *victim) override
void SetData(uint32 id, uint32 value) override
void JustEngagedWith(Unit *who) override
void OnSpellFailed(SpellInfo const *spellInfo) override
void OnSpellStart(SpellInfo const *spellInfo) override
void UpdateAI(uint32 diff) override
uint32 GetData(uint32 id) const override
void DoAction(int32 action) override
void EnterEvadeMode(EvadeReason) override