Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_netherspite.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_Netherspite
8SD%Complete: 90
9SDComment: Not sure about timing and portals placing
10SDCategory: Karazhan
11EndScriptData */
12
13#include "ScriptMgr.h"
14#include "ScriptedCreature.h"
15#include "karazhan.h"
16#include "Player.h"
17
32
33
34const float PortalCoord[3][3] =
35{
36 {-11195.353516f, -1613.237183f, 278.237258f}, // Left side
37 {-11137.846680f, -1685.607422f, 278.239258f}, // Right side
38 {-11094.493164f, -1591.969238f, 279.949188f} // Back side
39};
40
42 RED_PORTAL = 0, // Perseverence
43 GREEN_PORTAL = 1, // Serenity
44 BLUE_PORTAL = 2 // Dominance
45};
46
47const uint32 PortalID[3] = {17369, 17367, 17368};
48const uint32 PortalVisual[3] = {30487, 30490, 30491};
49const uint32 PortalBeam[3] = {30465, 30464, 30463};
50const uint32 PlayerBuff[3] = {30421, 30422, 30423};
51const uint32 NetherBuff[3] = {30466, 30467, 30468};
52const uint32 PlayerDebuff[3] = {38637, 38638, 38639};
53
55{
56public:
57 boss_netherspite() : CreatureScript("boss_netherspite") { }
58
60 {
61 return new boss_netherspiteAI(creature);
62 }
63
65 {
66 boss_netherspiteAI(Creature* creature) : ScriptedAI(creature)
67 {
68 instance = creature->GetInstanceScript();
69
70 for (int i=0; i<3; ++i)
71 {
72 PortalGUID[i] = 0;
73 BeamTarget[i] = 0;
74 BeamerGUID[i] = 0;
75 }
76 }
77
79
81 bool Berserk;
82 uint32 PhaseTimer; // timer for phase switching
84 uint32 NetherInfusionTimer; // berserking timer
87 uint32 PortalTimer; // timer for beam checking
88 uint64 PortalGUID[3]; // guid's of portals
89 uint64 BeamerGUID[3]; // guid's of auxiliary beaming portals
90 uint64 BeamTarget[3]; // guid's of portals' current targets
91
92 bool IsBetween(WorldObject* u1, WorldObject* target, WorldObject* u2) // the in-line checker
93 {
94 if (!u1 || !u2 || !target)
95 return false;
96
97 float xn, yn, xp, yp, xh, yh;
98 xn = u1->GetPositionX();
99 yn = u1->GetPositionY();
100 xp = u2->GetPositionX();
101 yp = u2->GetPositionY();
102 xh = target->GetPositionX();
103 yh = target->GetPositionY();
104
105 // check if target is between (not checking distance from the beam yet)
106 if (dist(xn, yn, xh, yh) >= dist(xn, yn, xp, yp) || dist(xp, yp, xh, yh) >= dist(xn, yn, xp, yp))
107 return false;
108 // check distance from the beam
109 return (abs((xn-xp)*yh+(yp-yn)*xh-xn*yp+xp*yn)/dist(xn, yn, xp, yp) < 1.5f);
110 }
111
112 float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance
113 {
114 return sqrt((xa-xb)*(xa-xb) + (ya-yb)*(ya-yb));
115 }
116
118 {
119 Berserk = false;
120 NetherInfusionTimer = 540000;
121 VoidZoneTimer = 15000;
122 NetherbreathTimer = 3000;
123
124 HandleDoors(true);
126 }
127
129 {
130 uint8 r = rand()%4;
131 uint8 pos[3];
132 pos[RED_PORTAL] = ((r % 2) ? (r > 1 ? 2 : 1) : 0);
133 pos[GREEN_PORTAL] = ((r % 2) ? 0 : (r > 1 ? 2 : 1));
134 pos[BLUE_PORTAL] = (r > 1 ? 1 : 2); // Blue Portal not on the left side (0)
135
136 for (int i=0; i<3; ++i)
137 if (Creature* portal = me->SummonCreature(PortalID[i], PortalCoord[pos[i]][0], PortalCoord[pos[i]][1], PortalCoord[pos[i]][2], 0, TempSummonType::TEMPSUMMON_TIMED_DESPAWN, 60000))
138 {
139 PortalGUID[i] = portal->GetGUID();
140 portal->AddAura(PortalVisual[i], portal);
141 }
142 }
143
145 {
146 for (int i=0; i<3; ++i)
147 {
148 if (Creature* portal = Unit::GetCreature(*me, PortalGUID[i]))
149 portal->DisappearAndDie();
150 if (Creature* portal = Unit::GetCreature(*me, BeamerGUID[i]))
151 portal->DisappearAndDie();
152 PortalGUID[i] = 0;
153 BeamTarget[i] = 0;
154 }
155 }
156
157 void UpdatePortals() // Here we handle the beams' behavior
158 {
159 for (int j=0; j<3; ++j) // j = color
160 if (Creature* portal = Unit::GetCreature(*me, PortalGUID[j]))
161 {
162 // the one who's been casted upon before
163 Unit* current = Unit::GetUnit(*portal, BeamTarget[j]);
164 // temporary store for the best suitable beam reciever
165 Unit* target = me;
166
167 if (Map* map = me->GetMap())
168 {
169 Map::PlayerList const& players = map->GetPlayers();
170
171 // get the best suitable target
172 for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
173 {
174 Player* p = i->GetSource();
175 if (p && p->IsAlive() // alive
176 && (!target || target->GetDistance2d(portal)>p->GetDistance2d(portal)) // closer than current best
177 && !p->HasAura(PlayerDebuff[j], 0) // not exhausted
178 && !p->HasAura(PlayerBuff[(j+1)%3], 0) // not on another beam
179 && !p->HasAura(PlayerBuff[(j+2)%3], 0)
180 && IsBetween(me, p, portal)) // on the beam
181 target = p;
182 }
183 }
184 // buff the target
185 if (target->GetTypeId() == TypeID::TYPEID_PLAYER)
186 target->AddAura(PlayerBuff[j], target);
187 else
188 target->AddAura(NetherBuff[j], target);
189 // cast visual beam on the chosen target if switched
190 // simple target switching isn't working -> using BeamerGUID to cast (workaround)
191 if (!current || target != current)
192 {
193 BeamTarget[j] = target->GetGUID();
194 // remove currently beaming portal
195 if (Creature* beamer = Unit::GetCreature(*portal, BeamerGUID[j]))
196 {
197 beamer->CastSpell(target, PortalBeam[j], false);
198 beamer->DisappearAndDie();
199 BeamerGUID[j] = 0;
200 }
201 // create new one and start beaming on the target
202 if (Creature* beamer = portal->SummonCreature(PortalID[j], portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), portal->GetOrientation(), TempSummonType::TEMPSUMMON_TIMED_DESPAWN, 60000))
203 {
204 beamer->CastSpell(target, PortalBeam[j], false);
205 BeamerGUID[j] = beamer->GetGUID();
206 }
207 }
208 // aggro target if Red Beam
209 if (j == RED_PORTAL && me->GetVictim() != target && target->GetTypeId() == TypeID::TYPEID_PLAYER)
210 me->getThreatManager().addThreat(target, 100000.0f+DoGetThreat(me->GetVictim()));
211 }
212 }
213
215 {
216 me->RemoveAurasDueToSpell(SPELL_BANISH_ROOT);
217 me->RemoveAurasDueToSpell(SPELL_BANISH_VISUAL);
219 PhaseTimer = 60000;
220 PortalPhase = true;
221 PortalTimer = 10000;
222 EmpowermentTimer = 10000;
224 }
225
227 {
228 me->RemoveAurasDueToSpell(SPELL_EMPOWERMENT);
229 me->RemoveAurasDueToSpell(SPELL_NETHERBURN_AURA);
233 PhaseTimer = 30000;
234 PortalPhase = false;
236
237 for (int i=0; i<3; ++i)
238 me->RemoveAurasDueToSpell(NetherBuff[i]);
239 }
240
241 void HandleDoors(bool open) // Massive Door switcher
242 {
244 Door->SetGoState(open ? GOState::GO_STATE_ACTIVE : GOState::GO_STATE_READY);
245 }
246
247 void EnterCombat(Unit* /*who*/) OVERRIDE
248 {
249 HandleDoors(false);
251 }
252
253 void JustDied(Unit* /*killer*/) OVERRIDE
254 {
255 HandleDoors(true);
257 }
258
260 {
261 if (!UpdateVictim())
262 return;
263
264 // Void Zone
265 if (VoidZoneTimer <= diff)
266 {
268 VoidZoneTimer = 15000;
269 } else VoidZoneTimer -= diff;
270
271 // NetherInfusion Berserk
272 if (!Berserk && NetherInfusionTimer <= diff)
273 {
274 me->AddAura(SPELL_NETHER_INFUSION, me);
276 Berserk = true;
277 } else NetherInfusionTimer -= diff;
278
279 if (PortalPhase) // PORTAL PHASE
280 {
281 // Distribute beams and buffs
282 if (PortalTimer <= diff)
283 {
285 PortalTimer = 1000;
286 } else PortalTimer -= diff;
287
288 // Empowerment & Nether Burn
289 if (EmpowermentTimer <= diff)
290 {
292 me->AddAura(SPELL_NETHERBURN_AURA, me);
293 EmpowermentTimer = 90000;
294 } else EmpowermentTimer -= diff;
295
296 if (PhaseTimer <= diff)
297 {
298 if (!me->IsNonMeleeSpellCasted(false))
299 {
301 return;
302 }
303 } else PhaseTimer -= diff;
304 }
305 else // BANISH PHASE
306 {
307 // Netherbreath
308 if (NetherbreathTimer <= diff)
309 {
310 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true))
311 DoCast(target, SPELL_NETHERBREATH);
312 NetherbreathTimer = std::rand() % 7000 + 5000;
313 } else NetherbreathTimer -= diff;
314
315 if (PhaseTimer <= diff)
316 {
317 if (!me->IsNonMeleeSpellCasted(false))
318 {
320 return;
321 }
322 } else PhaseTimer -= diff;
323 }
324
326 }
327 };
328};
329
331{
332 new boss_netherspite();
333}
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
@ GO_STATE_ACTIVE
Definition GameObject.h:576
@ GO_STATE_READY
Definition GameObject.h:577
@ TYPEID_PLAYER
Definition Object.h:55
@ TEMPSUMMON_TIMED_DESPAWN
Definition Object.h:70
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
const float PortalCoord[3][3]
const uint32 PlayerBuff[3]
@ SPELL_NETHERBURN_AURA
@ SPELL_EMPOWERMENT
@ SPELL_BANISH_VISUAL
@ SPELL_NETHER_INFUSION
@ SPELL_VOIDZONE
@ EMOTE_PHASE_BANISH
@ SPELL_NETHERSPITE_ROAR
@ SPELL_NETHERBREATH
@ SPELL_BANISH_ROOT
@ EMOTE_PHASE_PORTAL
const uint32 PortalBeam[3]
const uint32 NetherBuff[3]
const uint32 PlayerDebuff[3]
const uint32 PortalID[3]
Netherspite_Portal
@ GREEN_PORTAL
@ RED_PORTAL
@ BLUE_PORTAL
void AddSC_boss_netherspite()
const uint32 PortalVisual[3]
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
CreatureScript(const char *name)
static GameObject * GetGameObject(WorldObject &object, uint64 guid)
Definition Map.h:238
MapRefManager PlayerList
Definition Map.h:406
iterator end()
iterator begin()
LinkedListHead::Iterator< MapReference const > const_iterator
uint64 GetGUID() const
Definition Object.h:119
TypeID GetTypeId() const
Definition Object.h:131
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
Definition Unit.h:1367
Aura * AddAura(uint32 spellId, Unit *target)
bool IsAlive() const
Definition Unit.h:2032
bool HasAura(uint32 spellId, uint64 casterGUID=0, uint64 itemCasterGUID=0, uint32 reqEffMask=0) const
static Creature * GetCreature(WorldObject &object, uint64 guid)
Definition Unit.cpp:4905
static Unit * GetUnit(WorldObject &object, uint64 guid)
Definition Unit.cpp:4895
InstanceScript * GetInstanceScript()
Definition Object.cpp:1612
float GetDistance2d(WorldObject const *obj) const
Definition Object.cpp:1684
TempSummon * SummonCreature(uint32 id, Position const &pos, TempSummonType spwtype=TempSummonType::TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime=0, uint32 vehId=0) const
Definition Object.cpp:2703
CreatureAI * GetAI(Creature *creature) const OVERRIDE
@ DATA_GO_MASSIVE_DOOR
Definition karazhan.h:34
float GetPositionX() const
Definition Object.h:328
float GetPositionY() const
Definition Object.h:329
Creature * me
float DoGetThreat(Unit *unit)
ScriptedAI(Creature *creature)
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
float dist(float xa, float ya, float xb, float yb)
bool IsBetween(WorldObject *u1, WorldObject *target, WorldObject *u2)