// --- Scripted by M4ksiu --- // /* * TO DO: Fire Magtheridon throws around the battlefield. * Some banish/channeling spells must be replaced. DONE * Cave-in - not fully supported yet, but gonna work on it :) DONE * Yells - not all added. Some used in bad situations. DONE * Reset system - not added yet. DONE */ // Encounter Settings #define BANISH_TIMER 120 // 2 minutes #define YELL_TIMER 260 // 4 minutes and 20 seconds #define ACTIVE_CUBES_TO_BANISH 5 // 5 cubes // Coords structure to select/list some units by using arrays and vector tables struct Coords { float x; float y; float z; }; // Channelers Coords is list of spawn points of all 5 channelers casting spell on Magtheridon struct Coords Channelers[]= { { -55.638000f, 1.869050f, 0.630946f }, { -31.861300f, -35.919399f, 0.630945f }, { 10.469200f, -19.894800f, 0.630910f }, { 10.477100f, 24.445499f, 0.630891f }, { -32.171600f, 39.926800f, 0.630921f } }; // Columns coords used for Cave In spell to give "collapse" effect struct Coords Columns[]= { { 17.7522f, 34.5464f, 0.144816f }, { 19.0966f, -29.2772f, 0.133036f }, { -30.8852f, 46.6723f, -0.497104f }, { -60.2491f, 27.9361f, -0.018443f }, { -60.8202f, -21.9269f, -0.030260f }, { -29.7699f, -43.4445f, -0.522461f } }; // Cave In Target Triggers coords struct Coords CaveInPos[]= { { -37.183399f, -19.491400f, 0.312451f }, { -11.374900f, -29.121401f, 0.312463f }, { 13.133100f, 2.757930f, -0.312492f }, { -3.110930f, 29.142401f, -0.312490f }, { -29.691000f, 29.643000f, -0.034676f }, { -12.111600f, 1.011050f, -0.303638f } }; // Cube Triggers coords struct Coords CubeTriggers[]= { { -54.277199f, 2.343740f, 2.404560f }, { -31.471001f, -34.155998f, 2.335100f }, { 8.797220f, -19.480101f, 2.536460f }, { 9.358900f, 23.228600f, 2.348950f }, { -31.891800f, 38.430302f, 2.286470f } }; // Magtheridon Trigger AI - Creature AI Class #define CN_MAGTHERIDON_TRIGGER 133338 // Spell macros used in whole script #define BANISH 30231 // 31797 #define BANISHMENT 40825 #define SOUL_TRANSFER 30531 #define SHADOW_GRASP 30166 //30207 #define SHADOW_GRASP2 30410 class MagtheridonTriggerAI : public CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(MagtheridonTriggerAI); std::vector ChannelersTable; // Vector "list" of Channelers bool KilledChanneler[5]; // Bool that says if channeler died or not MagtheridonTriggerAI(Creature* pCreature) : CreatureAIScript(pCreature) { // We set default value for KillerdChanneler array to avoid any unexpected situations for (int i = 0; i < 5; i++) { KilledChanneler[i] = false; } // Variable initialization YellTimer = YELL_TIMER; EventStarted = false; PhaseOneTimer = 0; Phase = 0; // Trigger settings _unit->SetUInt64Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); _unit->GetAIInterface()->SetAllowedToEnterCombat(false); RegisterAIUpdateEvent(1000); // We set Gate (if exists) as opened GameObject* Gate = _unit->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(-72.5866f, 1.559f, 0.0f, 183847); if (Gate) Gate->SetUInt32Value(GAMEOBJECT_STATE, 0); } void AIUpdate() { // Magtheridon yells when raid progresses, but during fight with himself YellTimer--; if (Phase <= 1 && !YellTimer) { // If Magtheridon can be found we let him yell one of six different texts Unit* Magtheridon = NULL; Magtheridon = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(-22.657900f, 2.159050f, -0.345542f, 17257); if (Magtheridon) { uint32 SoundID = 0; std::string Text = ""; switch (RandomUInt(6)) { case 1: Text = "Wretched, meddling insects! Release me, and perhaps I will grant you a merciful death!"; SoundID = 10247; break; case 2: Text = "Vermin! Leeches! Take my blood and choke on it!"; SoundID = 10248; break; case 3: Text = "Illidan is an arrogant fool! I will crush him and reclaim Outland as my own!"; SoundID = 10249; break; case 4: Text = "Away, you mindless parasites! My blood is my own!"; SoundID = 10250; break; case 5: Text = "How long do you believe your pathetic sorcery can hold me?"; SoundID = 10251; break; case 6: Text = "My blood will be the end of you!"; SoundID = 10252; break; default: Text = "My blood will be the end of you!"; SoundID = 10252; } if (SoundID && Text != "") { Magtheridon->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, Text.c_str()); Magtheridon->PlaySoundToSet(SoundID); } } // We reset YellTimer to default value to let Pit Lord say something again and again YellTimer = YELL_TIMER; } // If our channeler "list" has unexpected size we try to recreate it if (ChannelersTable.size() < 5 && !EventStarted) { // We clear old "list" ChannelersTable.clear(); // In order to recreate channeler "list" we need ot look for them in hardcoded spawn positions Unit* Channeler; for (int i = 0; i < 5; i++) { Channeler = NULL; Channeler = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(Channelers[i].x, Channelers[i].y, Channelers[i].z, 17256); if (!Channeler) continue; // If Channeler was found we push him at the end of our "list" ChannelersTable.push_back(Channeler); // If Magtheridon is spawned we tell channeler to cast spell on Pit Lord Unit* Magtheridon = NULL; Magtheridon = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(-22.657900f, 2.159050f, -0.345542f, 17257); if (Magtheridon && Channeler->isAlive() && !Channeler->GetAIInterface()->GetNextTarget()) { Channeler->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, Magtheridon->GetGUID()); Channeler->SetUInt32Value(UNIT_CHANNEL_SPELL, SHADOW_GRASP); } } } // If ChannelersTable is not empty we check list to find if none of channelers died if (ChannelersTable.size() > 0) { // We look through list size_t Counter = 0; for (size_t i = 0; i < ChannelersTable.size(); i++) { // If channeler was already dead we count him as already dead one and go to others if (KilledChanneler[i]) { Counter++; continue; } // Safe check to prevent memory corruptions Unit *Channeler = ChannelersTable[i]; if ( Channeler && !Channeler->IsInWorld() ) { ChannelersTable[i] = NULL; Channeler = NULL; continue; } // If channeler wasn't dead before and now is not alive we buff other alive channelers if ( Channeler && !Channeler->isAlive() && Channeler->IsInWorld() ) { // We look through list of channelers to find alive ones and buff them Unit* BuffedChanneler; for (size_t x = 0; x < ChannelersTable.size(); x++) { // Safe check to prevent memory corruption BuffedChanneler = ChannelersTable[x]; if ( BuffedChanneler && !BuffedChanneler->IsInWorld() ) { ChannelersTable[x] = NULL; BuffedChanneler = NULL; continue; } // If channeler is found, alive and is not channeler we checked before if he's dead we move on if (BuffedChanneler && BuffedChanneler != Channeler && BuffedChanneler->isAlive()) { // We apply Soul Transfer Aura to channeler who should be buffed Aura * aura = new Aura( dbcSpell.LookupEntry(SOUL_TRANSFER), -1, BuffedChanneler, BuffedChanneler); BuffedChanneler->AddAura(aura); } } // We count channeler which died between last and this trigger as dead and count him as dead one KilledChanneler[i] = true; Counter++; } } // If only one channeler is alive we can clear list, because we won't need other channelers to be buffed /*if (Counter >= ChannelersTable.size() - 1) ChannelersTable.clear();*/ } // If table is empty (0 channelers spawned) we remove banish and go to phase 2 at once if (!ChannelersTable.size() && !Phase) { Unit* Magtheridon = NULL; Magtheridon = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(-22.657900f, 2.159050f, -0.345542f, 17257); if (Magtheridon) { Magtheridon->GetAIInterface()->SetAllowedToEnterCombat(true); Magtheridon->SetUInt64Value(UNIT_FIELD_FLAGS, 0); Magtheridon->RemoveAura(BANISHMENT); Magtheridon->RemoveAura(BANISH); } Phase = 2; } // If Event wasn't started yet we check if it shouldn't be marked as started if (!EventStarted) { // We look for channeler that may be In Combat or was killed by that unit enemy Unit* Channeler = NULL; Unit* UnitTarget = NULL; for (size_t i = 0; i < ChannelersTable.size(); i++) { // Safe check to prevent memory corruptions Channeler = ChannelersTable[i]; if ( Channeler && !Channeler->IsInWorld() ) { ChannelersTable[i] = NULL; Channeler = NULL; continue; } // If dead or channeler In Combat is found we check if we have already copied target if (Channeler && Channeler->isAlive() && Channeler->GetAIInterface()->GetNextTarget()) { // If channeler is In Combat and we haven't copied any target yet we copy it if (Channeler->GetAIInterface()->GetNextTarget() && !UnitTarget) { UnitTarget = Channeler->GetAIInterface()->GetNextTarget(); } // We switch phase and mark event as started EventStarted = true; Phase = 1; } } // Immediately after phase switching we check if channelers are In Combat if (EventStarted) { // We look through all channelers if they are In Combat and have targets for (size_t i = 0; i < ChannelersTable.size(); i++) { // Safe check to prevent memory corruption Channeler = ChannelersTable[i]; if ( Channeler && !Channeler->IsInWorld() ) { ChannelersTable[i] = NULL; Channeler = NULL; continue; } // If channeler is not In Combat we force him to attack target we copied before if (Channeler && !Channeler->GetAIInterface()->GetNextTarget() && UnitTarget) { Channeler->GetAIInterface()->SetAllowedToEnterCombat(true); Channeler->GetAIInterface()->AttackReaction(UnitTarget, 1, 0); } } // If Magtheridon is found we remove Banish aura from him Unit* Magtheridon = NULL; Magtheridon = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(-22.657900f, 2.159050f, -0.345542f, 17257); if (Magtheridon) Magtheridon->RemoveAura(BANISH); // If Gate is found we close it GameObject* Gate = _unit->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(-72.5866f, 1.559f, 0.0f, 183847); if (Gate) Gate->SetUInt32Value(GAMEOBJECT_STATE, 1); } } // We use different functions for each phase switch (Phase) { case 1: // If we are about to release Magtheridon we remove his Banishment aura, change his flag and use emotes that should be used PhaseOneTimer++; if (PhaseOneTimer == BANISH_TIMER-2) { Unit* Magtheridon = NULL; Magtheridon = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(-22.657900f, 2.159050f, -0.345542f, 17257); if (Magtheridon) { if (RandomUInt(4) == 1) { // on movies I saw only another text, but Magtheridon may use this one rarely too, so added here Magtheridon->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Thank you for releasing me. Now... die!"); Magtheridon->PlaySoundToSet(10254); } else { Magtheridon->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I... am... unleashed!"); Magtheridon->PlaySoundToSet(10253); } Magtheridon->SetUInt64Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); Magtheridon->Emote(EMOTE_ONESHOT_CREATURE_SPECIAL); Magtheridon->RemoveAura(BANISHMENT); } } // Time runs out, phase switches and Magtheridon can get In Combat if (PhaseOneTimer == BANISH_TIMER) { Unit* Magtheridon = NULL; Magtheridon = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(-22.657900f, 2.159050f, -0.345542f, 17257); if (Magtheridon) { Magtheridon->GetAIInterface()->SetAllowedToEnterCombat(true); Magtheridon->SetUInt64Value(UNIT_FIELD_FLAGS, 0); } Phase = 2; } // Setting checks to reset encounter if (PhaseOneTimer == 115 || PhaseOneTimer == 105 || PhaseOneTimer == 90 || PhaseOneTimer == 75 || PhaseOneTimer == 60 || PhaseOneTimer == 45 || PhaseOneTimer == 30 || PhaseOneTimer == 15) { // We check if any of channelers casts banish spell on Magtheridon and then we reset timer and setting Unit* Magtheridon = NULL; Magtheridon = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(-22.657900f, 2.159050f, -0.345542f, 17257); if (Magtheridon) { Aura *aura = Magtheridon->FindAura(BANISH); if (aura) { EventStarted = false; PhaseOneTimer = 0; Phase = 0; } } // Script creates vector "list" of alive channelers and counts those In Combat Unit *Channeler = NULL; size_t AliveInCombat = 0; std::vector AliveChannelers; for (size_t i = 0; i < ChannelersTable.size(); i++) { Channeler = ChannelersTable[i]; if ( Channeler && !Channeler->IsInWorld() ) { ChannelersTable[i] = NULL; Channeler = NULL; continue; } if (Channeler && Channeler->isAlive()) { AliveChannelers.push_back(Channeler); if (Channeler->GetAIInterface()->GetNextTarget()) AliveInCombat++; } } // If less than half of alive channelers is out of combat we open Magtheridon's gate if (AliveInCombat < AliveChannelers.size()/2) { GameObject* Gate = _unit->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(-72.5866f, 1.559f, 0.0f, 183847); if (Gate) Gate->SetUInt32Value(GAMEOBJECT_STATE, 0); } // After doing our job we can clear temporary channeler list AliveChannelers.clear(); } break; default: { } } } protected: bool EventStarted; uint32 PhaseOneTimer; uint32 YellTimer; uint32 Phase; }; // Manticron Cube Gameobject #define MANTICRON_CUBE 181713 #define MIND_EXHAUSTION 44032 class ManticronCubeGO : public GameObjectAIScript { public: ManticronCubeGO(GameObject* pGameObject) : GameObjectAIScript(pGameObject) { Magtheridon = CubeTrigger = NULL; } void OnActivate(Player * pPlayer) { // We check if player has aura that prevents anyone from using this GO Aura *aura = pPlayer->FindAura(MIND_EXHAUSTION); if (aura) return; // If we don't have Magtheridon we try to find it (with normal "getting creature" it was NOT working mostly). if (!Magtheridon) { for (int i = 0; i < 6; i++) { if (Magtheridon) continue; Magtheridon = _gameobject->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(CaveInPos[i].x, CaveInPos[i].y, CaveInPos[i].z, 17257); } } // We check if after trying to find Magtheridon we have found it at least if (!Magtheridon) return; // We check if Magtheridon is in world, is alive, has correct flag and so on if (!Magtheridon->isAlive() || !Magtheridon->GetAIInterface()->GetNextTarget()) return; // If we haven't "filled" pointer already we do that now if (!CubeTrigger) CubeTrigger = _gameobject->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(_gameobject->GetPositionX(), _gameobject->GetPositionY(), _gameobject->GetPositionZ(), 17376); // We check if Cube Trigger we want to use exists and if is alive if (!CubeTrigger || (CubeTrigger && !CubeTrigger->isAlive())) return; // We check if Cube Trigger is not in use if (CubeTrigger && CubeTrigger->GetUInt32Value(UNIT_CHANNEL_SPELL) == SHADOW_GRASP && CubeTrigger->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT) == Magtheridon->GetGUID()) return; // We set player to channel spell "on Cube" pPlayer->CastSpell(pPlayer, dbcSpell.LookupEntry(SHADOW_GRASP2), false); // We trigger channeling spell on Magtheridon for Cube Trigger CubeTrigger->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, Magtheridon->GetGUID()); CubeTrigger->SetUInt32Value(UNIT_CHANNEL_SPELL, SHADOW_GRASP); // We save player data in pointer as well as his position for further use x = pPlayer->GetPositionX(); y = pPlayer->GetPositionY(); z = pPlayer->GetPositionZ(); Channeler = pPlayer; // We save/initialize vars MagYell = false; // We register AI to check if GO is still being used RegisterAIUpdateEvent(1000); } void AIUpdate() { // Channeler settings check // We check if pointer has Channeler data and if so we check if that channeler is alive, in world and if channels Cube if (Channeler && (!Channeler->isAlive() || !Channeler->IsInWorld())) { CubeTrigger->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, 0); CubeTrigger->SetUInt32Value(UNIT_CHANNEL_SPELL, 0); Channeler = NULL; } // If player still exists (is in world, alive and so on) we check if he has "channeling aura" Aura* aura = NULL; if (Channeler) aura = Channeler->FindAura(SHADOW_GRASP2); // If player doesn't have aura we interrupt channeling if (Channeler && (!aura || !Channeler->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT))) { CubeTrigger->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, 0); CubeTrigger->SetUInt32Value(UNIT_CHANNEL_SPELL, 0); // If player's channeling went over (and he was hit before) aura won't be removed when channeling ends - core bug Channeler->RemoveAura(SHADOW_GRASP2); Channeler = NULL; } // Safe check to prevent crashes when Channeler was nulled if (!Channeler) { uint32 Counter = 0; for (int i = 0; i < 5; i++) { Unit* GlobalCubeTrigger = NULL; GlobalCubeTrigger = _gameobject->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(CubeTriggers[i].x, CubeTriggers[i].y, CubeTriggers[i].z, 17376); if (GlobalCubeTrigger && GlobalCubeTrigger->GetUInt32Value(UNIT_CHANNEL_SPELL) == SHADOW_GRASP && CubeTrigger->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT) == Magtheridon->GetGUID()) Counter++; } if (!Counter) { if (Magtheridon && Magtheridon->isAlive()) Magtheridon->RemoveAura(BANISH); MagYell = true; } return; } // We check if Magtheridon is spawned, is in world and so on if (!Magtheridon || (Magtheridon && (!Magtheridon->isAlive() || !Magtheridon->IsInWorld() || !Magtheridon->GetAIInterface()->GetNextTarget()))) { CubeTrigger->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, 0); CubeTrigger->SetUInt32Value(UNIT_CHANNEL_SPELL, 0); } // We count Cubes that channel spell on Magtheridon uint32 Counter = 0; for (int i = 0; i < 5; i++) { Unit* GlobalCubeTrigger = NULL; GlobalCubeTrigger = _gameobject->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(CubeTriggers[i].x, CubeTriggers[i].y, CubeTriggers[i].z, 17376); if (GlobalCubeTrigger && GlobalCubeTrigger->GetUInt32Value(UNIT_CHANNEL_SPELL) == SHADOW_GRASP && CubeTrigger->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT) == Magtheridon->GetGUID()) Counter++; } // If it's the first and the only one Cube triggering spell we use Magtheridon's yell if (Counter == 1 && !MagYell) { Magtheridon->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Not again... NOT AGAIN!"); Magtheridon->PlaySoundToSet(10256); MagYell = true; } // If we have all req. Cubes active we may banish Magtheridon if (Counter >= ACTIVE_CUBES_TO_BANISH && Magtheridon && Magtheridon->isAlive()) { Magtheridon->CastSpell(Magtheridon, dbcSpell.LookupEntry(BANISH), true); Magtheridon->GetAIInterface()->StopMovement(3000); Magtheridon->setAttackTimer(3000, false); if(Magtheridon->GetCurrentSpell()) Magtheridon->GetCurrentSpell()->cancel(); // We add channeling player aura that does not allow that go to be used again in 1.3 min Aura *aura = new Aura( dbcSpell.LookupEntry(MIND_EXHAUSTION), 78000, Magtheridon, Channeler); Channeler->AddAura(aura); MagYell = true; return; } // If not enough Cubes are active we eventually Banish from Magtheridon if (Counter < ACTIVE_CUBES_TO_BANISH && Magtheridon && Magtheridon->isAlive()) { Magtheridon->RemoveAura(BANISH); MagYell = true; } } static GameObjectAIScript *Create(GameObject * GO) { return new ManticronCubeGO(GO); } protected: bool MagYell; float x, y, z; Unit* Magtheridon; Player* Channeler; Unit* CubeTrigger; }; #define CN_CUBE_TRIGGER 17376 class CubeTriggerAI : public CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(CubeTriggerAI); CubeTriggerAI(Creature* pCreature) : CreatureAIScript(pCreature) { _unit->SetUInt64Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); _unit->GetAIInterface()->SetAllowedToEnterCombat(false); } }; // Hellfire Warder #define CN_HELLFIRE_WARDER 18829 #define HW_SHADOW_BOLT_VOLLEY 36275 // 39175 #define SHADOW_WORD_PAIN 34441 #define UNSTABLE_AFFLICTION 35183 #define DEATH_COIL 33130 #define RAIN_OF_FIRE 34435 #define HW_FEAR 34259 // this one is probably wrong #define SHADOW_BURST 34436 class HellfireWarderAI : public CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(HellfireWarderAI); SP_AI_Spell spells[7]; bool m_spellcheck[7]; HellfireWarderAI(Creature* pCreature) : CreatureAIScript(pCreature) { nrspells = 7; for(int i=0;iGetUInt32Value(UNIT_FIELD_BASEATTACKTIME)); for (int i = 0; i < nrspells; i++) spells[i].casttime = 0; } void OnCombatStop(Unit *mTarget) { _unit->GetAIInterface()->setCurrentAgent(AGENT_NULL); _unit->GetAIInterface()->SetAIState(STATE_IDLE); RemoveAIUpdateEvent(); } void OnDied(Unit * mKiller) { RemoveAIUpdateEvent(); } void AIUpdate() { float val = (float)RandomFloat(100.0f); SpellCast(val); } void SpellCast(float val) { if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget()) { float comulativeperc = 0; Unit *target = NULL; for(int i=0;iGetAIInterface()->GetNextTarget(); switch(spells[i].targettype) { case TARGET_SELF: case TARGET_VARIOUS: _unit->CastSpell(_unit, spells[i].info, spells[i].instant); break; case TARGET_ATTACKING: _unit->CastSpell(target, spells[i].info, spells[i].instant); break; case TARGET_DESTINATION: _unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break; case TARGET_RANDOM_FRIEND: case TARGET_RANDOM_SINGLE: case TARGET_RANDOM_DESTINATION: CastSpellOnRandomTarget(i, spells[i].mindist2cast, spells[i].maxdist2cast, spells[i].minhp2cast, spells[i].maxhp2cast); break; } m_spellcheck[i] = false; return; } uint32 t = (uint32)time(NULL); if(val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger) && t > spells[i].casttime) { _unit->setAttackTimer(spells[i].attackstoptimer, false); spells[i].casttime = t + spells[i].cooldown; m_spellcheck[i] = true; } comulativeperc += spells[i].perctrigger; } } } void CastSpellOnRandomTarget(uint32 i, float mindist2cast, float maxdist2cast, int minhp2cast, int maxhp2cast) { if (!maxdist2cast) maxdist2cast = 100.0f; if (!maxhp2cast) maxhp2cast = 100; if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget()) { std::vector TargetTable; /* From M4ksiu - Big THX to Capt who helped me with std stuff to make it simple and fully working <3 */ /* If anyone wants to use this function, then leave this note! */ for(set::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) { if (((spells[i].targettype == TARGET_RANDOM_FRIEND && isFriendly(_unit, (*itr))) || (spells[i].targettype != TARGET_RANDOM_FRIEND && isHostile(_unit, (*itr)) && (*itr) != _unit)) && ((*itr)->GetTypeId()== TYPEID_UNIT || (*itr)->GetTypeId() == TYPEID_PLAYER) && (*itr)->GetInstanceID() == _unit->GetInstanceID()) // isAttackable(_unit, (*itr)) && { Unit* RandomTarget = NULL; RandomTarget = (Unit*)(*itr); if (RandomTarget->isAlive() && _unit->GetDistance2dSq(RandomTarget) >= mindist2cast*mindist2cast && _unit->GetDistance2dSq(RandomTarget) <= maxdist2cast*maxdist2cast && ((RandomTarget->GetHealthPct() >= minhp2cast && RandomTarget->GetHealthPct() <= maxhp2cast && spells[i].targettype == TARGET_RANDOM_FRIEND) || (_unit->GetAIInterface()->getThreatByPtr(RandomTarget) > 0 && isHostile(_unit, RandomTarget)))) { TargetTable.push_back(RandomTarget); } } } if (_unit->GetHealthPct() >= minhp2cast && _unit->GetHealthPct() <= maxhp2cast && spells[i].targettype == TARGET_RANDOM_FRIEND) TargetTable.push_back(_unit); if (!TargetTable.size()) return; size_t RandTarget = rand()%TargetTable.size(); Unit * RTarget = TargetTable[RandTarget]; if (!RTarget) return; switch (spells[i].targettype) { case TARGET_RANDOM_FRIEND: case TARGET_RANDOM_SINGLE: _unit->CastSpell(RTarget, spells[i].info, spells[i].instant); break; case TARGET_RANDOM_DESTINATION: _unit->CastSpellAoF(RTarget->GetPositionX(), RTarget->GetPositionY(), RTarget->GetPositionZ(), spells[i].info, spells[i].instant); break; } TargetTable.clear(); } } protected: int nrspells; }; // Hellfire Channeler #define CN_HELLFIRE_CHANNELER 17256 #define SHADOW_BOLT_VOLLEY 30510 // 39175 #define FEAR 30615 // not sure #define DARK_MENDING 30528 #define BURNING_ABYSSAL 30511 class HellfireChannelerAI : public CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(HellfireChannelerAI); SP_AI_Spell spells[5]; bool m_spellcheck[5]; HellfireChannelerAI(Creature* pCreature) : CreatureAIScript(pCreature) { nrspells = 4; for(int i=0;iGetAIInterface()->SetAllowedToEnterCombat(false); } void OnCombatStart(Unit* mTarget) { RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME)); _unit->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, 0); _unit->SetUInt32Value(UNIT_CHANNEL_SPELL, 0); for (int i = 0; i < nrspells; i++) spells[i].casttime = 0; } void OnCombatStop(Unit *mTarget) { _unit->GetAIInterface()->setCurrentAgent(AGENT_NULL); _unit->GetAIInterface()->SetAIState(STATE_IDLE); RemoveAIUpdateEvent(); if (_unit->isAlive()) { Unit* Magtheridon = NULL; Magtheridon = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(-22.657900f, 2.159050f, -0.345542f, 17257); if (Magtheridon && Magtheridon->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9)) { _unit->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, Magtheridon->GetGUID()); _unit->SetUInt32Value(UNIT_CHANNEL_SPELL, SHADOW_GRASP); Magtheridon->CastSpell(Magtheridon, dbcSpell.LookupEntry(BANISH), true); } } } void OnDamageTaken(Unit* mAttacker, float fAmount) { if (!_unit->GetAIInterface()->GetAllowedToEnterCombat()) _unit->GetAIInterface()->SetAllowedToEnterCombat(true); } void OnDied(Unit * mKiller) { RemoveAIUpdateEvent(); _unit->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, 0); _unit->SetUInt32Value(UNIT_CHANNEL_SPELL, 0); } void AIUpdate() { float val = (float)RandomFloat(100.0f); SpellCast(val); } void SpellCast(float val) { if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget()) { float comulativeperc = 0; Unit *target = NULL; for(int i=0;iGetAIInterface()->GetNextTarget(); switch(spells[i].targettype) { case TARGET_SELF: case TARGET_VARIOUS: _unit->CastSpell(_unit, spells[i].info, spells[i].instant); break; case TARGET_ATTACKING: _unit->CastSpell(target, spells[i].info, spells[i].instant); break; case TARGET_DESTINATION: _unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break; case TARGET_RANDOM_FRIEND: case TARGET_RANDOM_SINGLE: case TARGET_RANDOM_DESTINATION: CastSpellOnRandomTarget(i, spells[i].mindist2cast, spells[i].maxdist2cast, spells[i].minhp2cast, spells[i].maxhp2cast); break; } m_spellcheck[i] = false; return; } uint32 t = (uint32)time(NULL); if(val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger) && t > spells[i].casttime) { if (i == 2 && _unit->GetHealthPct() > 50) continue; _unit->setAttackTimer(spells[i].attackstoptimer, false); spells[i].casttime = t + spells[i].cooldown; m_spellcheck[i] = true; } comulativeperc += spells[i].perctrigger; } } } void CastSpellOnRandomTarget(uint32 i, float mindist2cast, float maxdist2cast, int minhp2cast, int maxhp2cast) { if (!maxdist2cast) maxdist2cast = 100.0f; if (!maxhp2cast) maxhp2cast = 100; if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget()) { std::vector TargetTable; /* From M4ksiu - Big THX to Capt who helped me with std stuff to make it simple and fully working <3 */ /* If anyone wants to use this function, then leave this note! */ for(set::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) { if (((spells[i].targettype == TARGET_RANDOM_FRIEND && isFriendly(_unit, (*itr))) || (spells[i].targettype != TARGET_RANDOM_FRIEND && isHostile(_unit, (*itr)) && (*itr) != _unit)) && ((*itr)->GetTypeId()== TYPEID_UNIT || (*itr)->GetTypeId() == TYPEID_PLAYER) && (*itr)->GetInstanceID() == _unit->GetInstanceID()) // isAttackable(_unit, (*itr)) && { Unit* RandomTarget = NULL; RandomTarget = (Unit*)(*itr); if (RandomTarget->isAlive() && _unit->GetDistance2dSq(RandomTarget) >= mindist2cast*mindist2cast && _unit->GetDistance2dSq(RandomTarget) <= maxdist2cast*maxdist2cast && ((RandomTarget->GetHealthPct() >= minhp2cast && RandomTarget->GetHealthPct() <= maxhp2cast && spells[i].targettype == TARGET_RANDOM_FRIEND) || (_unit->GetAIInterface()->getThreatByPtr(RandomTarget) > 0 && isHostile(_unit, RandomTarget)))) { TargetTable.push_back(RandomTarget); } } } if (_unit->GetHealthPct() >= minhp2cast && _unit->GetHealthPct() <= maxhp2cast && spells[i].targettype == TARGET_RANDOM_FRIEND) TargetTable.push_back(_unit); if (!TargetTable.size()) return; size_t RandTarget = rand()%TargetTable.size(); Unit * RTarget = TargetTable[RandTarget]; if (!RTarget) return; switch (spells[i].targettype) { case TARGET_RANDOM_FRIEND: case TARGET_RANDOM_SINGLE: _unit->CastSpell(RTarget, spells[i].info, spells[i].instant); break; case TARGET_RANDOM_DESTINATION: _unit->CastSpellAoF(RTarget->GetPositionX(), RTarget->GetPositionY(), RTarget->GetPositionZ(), spells[i].info, spells[i].instant); break; } TargetTable.clear(); } } protected: int nrspells; }; // Burning Abyssal AI #define CN_BURNING_ABYSSAL 17454 #define FIRE_BLAST 37110 class BurningAbyssalAI : public CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(BurningAbyssalAI); SP_AI_Spell spells[1]; bool m_spellcheck[1]; BurningAbyssalAI(Creature* pCreature) : CreatureAIScript(pCreature) { nrspells = 1; for(int i=0;im_noRespawn = true; } void OnCombatStart(Unit* mTarget) { RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME)); for (int i = 0; i < nrspells; i++) spells[i].casttime = 0; } void OnCombatStop(Unit *mTarget) { _unit->GetAIInterface()->setCurrentAgent(AGENT_NULL); _unit->GetAIInterface()->SetAIState(STATE_IDLE); RemoveAIUpdateEvent(); } void OnDied(Unit * mKiller) { RemoveAIUpdateEvent(); } void AIUpdate() { float val = (float)RandomFloat(100.0f); SpellCast(val); } void SpellCast(float val) { if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget()) { float comulativeperc = 0; Unit *target = NULL; for(int i=0;iGetAIInterface()->GetNextTarget(); switch(spells[i].targettype) { case TARGET_SELF: case TARGET_VARIOUS: _unit->CastSpell(_unit, spells[i].info, spells[i].instant); break; case TARGET_ATTACKING: _unit->CastSpell(target, spells[i].info, spells[i].instant); break; case TARGET_DESTINATION: _unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break; case TARGET_RANDOM_FRIEND: case TARGET_RANDOM_SINGLE: case TARGET_RANDOM_DESTINATION: CastSpellOnRandomTarget(i, spells[i].mindist2cast, spells[i].maxdist2cast, spells[i].minhp2cast, spells[i].maxhp2cast); break; } m_spellcheck[i] = false; return; } uint32 t = (uint32)time(NULL); if(val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger) && t > spells[i].casttime) { _unit->setAttackTimer(spells[i].attackstoptimer, false); spells[i].casttime = t + spells[i].cooldown; m_spellcheck[i] = true; } comulativeperc += spells[i].perctrigger; } } } void CastSpellOnRandomTarget(uint32 i, float mindist2cast, float maxdist2cast, int minhp2cast, int maxhp2cast) { if (!maxdist2cast) maxdist2cast = 100.0f; if (!maxhp2cast) maxhp2cast = 100; if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget()) { std::vector TargetTable; /* From M4ksiu - Big THX to Capt who helped me with std stuff to make it simple and fully working <3 */ /* If anyone wants to use this function, then leave this note! */ for(set::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) { if (((spells[i].targettype == TARGET_RANDOM_FRIEND && isFriendly(_unit, (*itr))) || (spells[i].targettype != TARGET_RANDOM_FRIEND && isHostile(_unit, (*itr)) && (*itr) != _unit)) && ((*itr)->GetTypeId()== TYPEID_UNIT || (*itr)->GetTypeId() == TYPEID_PLAYER) && (*itr)->GetInstanceID() == _unit->GetInstanceID()) // isAttackable(_unit, (*itr)) && { Unit* RandomTarget = NULL; RandomTarget = (Unit*)(*itr); if (RandomTarget->isAlive() && _unit->GetDistance2dSq(RandomTarget) >= mindist2cast*mindist2cast && _unit->GetDistance2dSq(RandomTarget) <= maxdist2cast*maxdist2cast && ((RandomTarget->GetHealthPct() >= minhp2cast && RandomTarget->GetHealthPct() <= maxhp2cast && spells[i].targettype == TARGET_RANDOM_FRIEND) || (_unit->GetAIInterface()->getThreatByPtr(RandomTarget) > 0 && isHostile(_unit, RandomTarget)))) { TargetTable.push_back(RandomTarget); } } } if (_unit->GetHealthPct() >= minhp2cast && _unit->GetHealthPct() <= maxhp2cast && spells[i].targettype == TARGET_RANDOM_FRIEND) TargetTable.push_back(_unit); if (!TargetTable.size()) return; size_t RandTarget = rand()%TargetTable.size(); Unit * RTarget = TargetTable[RandTarget]; if (!RTarget) return; switch (spells[i].targettype) { case TARGET_RANDOM_FRIEND: case TARGET_RANDOM_SINGLE: _unit->CastSpell(RTarget, spells[i].info, spells[i].instant); break; case TARGET_RANDOM_DESTINATION: _unit->CastSpellAoF(RTarget->GetPositionX(), RTarget->GetPositionY(), RTarget->GetPositionZ(), spells[i].info, spells[i].instant); break; } TargetTable.clear(); } } protected: int nrspells; }; // Magtheridon #define CN_MAGTHERIDON 17257 // Normal Casts #define CLEAVE 31345 // not sure; should be better, but not sure if it gives 8k dmg #define CONFLAGRATION 23023 // 35840 - this one was affecting caster; not sure - it's not right spell, but better than nothing for now // Timed Casts #define QUAKE1 30571 // Each 40 sec after Phase 2 starts #define QUAKE2 30658 // Effect #define BLAST_NOVA 30616 // Each 60 sec after Phase 2 starts #define CAVE_IN 36240 // don't know correct timer #define CAMERA_SHAKE 36455 // is used when Magtheridon uses Cave In #define ENRAGE 34624 // dunno if it's correct spell -- 20 min after Phase 2 starts class MagtheridonAI : public CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(MagtheridonAI); SP_AI_Spell spells[7]; bool m_spellcheck[7]; MagtheridonAI(Creature* pCreature) : CreatureAIScript(pCreature) { nrspells = 2; for(int i=0;iSetUInt64Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9); Aura * aura = new Aura(dbcSpell.LookupEntry(BANISHMENT), -1, _unit, _unit); _unit->AddAura(aura); _unit->CastSpell(_unit, dbcSpell.LookupEntry(BANISH), true); _unit->GetAIInterface()->SetAllowedToEnterCombat(false); _unit->SetUInt32Value(UNIT_FIELD_BYTES_2, 1); timer_quake = timer_enrage = timer_blastNova = timer_caveIn = 0; PhaseSwitch = false; } void OnCombatStart(Unit* mTarget) { timer_quake = timer_enrage = timer_blastNova = timer_caveIn = 0; PhaseSwitch = false; RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME)); for (int i = 0; i < nrspells; i++) spells[i].casttime = 0; GameObject *Gate = _unit->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(-72.5866f, 1.559f, 0.0f, 183847); if (Gate) Gate->SetUInt32Value(GAMEOBJECT_STATE, 1); } void OnCombatStop(Unit *mTarget) { _unit->GetAIInterface()->setCurrentAgent(AGENT_NULL); _unit->GetAIInterface()->SetAIState(STATE_IDLE); RemoveAIUpdateEvent(); if (_unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9) || _unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2)) return; GameObject* Gate = NULL; for (int i = 0; i < 6; i++) { Gate = _unit->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(Columns[i].x, Columns[i].y, Columns[i].z, 184634+i); if (Gate) Gate->SetUInt32Value(GAMEOBJECT_STATE, 1); } Gate = _unit->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(0.0f, 0.0f, 0.0f, 184653); if (Gate) Gate->SetUInt32Value(GAMEOBJECT_STATE, 1); Gate = _unit->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(-72.5866f, 1.559f, 0.0f, 183847); if (Gate) Gate->SetUInt32Value(GAMEOBJECT_STATE, 0); } void OnDied(Unit * mKiller) { _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "The Legion... will consume you... all...."); _unit->PlaySoundToSet(10258); RemoveAIUpdateEvent(); } void OnTargetDied(Unit* mTarget) { if (_unit->GetHealthPct() > 0) { _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Did you think me weak? Soft? Who is the weak one now?!"); _unit->PlaySoundToSet(10255); } } void AIUpdate() { if (PhaseSwitch) PhaseThree(); else PhaseTwo(); } void PhaseTwo() { Aura *aura = _unit->FindAura(BANISH); if (_unit->GetHealthPct() <= 30) { timer_caveIn = 1; PhaseSwitch = true; } timer_quake++; timer_enrage++; timer_blastNova++; if (timer_quake > 27) { if (timer_quake < 33) { _unit->CastSpell(_unit, spells[2].info, spells[2].instant); for (int i = 0; i < 6; i++) { Unit* Trigger = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(CaveInPos[i].x, CaveInPos[i].y, CaveInPos[i].z, 17474); if (Trigger) { Trigger->CastSpell(Trigger, spells[3].info, spells[3].instant); } } } if (timer_quake == 32) timer_quake = 0; } if (timer_blastNova == 33) { _unit->SendChatMessageAlternateEntry(17257, CHAT_MSG_RAID_BOSS_EMOTE, LANG_UNIVERSAL, " begins to cast Blast Nova!"); } if(timer_blastNova > 33 && _unit->GetCurrentSpell() == NULL && !aura) { _unit->GetAIInterface()->StopMovement(3000); _unit->setAttackTimer(3000, false); _unit->CastSpell(_unit, dbcSpell.LookupEntry(BLAST_NOVA), false); timer_blastNova = 0; timer_quake = 0; return; } if(timer_enrage > 667 && _unit->GetCurrentSpell() == NULL && !aura) { _unit->CastSpell(_unit, dbcSpell.LookupEntry(ENRAGE), true); timer_enrage = 0; } if (!aura) { float val = (float)RandomFloat(100.0f); SpellCast(val); } } void PhaseThree() { Aura *aura = _unit->FindAura(BANISH); timer_quake++; timer_enrage++; timer_blastNova++; if (timer_quake > 27) { if (timer_quake < 33) { _unit->CastSpell(_unit, spells[2].info, spells[2].instant); for (int i = 0; i < 6; i++) { Unit* Trigger = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(CaveInPos[i].x, CaveInPos[i].y, CaveInPos[i].z, 17474); if (Trigger) { Trigger->CastSpell(Trigger, spells[3].info, spells[3].instant); } } } if (timer_quake == 32) timer_quake = 0; } if (timer_blastNova == 33) { _unit->SendChatMessageAlternateEntry(17257, CHAT_MSG_RAID_BOSS_EMOTE, LANG_UNIVERSAL, " begins to cast Blast Nova!"); } if(timer_blastNova > 33 && _unit->GetCurrentSpell() == NULL && !aura) { _unit->GetAIInterface()->StopMovement(3000); _unit->setAttackTimer(3000, false); _unit->CastSpell(_unit, dbcSpell.LookupEntry(BLAST_NOVA), false); timer_blastNova = 0; timer_quake = 0; return; } if(timer_caveIn && (timer_caveIn != 1 || (_unit->GetCurrentSpell() == NULL && timer_caveIn == 1 && !aura))) { timer_caveIn++; if (timer_caveIn == 2) { _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I will not be taken so easily. Let the walls of this prison tremble... and FALL!!!"); _unit->PlaySoundToSet(10257); _unit->GetAIInterface()->StopMovement(2000); _unit->setAttackTimer(2000, false); _unit->CastSpell(_unit, dbcSpell.LookupEntry(CAMERA_SHAKE), true); return; } if (timer_caveIn == 3) { GameObject* Gate = NULL; for (int i = 0; i < 6; i++) { Gate = _unit->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(Columns[i].x, Columns[i].y, Columns[i].z, 184634+i); if (Gate) Gate->SetUInt32Value(GAMEOBJECT_STATE, 0); } Gate = _unit->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(0.0f, 0.0f, 0.0f, 184653); if (Gate) Gate->SetUInt32Value(GAMEOBJECT_STATE, 0); } if (timer_caveIn == 5) { for (int i = 0; i < 6; i++) { Unit* Trigger = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(CaveInPos[i].x, CaveInPos[i].y, CaveInPos[i].z, 17474); if (Trigger) { Trigger->CastSpellAoF(CaveInPos[i].x, CaveInPos[i].y, CaveInPos[i].z, spells[5].info, spells[5].instant); } } timer_caveIn = 0; } } if(timer_enrage > 667 && _unit->GetCurrentSpell() == NULL && !aura) { _unit->CastSpell(_unit, dbcSpell.LookupEntry(ENRAGE), true); timer_enrage = 0; //return; } if (!aura) { float val = (float)RandomFloat(100.0f); SpellCast(val); } } void SpellCast(float val) { if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget()) { float comulativeperc = 0; Unit *target = NULL; for(int i=0;iGetAIInterface()->GetNextTarget(); switch(spells[i].targettype) { case TARGET_SELF: case TARGET_VARIOUS: _unit->CastSpell(_unit, spells[i].info, spells[i].instant); break; case TARGET_ATTACKING: _unit->CastSpell(target, spells[i].info, spells[i].instant); break; case TARGET_DESTINATION: _unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break; case TARGET_RANDOM_FRIEND: case TARGET_RANDOM_SINGLE: case TARGET_RANDOM_DESTINATION: CastSpellOnRandomTarget(i, spells[i].mindist2cast, spells[i].maxdist2cast, spells[i].minhp2cast, spells[i].maxhp2cast); break; } m_spellcheck[i] = false; return; } uint32 t = (uint32)time(NULL); if(val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger) && t > spells[i].casttime) { _unit->setAttackTimer(spells[i].attackstoptimer, false); spells[i].casttime = t + spells[i].cooldown; m_spellcheck[i] = true; } comulativeperc += spells[i].perctrigger; } } } void CastSpellOnRandomTarget(uint32 i, float mindist2cast, float maxdist2cast, int minhp2cast, int maxhp2cast) { if (!maxdist2cast) maxdist2cast = 100.0f; if (!maxhp2cast) maxhp2cast = 100; if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget()) { std::vector TargetTable; /* From M4ksiu - Big THX to Capt who helped me with std stuff to make it simple and fully working <3 */ /* If anyone wants to use this function, then leave this note! */ for(set::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) { if (((spells[i].targettype == TARGET_RANDOM_FRIEND && isFriendly(_unit, (*itr))) || (spells[i].targettype != TARGET_RANDOM_FRIEND && isHostile(_unit, (*itr)) && (*itr) != _unit)) && ((*itr)->GetTypeId()== TYPEID_UNIT || (*itr)->GetTypeId() == TYPEID_PLAYER) && (*itr)->GetInstanceID() == _unit->GetInstanceID()) // isAttackable(_unit, (*itr)) && { Unit* RandomTarget = NULL; RandomTarget = (Unit*)(*itr); if (RandomTarget->isAlive() && _unit->GetDistance2dSq(RandomTarget) >= mindist2cast*mindist2cast && _unit->GetDistance2dSq(RandomTarget) <= maxdist2cast*maxdist2cast && ((RandomTarget->GetHealthPct() >= minhp2cast && RandomTarget->GetHealthPct() <= maxhp2cast && spells[i].targettype == TARGET_RANDOM_FRIEND) || (_unit->GetAIInterface()->getThreatByPtr(RandomTarget) > 0 && isHostile(_unit, RandomTarget)))) { TargetTable.push_back(RandomTarget); } } } if (_unit->GetHealthPct() >= minhp2cast && _unit->GetHealthPct() <= maxhp2cast && spells[i].targettype == TARGET_RANDOM_FRIEND) TargetTable.push_back(_unit); if (!TargetTable.size()) return; size_t RandTarget = rand()%TargetTable.size(); Unit * RTarget = TargetTable[RandTarget]; if (!RTarget) return; switch (spells[i].targettype) { case TARGET_RANDOM_FRIEND: case TARGET_RANDOM_SINGLE: _unit->CastSpell(RTarget, spells[i].info, spells[i].instant); break; case TARGET_RANDOM_DESTINATION: _unit->CastSpellAoF(RTarget->GetPositionX(), RTarget->GetPositionY(), RTarget->GetPositionZ(), spells[i].info, spells[i].instant); break; } TargetTable.clear(); } } protected: int nrspells; int timer_quake; int timer_enrage; int timer_caveIn; int timer_blastNova; bool PhaseSwitch; }; void SetupMagtheridonsLair(ScriptMgr * mgr) { mgr->register_gameobject_script(MANTICRON_CUBE, &ManticronCubeGO::Create); mgr->register_creature_script(CN_MAGTHERIDON_TRIGGER, &MagtheridonTriggerAI::Create); mgr->register_creature_script(CN_CUBE_TRIGGER, &CubeTriggerAI::Create); mgr->register_creature_script(CN_HELLFIRE_WARDER, &HellfireWarderAI::Create); mgr->register_creature_script(CN_HELLFIRE_CHANNELER, &HellfireChannelerAI::Create); mgr->register_creature_script(CN_BURNING_ABYSSAL, &BurningAbyssalAI::Create); mgr->register_creature_script(CN_MAGTHERIDON, &MagtheridonAI::Create); }