Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_selin_fireheart.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/* ScriptData
7SDName: Boss_Selin_Fireheart
8SD%Complete: 90
9SDComment: Heroic and Normal Support. Needs further testing.
10SDCategory: Magister's Terrace
11EndScriptData */
12
13#include "ScriptMgr.h"
14#include "ScriptedCreature.h"
15#include "magisters_terrace.h"
16
26
28{
29 //Crystal effect spells
33 SPELL_MANA_RAGE = 44320, // This spell triggers 44321, which changes scale and regens mana Requires an entry in spell_script_target
34
35 //Selin's spells
38
39 SPELL_DRAIN_MANA = 46153 // Heroic only
40};
41
48
50{
51public:
52 boss_selin_fireheart() : CreatureScript("boss_selin_fireheart") { }
53
55 {
56 return new boss_selin_fireheartAI(creature);
57 };
58
60 {
62 {
63 instance = creature->GetInstanceScript();
64
65 Crystals.clear();
66 //GUIDs per instance is static, so we only need to load them once.
67 if (instance)
68 {
69 uint32 size = instance->GetData(DATA_FEL_CRYSTAL_SIZE);
70 for (uint8 i = 0; i < size; ++i)
71 {
72 instance->SetData64(DATA_FEL_CRYSTAL, i);
73 uint64 guid = instance->GetData64(DATA_FEL_CRYSTAL);
74 SF_LOG_DEBUG("scripts", "Selin: Adding Fel Crystal " UI64FMTD " to list", guid);
75 Crystals.push_back(guid);
76 }
77 }
78 }
79
81
82 std::list<uint64> Crystals;
83
89
92
93 uint64 CrystalGUID; // This will help us create a pointer to the crystal we are draining. We store GUIDs, never units in case unit is deleted/offline (offline if player of course).
94
96 {
97 if (instance)
98 {
99 //for (uint8 i = 0; i < CRYSTALS_NUMBER; ++i)
100 for (std::list<uint64>::const_iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr)
101 {
102 //Unit* unit = Unit::GetUnit(*me, FelCrystals[i]);
103 if (Creature* creature = Unit::GetCreature(*me, *itr))
104 {
105 if (!creature->IsAlive())
106 creature->Respawn(); // Let the core handle setting death state, etc.
107
108 // Only need to set unselectable flag. You can't attack unselectable units so non_attackable flag is not necessary here.
109 creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
110 }
111 }
112
113 // Set Inst data for encounter
115 } else SF_LOG_ERROR("scripts", ERROR_INST_DATA);
116
117 DrainLifeTimer = std::rand() % 7000 + 3000;
119 FelExplosionTimer = 2100;
120 if (IsHeroic())
121 DrainCrystalTimer = std::rand() % 15000 + 10000;
122 else
123 DrainCrystalTimer = std::rand() % 25000 + 20000;
124 EmpowerTimer = 10000;
125
126 IsDraining = false;
127 DrainingCrystal = false;
128 CrystalGUID = 0;
129 }
130
132 {
133 if (Crystals.empty())
134 return;
135
136 //float ShortestDistance = 0;
137 CrystalGUID = 0;
138 Unit* pCrystal = NULL;
139 Unit* CrystalChosen = NULL;
140 //for (uint8 i = 0; i < CRYSTALS_NUMBER; ++i)
141 for (std::list<uint64>::const_iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr)
142 {
143 pCrystal = NULL;
144 //pCrystal = Unit::GetUnit(*me, FelCrystals[i]);
145 pCrystal = Unit::GetUnit(*me, *itr);
146 if (pCrystal && pCrystal->IsAlive())
147 {
148 // select nearest
149 if (!CrystalChosen || me->GetDistanceOrder(pCrystal, CrystalChosen, false))
150 {
151 CrystalGUID = pCrystal->GetGUID();
152 CrystalChosen = pCrystal; // Store a copy of pCrystal so we don't need to recreate a pointer to closest crystal for the movement and yell.
153 }
154 }
155 }
156 if (CrystalChosen)
157 {
160
161 CrystalChosen->CastSpell(CrystalChosen, SPELL_FEL_CRYSTAL_COSMETIC, true);
162
163 float x, y, z; // coords that we move to, close to the crystal.
164 CrystalChosen->GetClosePoint(x, y, z, me->GetObjectSize(), CONTACT_DISTANCE);
165
166 me->SetWalk(false);
167 me->GetMotionMaster()->MovePoint(1, x, y, z);
168 DrainingCrystal = true;
169 }
170 }
171
173 {
174 if (Crystals.empty())
175 return;
176
177 //for (uint8 i = 0; i < CRYSTALS_NUMBER; ++i)
178 for (std::list<uint64>::const_iterator itr = Crystals.begin(); itr != Crystals.end(); ++itr)
179 {
180 //Creature* pCrystal = (Unit::GetCreature(*me, FelCrystals[i]));
181 Creature* pCrystal = Unit::GetCreature(*me, *itr);
182 if (pCrystal && pCrystal->IsAlive())
183 pCrystal->Kill(pCrystal);
184 }
185 }
186
187 void EnterCombat(Unit* /*who*/) OVERRIDE
188 {
190 if (instance)
192 }
193
194 void KilledUnit(Unit* /*victim*/) OVERRIDE
195 {
196 Talk(SAY_KILL);
197 }
198
200 {
201 if (type == POINT_MOTION_TYPE && id == 1)
202 {
203 Unit* CrystalChosen = Unit::GetUnit(*me, CrystalGUID);
204 if (CrystalChosen && CrystalChosen->IsAlive())
205 {
206 // Make the crystal attackable
207 // We also remove NON_ATTACKABLE in case the database has it set.
209 CrystalChosen->CastSpell(me, SPELL_MANA_RAGE, true);
210 IsDraining = true;
211 }
212 else
213 {
214 // Make an error message in case something weird happened here
215 SF_LOG_ERROR("scripts", "Selin Fireheart unable to drain crystal as the crystal is either dead or despawned");
216 DrainingCrystal = false;
217 }
218 }
219 }
220
221 void JustDied(Unit* /*killer*/) OVERRIDE
222 {
224
225 if (!instance)
226 return;
227
228 instance->SetData(DATA_SELIN_EVENT, DONE); // Encounter complete!
230 }
231
233 {
234 if (!UpdateVictim())
235 return;
236
237 if (!DrainingCrystal)
238 {
239 uint32 maxPowerMana = me->GetMaxPower(POWER_MANA);
240 if (maxPowerMana && ((me->GetPower(POWER_MANA)*100 / maxPowerMana) < 10))
241 {
242 if (DrainLifeTimer <= diff)
243 {
245 DrainLifeTimer = 10000;
246 } else DrainLifeTimer -= diff;
247
248 // Heroic only
249 if (IsHeroic())
250 {
251 if (DrainManaTimer <= diff)
252 {
254 DrainManaTimer = 10000;
255 } else DrainManaTimer -= diff;
256 }
257 }
258
259 if (FelExplosionTimer <= diff)
260 {
261 if (!me->IsNonMeleeSpellCasted(false))
262 {
264 FelExplosionTimer = 2000;
265 }
266 } else FelExplosionTimer -= diff;
267
268 // If below 10% mana, start recharging
269 maxPowerMana = me->GetMaxPower(POWER_MANA);
270 if (maxPowerMana && ((me->GetPower(POWER_MANA)*100 / maxPowerMana) < 10))
271 {
272 if (DrainCrystalTimer <= diff)
273 {
275 if (IsHeroic())
276 DrainCrystalTimer = std::rand() % 15000 + 10000;
277 else
278 DrainCrystalTimer = std::rand() % 25000 + 20000;
279 } else DrainCrystalTimer -= diff;
280 }
281 }else
282 {
283 if (IsDraining)
284 {
285 if (EmpowerTimer <= diff)
286 {
287 IsDraining = false;
288 DrainingCrystal = false;
289
291
292 Unit* CrystalChosen = Unit::GetUnit(*me, CrystalGUID);
293 if (CrystalChosen && CrystalChosen->IsAlive())
294 // Use Deal Damage to kill it, not setDeathState.
295 CrystalChosen->Kill(CrystalChosen);
296
297 CrystalGUID = 0;
298
299 me->GetMotionMaster()->Clear();
300 me->GetMotionMaster()->MoveChase(me->GetVictim());
301 } else EmpowerTimer -= diff;
302 }
303 }
304
305 DoMeleeAttackIfReady(); // No need to check if we are draining crystal here, as the spell has a stun.
306 }
307 };
308};
309
311{
312public:
313 npc_fel_crystal() : CreatureScript("npc_fel_crystal") { }
314
316 {
317 return new npc_fel_crystalAI(creature);
318 };
319
321 {
322 npc_fel_crystalAI(Creature* creature) : ScriptedAI(creature) { }
323
324 void Reset() OVERRIDE { }
325 void EnterCombat(Unit* /*who*/) OVERRIDE { }
326 void AttackStart(Unit* /*who*/) OVERRIDE { }
327 void MoveInLineOfSight(Unit* /*who*/) OVERRIDE { }
328
329 void UpdateAI(uint32 /*diff*/) OVERRIDE { }
330
331 void JustDied(Unit* /*killer*/) OVERRIDE
332 {
333 if (InstanceScript* instance = me->GetInstanceScript())
334 {
335 Creature* Selin = (Unit::GetCreature(*me, instance->GetData64(DATA_SELIN)));
336 if (Selin && Selin->IsAlive())
337 {
338 if (CAST_AI(boss_selin_fireheart::boss_selin_fireheartAI, Selin->AI())->CrystalGUID == me->GetGUID())
339 {
340 // Set this to false if we are the Creature that Selin is draining so his AI flows properly
341 CAST_AI(boss_selin_fireheart::boss_selin_fireheartAI, Selin->AI())->DrainingCrystal = false;
342 CAST_AI(boss_selin_fireheart::boss_selin_fireheartAI, Selin->AI())->IsDraining = false;
343 CAST_AI(boss_selin_fireheart::boss_selin_fireheartAI, Selin->AI())->EmpowerTimer = 10000;
344 if (Selin->GetVictim())
345 {
346 Selin->AI()->AttackStart(Selin->GetVictim());
347 Selin->GetMotionMaster()->MoveChase(Selin->GetVictim());
348 }
349 }
350 }
351 } else SF_LOG_ERROR("scripts", ERROR_INST_DATA);
352 }
353 };
354};
355
#define UI64FMTD
Definition Define.h:64
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
@ IN_PROGRESS
@ DONE
@ NOT_STARTED
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
@ POINT_MOTION_TYPE
#define CONTACT_DISTANCE
Definition Object.h:20
#define CAST_AI(a, b)
@ POWER_MANA
@ UNIT_FLAG_NON_ATTACKABLE
Definition Unit.h:626
@ UNIT_FLAG_NOT_SELECTABLE
Definition Unit.h:650
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
@ UNIT_FIELD_FLAGS
#define SAY_DEATH
#define SAY_AGGRO
#define SAY_KILL
void AddSC_boss_selin_fireheart()
@ CREATURE_FEL_CRYSTAL
@ CRYSTALS_NUMBER
@ SPELL_MANA_RAGE
@ SPELL_FEL_EXPLOSION
@ SPELL_FEL_CRYSTAL_DUMMY
@ SPELL_DRAIN_MANA
@ SPELL_FEL_CRYSTAL_VISUAL
@ SPELL_FEL_CRYSTAL_COSMETIC
@ SPELL_DRAIN_LIFE
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
CreatureAI * AI() const
Definition Creature.h:483
CreatureScript(const char *name)
void MoveChase(Unit *target, float dist=0.0f, float angle=0.0f)
uint64 GetGUID() const
Definition Object.h:119
void RemoveFlag(uint16 index, uint32 oldFlag)
Definition Object.cpp:1280
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
virtual void AttackStart(Unit *)
Definition UnitAI.cpp:16
Definition Unit.h:1367
void Kill(Unit *victim, bool durabilityLoss=true)
Definition Unit.cpp:6342
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)
MotionMaster * GetMotionMaster()
Definition Unit.h:2605
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
Unit * GetVictim() const
Definition Unit.h:1468
InstanceScript * GetInstanceScript()
Definition Object.cpp:1612
void GetClosePoint(float &x, float &y, float &z, float size, float distance2d=0, float angle=0) const
Definition Object.cpp:3070
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
#define ERROR_INST_DATA(a)
Definition karazhan.h:52
@ DATA_SELIN
@ DATA_FEL_CRYSTAL_SIZE
@ DATA_FEL_CRYSTAL
@ DATA_SELIN_EVENT
bool IsHeroic() const
Creature * me
ScriptedAI(Creature *creature)
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void MovementInform(uint32 type, uint32 id) OVERRIDE
void UpdateAI(uint32) OVERRIDE
== Triggered Actions Requested ==================