TrinityCore
boss_netherspite.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/* ScriptData
19SDName: Boss_Netherspite
20SD%Complete: 90
21SDComment: Not sure about timing and portals placing
22SDCategory: Karazhan
23EndScriptData */
24
25#include "ScriptMgr.h"
26#include "GameObject.h"
27#include "InstanceScript.h"
28#include "karazhan.h"
29#include "Map.h"
30#include "ObjectAccessor.h"
31#include "Player.h"
32#include "ScriptedCreature.h"
33#include "TemporarySummon.h"
34
36{
39
48};
49
50const float PortalCoord[3][3] =
51{
52 {-11195.353516f, -1613.237183f, 278.237258f}, // Left side
53 {-11137.846680f, -1685.607422f, 278.239258f}, // Right side
54 {-11094.493164f, -1591.969238f, 279.949188f} // Back side
55};
56
58 RED_PORTAL = 0, // Perseverence
59 GREEN_PORTAL = 1, // Serenity
60 BLUE_PORTAL = 2 // Dominance
61};
62
63const uint32 PortalID[3] = {17369, 17367, 17368};
64const uint32 PortalVisual[3] = {30487, 30490, 30491};
65const uint32 PortalBeam[3] = {30465, 30464, 30463};
66const uint32 PlayerBuff[3] = {30421, 30422, 30423};
67const uint32 NetherBuff[3] = {30466, 30467, 30468};
68const uint32 PlayerDebuff[3] = {38637, 38638, 38639};
69
71{
72public:
73 boss_netherspite() : CreatureScript("boss_netherspite") { }
74
75 CreatureAI* GetAI(Creature* creature) const override
76 {
77 return GetKarazhanAI<boss_netherspiteAI>(creature);
78 }
79
81 {
82 boss_netherspiteAI(Creature* creature) : ScriptedAI(creature)
83 {
84 Initialize();
85 instance = creature->GetInstanceScript();
86
87 PortalPhase = false;
88 PhaseTimer = 0;
90 PortalTimer = 0;
91 }
92
94 {
95 Berserk = false;
96 NetherInfusionTimer = 540000;
97 VoidZoneTimer = 15000;
98 NetherbreathTimer = 3000;
99 }
100
102
105 uint32 PhaseTimer; // timer for phase switching
107 uint32 NetherInfusionTimer; // berserking timer
110 uint32 PortalTimer; // timer for beam checking
111 ObjectGuid PortalGUID[3]; // guid's of portals
112 ObjectGuid BeamerGUID[3]; // guid's of auxiliary beaming portals
113 ObjectGuid BeamTarget[3]; // guid's of portals' current targets
114
115 bool IsBetween(WorldObject* u1, WorldObject* target, WorldObject* u2) // the in-line checker
116 {
117 if (!u1 || !u2 || !target)
118 return false;
119
120 float xn, yn, xp, yp, xh, yh;
121 xn = u1->GetPositionX();
122 yn = u1->GetPositionY();
123 xp = u2->GetPositionX();
124 yp = u2->GetPositionY();
125 xh = target->GetPositionX();
126 yh = target->GetPositionY();
127
128 // check if target is between (not checking distance from the beam yet)
129 if (dist(xn, yn, xh, yh) >= dist(xn, yn, xp, yp) || dist(xp, yp, xh, yh) >= dist(xn, yn, xp, yp))
130 return false;
131 // check distance from the beam
132 return (std::abs((xn-xp)*yh+(yp-yn)*xh-xn*yp+xp*yn)/dist(xn, yn, xp, yp) < 1.5f);
133 }
134
135 float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance
136 {
137 return std::sqrt((xa-xb)*(xa-xb) + (ya-yb)*(ya-yb));
138 }
139
140 void Reset() override
141 {
142 Initialize();
143
144 HandleDoors(true);
146
148 }
149
151 {
152 uint8 r = rand32() % 4;
153 uint8 pos[3];
154 pos[RED_PORTAL] = ((r % 2) ? (r > 1 ? 2 : 1) : 0);
155 pos[GREEN_PORTAL] = ((r % 2) ? 0 : (r > 1 ? 2 : 1));
156 pos[BLUE_PORTAL] = (r > 1 ? 1 : 2); // Blue Portal not on the left side (0)
157
158 for (int i = 0; i < 3; ++i)
159 if (Creature* portal = me->SummonCreature(PortalID[i], PortalCoord[pos[i]][0], PortalCoord[pos[i]][1], PortalCoord[pos[i]][2], 0, TEMPSUMMON_TIMED_DESPAWN, 1min))
160 {
161 PortalGUID[i] = portal->GetGUID();
162 portal->AddAura(PortalVisual[i], portal);
163 }
164 }
165
167 {
168 for (int i=0; i<3; ++i)
169 {
171 portal->DisappearAndDie();
173 portal->DisappearAndDie();
174 PortalGUID[i].Clear();
175 BeamTarget[i].Clear();
176 }
177 }
178
179 void UpdatePortals() // Here we handle the beams' behavior
180 {
181 for (int j = 0; j < 3; ++j) // j = color
183 {
184 // the one who's been cast upon before
185 Unit* current = ObjectAccessor::GetUnit(*portal, BeamTarget[j]);
186 // temporary store for the best suitable beam reciever
187 Unit* target = me;
188
189 Map::PlayerList const& players = me->GetMap()->GetPlayers();
190
191 // get the best suitable target
192 for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
193 {
194 Player* p = i->GetSource();
195 if (p && p->IsAlive() // alive
196 && (!target || target->GetDistance2d(portal)>p->GetDistance2d(portal)) // closer than current best
197 && !p->HasAura(PlayerDebuff[j]) // not exhausted
198 && !p->HasAura(PlayerBuff[(j + 1) % 3]) // not on another beam
199 && !p->HasAura(PlayerBuff[(j + 2) % 3])
200 && IsBetween(me, p, portal)) // on the beam
201 target = p;
202 }
203
204 // buff the target
205 if (target->GetTypeId() == TYPEID_PLAYER)
206 target->AddAura(PlayerBuff[j], target);
207 else
208 target->AddAura(NetherBuff[j], target);
209 // cast visual beam on the chosen target if switched
210 // simple target switching isn't working -> using BeamerGUID to cast (workaround)
211 if (!current || target != current)
212 {
213 BeamTarget[j] = target->GetGUID();
214 // remove currently beaming portal
215 if (Creature* beamer = ObjectAccessor::GetCreature(*portal, BeamerGUID[j]))
216 {
217 beamer->CastSpell(target, PortalBeam[j], false);
218 beamer->DisappearAndDie();
219 BeamerGUID[j].Clear();
220 }
221 // create new one and start beaming on the target
222 if (Creature* beamer = portal->SummonCreature(PortalID[j], portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), portal->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 1min))
223 {
224 beamer->CastSpell(target, PortalBeam[j], false);
225 BeamerGUID[j] = beamer->GetGUID();
226 }
227 }
228 // aggro target if Red Beam
229 if (j == RED_PORTAL && me->GetVictim() != target && target->GetTypeId() == TYPEID_PLAYER)
230 AddThreat(target, 100000.0f);
231 }
232 }
233
235 {
239 PhaseTimer = 60000;
240 PortalPhase = true;
241 PortalTimer = 10000;
242 EmpowermentTimer = 10000;
244 }
245
247 {
253 PhaseTimer = 30000;
254 PortalPhase = false;
256
257 for (uint8 i = 0; i < 3; ++i)
259 }
260
261 void HandleDoors(bool open) // Massive Door switcher
262 {
264 Door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY);
265 }
266
267 void JustEngagedWith(Unit* /*who*/) override
268 {
269 HandleDoors(false);
271
273 }
274
275 void JustDied(Unit* /*killer*/) override
276 {
277 HandleDoors(true);
279
281 }
282
283 void UpdateAI(uint32 diff) override
284 {
285 if (!UpdateVictim())
286 return;
287
288 // Void Zone
289 if (VoidZoneTimer <= diff)
290 {
292 VoidZoneTimer = 15000;
293 } else VoidZoneTimer -= diff;
294
295 // NetherInfusion Berserk
296 if (!Berserk && NetherInfusionTimer <= diff)
297 {
300 Berserk = true;
301 } else NetherInfusionTimer -= diff;
302
303 if (PortalPhase) // PORTAL PHASE
304 {
305 // Distribute beams and buffs
306 if (PortalTimer <= diff)
307 {
309 PortalTimer = 1000;
310 } else PortalTimer -= diff;
311
312 // Empowerment & Nether Burn
313 if (EmpowermentTimer <= diff)
314 {
317 EmpowermentTimer = 90000;
318 } else EmpowermentTimer -= diff;
319
320 if (PhaseTimer <= diff)
321 {
322 if (!me->IsNonMeleeSpellCast(false))
323 {
325 return;
326 }
327 } else PhaseTimer -= diff;
328 }
329 else // BANISH PHASE
330 {
331 // Netherbreath
332 if (NetherbreathTimer <= diff)
333 {
334 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40, true))
335 DoCast(target, SPELL_NETHERBREATH);
336 NetherbreathTimer = urand(5000, 7000);
337 } else NetherbreathTimer -= diff;
338
339 if (PhaseTimer <= diff)
340 {
341 if (!me->IsNonMeleeSpellCast(false))
342 {
344 return;
345 }
346 } else PhaseTimer -= diff;
347 }
348 }
349 };
350};
351
353{
354 new boss_netherspite();
355}
uint8_t uint8
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:142
@ IN_PROGRESS
@ DONE
@ NOT_STARTED
@ TEMPSUMMON_TIMED_DESPAWN
Definition: ObjectDefines.h:65
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
uint32 rand32()
Definition: Random.cpp:70
@ GO_STATE_READY
@ GO_STATE_ACTIVE
const float PortalCoord[3][3]
const uint32 PlayerBuff[3]
Netherspite
@ 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=nullptr)
Definition: CreatureAI.cpp:56
bool UpdateVictim()
Definition: CreatureAI.cpp:245
Creature *const me
Definition: CreatureAI.h:61
virtual bool SetBossState(uint32 id, EncounterState state)
virtual ObjectGuid GetGuidData(uint32 type) const override
iterator end()
Definition: MapRefManager.h:35
iterator begin()
Definition: MapRefManager.h:34
PlayerList const & GetPlayers() const
Definition: Map.h:367
void Clear()
Definition: ObjectGuid.h:286
TypeID GetTypeId() const
Definition: Object.h:173
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition: UnitAI.cpp:79
SpellCastResult DoCast(uint32 spellId)
Definition: UnitAI.cpp:89
Definition: Unit.h:627
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition: Unit.cpp:3059
Aura * AddAura(uint32 spellId, Unit *target)
Definition: Unit.cpp:11618
bool IsAlive() const
Definition: Unit.h:1164
Unit * GetVictim() const
Definition: Unit.h:715
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
Map * GetMap() const
Definition: Object.h:624
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
TempSummon * SummonCreature(uint32 entry, Position const &pos, TempSummonType despawnType=TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime=0s, uint32 vehId=0, uint32 spellId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Definition: Object.cpp:2025
float GetDistance2d(WorldObject const *obj) const
Definition: Object.cpp:1096
CreatureAI * GetAI(Creature *creature) const override
@ DATA_GO_MASSIVE_DOOR
Definition: karazhan.h:50
@ DATA_NETHERSPITE
Definition: karazhan.h:38
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API GameObject * GetGameObject(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
void AddThreat(Unit *victim, float amount, Unit *who=nullptr)
void UpdateAI(uint32 diff) override
float dist(float xa, float ya, float xb, float yb)
bool IsBetween(WorldObject *u1, WorldObject *target, WorldObject *u2)