Index: scripts/zone/black_temple/boss_bloodboil.cpp =================================================================== --- scripts/zone/black_temple/boss_bloodboil.cpp (revision 272) +++ scripts/zone/black_temple/boss_bloodboil.cpp (working copy) @@ -17,14 +17,13 @@ /* ScriptData SDName: Boss_Bloodboil SD%Complete: 80 -SDComment: Bloodboil not working correctly +SDComment: Bloodboil not working correctly, missing enrage SDCategory: Black Temple EndScriptData */ #include "../../sc_defines.h" #include "def_black_temple.h" #include "../../../../../game/TargetedMovementGenerator.h" -#include "../../../../../game/SpellAuras.h" //Spells #define SPELL_ACID_GEYSER 40630 @@ -76,19 +75,19 @@ struct MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI { boss_gurtogg_bloodboilAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - SetVariables(); - } + { + pInstance = ((ScriptedInstance*)c->GetInstanceData()); + SetVariables(); + } - ScriptedInstance* pInstance; + ScriptedInstance* pInstance; - uint64 TargetGUID; + uint64 TargetGUID; - float TargetThreat; + float TargetThreat; - uint32 BloodboilTimer; - uint32 BloodboilCount; + uint32 BloodboilTimer; + uint32 BloodboilCount; uint32 AcidGeyserTimer; uint32 AcidicWoundTimer; uint32 ArcingSmashTimer; @@ -120,6 +119,23 @@ PhaseChangeTimer = 60000; Phase1 = true; + + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); } void EnterEvadeMode() @@ -203,7 +219,7 @@ DoPlaySoundToSet(m_creature,SOUND_DEATH); } - // Note: This seems like a very complicated fix. + // Note: This seems like a very complicated fix. The fix needs to be handled by the core, as implementation of limited-target AoE spells are still not implemented. void CastBloodboil() { // Get the Threat List @@ -238,7 +254,6 @@ { uint8 eff = spellInfo->Effect[i]; if (eff>=TOTAL_SPELL_EFFECTS) - continue; Aura *Aur = new Aura(spellInfo, i, NULL, target); target->AddAura(Aur); @@ -313,7 +328,7 @@ if(BloodboilTimer < diff) { - CastBloodboil(); + DoCast(SelectUnit(SELECT_TARGET_RANDOM, 1), SPELL_BLOODBOIL); BloodboilCount++; if(BloodboilCount < 5) BloodboilTimer = 10000*BloodboilCount; Index: scripts/zone/black_temple/boss_illidan.cpp =================================================================== --- scripts/zone/black_temple/boss_illidan.cpp (revision 272) +++ scripts/zone/black_temple/boss_illidan.cpp (working copy) @@ -17,7 +17,7 @@ /* ScriptData SDName: boss_illidan_stormrage SD%Complete: 90 -SDComment: Eye Blast is buggy, some workarounds for Flame Crash and Parasitic Shadowfiend, unable to summon GOs. +SDComment: Eye Blast is buggy, some workarounds for Flame Crash, Flame Burst (damage portion) and Parasitic Shadowfiend, unable to summon GOs. SDCategory: Black Temple EndScriptData */ @@ -26,7 +26,6 @@ #include "def_black_temple.h" #include "../../../../../game/TargetedMovementGenerator.h" #include "../../../../../shared/WorldPacket.h" -#include "../../../../../game/SpellAuras.h" #include "../../../../../game/Player.h" #include "../../../../../game/GossipDef.h" @@ -36,89 +35,89 @@ // Intro speech with Akama #define SAY_INTRO_ILL1 "Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago." -#define SOUND_INTRO_ILL1 11463 // ~13 seconds +#define SOUND_INTRO_ILL1 11463 // ~13 seconds #define SAY_INTRO_AKA1 "We've come to end your reign, Illidan. My people and all of Outland shall be free!" -#define SOUND_INTRO_AKA1 11389 // ~12 seconds +#define SOUND_INTRO_AKA1 11389 // ~12 seconds #define SAY_INTRO_ILL2 "Boldly said. But I remain unconvinced." -#define SOUND_INTRO_ILL2 11464 // ~8 seconds +#define SOUND_INTRO_ILL2 11464 // ~8 seconds #define SAY_INTRO_AKA2 "The time has come! The moment is at hand!" -#define SOUND_INTRO_AKA2 11380 // ~5 seconds +#define SOUND_INTRO_AKA2 11380 // ~5 seconds #define SAY_INTRO_ILL3 "You are not prepared!" // He conjectures that your level of preparation could perhaps be improved somewhat -#define SOUND_INTRO_ILL3 11466 +#define SOUND_INTRO_ILL3 11466 // Signal for Akama to leave -#define SAY_AKAMA_MINION "Come, my minions. Deal with this traitor as he deserves!" -#define SOUND_AKAMA_MINION 11465 -#define SAY_AKAMA_LEAVE "I'll deal with these mongrels. Strike now, friends! Strike at the betrayer!" -#define SOUND_AKAMA_LEAVE 11390 +#define SAY_AKAMA_MINION "Come, my minions. Deal with this traitor as he deserves!" +#define SOUND_AKAMA_MINION 11465 +#define SAY_AKAMA_LEAVE "I'll deal with these mongrels. Strike now, friends! Strike at the betrayer!" +#define SOUND_AKAMA_LEAVE 11390 // Taunts? -#define SAY_HATRED "I can feel your hatred" -#define SOUND_HATRED 11467 -#define SAY_FEAR "Give in to your fear!" -#define SOUND_FEAR 11468 -#define SAY_POWER "You know nothing of power!" -#define SOUND_POWER 11469 -#define SAY_ARROGANCE "Such..arrogance!" -#define SOUND_ARROGANCE 11471 -#define SAY_RABBLE "I will not be touched by rabble such as you!" -#define SOUND_RABBLE 11479 +#define SAY_HATRED "I can feel your hatred" +#define SOUND_HATRED 11467 +#define SAY_FEAR "Give in to your fear!" +#define SOUND_FEAR 11468 +#define SAY_POWER "You know nothing of power!" +#define SOUND_POWER 11469 +#define SAY_ARROGANCE "Such..arrogance!" +#define SOUND_ARROGANCE 11471 // Maiev - Taunts -#define SAY_NAISHA "That is for Naisha!" -#define SOUND_NAISHA 11493 -#define SAY_BLEED "Bleed as I have bled!" -#define SOUND_BLEED 11494 -#define SAY_PRISON "There shall be no prison for you this time!" -#define SOUND_PRISON 11495 -#define SAY_MEET_END "Meet your end, demon!" -#define SOUND_MEET_END 11500 +#define SAY_NAISHA "That is for Naisha!" +#define SOUND_NAISHA 11493 +#define SAY_BLEED "Bleed as I have bled!" +#define SOUND_BLEED 11494 +#define SAY_PRISON "There shall be no prison for you this time!" +#define SOUND_PRISON 11495 +#define SAY_MEET_END "Meet your end, demon!" +#define SOUND_MEET_END 11500 -// Attacking Maeiv -#define SAY_ATT_MAIEV "Feel the hatred of ten thousand years!" -#define SOUND_ATT_MAIEV 11470 - // Self explanatory -#define SAY_KILL1 "Who shall be next to taste my blades?!" -#define SOUND_KILL1 11473 -#define SAY_KILL2 "This is too easy!" -#define SOUND_KILL2 11472 +#define SAY_KILL1 "Who shall be next to taste my blades?!" +#define SOUND_KILL1 11473 +#define SAY_KILL2 "This is too easy!" +#define SOUND_KILL2 11472 // I think I'll fly now and let my subordinates take you on -#define SAY_PHASE2 "Behold the flames of Azzinoth!" -#define SOUND_PHASE2 11480 +#define SAY_TAKEOFF "I will not be touched by rabble such as you!" +#define SOUND_TAKEOFF 11479 +#define SAY_SUMMONFLAMES "Behold the flames of Azzinoth!" +#define SOUND_SUMMONFLAMES 11480 // When casting Eye Blast. Demon Fire will be appear on places that he casts this -#define SAY_EYE_BLAST "Stare into the eyes of the Betrayer!" -#define SOUND_EYE_BLAST 11481 +#define SAY_EYE_BLAST "Stare into the eyes of the Betrayer!" +#define SOUND_EYE_BLAST 11481 // kk, I go big, dark and demon on you. -#define SAY_MORPH "Behold the power... of the demon within!" -#define SOUND_MORPH 11475 +#define SAY_MORPH "Behold the power... of the demon within!" +#define SOUND_MORPH 11475 // I KILL! -#define SAY_ENRAGE "You've wasted too much time mortals, now you shall fall!" -#define SOUND_ENRAGE 11474 +#define SAY_ENRAGE "You've wasted too much time mortals, now you shall fall!" +#define SOUND_ENRAGE 11474 // Speech when Maiev enters -#define SAY_SUMMON_MAIEV "Is this it, mortals? Is this all the fury you can muster?" -#define SOUND_SUMMON_MAIEV 11476 // ~8 seconds -#define SAY_MAIEV1 "Their fury pales before mine, Illidan. We have some unsettled business between us." -#define SOUND_MAIEV1 11491 // ~9 seconds -#define SAY_MAIEV_ILL2 "Maiev... How is this even possible?" -#define SOUND_MAIEV_ILL2 11477 // ~7 seconds -#define SAY_MAIEV2 "Ah, my long hunt is finally over. Today, Justice will be done!" -#define SOUND_MAIEV2 11492 // ~10 seconds +#define SAY_SUMMON_MAIEV "Is this it, mortals? Is this all the fury you can muster?" +#define SOUND_SUMMON_MAIEV 11476 // ~8 seconds +#define SAY_MAIEV1 "Their fury pales before mine, Illidan. We have some unsettled business between us." +#define SOUND_MAIEV1 11491 // ~9 seconds +#define SAY_MAIEV_ILL2 "Maiev... How is this even possible?" +#define SOUND_MAIEV_ILL2 11477 // ~7 seconds +#define SAY_MAIEV2 "Ah, my long hunt is finally over. Today, Justice will be done!" +#define SOUND_MAIEV2 11492 // ~10 seconds +// Attacking Maeiv +#define SAY_ATT_MAIEV "Feel the hatred of ten thousand years!" +#define SOUND_ATT_MAIEV 11470 + // Death speech -#define SAY_DEATH_MAIEV1 "Ahh... It is finished. You are beaten." -#define SOUND_DEATH_MAIEV1 11496 // ~6 seconds -#define SAY_DEATH_ILL "You have won... Maiev. But the huntress... is nothing without the hunt. You... are nothing... without me." -#define SOUND_DEATH_ILL 11478 // ~22 seconds -#define SAY_DEATH_MAIEV2 "He's right. I feel nothing. I am nothing. Farewell, champions." -#define SOUND_DEATH_MAIEV2 11497 // ~9 seconds -#define SAY_DEATH_AKA "The Light will fill these dismal halls once again. I swear it." -#define SOUND_DEATH_AKA 11387 // ~8 seconds +#define SAY_DEATH_MAIEV1 "Ahh... It is finished. You are beaten." +#define SOUND_DEATH_MAIEV1 11496 // ~6 seconds +#define SAY_DEATH_ILL "You have won... Maiev. But the huntress... is nothing without the hunt. You... are nothing... without me." +#define SOUND_DEATH_ILL 11478 // ~22 seconds +#define SAY_DEATH_MAIEV2 "He's right. I feel nothing. I am nothing. Farewell, champions." +#define SOUND_DEATH_MAIEV2 11497 // ~9 seconds +#define SAY_DEATH_AKA "The Light will fill these dismal halls once again. I swear it." +#define SOUND_DEATH_AKA 11387 // ~8 seconds /************** Spells *************/ // Normal Form @@ -170,59 +169,65 @@ #define Y_GLAIVE 305.303 #define Z_GLAIVE 354.256 -/**** Creature Summon IDs ****/ -#define CREATURE_BLADE_OF_AZZINOTH 22996 -#define CREATURE_FLAME_OF_AZZINOTH 22997 -#define CREATURE_MAIEV_SHADOWSONG 23197 -#define CREATURE_SHADOW_DEMON 23375 -#define CREATURE_TARGET_TRIGGER 17474 +/**** Creature Summon and Recognition IDs ****/ +enum CreatureEntry +{ + EMPTY = 0, + AKAMA = 22990, + ILLIDAN_STORMRAGE = 22917, + BLADE_OF_AZZINOTH = 22996, + FLAME_OF_AZZINOTH = 22997, + MAIEV_SHADOWSONG = 23197, + SHADOW_DEMON = 23375, + DEMON_FIRE = 23069, + FLAME_CRASH = 23336, +}; struct Yells { uint32 sound; char* text; - char* creature; + uint32 creature; uint32 timer, emote; bool Talk; }; static Yells Conversation[]= { - {SOUND_INTRO_ILL1, SAY_INTRO_ILL1, "Illidan", 8000, 0, true}, - {0, NULL, "Illidan", 5000, 396, true}, - {SOUND_INTRO_AKA1, SAY_INTRO_AKA1, "Akama", 7000, 25, true}, - {0, NULL, "Akama", 5000, 66, true}, - {SOUND_INTRO_ILL2, SAY_INTRO_ILL2, "Illidan", 8000, 396, true}, - {SOUND_INTRO_AKA2, SAY_INTRO_AKA2, "Akama", 3000, 22, true}, - {0, NULL, "Akama", 2000, 15, true}, - {SOUND_INTRO_ILL3, SAY_INTRO_ILL3, "Illidan", 3000, 406, true}, - {0, NULL, "Empty", 1000, 0, true}, - {0, NULL, "Empty", 0, 0, false}, - {SOUND_SUMMON_MAIEV, SAY_SUMMON_MAIEV, "Illidan", 8000, 0, true}, - {SOUND_MAIEV1, SAY_MAIEV1, "Maiev", 8000, 5, true}, - {SOUND_MAIEV_ILL2, SAY_MAIEV_ILL2, "Illidan", 7000, 1, true}, - {SOUND_MAIEV2, SAY_MAIEV2, "Maiev", 8000, 15, true}, - {SOUND_ATT_MAIEV, SAY_ATT_MAIEV, "Illidan", 1000, 0, false}, - {SOUND_DEATH_MAIEV1, SAY_DEATH_MAIEV1, "Maiev", 6000, 0, true}, - {SOUND_DEATH_ILL, SAY_DEATH_ILL, "Illidan", 22000, 65, true}, // Emote death but do not kill him - {SOUND_DEATH_MAIEV2, SAY_DEATH_MAIEV2, "Maiev", 9000, 0, true}, - {SOUND_DEATH_AKA, SAY_DEATH_AKA, "Akama", 8000, 0, false} + {SOUND_INTRO_ILL1, SAY_INTRO_ILL1, ILLIDAN_STORMRAGE, 8000, 0, true}, + {0, NULL, ILLIDAN_STORMRAGE, 5000, 396, true}, + {SOUND_INTRO_AKA1, SAY_INTRO_AKA1, AKAMA, 7000, 25, true}, + {0, NULL, AKAMA, 5000, 66, true}, + {SOUND_INTRO_ILL2, SAY_INTRO_ILL2, ILLIDAN_STORMRAGE, 8000, 396, true}, + {SOUND_INTRO_AKA2, SAY_INTRO_AKA2, AKAMA, 3000, 22, true}, + {0, NULL, AKAMA, 2000, 15, true}, + {SOUND_INTRO_ILL3, SAY_INTRO_ILL3, ILLIDAN_STORMRAGE, 3000, 406, true}, + {0, NULL, EMPTY, 1000, 0, true}, + {0, NULL, EMPTY, 0, 0, false}, + {SOUND_SUMMON_MAIEV, SAY_SUMMON_MAIEV, ILLIDAN_STORMRAGE, 8000, 0, true}, + {SOUND_MAIEV1, SAY_MAIEV1, MAIEV_SHADOWSONG, 8000, 5, true}, + {SOUND_MAIEV_ILL2, SAY_MAIEV_ILL2, ILLIDAN_STORMRAGE, 7000, 1, true}, + {SOUND_MAIEV2, SAY_MAIEV2, MAIEV_SHADOWSONG, 8000, 15, true}, + {SOUND_ATT_MAIEV, SAY_ATT_MAIEV, ILLIDAN_STORMRAGE, 1000, 0, false}, + {SOUND_DEATH_MAIEV1, SAY_DEATH_MAIEV1, MAIEV_SHADOWSONG, 6000, 0, true}, + {SOUND_DEATH_ILL, SAY_DEATH_ILL, ILLIDAN_STORMRAGE, 22000, 65, true}, // Emote death but do not kill him + {SOUND_DEATH_MAIEV2, SAY_DEATH_MAIEV2, MAIEV_SHADOWSONG, 9000, 0, true}, + {SOUND_DEATH_AKA, SAY_DEATH_AKA, AKAMA, 8000, 0, false} }; static Yells RandomTaunts[]= { - {SOUND_HATRED, SAY_HATRED, "Illidan", 0, 0, false}, - {SOUND_FEAR, SAY_FEAR, "Illidan", 0, 0, false}, - {SOUND_POWER, SAY_POWER, "Illidan", 0, 0, false}, - {SOUND_ARROGANCE, SAY_ARROGANCE, "Illidan", 0, 0, false}, - {SOUND_RABBLE, SAY_RABBLE, "Illidan", 0, 0, false} + {SOUND_HATRED, SAY_HATRED, ILLIDAN_STORMRAGE, 0, 0, false}, + {SOUND_FEAR, SAY_FEAR, ILLIDAN_STORMRAGE, 0, 0, false}, + {SOUND_POWER, SAY_POWER, ILLIDAN_STORMRAGE, 0, 0, false}, + {SOUND_ARROGANCE, SAY_ARROGANCE, ILLIDAN_STORMRAGE, 0, 0, false} }; static Yells MaievTaunts[]= { - {11493, "That is for Naisha!", "Maiev", 0, 0, false}, - {11494, "Bleed as I have bled!", "Maiev", 0, 0, false}, - {11495, "There shall be no prison for you this time!", "Maiev", 0, 0, false}, - {11500, "Meet your end, demon!", "Maiev", 0, 0, false}, + {SOUND_NAISHA, SAY_NAISHA, MAIEV_SHADOWSONG, 0, 0, false}, + {SOUND_BLEED, SAY_BLEED, MAIEV_SHADOWSONG, 0, 0, false}, + {SOUND_PRISON, SAY_PRISON, MAIEV_SHADOWSONG, 0, 0, false}, + {SOUND_MEET_END, SAY_MEET_END, MAIEV_SHADOWSONG, 0, 0, false} }; struct Locations @@ -241,10 +246,10 @@ static Locations EyeBlast[]= { - {653, 321, 354}, - {653, 275, 354}, - {702, 272, 353}, - {713, 325, 353} + {650.697, 320.128, 353.730}, + {652.799, 275.091, 353.367}, + {701.527, 273.815, 353.230}, + {709.865, 325.654, 353.322} }; static Locations CageTrap[]= @@ -266,7 +271,7 @@ static Animation DemonTransformation[]= { - {40511, 0, 1500, 0, 0, 6, true}, + {40511, 0, 1300, 0, 0, 6, true}, {40398, 40511, 4000, 0, 0, 6, true}, {0, 0, 3000, 1073741824, 21322, 6, false}, {40510, 40398, 3500, 0, 0, 6, false}, @@ -277,9 +282,65 @@ {40510, 40398, 3500, 0, 0, 6, true}, {0, 0, 0, 0, 0, 8, true} }; +/**** Demon Fire will be used for Eye Blast. Illidan needs to have access to it's vars and functions, so we'll set it here ****/ +struct MANGOS_DLL_DECL demonfireAI : public ScriptedAI +{ + demonfireAI(Creature *c) : ScriptedAI(c) {EnterEvadeMode();} + + bool IsWayPoint; + uint32 DemonFireTimer; + uint32 DespawnTimer; + + void EnterEvadeMode() + { + IsWayPoint = false; + + DemonFireTimer = 0; + DespawnTimer = 60000; + + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + DoGoHome(); + } + + void AttackStart(Unit *who) + { + if(!who || IsWayPoint || (who->GetTypeId() == TYPEID_PLAYER)) + return; + + if (who->isTargetableForAttack() && who!= m_creature) + { + //Begin melee attack if we are within range + DoStartMeleeAttack(who); + } + } + + void MoveInLineOfSight(Unit *who){ return; } + + void UpdateAI(const uint32 diff) + { + if(IsWayPoint) + return; + + if(DemonFireTimer < diff) + { + DoCast(m_creature, SPELL_DEMON_FIRE); + DemonFireTimer = 30000; + }else DemonFireTimer -= diff; + + if(DespawnTimer < diff) + { + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); + }else DespawnTimer -= diff; + + DoMeleeAttackIfReady(); + } +}; + /******* Functions and vars for Akama's AI ******/ - struct MANGOS_DLL_SPEC npc_akama_illidanAI : public ScriptedAI { npc_akama_illidanAI(Creature* c) : ScriptedAI(c) @@ -318,7 +379,7 @@ boss_illidan_stormrageAI(Creature* c) : ScriptedAI(c) { pInstance = ((ScriptedInstance*)c->GetInstanceData()); - SetVariables(); + EnterEvadeMode(); } /** Instance Data **/ @@ -373,28 +434,22 @@ { if(FlameGUID[i]) { - if(InCombat) + Unit* Flame = Unit::GetUnit((*m_creature), FlameGUID[i]); + if(Flame) { - Unit* Flame = Unit::GetUnit((*m_creature), FlameGUID[i]); - if(Flame) - { - Flame->SetVisibility(VISIBILITY_OFF); - Flame->DealDamage(Flame, Flame->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); - } + Flame->SetVisibility(VISIBILITY_OFF); + Flame->DealDamage(Flame, Flame->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); } FlameGUID[i] = 0; } if(GlaiveGUID[i]) { - if(InCombat) + Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]); + if(Glaive) { - Unit* Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]); - if(Glaive) - { - Glaive->SetVisibility(VISIBILITY_OFF); - Glaive->DealDamage(Glaive, Glaive->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); - } + Glaive->SetVisibility(VISIBILITY_OFF); + Glaive->DealDamage(Glaive, Glaive->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); } GlaiveGUID[i] = 0; } @@ -458,6 +513,24 @@ //m_creature->setFaction(35); // Start him off as friendly. m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + // Immunities + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); } void EnterEvadeMode() @@ -471,7 +544,7 @@ m_creature->RemoveAllAuras(); m_creature->DeleteThreatList(); m_creature->CombatStop(); - DoGoHome(); + m_creature->GetMotionMaster()->TargetedHome(); SetVariables(); } @@ -519,6 +592,8 @@ pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, 3); // Completed IsTalking = false; InCombat = false; + TalkCount = 0; + TalkTimer = 0; m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } @@ -541,7 +616,7 @@ void DamageTaken(Unit *done_by, uint32 &damage) { - if(damage>m_creature->GetHealth()) + if(damage>m_creature->GetHealth()) // Don't let ourselves be killed before we do our death speech { damage = 0; m_creature->SetHealth(m_creature->GetMaxHealth()/100); @@ -592,11 +667,11 @@ float final_Y = EyeBlast[final].y; float final_Z = EyeBlast[final].z; Creature* BlastTrigger = NULL; // This mob will have fun running across the summit and spawning Demon Fires - BlastTrigger = m_creature->SummonCreature(CREATURE_TARGET_TRIGGER, initial_X, initial_Y, initial_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 40000); + BlastTrigger = m_creature->SummonCreature(DEMON_FIRE, initial_X, initial_Y, initial_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 40000); Creature* BlueFlame = NULL; // This mob just does the Blue Flame animation. It follows close behind BlastTrigger...cosmetics ftw. - BlueFlame = m_creature->SummonCreature(CREATURE_TARGET_TRIGGER, initial_X,initial_Y,initial_Z,0,TEMPSUMMON_TIMED_DESPAWN,40000); + BlueFlame = m_creature->SummonCreature(DEMON_FIRE, initial_X,initial_Y,initial_Z,0,TEMPSUMMON_TIMED_DESPAWN,40000); Creature* MoveTarget = NULL; // This is the mob that BlastTrigger will run towards. - MoveTarget = m_creature->SummonCreature(CREATURE_TARGET_TRIGGER,final_X,final_Y,final_Z,0,TEMPSUMMON_TIMED_DESPAWN, 40000); + MoveTarget = m_creature->SummonCreature(DEMON_FIRE,final_X,final_Y,final_Z,0,TEMPSUMMON_TIMED_DESPAWN, 40000); if(BlastTrigger) { DoCast(BlastTrigger, SPELL_BLUE_BEAM); @@ -612,16 +687,21 @@ //BlueFlame->GetMotionMaster()->Clear(false); //BlueFlame->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*BlastTrigger)); BlueFlame->AddThreat(BlastTrigger, 1000000.0f); + BlueFlame->AI()->AttackStart(BlastTrigger); + BlueFlame->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*BlastTrigger)); BlastTrigger->SetHealth(100000); // Just so it won't die when attacked. BlueFlame->SetHealth(100000); } if(MoveTarget) { + ((demonfireAI*)MoveTarget->AI())->IsWayPoint = true; MoveTarget->SetUInt32Value(UNIT_FIELD_DISPLAYID, 11686); // Same reason as above two mobs... MoveTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // You know why... //BlastTrigger->GetMotionMaster()->Clear(false); //BlastTrigger->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*MoveTarget)); BlastTrigger->AddThreat(MoveTarget, 100000.0f); + BlastTrigger->AI()->AttackStart(MoveTarget); + BlastTrigger->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*MoveTarget)); MoveTarget->SetHealth(100000); // Same reason as BlastTrigger->SetHealth } } @@ -647,7 +727,7 @@ { std::list& m_threatlist = m_creature->getThreatManager().getThreatList(); std::list::iterator i = m_threatlist.begin(); - for(i = m_threatlist.begin(); i != m_threatlist.end(); ++i) + for(i = m_threatlist.begin(); i != m_threatlist.end(); ++i) // Go through threatlist and set threat to -100% for everyone in it. { Unit* pUnit = NULL; pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); @@ -662,56 +742,50 @@ void Talk(uint32 count) { uint32 sound = Conversation[count].sound; - char* text; + char* text = NULL; if(Conversation[count].text) text = Conversation[count].text; TalkTimer = Conversation[count].timer; uint32 emote = Conversation[count].emote; IsTalking = Conversation[count].Talk; - if(Conversation[count].creature == "Illidan") + Creature* creature = NULL; + uint64 GUID = 0; + if(Conversation[count].creature == ILLIDAN_STORMRAGE) + creature = m_creature; + else if(Conversation[count].creature == AKAMA) { - if(text) - DoYell(text, LANG_UNIVERSAL, NULL); - m_creature->HandleEmoteCommand(emote); - if(sound) - DoPlaySoundToSet(m_creature, sound); - } - else if(Conversation[count].creature == "Akama") - { if(!AkamaGUID) { if(pInstance) { AkamaGUID = pInstance->GetData64(DATA_AKAMA); - if(!AkamaGUID) return; + if(!AkamaGUID) + return; + GUID = AkamaGUID; } } - - Creature* Akama = ((Creature*)Unit::GetUnit((*m_creature), AkamaGUID)); - if(Akama) - { - if(text) - Akama->Yell(text, LANG_UNIVERSAL, 0); - Akama->HandleEmoteCommand(emote); - if(sound) - DoPlaySoundToSet(Akama, sound); - } + else GUID = AkamaGUID; } - else if(Conversation[count].creature == "Maiev") + else if(Conversation[count].creature == MAIEV_SHADOWSONG) { - if(!MaievGUID) return; - Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID)); - if(Maiev) - { - if(text) - Maiev->Yell(text, LANG_UNIVERSAL, 0); - Maiev->HandleEmoteCommand(emote); - if(sound) - DoPlaySoundToSet(Maiev, sound); - } + if(!MaievGUID) + return; + GUID = MaievGUID; } - else if(Conversation[count].creature == "Empty") // This is just for special cases without speech/sounds/emotes. + else if(Conversation[count].creature == EMPTY) // This is just for special cases without speech/sounds/emotes. return; + + if(GUID) // Now we check if we actually specified a GUID, if so: + creature = ((Creature*)Unit::GetUnit((*m_creature), GUID)); // we grab a pointer to that creature + + if(creature) + { + if(text) + creature->Yell(text, LANG_UNIVERSAL, 0); // Have the creature yell out some text + if(sound) + DoPlaySoundToSet(creature, sound); // Play some sound on the creature + creature->HandleEmoteCommand(emote); // Make the creature do some animation! + } } void Move(float X, float Y, float Z, uint32 Time, Unit* c, uint32 flags = 0x0200) @@ -758,27 +832,27 @@ DoCast(m_creature, aura, true); if(displayid) - m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, displayid); + m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, displayid); // It's morphin time! if(size) - m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, size); + m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, size); // Let us grow! (or shrink) if(DemonTransformation[count].equip) { - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); // Requip warglaives if needed m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); } else { - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); // Unequip warglaives if needed m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); } if(DemonTransformation[count].phase != 8) - Phase = DemonTransformation[count].phase; + Phase = DemonTransformation[count].phase; // Set phase properly else { - m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature->getVictim())); - if(MaievGUID) Phase = 5; + m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature->getVictim())); // Refollow and attack our old victim + if(MaievGUID) Phase = 5; // Depending on whether we summoned Maiev, we switch to either phase 5 or 3 else Phase = 3; } @@ -797,20 +871,20 @@ void UpdateAI(const uint32 diff) { /*** This section will handle the conversations ***/ - if(IsTalking) // Is there a better way to do this without a long switch statement? + if(IsTalking) // Somewhat more efficient using a function rather than a long switch { if(TalkTimer < diff) { switch(TalkCount) // This is only for specialized cases { case 0: - m_creature->RemoveAurasDueToSpell( SPELL_KNEEL ); + m_creature->RemoveAurasDueToSpell( SPELL_KNEEL ); // Time to stand up! break; case 8: - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); // Equip our warglaives! m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); - m_creature->HandleEmoteCommand(406); - m_creature->setFaction(14); + m_creature->HandleEmoteCommand(406); // Animate the equipping + m_creature->setFaction(14); // Hostile if we weren't before break; case 9: if(AkamaGUID) @@ -819,9 +893,9 @@ if(Akama) { Akama->GetMotionMaster()->Clear(false); - Akama->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature)); + Akama->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature)); // Akama runs to us! m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature)); + m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature)); // We run to Akama! Akama->AddThreat(m_creature, 1000000.0f); AttackStart(Akama); // Start attacking Akama ((npc_akama_illidanAI*)Akama->AI())->IsTalking = false; @@ -830,7 +904,7 @@ } m_creature->RemoveAllAuras(); // Remove any auras we have on us m_creature->setFaction(14); // Make him hostile after Intro is done. - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE); // We are now attackable! break; case 11: if(MaievGUID) @@ -838,10 +912,10 @@ Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID); if(Maiev) { - Maiev->SetVisibility(VISIBILITY_ON); - Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); - Maiev->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); - m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Maiev->GetGUID()); + Maiev->SetVisibility(VISIBILITY_ON); // Maiev is now visible + Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); // onoz she looks like she teleported! + Maiev->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->GetGUID()); // Have her face us + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Maiev->GetGUID()); // Face her, so it's not rude =P } } break; @@ -853,8 +927,8 @@ { Maiev->GetMotionMaster()->Clear(false); Maiev->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature)); + Maiev->AddThreat(m_creature, 10000000.0f); // Have Maiev add a lot of threat on us so that players don't pull her off if they damage her via AOE Maiev->AI()->AttackStart(m_creature); // Force Maiev to attack us. - Maiev->AddThreat(m_creature, 10000000.0f); // Have Maiev add a lot of threat on us so that players don't pull her off Maiev->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } } @@ -925,60 +999,67 @@ /** Signal to change to phase 2 **/ if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 65) && (Phase == 1)) { - SummonTimer = 10000; + DoYell(SAY_TAKEOFF, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_TAKEOFF); + + SummonTimer = 10000; // SUmmon the Glaives + Flames when this decrements Phase = 2; - m_creature->SetHover(true); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); - m_creature->GetMotionMaster()->Clear(false); + m_creature->SetHover(true); // We now hover! + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // So players don't shoot us down + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); // ANimate our take off! + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0); // We no longer wear the glaives! + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 0); // since they are now channeling the flames + m_creature->GetMotionMaster()->Clear(false); // Stop moving! } /** Signal to summon Maiev **/ if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30) && (!MaievGUID)) { - m_creature->setEmoteState(EMOTE_STATE_NONE); - m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); - Creature* Maiev = NULL; - Maiev = m_creature->SummonCreature(CREATURE_MAIEV_SHADOWSONG, m_creature->GetPositionX() + 10, m_creature->GetPositionY() + 5, m_creature->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->setEmoteState(EMOTE_STATE_NONE); // Stop whatever emote we might be doing + m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); // Interrupt any of our spells + Creature* Maiev = NULL; // Summon Maiev near Illidan + Maiev = m_creature->SummonCreature(MAIEV_SHADOWSONG, m_creature->GetPositionX() + 10, m_creature->GetPositionY() + 5, m_creature->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); if(Maiev) { - m_creature->GetMotionMaster()->Clear(false); + m_creature->GetMotionMaster()->Clear(false); // STop moving, it's rude to walk and talk! m_creature->GetMotionMaster()->Idle(); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // Just in case someone is unaffected by Shadow Prison DoCast(m_creature, SPELL_SHADOW_PRISON); TalkCount = 10; - IsTalking = true; + IsTalking = true; // We are now talking/ Maiev->SetVisibility(VISIBILITY_OFF); // Leave her invisible until she has to talk MaievGUID = Maiev->GetGUID(); } + else // If Maiev cannot be summoned, reset the encounter and post some errors to the console. + { + EnterEvadeMode(); + error_log("ERROR: Unable to summon Maiev Shadowsong (entry: 23197). Check your database to see if you have the proper SQL for Maiev Shadowsong (entry: 23197)"); + } } /** Time for the death speech **/ if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 1) && (!IsTalking)) { - DoCast(m_creature, SPELL_DEATH); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->GetMotionMaster()->Clear(false); + DoCast(m_creature, SPELL_DEATH); // Animate his kneeling + stun him + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // Don't let the players interrupt our talk! + m_creature->GetMotionMaster()->Clear(false); // No moving! m_creature->GetMotionMaster()->Idle(); if(MaievGUID) { Creature* Maiev = ((Creature*)Unit::GetUnit((*m_creature), MaievGUID)); if(Maiev) { - Maiev->CombatStop(); - Maiev->GetMotionMaster()->Clear(false); + Maiev->CombatStop(); // Maiev shouldn't do anything either. No point in her attacking us =] + Maiev->GetMotionMaster()->Clear(false); // Stop her from moving as well Maiev->GetMotionMaster()->Idle(); } } // Since we killed Akama before, summon him now. - Creature* Akama = DoSpawnCreature(22990, 10, 10, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 120000); + Creature* Akama = DoSpawnCreature(AKAMA, 10, 10, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000); if(Akama) { - ((npc_akama_illidanAI*)Akama->AI())->RunAway = true; // Since we are resummoning him, his vars are at the default. That means he'll yell the Minions speech out. We have to avoid that like this - AkamaGUID = Akama->GetGUID(); - Akama->SetVisibility(VISIBILITY_OFF); + AkamaGUID = Akama->GetGUID(); // Overwrite old GUID + Akama->SetVisibility(VISIBILITY_OFF); // Invisible for now, we'll make him visible during his turn to talk Akama->SetUInt32Value(UNIT_NPC_FLAGS, 0); // So they don't make him restart the event ~~ } IsTalking = true; @@ -988,13 +1069,15 @@ /***** Spells for Phase 1, 3 and 5 (Normal Form) ******/ if(Phase == 1 || Phase == 3 || Phase == 5) { - if(TauntTimer < diff) + if(TauntTimer < diff) // His random taunt/yell timer. { uint32 random = rand()%5; char* text = RandomTaunts[random].text; uint32 sound = RandomTaunts[random].sound; - DoYell(text, LANG_UNIVERSAL, NULL); - DoPlaySoundToSet(m_creature, sound); + if(text) + DoYell(text, LANG_UNIVERSAL, NULL); + if(sound) + DoPlaySoundToSet(m_creature, sound); TauntTimer = 32000; }else TauntTimer -= diff; @@ -1012,7 +1095,7 @@ // It spawns multiple flames sometimes. Therefore, we'll do this manually. // DoCast(m_creature->getVictim(), SPELL_FLAME_CRASH); m_creature->HandleEmoteCommand(402); - Creature* FlameCrash = DoSpawnCreature(23336, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 40000); + Creature* FlameCrash = DoSpawnCreature(FLAME_CRASH, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 40000); FlameCrashTimer = 35000; GlobalTimer += 2000; }else FlameCrashTimer -= diff; @@ -1023,9 +1106,9 @@ target = SelectUnit(SELECT_TARGET_RANDOM,1); if(target && target->isAlive()) { - DoCast(target, SPELL_PARASITIC_SHADOWFIEND); - ParasiticTargetGUID = target->GetGUID(); - SummonParasiticTimer = 10000; + DoCast(target, SPELL_PARASITIC_SHADOWFIEND); // The Parasitic Shadowfiend debuff doesn't summon 2 Shadowfiends on the target when it fades + ParasiticTargetGUID = target->GetGUID(); // So we'll do it somewhat manually by recording the afflicted target's GUID and setting the summon timer + SummonParasiticTimer = 10000; // Once the timer runs out, we cast the summon shadowfiend spell on the target and thereby summon the mobs. } ParasiticShadowFiendTimer = 40000; }else ParasiticShadowFiendTimer -= diff; @@ -1049,43 +1132,47 @@ { if(SummonTimer < diff) { + DoYell(SAY_SUMMONFLAMES, LANG_UNIVERSAL, NULL); + DoPlaySoundToSet(m_creature, SOUND_SUMMONFLAMES); + Creature* Flame1 = NULL; Creature* Flame2 = NULL; Creature* Glaive1 = NULL; Creature* Glaive2 = NULL; // Summon Glaives. - Glaive1 = m_creature->SummonCreature(CREATURE_BLADE_OF_AZZINOTH, X_GLAIVE1, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - Glaive2 = m_creature->SummonCreature(CREATURE_BLADE_OF_AZZINOTH, X_GLAIVE2, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + Glaive1 = m_creature->SummonCreature(BLADE_OF_AZZINOTH, X_GLAIVE1, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + Glaive2 = m_creature->SummonCreature(BLADE_OF_AZZINOTH, X_GLAIVE2, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); // Summon Flames near the Glaives and have the Glaives channel a green beam on the flames if(Glaive1) { - GlaiveGUID[0] = Glaive1->GetGUID(); - Glaive1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Flame1 = m_creature->SummonCreature(22997, X_GLAIVE1-5, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); + GlaiveGUID[0] = Glaive1->GetGUID(); // We'll need the GUID to later remove the Glaive + Glaive1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // They could be AoE'd to death if they were selectable + Flame1 = m_creature->SummonCreature(FLAME_OF_AZZINOTH, X_GLAIVE1-5, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // BRING ON THE FLAME! if(Flame1) { Flame1->SetUInt32Value(OBJECT_FIELD_SCALE_X, 1073741824); // Make the Flame bigger - Flame1->setFaction(m_creature->getFaction()); + Flame1->setFaction(m_creature->getFaction()); // Just in case the database has it as a different faction Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - Flame1->Attack(target); - FlameGUID[0] = Flame1->GetGUID(); - Glaive1->CastSpell(Flame1, SPELL_GREEN_BEAM, true); + Flame1->AI()->AttackStart(target); // Attack our target! + FlameGUID[0] = Flame1->GetGUID(); // Record GUID in order to check if they're dead later on to move to the next phase + Glaive1->CastSpell(Flame1, SPELL_GREEN_BEAM, true); // Glaives do some random Beam type channel on it. } } + // Rinse and repeat with Glaive #2 if(Glaive2) { GlaiveGUID[1] = Glaive2->GetGUID(); Glaive2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Flame2 = m_creature->SummonCreature(22997, X_GLAIVE2+5, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); + Flame2 = m_creature->SummonCreature(FLAME_OF_AZZINOTH, X_GLAIVE2+5, Y_GLAIVE, Z_GLAIVE, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); if(Flame2) { Flame2->SetUInt32Value(OBJECT_FIELD_SCALE_X, 1073741824); // BIG Flame Flame2->setFaction(m_creature->getFaction()); Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - Flame2->Attack(target); + Flame2->AI()->AttackStart(target); FlameGUID[1] = Flame2->GetGUID(); Glaive2->CastSpell(Flame2, SPELL_GREEN_BEAM, true); } @@ -1097,8 +1184,8 @@ // Check if we are hovering. Recast if we are not. if(!m_creature->isHover()) m_creature->SetHover(true); - if(!m_creature->GetMotionMaster()->empty()) - m_creature->GetMotionMaster()->Clear(false); +/* if(!m_creature->GetMotionMaster()->empty()) + m_creature->GetMotionMaster()->Clear(false);*/ if(HasSummoned) { @@ -1110,6 +1197,7 @@ Unit* Flame = NULL; Flame = Unit::GetUnit((*m_creature), FlameGUID[i]); + // If the flame dies, or somehow the pointer becomes invalid, reset GUID to 0. if(!Flame || !Flame->isAlive()) FlameGUID[i] = 0; } @@ -1125,23 +1213,23 @@ Unit* Glaive = NULL; Glaive = Unit::GetUnit((*m_creature), GlaiveGUID[i]); if(Glaive) - Glaive->DealDamage(Glaive, Glaive->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); + Glaive->DealDamage(Glaive, Glaive->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); // No point letting the Glaives continue to exist GlaiveGUID[i] = 0; - LandTimer = 10000; - m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); + LandTimer = 10000; // Prepare for landin! + m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); // Interrupt any spells we might be doing *cough* DArk Barrage *cough* } } if(LandTimer) { - if(LandTimer < diff) + if(LandTimer < diff) // Time to land! { m_creature->SetHover(false); - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); // anndddd touchdown! Phase = 3; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature->getVictim())); - m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // We should let the raid fight us =) + m_creature->GetMotionMaster()->Mutate(new TargetedMovementGenerator(*m_creature->getVictim())); // Chase our victim! + m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 45479); // Re-equip our warblades! m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY+1, 45481); }else LandTimer -= diff; return; // Do not continue past this point if LandTimer is not 0 and we are in phase 2. @@ -1239,11 +1327,18 @@ target = SelectUnit(SELECT_TARGET_RANDOM,0); if(target && target->GetTypeId() == TYPEID_PLAYER) // only on players. { - ShadowDemon = DoSpawnCreature(CREATURE_SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN,0); + ShadowDemon = DoSpawnCreature(SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN,0); if(ShadowDemon) { + ShadowDemon->AddThreat(target, 5000000.0f); ShadowDemon->AI()->AttackStart(target); - ShadowDemon->AddThreat(target, 5000000.0f); + // Run through threatlist and give Shadow Demons targets if they kill the initial one. + for(std::list::iterator itr = m_creature->getThreatManager().getThreatList().begin(); itr != m_creature->getThreatManager().getThreatList().end(); ++itr) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + if(pUnit && pUnit->isAlive()) + ShadowDemon->AddThreat(pUnit, 1.0f); + } } } } @@ -1255,13 +1350,13 @@ if(ShadowBlastTimer < diff) { Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0); - if(target) + if(target && target->isAlive()) { m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); - DoCast(SelectUnit(SELECT_TARGET_TOPAGGRO, 0), SPELL_SHADOW_BLAST); - } - ShadowBlastTimer = 4000; - GlobalTimer += 1500; + DoCast(target, SPELL_SHADOW_BLAST); + ShadowBlastTimer = 4000; + GlobalTimer += 1500; + }else EnterEvadeMode(); // There were issues where he got stuck in demon form after raid wiped, possibly because TOPAGGRO is still there but dead? }else ShadowBlastTimer -= diff; if(FlameBurstTimer < diff) @@ -1285,6 +1380,7 @@ TransformTimer += 10000; }else EnrageTimer -= diff; + // We'll handle Cage Trap in Illidan's script for simplicity's sake if(CageTimer < diff) { if(MaievGUID) @@ -1292,13 +1388,13 @@ Unit* Maiev = Unit::GetUnit((*m_creature), MaievGUID); if(!Maiev) return; - uint32 random = rand()%7; + uint32 random = rand()%7; // Get the location of a random cage trap float X = CageTrap[random].x; float Y = CageTrap[random].y; float Z = CageTrap[random].z; - Move(X, Y, Z, 0, Maiev); - Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); - Maiev->CastSpell(Maiev, SPELL_CAGE_TRAP_SUMMON, false); + Move(X, Y, Z, 0, Maiev); // Move Maiev there via our workaround + Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); // Make it look like she 'teleported' + Maiev->CastSpell(Maiev, SPELL_CAGE_TRAP_SUMMON, false); // summon the trap! } CageTimer = 15000; }else CageTimer -= diff; @@ -1325,7 +1421,6 @@ InCombat = false; IsTalking = false; - RunAway = false; m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 1); // Gossip flag m_creature->SetVisibility(VISIBILITY_ON); @@ -1428,7 +1523,7 @@ if(Illidan->IsInEvadeMode() && !m_creature->IsInEvadeMode()) EnterEvadeMode(); - if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 85) && (!RunAway)) + if(((Illidan->GetHealth()*100 / Illidan->GetMaxHealth()) < 85) && InCombat) { if(TalkTimer < diff) { @@ -1694,11 +1789,30 @@ FlameBlastTimer = 15000; SummonBlazeTimer = 10000; ChargeTimer = 5000; + + InCombat = false; + + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); } void EnterEvadeMode() { - InCombat = false; + SetVariables(); m_creature->RemoveAllAuras(); m_creature->DeleteThreatList(); @@ -1809,15 +1923,31 @@ uint64 TargetGUID; bool InCombat; - bool HasCast; void EnterEvadeMode() { TargetGUID = 0; InCombat = false; - HasCast = false; + + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); + m_creature->RemoveAllAuras(); m_creature->DeleteThreatList(); m_creature->CombatStop(); @@ -1877,22 +2007,17 @@ if(m_creature->getVictim()->GetTypeId() != TYPEID_PLAYER) return; // Only cast the below on players. - if(!HasCast) + if(!m_creature->getVictim()->HasAura(SPELL_PARALYZE, 0)) { TargetGUID = m_creature->getVictim()->GetGUID(); m_creature->AddThreat(m_creature->getVictim(), 10000000.0f); DoCast(m_creature, SPELL_SHADOW_DEMON_PASSIVE, true); DoCast(m_creature->getVictim(), SPELL_PURPLE_BEAM, true); DoCast(m_creature->getVictim(), SPELL_PARALYZE, true); - HasCast = true; } - + // Kill our target if we're very close. if(m_creature->IsWithinDistInMap(m_creature->getVictim(), 3)) - { - // Kill our target if we're very close. m_creature->DealDamage(m_creature->getVictim(), m_creature->getVictim()->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); - HasCast = false; // Just in case we aggro someone else after this - } } }; struct MANGOS_DLL_DECL flamecrashAI : public ScriptedAI @@ -1933,44 +2058,6 @@ } }; -struct MANGOS_DLL_DECL demonfireAI : public ScriptedAI -{ - demonfireAI(Creature *c) : ScriptedAI(c) {EnterEvadeMode();} - - uint32 DemonFireTimer; - uint32 DespawnTimer; - - void EnterEvadeMode() - { - DemonFireTimer = 0; - DespawnTimer = 60000; - - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - DoGoHome(); - } - - void AttackStart(Unit *who){ return; } - - void MoveInLineOfSight(Unit *who){ return; } - - void UpdateAI(const uint32 diff) - { - if(DemonFireTimer < diff) - { - DoCast(m_creature, SPELL_DEMON_FIRE); - DemonFireTimer = 30000; - }else DemonFireTimer -= diff; - - if(DespawnTimer < diff) - { - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_NORMAL, NULL, false); - }else DespawnTimer -= diff; - } -}; - struct MANGOS_DLL_DECL blazeAI : public ScriptedAI { blazeAI(Creature *c) : ScriptedAI(c) {EnterEvadeMode();} Index: scripts/zone/black_temple/boss_mother_shahraz.cpp =================================================================== --- scripts/zone/black_temple/boss_mother_shahraz.cpp (revision 272) +++ scripts/zone/black_temple/boss_mother_shahraz.cpp (working copy) @@ -25,6 +25,7 @@ #include "def_black_temple.h" #include "../../../../../game/Player.h" #include "../../../../../game/TargetedMovementGenerator.h" +#include "../../../../../shared/WorldPacket.h" //Spells #define SPELL_BEAM_SINISTER 40859 @@ -221,6 +222,47 @@ DoPlaySoundToSet(m_creature,SOUND_DEATH); } + void TeleportPlayers() + { + std::list m_threatlist = m_creature->getThreatManager().getThreatList(); + if(m_threatlist.empty()) + return; + std::list::iterator itr = m_threatlist.begin(); + std::list targets; + for( ; itr != m_threatlist.end(); ++itr) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + if(pUnit && pUnit->isAlive() && (pUnit->GetTypeId() == TYPEID_PLAYER) && (pUnit != m_creature->getVictim())) + targets.push_back(pUnit); + } + if(targets.empty() || (targets.size() < 3)) + return; + targets.resize(3); + uint32 random = rand()%7; + float X = TeleportPoint[random].x; + float Y = TeleportPoint[random].y; + float Z = TeleportPoint[random].z; + std::list::iterator i = targets.begin(); + uint32 index = 0; + for( ; i != targets.end(); ++itr) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + if(pUnit && pUnit->isAlive()) + { + if(index < 3) + { + TargetGUID[index] = pUnit->GetGUID(); + index++; + } + pUnit->CastSpell(pUnit, SPELL_TELEPORT_VISUAL, true); + WorldPacket data; + ((Player*)pUnit)->BuildTeleportAckMsg(&data, X, Y, Z, pUnit->GetOrientation()); + ((Player*)pUnit)->GetSession()->SendPacket(&data); + ((Player*)pUnit)->SetPosition(X, Y, Z, pUnit->GetOrientation(), true); + } + } + } + void UpdateAI(const uint32 diff) { if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) @@ -303,22 +345,9 @@ // Select 3 random targets (can select same target more than once), teleport to a random location then make them cast explosions until they get away from each other. if(FatalAttractionTimer < diff) { - uint32 random = rand()%7; - float X = TeleportPoint[random].x; - float Y = TeleportPoint[random].y; - float Z = TeleportPoint[random].z; ExplosionCount = 0; - for(uint32 i = 0; i<4; i++) - { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if (target && target->GetTypeId() == TYPEID_PLAYER) - { - ((Player*)target)->TeleportTo(m_creature->GetMapId(), X, Y, Z, target->GetOrientation()); - TargetGUID[i] = target->GetGUID(); - target->CastSpell(target, SPELL_TELEPORT_VISUAL, true); - } - } + TeleportPlayers(); switch(rand()%2) { Index: scripts/zone/black_temple/boss_reliquary_of_souls.cpp =================================================================== --- scripts/zone/black_temple/boss_reliquary_of_souls.cpp (revision 272) +++ scripts/zone/black_temple/boss_reliquary_of_souls.cpp (working copy) @@ -29,22 +29,16 @@ //Suffering #define SUFF_SAY_FREED "Pain and suffering are all that await you!" #define SUFF_SOUND_FREED 11415 - #define SUFF_SAY_AGGRO "Don't leave me alone!" #define SUFF_SOUND_AGGRO 11416 - #define SUFF_SAY_SLAY1 "Look at what you make me do!" #define SUFF_SOUND_SLAY1 11417 - #define SUFF_SAY_SLAY2 "I didn't ask for this!" #define SUFF_SOUND_SLAY2 11418 - #define SUFF_SAY_SLAY3 "The pain is only beginning!" #define SUFF_SOUND_SLAY3 11419 - #define SUFF_SAY_RECAP "I don't want to go back!" #define SUFF_SOUND_RECAP 11420 - #define SUFF_SAY_AFTER "Now what do I do?" #define SUFF_SOUND_AFTER 11421 @@ -52,48 +46,34 @@ //Desire #define DESI_SAY_FREED "You can have anything you desire... for a price." #define DESI_SOUND_FREED 11408 - #define DESI_SAY_SLAY1 "Fulfilment is at hand!" #define DESI_SOUND_SLAY1 11409 - #define DESI_SAY_SLAY2 "Yes... you'll stay with us now..." #define DESI_SOUND_SLAY2 11410 - #define DESI_SAY_SLAY3 "Your reach exceeds your grasp." #define DESI_SOUND_SLAY3 11412 - #define DESI_SAY_SPEC "Be careful what you wish for..." #define DESI_SOUND_SPEC 11411 - #define DESI_SAY_RECAP "I'll be waiting..." #define DESI_SOUND_RECAP 11413 - #define DESI_SAY_AFTER "I won't be far..." #define DESI_SOUND_AFTER 11414 //Anger #define ANGER_SAY_FREED "Beware... I live." #define ANGER_SOUND_FREED 11399 - #define ANGER_SAY_FREED2 "So... foolish." #define ANGER_SOUND_FREED2 11400 - #define ANGER_SOUND_SLAY1 11401 - #define ANGER_SAY_SLAY2 "Enough. No more." #define ANGER_SOUND_SLAY2 11402 - #define ANGER_SAY_SPEC "On your knees!" #define ANGER_SOUND_SPEC 11403 - #define ANGER_SAY_BEFORE "Beware, coward." #define ANGER_SOUND_BEFORE 11405 - #define ANGER_SAY_DEATH "I won't... be... ignored." #define ANGER_SOUND_DEATH 11404 - - //Spells #define AURA_OF_SUFFERING 41292 #define AURA_OF_SUFFERING_ARMOR 42017 @@ -298,6 +278,27 @@ m_creature->getThreatManager().setCurrentVictim(target->getThreatManager().getCurrentVictim()); // Set the target's current victim to ours. } + void AddImmunities(Unit* target) + { + if(!target) + return; + + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + target->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); + } void JustDied(Unit* killer) { InCombat = false; @@ -305,7 +306,7 @@ void UpdateAI(const uint32 diff) { - if(Phase == 0) + if(Phase == 0 || !m_creature->SelectHostilTarget()) return; if(Phase == 1) @@ -325,7 +326,9 @@ if(EssenceSuffering) { + AddImmunities(EssenceSuffering); EssenceSuffering->AddThreat(m_creature->getVictim(), 1.0f); + EssenceSuffering->AI()->AttackStart(m_creature->getVictim()); SufferingGUID = EssenceSuffering->GetGUID(); } @@ -422,10 +425,12 @@ if(EssenceDesire) { + AddImmunities(EssenceDesire); Unit* target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM, 0); EssenceDesire->AddThreat(target, 1.0f); + EssenceDesire->AI()->AttackStart(target); DesireGUID = EssenceDesire->GetGUID(); SoulDeathCount = 0; } @@ -519,11 +524,13 @@ { m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,373); // Ribs: open Creature* EssenceAnger = NULL; - EssenceAnger = m_creature->SummonCreature(23420, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_DEAD_DESPAWN, 0); + EssenceAnger = m_creature->SummonCreature(23420, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5000); if(EssenceAnger) { + AddImmunities(EssenceAnger); EssenceAnger->AddThreat(m_creature->getVictim(), 1.0f); + EssenceAnger->AI()->AttackStart(m_creature->getVictim()); AngerGUID = EssenceAnger->GetGUID(); DoPlaySoundToSet(m_creature, ANGER_SOUND_FREED); EssenceAnger->Yell(ANGER_SAY_FREED, LANG_UNIVERSAL, 0); Index: scripts/zone/black_temple/boss_shade_of_akama.cpp =================================================================== --- scripts/zone/black_temple/boss_shade_of_akama.cpp (revision 272) +++ scripts/zone/black_temple/boss_shade_of_akama.cpp (working copy) @@ -89,8 +89,11 @@ mob_ashtongue_channelerAI(Creature* c) : ScriptedAI(c) { SetVariables(); + pInstance = ((ScriptedInstance*)c->GetInstanceData()); } + ScriptedInstance* pInstance; + uint64 ShadeGUID; bool InCombat; @@ -127,11 +130,10 @@ { if(!InCombat) InCombat = true; - if(ShadeGUID) + if(!ShadeGUID) { - Unit* Shade = Unit::GetUnit((*m_creature), ShadeGUID); - if(Shade) - DoCast(Shade, SPELL_BEAM); + if(pInstance) + ShadeGUID = pInstance->GetData64(DATA_SHADEOFAKAMA); } } @@ -278,7 +280,23 @@ InCombat = false; HasKilledAkama = false; + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, SPELL_AURA_MOD_TAUNT, true); + m_creature->SetVisibility(VISIBILITY_ON); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); Index: scripts/zone/black_temple/boss_supremus.cpp =================================================================== --- scripts/zone/black_temple/boss_supremus.cpp (revision 272) +++ scripts/zone/black_temple/boss_supremus.cpp (working copy) @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Supremus -SD%Complete: 90 -SDComment: Using incorrect summon ids that are not official creature ids +SD%Complete: 98 +SDComment: Missing Enrage SDCategory: Black Temple EndScriptData */ @@ -196,11 +196,11 @@ void npc_volcanoAI::UpdateAI(const uint32 diff) { // Workaround for the visual of the fireball that is spammed around the volcano. This seems to cause lots of lag and maybe client freezes? - /* if(FireballTimer < diff) + if(FireballTimer < diff) { float X = CalculateRandomCoord(); float Y = CalculateRandomCoord(); - Creature* Target = DoSpawnCreature(24550, X, Y, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 1000); + Creature* Target = DoSpawnCreature(24550, X, Y, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 600); if(Target) { Target->SetVisibility(VISIBILITY_OFF); @@ -208,7 +208,7 @@ DoCast(Target, SPELL_VOLCANIC_FIREBALL); } FireballTimer = 500; - }else FireballTimer -= diff;*/ + }else FireballTimer -= diff; if(CheckTimer < diff) { @@ -260,6 +260,22 @@ SummonVolcanoTimer = 5000; Phase1 = true; + + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); } void EnterEvadeMode() Index: scripts/zone/black_temple/boss_teron_gorefiend.cpp =================================================================== --- scripts/zone/black_temple/boss_teron_gorefiend.cpp (revision 272) +++ scripts/zone/black_temple/boss_teron_gorefiend.cpp (working copy) @@ -25,15 +25,13 @@ EndScriptData */ //Spells - -#define SPELL_INCINERATE 40239 +#define SPELL_INCINERATE 40239 #define SPELL_CRUSHING_SHADOWS 40243 -#define SPELL_SHADOWBOLT 40185 +#define SPELL_SHADOWBOLT 40185 #define SPELL_PASSIVE_SHADOWFORM 41913 //Speech'n'sound - #define SAY_INTRO "I was the first, you know. For me, the wheel of death has spun many times. So much time has passed. I have a lot of catching up to do..." #define SOUND_INTRO 11512 @@ -65,12 +63,9 @@ #define SOUND_DEATH 11521 //Locations - #define Z_SUMMON 193.201141 - #define X_SUMMON1 527.814087 #define Y_SUMMON1 380.843170 - #define X_SUMMON2 527.814087 #define Y_SUMMON2 421.829803 @@ -196,6 +191,22 @@ HasEnraged = false; m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE); // Start off unattackable so that the intro is done properly + + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); } void EnterEvadeMode() @@ -214,7 +225,7 @@ void AttackStart(Unit *who) { - if(!who || Intro) + if(!who || !InCombat) return; if(who->isTargetableForAttack() && who!= m_creature) @@ -239,7 +250,7 @@ m_creature->AddThreat(who, 1.0f); } - if(!InCombat && !Intro && m_creature->IsWithinDistInMap(who, 200.0f)) + if(!InCombat && !Intro && m_creature->IsWithinDistInMap(who, 200.0f) && (who->GetTypeId() == TYPEID_PLAYER)) { if(pInstance) pInstance->SetData(DATA_TERONGOREFIENDEVENT, 1); @@ -328,7 +339,8 @@ { Unit* pUnit = Unit::GetUnit((*m_creature), AggroTargetGUID); if(pUnit) AttackStart(pUnit); - } + }else EnterEvadeMode(); + }else AggroTimer -= diff; } Index: scripts/zone/black_temple/boss_warlord_najentus.cpp =================================================================== --- scripts/zone/black_temple/boss_warlord_najentus.cpp (revision 272) +++ scripts/zone/black_temple/boss_warlord_najentus.cpp (working copy) @@ -172,6 +172,23 @@ if(pInstance) pInstance->SetData(DATA_HIGHWARLORDNAJENTUSEVENT, 0); + + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); } void EnterEvadeMode() Index: scripts/zone/black_temple/illidari_council.cpp =================================================================== --- scripts/zone/black_temple/illidari_council.cpp (revision 272) +++ scripts/zone/black_temple/illidari_council.cpp (working copy) @@ -25,20 +25,21 @@ #include "def_black_temple.h" #include "../../../../../game/TargetedMovementGenerator.h" -//Spells - +// High Nethermancer Zerevor's spells #define SPELL_FLAMESTRIKE 41481 #define SPELL_BLIZZARD 41482 #define SPELL_ARCANE_BOLT 41483 #define SPELL_ARCANE_EXPLOSION 41524 #define SPELL_DAMPEN_MAGIC 41478 +// Lady Malande's spells #define SPELL_EMPOWERED_SMITE 41471 #define SPELL_CIRCLE_OF_HEALING 41455 #define SPELL_REFLECTIVE_SHIELD 41475 #define SPELL_DIVINE_WRATH 41472 #define SPELL_HEAL_VISUAL 24171 +// Gathios the Shatterer's spells #define SPELL_BLESS_PROTECTION 41450 #define SPELL_BLESS_SPELLWARD 41451 #define SPELL_CONSECRATION 41541 @@ -48,102 +49,73 @@ #define SPELL_CHROMATIC_AURA 41453 #define SPELL_DEVOTION_AURA 41452 +// Veras Darkshadow's spells #define SPELL_DEADLY_POISON 41485 #define SPELL_ENVENOM 41487 #define SPELL_VANISH 41479 //Speech'n'Sounds - #define SAY_GATH_AGGRO "I have better things to do!" #define SOUND_GATH_AGGRO 11422 - #define SAY_GATH_SLAY "Selama am'oronor!" #define SOUND_GATH_SLAY 11423 - #define SAY_GATH_COMNT "Well done!" #define SOUND_GATH_COMNT 11424 - #define SAY_GATH_DEATH "Lord Illidan... I..." #define SOUND_GATH_DEATH 11425 - #define SAY_GATH_SPECIAL1 "Enjoy your final moments!" #define SOUND_GATH_SPECIAL1 11426 - #define SAY_GATH_SPECIAL2 "You are mine!" #define SOUND_GATH_SPECIAL2 11427 - #define SAY_GATH_ENRAGE "Enough games!" #define SOUND_GATH_ENRAGE 11428 #define SAY_MALA_AGGRO "Flee, or die!" #define SOUND_MALA_AGGRO 11482 - #define SAY_MALA_SLAY "My work is done." #define SOUND_MALA_SLAY 11483 - #define SAY_MALA_COMNT "As it should be!" #define SOUND_MALA_COMNT 11484 - #define SAY_MALA_DEATH "Destiny... awaits." #define SOUND_MALA_DEATH 11485 - #define SAY_MALA_SPECIAL1 "No second chances!" #define SOUND_MALA_SPECIAL1 11486 - #define SAY_MALA_SPECIAL2 "I'm full of surprises!" #define SOUND_MALA_SPECIAL2 11487 - #define SAY_MALA_ENRAGE "For Quel'Thalas! For the Sunwell!" #define SOUND_MALA_ENRAGE 11488 #define SAY_ZERE_AGGRO "Common... such a crude language. Bandal!" #define SOUND_ZERE_AGGRO 11440 - #define SAY_ZERE_SLAY "Shorel'aran." #define SOUND_ZERE_SLAY 11441 - #define SAY_ZERE_COMNT "Belesa menoor!" #define SOUND_ZERE_COMNT 11442 - #define SAY_ZERE_DEATH "Diel ma'ahn... oreindel'o" #define SOUND_ZERE_DEATH 11443 - #define SAY_ZERE_SPECIAL1 "Diel fin'al" #define SOUND_ZERE_SPECIAL1 11444 - #define SAY_ZERE_SPECIAL2 "Sha'amoor ara mashal?" #define SOUND_ZERE_SPECIAL2 11445 - #define SAY_ZERE_ENRAGE "Sha'amoor sine menoor!" #define SOUND_ZERE_ENRAGE 11446 #define SAY_VERA_AGGRO "You wish to test me?" #define SOUND_VERA_AGGRO 11524 - #define SAY_VERA_SLAY "Valiant effort!" #define SOUND_VERA_SLAY 11525 - #define SAY_VERA_COMNT "A glorious kill!" #define SOUND_VERA_COMNT 11526 - #define SAY_VERA_DEATH "You got lucky!" #define SOUND_VERA_DEATH 11527 - #define SAY_VERA_SPECIAL1 "You're not caught up for this!" #define SOUND_VERA_SPECIAL1 11528 - #define SAY_VERA_SPECIAL2 "Anar'alah belore!" #define SOUND_VERA_SPECIAL2 11529 - #define SAY_VERA_ENRAGE "You wish to kill me? Hahaha, you first!" #define SOUND_VERA_ENRAGE 11530 -//Locations -#define X_VANISH 111.643913 -#define Y_VANISH 561.843872 -#define Z_VANISH 98.430679 - struct MANGOS_DLL_DECL boss_illidari_councilAI : public ScriptedAI { boss_illidari_councilAI(Creature *c) : ScriptedAI(c) @@ -251,18 +223,52 @@ Malande = ((Creature*)Unit::GetUnit((*m_creature), Council[2])); Veras = ((Creature*)Unit::GetUnit((*m_creature), Council[3])); if(Gathios) + { Gathios->AddThreat(target, 1.0f); + AddImmunitiesToCouncil(Gathios); + } if(Zerevor) + { Zerevor->AddThreat(target, 1.0f); + AddImmunitiesToCouncil(Zerevor); + } if(Malande) + { Malande->AddThreat(target, 1.0f); + AddImmunitiesToCouncil(Malande); + } if(Veras) + { Veras->AddThreat(target, 1.0f); + AddImmunitiesToCouncil(Veras); + } pInstance->SetData(DATA_ILLIDARICOUNCILEVENT, 1); } } + void AddImmunitiesToCouncil(Unit* Member) + { + if(!Member) + return; + + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISARM, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_INTERRUPT, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CONFUSED, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM , true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR , true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); + Member->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); + } + void UpdateAI(const uint32 diff) { if(!InCombat) return; @@ -732,8 +738,8 @@ { CastDampenMagicWorkaround(); Cooldown = 1000; - DampenMagicTimer = 2000; // Should be ~2 minutes. - ArcaneBoltTimer += 2000; + DampenMagicTimer = 5000; // Should be ~2 minutes. + ArcaneBoltTimer += 1000; }else DampenMagicTimer -= diff; if(ArcaneExplosionTimer < diff) @@ -1019,7 +1025,6 @@ AggroYellTimer = 0; HasVanished = false; - (*m_creature).GetMotionMaster()->Clear(false); m_creature->SetVisibility(VISIBILITY_ON); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } Index: scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp =================================================================== --- scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp (revision 272) +++ scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp (working copy) @@ -29,7 +29,8 @@ NextWaveTimer = 10000; WaveCount = 0; - CheckTimer = 0; + CheckRaidTimer = 0; + CheckBossTimer = 0; Faction = 0; EventBegun = false; @@ -42,8 +43,6 @@ void hyjalAI::EnterEvadeMode() { - SetVariables(); - m_creature->RemoveAllAuras(); m_creature->DeleteThreatList(); m_creature->CombatStop(); @@ -61,10 +60,10 @@ if(!InCombat) { + Talk(ATTACKED); InCombat = true; } } - } void hyjalAI::MoveInLineOfSight(Unit *who) @@ -88,6 +87,11 @@ } } +void hyjalAI::JustDied(Unit* killer) +{ + Talk(DEATH); +} + void hyjalAI::SetFaction(uint32 faction) { Faction = faction; @@ -119,7 +123,10 @@ { Unit* pUnit = Unit::GetUnit((*m_creature), PlayerGUID); if(pUnit) + { pCreature->AddThreat(pUnit, 10.0f); + pCreature->AI()->AttackStart(pUnit); + } } pCreature->AddThreat(m_creature, 1.0f); @@ -128,13 +135,16 @@ if(!FirstBossDead) BossGUID[0] = pCreature->GetGUID(); else BossGUID[1] = pCreature->GetGUID(); + CheckBossTimer = 5000; } } } - void hyjalAI::SummonNextWave(Wave wave[18], uint32 Count, uint32 faction) { + if(rand()%6 == 0) // 1 in 6 chance we give a rally yell. Not sure if the chance is Blizzlike. + Talk(RALLY); + if(wave[Count].IsBoss) SummonCreature(wave[Count].Mob1, true); @@ -240,10 +250,58 @@ return 0; } +void hyjalAI::Talk(uint32 id) +{ + std::list index; + for(uint8 i = 0; i < 9; i++) + { + if(Faction == 0) // Alliance + { + if(JainaQuotes[i].id == id) + index.push_back(i); + } + else if(Faction == 1) // Horde + { + if(ThrallQuotes[i].id == id) + index.push_back(i); + } + } + + if(index.empty()) + return; // No quotes found, no use to continue + + uint8 ind = *(index.begin()) + rand()%index.size(); + + char* Yell; + uint32 Sound; + if(Faction == 0) // Alliance + { + Yell = JainaQuotes[ind].text; + Sound = JainaQuotes[ind].sound; + } + else if(Faction == 1) // Horde + { + Yell = ThrallQuotes[ind].text; + Sound = ThrallQuotes[ind].sound; + } + if(Yell) + DoYell(Yell, LANG_UNIVERSAL, NULL); + if(Sound) + DoPlaySoundToSet(m_creature, Sound); +} + +void hyjalAI::Debug(char* text, ...) +{ +/* if(text) + sWorld.SendZoneText(m_creature->GetZoneId(), text); */ + if(text) + debug_log(text); +} + void hyjalAI::UpdateAI(const uint32 diff) { if(!EventBegun) return; - +/* if(NextWaveTimer) { if(NextWaveTimer < diff) @@ -255,8 +313,8 @@ WaveCount++; }else NextWaveTimer -= diff; } - - if(CheckTimer < diff) +*/ + if(CheckRaidTimer < diff) { if(NextWaveTimer) { @@ -284,7 +342,7 @@ { Player* member = ((Player*)Unit::GetUnit((*m_creature), itr->guid)); - if(member->GetMapId() != m_creature->GetMapId()) // Make sure they are in the same map. + if(member && (member->GetMapId() != m_creature->GetMapId())) // Make sure they are in the same map. break; if(member && member->isAlive()) @@ -292,40 +350,60 @@ else DeathCount++; + Debug("Raid Count is %d", RaidCount); RaidCount++; } if(DeathCount == RaidCount) { + Talk(FAILED); EventBegun = false; EnterEvadeMode(); + SetVariables(); } }else { EventBegun = false; EnterEvadeMode(); + SetVariables(); } } } } + CheckRaidTimer = 25000; + }else CheckRaidTimer -= diff; - for(uint8 i = 0; i < 2; i++) + if(CheckBossTimer) + { + if(CheckBossTimer < diff) { - if(BossGUID[i]) + Debug("Checking for boss deaths..."); + for(uint8 i = 0; i < 2; i++) { - Unit* pUnit = Unit::GetUnit((*m_creature), BossGUID[i]); - if(pUnit && (!pUnit->isAlive())) + if(BossGUID[i]) { - if(BossGUID[i] == BossGUID[0]) - FirstBossDead = true; - else if(BossGUID[i] == BossGUID[1]) - SecondBossDead = true; - m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 1); - BossGUID[i] = 0; + Unit* pUnit = Unit::GetUnit((*m_creature), BossGUID[i]); + if(pUnit && (!pUnit->isAlive())) + { + Debug("Boss death detected..."); + if(BossGUID[i] == BossGUID[0]) + { + Talk(INCOMING); + FirstBossDead = true; + } + else if(BossGUID[i] == BossGUID[1]) + { + Talk(SUCCESS); + SecondBossDead = true; + } + CheckBossTimer = 0; + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 1); + BossGUID[i] = 0; + } } + CheckBossTimer = 5000; } - } - CheckTimer = 25000; - }else CheckTimer -= diff; + }else CheckBossTimer -= diff; + } if(!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return; Index: scripts/zone/caverns_of_time/hyjal/hyjalAI.h =================================================================== --- scripts/zone/caverns_of_time/hyjal/hyjalAI.h (revision 272) +++ scripts/zone/caverns_of_time/hyjal/hyjalAI.h (working copy) @@ -18,6 +18,8 @@ #include "../../../../../../game/Player.h" #include "../../../../../../game/Group.h" #include "../../../../../../game/GossipDef.h" +//#include "../../../../../../game/World.h" +//#include "../../../../../../game/WorldSession.h" // Trash Mobs summoned in waves #define NECROMANCER 17899 @@ -138,26 +140,28 @@ static Yells JainaQuotes[]= { - {ATTACKED, "I'm in jeopardy, help me if you can!", 0}, - {ATTACKED, "They've broken through!", 0}, - {INCOMING, "Stay alert! Another wave approaches.", 0}, - {RALLY, "Don't give up! We must prevail!", 0}, - {RALLY, "We must hold strong!", 0}, - {FAILED, "We are lost. Fall back!", 0}, - {SUCCESS, "We have won valuable time. Now we must pull back!", 0}, - {SUCCESS, "We have played our part and done well. It is up to the others now.", 0}, - {DEATH, "I did... my best.", 0}, + {ATTACKED, "I'm in jeopardy, help me if you can!", 11007}, + {ATTACKED, "They've broken through!", 11049}, + {INCOMING, "Stay alert! Another wave approaches.", 11008}, + {RALLY, "Don't give up! We must prevail!", 11006}, + {RALLY, "Hold them back as long as possible", 11050}, + {RALLY, "We must hold strong!", 11051}, + {FAILED, "We are lost. Fall back!", 11009}, + {SUCCESS, "We have won valuable time. Now we must pull back!", 11011}, + {DEATH, "I did... my best.", 11010}, }; static Yells ThrallQuotes[]= { - {ATTACKED, "I will lie down for no one!", 0}, - {ATTACKED, "Bring the fight to me and pay with your lives!", 0}, - {INCOMING, "Make ready for another wave! Lok-Tar Ogar!", 0}, - {RALLY, "Hold them back! Do not falter!", 0}, - {RALLY, "Victory or death!", 0}, - {RALLY, "Do not give an inch of ground!", 0}, - {FAILED, "It is over. Withdraw! We have failed.", 0}, + {ATTACKED, "I will lie down for no one!", 11031}, + {ATTACKED, "Bring the fight to me and pay with your lives!", 11051}, + {INCOMING, "Make ready for another wave! LOK-TAR OGAR!", 11032}, + {RALLY, "Hold them back! Do not falter!", 11030}, + {RALLY, "Victory or death!", 11059}, + {RALLY, "Do not give an inch of ground!", 11060}, + {FAILED, "It is over. Withdraw! We have failed.", 11033}, + {SUCCESS, "We have played our part and done well. It is up to the others now.", 11035}, + {DEATH, "Uraaa...", 11034}, }; struct MANGOS_DLL_DECL hyjalAI : public ScriptedAI @@ -174,6 +178,8 @@ void UpdateAI(const uint32 diff); + void JustDied(Unit* killer); + void SetFaction(uint32 faction); void TeleportRaid(Player *player, float X, float Y, float Z); @@ -189,6 +195,8 @@ uint32 GetInstanceData(uint32 Event); void Talk(uint32 id); + + void Debug(char* text, ...); public: ScriptedInstance* pInstance; @@ -197,7 +205,8 @@ uint32 NextWaveTimer; uint32 WaveCount; - uint32 CheckTimer; + uint32 CheckRaidTimer; + uint32 CheckBossTimer; uint32 Faction; bool EventBegun; @@ -206,4 +215,4 @@ private: bool InCombat; -}; +}; \ No newline at end of file Index: scripts/zone/caverns_of_time/hyjal/npc_hyjal.cpp =================================================================== --- scripts/zone/caverns_of_time/hyjal/npc_hyjal.cpp (revision 272) +++ scripts/zone/caverns_of_time/hyjal/npc_hyjal.cpp (working copy) @@ -170,4 +170,4 @@ newscript->Name = "npc_tyrande_whisperwind"; newscript->pGossipHello = &GossipHello_npc_tyrande_whisperwind; m_scripts[nrscripts++] = newscript; -} +} \ No newline at end of file