PageRenderTime 137ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/src/bindings/scripts/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp

https://github.com/xiaofeng2009/TC2
C++ | 343 lines | 265 code | 40 blank | 38 comment | 60 complexity | c7ba6d563e72832751897acac9d4fcde MD5 | raw file
  1. /* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License as published by
  4. * the Free Software Foundation; either version 2 of the License, or
  5. * (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software
  14. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. */
  16. /* ScriptData
  17. SDName: Boss_Netherspite
  18. SD%Complete: 90
  19. SDComment: Not sure about timing and portals placing
  20. SDCategory: Karazhan
  21. EndScriptData */
  22. #include "precompiled.h"
  23. #include "karazhan.h"
  24. #define EMOTE_PHASE_PORTAL -1532089
  25. #define EMOTE_PHASE_BANISH -1532090
  26. #define SPELL_NETHERBURN_AURA 30522
  27. #define SPELL_VOIDZONE 37063
  28. #define SPELL_NETHER_INFUSION 38688
  29. #define SPELL_NETHERBREATH 38523
  30. #define SPELL_BANISH_VISUAL 39833
  31. #define SPELL_BANISH_ROOT 42716
  32. #define SPELL_EMPOWERMENT 38549
  33. #define SPELL_NETHERSPITE_ROAR 38684
  34. const float PortalCoord[3][3] =
  35. {
  36. {-11195.353516, -1613.237183, 278.237258}, // Left side
  37. {-11137.846680, -1685.607422, 278.239258}, // Right side
  38. {-11094.493164, -1591.969238, 279.949188} // Back side
  39. };
  40. enum Netherspite_Portal{
  41. RED_PORTAL = 0, // Perseverence
  42. GREEN_PORTAL = 1, // Serenity
  43. BLUE_PORTAL = 2 // Dominance
  44. };
  45. const uint32 PortalID[3] = {17369, 17367, 17368};
  46. const uint32 PortalVisual[3] = {30487,30490,30491};
  47. const uint32 PortalBeam[3] = {30465,30464,30463};
  48. const uint32 PlayerBuff[3] = {30421,30422,30423};
  49. const uint32 NetherBuff[3] = {30466,30467,30468};
  50. const uint32 PlayerDebuff[3] = {38637,38638,38639};
  51. struct TRINITY_DLL_DECL boss_netherspiteAI : public ScriptedAI
  52. {
  53. boss_netherspiteAI(Creature* c) : ScriptedAI(c)
  54. {
  55. pInstance = c->GetInstanceData();
  56. for (int i=0; i<3; ++i)
  57. {
  58. PortalGUID[i] = 0;
  59. BeamTarget[i] = 0;
  60. BeamerGUID[i] = 0;
  61. }
  62. // need core fix
  63. for (int i=0; i<3; ++i)
  64. {
  65. if(SpellEntry *spell = (SpellEntry*)GetSpellStore()->LookupEntry(PlayerBuff[i]))
  66. spell->AttributesEx |= SPELL_ATTR_EX_NEGATIVE;
  67. }
  68. }
  69. ScriptedInstance* pInstance;
  70. bool PortalPhase;
  71. bool Berserk;
  72. uint32 PhaseTimer; // timer for phase switching
  73. uint32 VoidZoneTimer;
  74. uint32 NetherInfusionTimer; // berserking timer
  75. uint32 NetherbreathTimer;
  76. uint32 EmpowermentTimer;
  77. uint32 PortalTimer; // timer for beam checking
  78. uint64 PortalGUID[3]; // guid's of portals
  79. uint64 BeamerGUID[3]; // guid's of auxiliary beaming portals
  80. uint64 BeamTarget[3]; // guid's of portals' current targets
  81. bool IsBetween(WorldObject* u1, WorldObject *pTarget, WorldObject* u2) // the in-line checker
  82. {
  83. if(!u1 || !u2 || !pTarget)
  84. return false;
  85. float xn, yn, xp, yp, xh, yh;
  86. xn = u1->GetPositionX();
  87. yn = u1->GetPositionY();
  88. xp = u2->GetPositionX();
  89. yp = u2->GetPositionY();
  90. xh = pTarget->GetPositionX();
  91. yh = pTarget->GetPositionY();
  92. // check if target is between (not checking distance from the beam yet)
  93. if(dist(xn,yn,xh,yh)>=dist(xn,yn,xp,yp) || dist(xp,yp,xh,yh)>=dist(xn,yn,xp,yp))
  94. return false;
  95. // check distance from the beam
  96. return (abs((xn-xp)*yh+(yp-yn)*xh-xn*yp+xp*yn)/dist(xn,yn,xp,yp) < 1.5f);
  97. }
  98. float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance
  99. {
  100. return sqrt((xa-xb)*(xa-xb) + (ya-yb)*(ya-yb));
  101. }
  102. void Reset()
  103. {
  104. Berserk = false;
  105. NetherInfusionTimer = 540000;
  106. VoidZoneTimer = 15000;
  107. NetherbreathTimer = 3000;
  108. HandleDoors(true);
  109. DestroyPortals();
  110. }
  111. void SummonPortals()
  112. {
  113. uint8 r = rand()%4;
  114. uint8 pos[3];
  115. pos[RED_PORTAL] = (r%2 ? (r>1 ? 2: 1): 0);
  116. pos[GREEN_PORTAL] = (r%2 ? 0: (r>1 ? 2: 1));
  117. pos[BLUE_PORTAL] = (r>1 ? 1: 2); // Blue Portal not on the left side (0)
  118. for (int i=0; i<3; ++i)
  119. if(Creature *portal = m_creature->SummonCreature(PortalID[i],PortalCoord[pos[i]][0],PortalCoord[pos[i]][1],PortalCoord[pos[i]][2],0,TEMPSUMMON_TIMED_DESPAWN,60000))
  120. {
  121. PortalGUID[i] = portal->GetGUID();
  122. portal->AddAura(PortalVisual[i], portal);
  123. }
  124. }
  125. void DestroyPortals()
  126. {
  127. for (int i=0; i<3; ++i)
  128. {
  129. if(Creature *portal = Unit::GetCreature(*m_creature, PortalGUID[i]))
  130. portal->DisappearAndDie();
  131. if(Creature *portal = Unit::GetCreature(*m_creature, BeamerGUID[i]))
  132. portal->DisappearAndDie();
  133. PortalGUID[i] = 0;
  134. BeamTarget[i] = 0;
  135. }
  136. }
  137. void UpdatePortals() // Here we handle the beams' behavior
  138. {
  139. for (int j=0; j<3; ++j) // j = color
  140. if(Creature *portal = Unit::GetCreature(*m_creature, PortalGUID[j]))
  141. {
  142. // the one who's been casted upon before
  143. Unit *current = Unit::GetUnit(*portal, BeamTarget[j]);
  144. // temporary store for the best suitable beam reciever
  145. Unit *pTarget = m_creature;
  146. if(Map* map = m_creature->GetMap())
  147. {
  148. Map::PlayerList const& players = map->GetPlayers();
  149. // get the best suitable target
  150. for (Map::PlayerList::const_iterator i = players.begin(); i!=players.end(); ++i)
  151. {
  152. Player* p = i->getSource();
  153. if(p && p->isAlive() // alive
  154. && (!pTarget || pTarget->GetDistance2d(portal)>p->GetDistance2d(portal)) // closer than current best
  155. && !p->HasAura(PlayerDebuff[j],0) // not exhausted
  156. && !p->HasAura(PlayerBuff[(j+1)%3],0) // not on another beam
  157. && !p->HasAura(PlayerBuff[(j+2)%3],0)
  158. && IsBetween(m_creature, p, portal)) // on the beam
  159. pTarget = p;
  160. }
  161. }
  162. // buff the target
  163. if(pTarget->GetTypeId() == TYPEID_PLAYER)
  164. pTarget->AddAura(PlayerBuff[j], pTarget);
  165. else
  166. pTarget->AddAura(NetherBuff[j], pTarget);
  167. // cast visual beam on the chosen target if switched
  168. // simple target switching isn't working -> using BeamerGUID to cast (workaround)
  169. if(!current || pTarget != current)
  170. {
  171. BeamTarget[j] = pTarget->GetGUID();
  172. // remove currently beaming portal
  173. if(Creature *beamer = Unit::GetCreature(*portal, BeamerGUID[j]))
  174. {
  175. beamer->CastSpell(pTarget, PortalBeam[j], false);
  176. beamer->DisappearAndDie();
  177. BeamerGUID[j] = 0;
  178. }
  179. // create new one and start beaming on the target
  180. if(Creature *beamer = portal->SummonCreature(PortalID[j],portal->GetPositionX(),portal->GetPositionY(),portal->GetPositionZ(),portal->GetOrientation(),TEMPSUMMON_TIMED_DESPAWN,60000))
  181. {
  182. beamer->CastSpell(pTarget, PortalBeam[j], false);
  183. BeamerGUID[j] = beamer->GetGUID();
  184. }
  185. }
  186. // aggro target if Red Beam
  187. if(j==RED_PORTAL && m_creature->getVictim() != pTarget && pTarget->GetTypeId() == TYPEID_PLAYER)
  188. m_creature->getThreatManager().addThreat(pTarget, 100000.0f+DoGetThreat(m_creature->getVictim()));
  189. }
  190. }
  191. void SwitchToPortalPhase()
  192. {
  193. m_creature->RemoveAurasDueToSpell(SPELL_BANISH_ROOT);
  194. m_creature->RemoveAurasDueToSpell(SPELL_BANISH_VISUAL);
  195. SummonPortals();
  196. PhaseTimer = 60000;
  197. PortalPhase = true;
  198. PortalTimer = 10000;
  199. EmpowermentTimer = 10000;
  200. DoScriptText(EMOTE_PHASE_PORTAL,m_creature);
  201. }
  202. void SwitchToBanishPhase()
  203. {
  204. m_creature->RemoveAurasDueToSpell(SPELL_EMPOWERMENT);
  205. m_creature->RemoveAurasDueToSpell(SPELL_NETHERBURN_AURA);
  206. DoCast(m_creature,SPELL_BANISH_VISUAL,true);
  207. DoCast(m_creature,SPELL_BANISH_ROOT,true);
  208. DestroyPortals();
  209. PhaseTimer = 30000;
  210. PortalPhase = false;
  211. DoScriptText(EMOTE_PHASE_BANISH,m_creature);
  212. for (int i=0; i<3; ++i)
  213. m_creature->RemoveAurasDueToSpell(NetherBuff[i]);
  214. }
  215. void HandleDoors(bool open) // Massive Door switcher
  216. {
  217. if(GameObject *Door = GameObject::GetGameObject(*m_creature, pInstance ? pInstance->GetData64(DATA_GO_MASSIVE_DOOR) : 0))
  218. Door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY);
  219. }
  220. void Aggro(Unit *who)
  221. {
  222. HandleDoors(false);
  223. SwitchToPortalPhase();
  224. }
  225. void JustDied(Unit* killer)
  226. {
  227. HandleDoors(true);
  228. DestroyPortals();
  229. }
  230. void UpdateAI(const uint32 diff)
  231. {
  232. if(!UpdateVictim())
  233. return;
  234. // Void Zone
  235. if (VoidZoneTimer <= diff)
  236. {
  237. DoCast(SelectTarget(SELECT_TARGET_RANDOM,1,45,true),SPELL_VOIDZONE,true);
  238. VoidZoneTimer = 15000;
  239. } else VoidZoneTimer -= diff;
  240. // NetherInfusion Berserk
  241. if (!Berserk && NetherInfusionTimer <= diff)
  242. {
  243. m_creature->AddAura(SPELL_NETHER_INFUSION, m_creature);
  244. DoCast(m_creature, SPELL_NETHERSPITE_ROAR);
  245. Berserk = true;
  246. } else NetherInfusionTimer -= diff;
  247. if(PortalPhase) // PORTAL PHASE
  248. {
  249. // Distribute beams and buffs
  250. if (PortalTimer <= diff)
  251. {
  252. UpdatePortals();
  253. PortalTimer = 1000;
  254. } else PortalTimer -= diff;
  255. // Empowerment & Nether Burn
  256. if (EmpowermentTimer <= diff)
  257. {
  258. DoCast(m_creature, SPELL_EMPOWERMENT);
  259. m_creature->AddAura(SPELL_NETHERBURN_AURA, m_creature);
  260. EmpowermentTimer = 90000;
  261. } else EmpowermentTimer -= diff;
  262. if (PhaseTimer <= diff)
  263. {
  264. if (!m_creature->IsNonMeleeSpellCasted(false))
  265. {
  266. SwitchToBanishPhase();
  267. return;
  268. }
  269. } else PhaseTimer -= diff;
  270. }
  271. else // BANISH PHASE
  272. {
  273. // Netherbreath
  274. if (NetherbreathTimer <= diff)
  275. {
  276. if(Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM,0,40,true))
  277. DoCast(pTarget,SPELL_NETHERBREATH);
  278. NetherbreathTimer = urand(5000,7000);
  279. } else NetherbreathTimer -= diff;
  280. if (PhaseTimer <= diff)
  281. {
  282. if (!m_creature->IsNonMeleeSpellCasted(false))
  283. {
  284. SwitchToPortalPhase();
  285. return;
  286. }
  287. } else PhaseTimer -= diff;
  288. }
  289. DoMeleeAttackIfReady();
  290. }
  291. };
  292. CreatureAI* GetAI_boss_netherspite(Creature *pCreature)
  293. {
  294. return new boss_netherspiteAI(pCreature);
  295. }
  296. void AddSC_boss_netherspite()
  297. {
  298. Script *newscript;
  299. newscript = new Script;
  300. newscript->Name = "boss_netherspite";
  301. newscript->GetAI = GetAI_boss_netherspite;
  302. newscript->RegisterSelf();
  303. }