Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_four_horsemen.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 "ScriptMgr.h"
7#include "ScriptedCreature.h"
8#include "SpellScript.h"
9#include "SpellAuraEffects.h"
10#include "naxxramas.h"
11
19
21{
23};
24
32
34{
35 // Thane waypoints
36 {2542.3f, -2984.1f, 241.49f, 5.362f},
37 {2547.6f, -2999.4f, 241.34f, 5.049f},
38 {2542.9f, -3015.0f, 241.35f, 4.654f},
39 // Lady waypoints
40 {2498.3f, -2961.8f, 241.28f, 3.267f},
41 {2487.7f, -2959.2f, 241.28f, 2.890f},
42 {2469.4f, -2947.6f, 241.28f, 2.576f},
43 // Baron waypoints
44 {2553.8f, -2968.4f, 241.33f, 5.757f},
45 {2564.3f, -2972.5f, 241.33f, 5.890f},
46 {2583.9f, -2971.67f, 241.35f, 0.008f},
47 // Sir waypoints
48 {2534.5f, -2921.7f, 241.53f, 1.363f},
49 {2523.5f, -2902.8f, 241.28f, 2.095f},
50 {2517.8f, -2896.6f, 241.28f, 2.315f},
51};
52
53const uint32 NPC_HORSEMEN[] = {16064, 16065, 30549, 16063};
54const uint32 SPELL_MARK[] = {28832, 28833, 28834, 28835};
55#define SPELL_PRIMARY(i) RAID_MODE(SPELL_PRIMARY_N[i], SPELL_PRIMARY_H[i])
56const uint32 SPELL_PRIMARY_N[] = {28884, 28863, 28882, 28883};
57const uint32 SPELL_PRIMARY_H[] = {57467, 57463, 57369, 57466};
58#define SPELL_SECONDARY(i) RAID_MODE(SPELL_SECONDARY_N[i], SPELL_SECONDARY_H[i])
59const uint32 SPELL_SECONDARY_N[]= {0, 57374, 0, 57376};
60const uint32 SPELL_SECONDARY_H[]= {0, 57464, 0, 57465};
61const uint32 SPELL_PUNISH[] = {0, 57381, 0, 57377};
62#define SPELL_BERSERK 26662
63
72
74{
75public:
76 boss_four_horsemen() : CreatureScript("boss_four_horsemen") { }
77
79 {
80 return new boss_four_horsemenAI(creature);
81 }
82
84 {
86 {
87 id = Horsemen(0);
88 for (uint8 i = 0; i < 4; ++i)
89 if (me->GetEntry() == NPC_HORSEMEN[i])
90 id = Horsemen(i);
91 caster = (id == HORSEMEN_LADY || id == HORSEMEN_SIR);
93 }
94
99 bool caster;
106
108 {
110 DoEncounteraction(NULL, false, true, false);
111
112 if (instance)
113 instance->SetData(DATA_HORSEMEN0 + id, NOT_STARTED);
114
115 me->SetReactState(REACT_AGGRESSIVE);
117 nextWP = 0;
118 punishTimer = 2000;
119 nextMovementStarted = false;
120 movementCompleted = false;
121 movementStarted = false;
122 encounterActionAttack = false;
123 encounterActionReset = false;
124 doDelayPunish = false;
125 _Reset();
126 }
127
128 bool DoEncounteraction(Unit* who, bool attack, bool reset, bool checkAllDead)
129 {
130 if (!instance)
131 return false;
132
133 Creature* Thane = Unit::GetCreature(*me, instance->GetData64(DATA_THANE));
134 Creature* Lady = Unit::GetCreature(*me, instance->GetData64(DATA_LADY));
135 Creature* Baron = Unit::GetCreature(*me, instance->GetData64(DATA_BARON));
136 Creature* Sir = Unit::GetCreature(*me, instance->GetData64(DATA_SIR));
137
138 if (Thane && Lady && Baron && Sir)
139 {
140 if (attack && who)
141 {
142 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Thane->AI())->encounterActionAttack = true;
143 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Lady->AI())->encounterActionAttack = true;
144 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Baron->AI())->encounterActionAttack = true;
145 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Sir->AI())->encounterActionAttack = true;
146
147 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Thane->AI())->AttackStart(who);
148 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Lady->AI())->AttackStart(who);
149 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Baron->AI())->AttackStart(who);
150 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Sir->AI())->AttackStart(who);
151 }
152
153 if (reset)
154 {
155 if (instance->GetBossState(BOSS_HORSEMEN) != NOT_STARTED)
156 {
157 if (!Thane->IsAlive())
158 Thane->Respawn();
159
160 if (!Lady->IsAlive())
161 Lady->Respawn();
162
163 if (!Baron->IsAlive())
164 Baron->Respawn();
165
166 if (!Sir->IsAlive())
167 Sir->Respawn();
168
169 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Thane->AI())->encounterActionReset = true;
170 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Lady->AI())->encounterActionReset = true;
171 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Baron->AI())->encounterActionReset = true;
172 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Sir->AI())->encounterActionReset = true;
173
174 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Thane->AI())->EnterEvadeMode();
175 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Lady->AI())->EnterEvadeMode();
176 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Baron->AI())->EnterEvadeMode();
177 CAST_AI(boss_four_horsemen::boss_four_horsemenAI, Sir->AI())->EnterEvadeMode();
178 }
179 }
180
181 if (checkAllDead)
182 return !Thane->IsAlive() && !Lady->IsAlive() && !Baron->IsAlive() && !Sir->IsAlive();
183 }
184 return false;
185 }
186
188 {
189 movementStarted = true;
190 me->SetReactState(REACT_PASSIVE);
191 me->SetWalk(false);
192 me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN), true);
193
194 switch (id)
195 {
196 case HORSEMEN_THANE:
197 me->GetMotionMaster()->MovePoint(0, WaypointPositions[0]);
198 break;
199 case HORSEMEN_LADY:
200 me->GetMotionMaster()->MovePoint(3, WaypointPositions[3]);
201 break;
202 case HORSEMEN_BARON:
203 me->GetMotionMaster()->MovePoint(6, WaypointPositions[6]);
204 break;
205 case HORSEMEN_SIR:
206 me->GetMotionMaster()->MovePoint(9, WaypointPositions[9]);
207 break;
208 }
209 }
210
212 {
213 if (type != POINT_MOTION_TYPE)
214 return;
215
216 if (id == 2 || id == 5 || id == 8 || id == 11)
217 {
218 movementCompleted = true;
219 me->SetReactState(REACT_AGGRESSIVE);
220
221 Unit* eventStarter = Unit::GetUnit(*me, uiEventStarterGUID);
222
223 if (eventStarter && me->IsValidAttackTarget(eventStarter))
224 AttackStart(eventStarter);
225 else if (!UpdateVictim())
226 {
228 return;
229 }
230
231 if (caster)
232 {
233 me->GetMotionMaster()->Clear();
234 me->GetMotionMaster()->MoveIdle();
235 }
236
237 return;
238 }
239
240 nextMovementStarted = false;
241 nextWP = id + 1;
242 }
243
244 // switch to "who" if nearer than current target.
246 {
247 if (me->GetVictim() && me->GetDistanceOrder(who, me->GetVictim()) && me->IsValidAttackTarget(who))
248 {
249 me->getThreatManager().modifyThreatPercent(me->GetVictim(), -100);
250 me->AddThreat(who, 1000000.0f);
251 }
252 }
253
255
256 {
258 if (caster)
260 }
261
263 {
265 {
266 uiEventStarterGUID = who->GetGUID();
268
270 DoEncounteraction(who, true, false, false);
271 }
273 {
274 if (caster)
275 me->Attack(who, false);
276 else
278 }
279 }
280
281 void KilledUnit(Unit* /*victim*/) OVERRIDE
282 {
283 if (!(rand()%5))
284 Talk(SAY_SLAY);
285 }
286
287 void JustDied(Unit* /*killer*/) OVERRIDE
288 {
289 events.Reset();
290 summons.DespawnAll();
291
292 if (instance)
293 instance->SetData(DATA_HORSEMEN0 + id, DONE);
294
295 if (instance && DoEncounteraction(NULL, false, false, true))
296 {
297 instance->SetBossState(BOSS_HORSEMEN, DONE);
298 instance->SaveToDB();
299
300 // Achievements related to the 4-horsemen are given through spell 59450 which does not exist.
301 // There is thus no way it can be given by casting the spell on the players.
302 instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 59450);
303 }
304
306 }
307
308 void EnterCombat(Unit* /*who*/) OVERRIDE
309 {
310 _EnterCombat();
312
313 events.ScheduleEvent(EVENT_MARK, 15000);
314 events.ScheduleEvent(EVENT_CAST, 20000+rand()%5000);
315 events.ScheduleEvent(EVENT_BERSERK, 15*100*1000);
316 }
317
319 {
321 {
322 nextMovementStarted = true;
323 me->GetMotionMaster()->MovePoint(nextWP, WaypointPositions[nextWP]);
324 }
325
327 return;
328
329 events.Update(diff);
330
331 if (me->HasUnitState(UNIT_STATE_CASTING))
332 return;
333
334 while (uint32 eventId = events.ExecuteEvent())
335 {
336 switch (eventId)
337 {
338 case EVENT_MARK:
339 if (!(rand()%5))
342 events.ScheduleEvent(EVENT_MARK, 15000);
343 break;
344 case EVENT_CAST:
345 if (!(rand()%5))
347
348 if (caster)
349 {
350 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f))
351 DoCast(target, SPELL_PRIMARY(id));
352 }
353 else
355
356 events.ScheduleEvent(EVENT_CAST, 15000);
357 break;
358 case EVENT_BERSERK:
361 break;
362 }
363 }
364
365 if (punishTimer <= diff)
366 {
367 if (doDelayPunish)
368 {
369 DoCastAOE(SPELL_PUNISH[id], true);
370 doDelayPunish = false;
371 }
372 punishTimer = 2000;
373 } else punishTimer -= diff;
374
375 if (!caster)
377 else if ((!DoSpellAttackIfReady(SPELL_SECONDARY(id)) || !me->IsWithinLOSInMap(me->GetVictim())) && movementCompleted && !doDelayPunish)
378 doDelayPunish = true;
379 }
380 };
381};
382
384{
385 public:
386 spell_four_horsemen_mark() : SpellScriptLoader("spell_four_horsemen_mark") { }
387
389 {
391
392 void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
393 {
394 if (Unit* caster = GetCaster())
395 {
396 int32 damage;
397 switch (GetStackAmount())
398 {
399 case 1:
400 damage = 0;
401 break;
402 case 2:
403 damage = 500;
404 break;
405 case 3:
406 damage = 1000;
407 break;
408 case 4:
409 damage = 1500;
410 break;
411 case 5:
412 damage = 4000;
413 break;
414 case 6:
415 damage = 12000;
416 break;
417 default:
418 damage = 20000 + 1000 * (GetStackAmount() - 7);
419 break;
420 }
421 if (damage)
422 caster->CastCustomSpell(SPELL_MARK_DAMAGE, SPELLVALUE_BASE_POINT0, damage, GetTarget());
423 }
424 }
425
430 };
431
436};
437
@ ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET
Definition DBCEnums.h:193
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
#define OVERRIDE
Definition Define.h:60
std::uint64_t uint64
Definition Define.h:76
@ DONE
@ NOT_STARTED
@ POINT_MOTION_TYPE
#define CAST_AI(a, b)
@ EFFECT_0
@ SPELL_AURA_DUMMY
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK
#define AuraEffectApplyFn(F, I, N, M)
@ SPELLVALUE_BASE_POINT0
Definition Unit.h:114
@ UNIT_STATE_CASTING
Definition Unit.h:527
@ MOVE_RUN
Definition Unit.h:556
@ REACT_PASSIVE
Definition Unit.h:1156
@ REACT_AGGRESSIVE
Definition Unit.h:1158
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
@ SAY_SLAY
#define SAY_DEATH
#define SAY_AGGRO
@ EVENT_NONE
const uint32 SPELL_PUNISH[]
const uint32 SPELL_MARK[]
#define SPELL_SECONDARY(i)
@ SPELL_MARK_DAMAGE
const uint32 SPELL_PRIMARY_H[]
const uint32 SPELL_PRIMARY_N[]
const Position WaypointPositions[12]
const uint32 SPELL_SECONDARY_H[]
@ HORSEMEN_LADY
@ HORSEMEN_BARON
@ HORSEMEN_THANE
@ HORSEMEN_SIR
#define SPELL_PRIMARY(i)
const uint32 NPC_HORSEMEN[]
@ SAY_SPECIAL
const uint32 SPELL_SECONDARY_N[]
@ EVENT_BERSERK
void AddSC_boss_four_horsemen()
@ SPELL_MARK_DAMAGE
@ SPELL_MARK
@ EVENT_BERSERK
HookList< EffectApplyHandler > AfterEffectApply
Unit * GetCaster() const
Unit * GetTarget() const
uint8 GetStackAmount() const
InstanceScript *const instance
bool CheckInRoom()
SummonList summons
EventMap events
BossAI(Creature *creature, uint32 bossId)
void _EnterCombat()
virtual void MoveInLineOfSight(Unit *)
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
virtual void EnterEvadeMode()
void Respawn(bool force=false)
CreatureAI * AI() const
Definition Creature.h:483
CreatureScript(const char *name)
SpellScriptLoader(const char *name)
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
bool DoSpellAttackIfReady(uint32 spell)
Definition UnitAI.cpp:48
void DoCastVictim(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:168
void DoCastAOE(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:176
virtual void AttackStart(Unit *)
Definition UnitAI.cpp:16
Definition Unit.h:1367
bool IsAlive() const
Definition Unit.h:2032
static Creature * GetCreature(WorldObject &object, uint64 guid)
Definition Unit.cpp:4905
static Unit * GetUnit(WorldObject &object, uint64 guid)
Definition Unit.cpp:4895
CreatureAI * GetAI(Creature *creature) const OVERRIDE
void OnApply(AuraEffect const *, AuraEffectHandleModes)
PrepareAuraScript(spell_four_horsemen_mark_AuraScript)
AuraScript * GetAuraScript() const OVERRIDE
@ DATA_THANE
Definition naxxramas.h:46
@ DATA_SIR
Definition naxxramas.h:49
@ DATA_LADY
Definition naxxramas.h:47
@ BOSS_HORSEMEN
Definition naxxramas.h:25
@ DATA_HORSEMEN0
Definition naxxramas.h:36
@ DATA_BARON
Definition stratholme.h:20
Creature * me
bool DoEncounteraction(Unit *who, bool attack, bool reset, bool checkAllDead)
void MovementInform(uint32 type, uint32 id) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================