diff options
Diffstat (limited to 'src/server/scripts')
9 files changed, 1100 insertions, 492 deletions
| diff --git a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp index 5c8d4b8691a..8b83c9bf3bf 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp @@ -27,7 +27,8 @@ enum Spells      SPELL_EARTH_SHIELD                          = 54479,      SPELL_EARTH_SHOCK                           = 54511,      SPELL_LIGHTNING_BOLT                        = 53044, -    SPELL_STORMSTRIKE                           = 51876 +    SPELL_STORMSTRIKE                           = 51876, +    SPELL_WINDFURY                              = 54493  };  enum Yells @@ -40,6 +41,17 @@ enum Yells      SAY_BOTH_ADDS_KILLED                        = 5  }; +enum ErekemEvents +{ +    EVENT_EARTH_SHIELD                          = 1, +    EVENT_CHAIN_HEAL, +    EVENT_BLOODLUST, +    EVENT_LIGHTNING_BOLT, +    EVENT_EARTH_SHOCK, +    EVENT_WINDFURY, +    EVENT_STORMSTRIKE, +}; +  class boss_erekem : public CreatureScript  {  public: @@ -49,47 +61,57 @@ public:      {          boss_erekemAI(Creature* creature) : ScriptedAI(creature)          { -            Initialize();              instance = creature->GetInstanceScript();          }          void Initialize()          { -            uiBloodlustTimer = 15000; -            uiChainHealTimer = 0; -            uiEarthShockTimer = urand(2000, 8000); -            uiLightningBoltTimer = urand(5000, 10000); -            uiEarthShieldTimer = 20000; +            events.Reset(); +            phase = 0; +            breakBondsCd = 0;          } -        uint32 uiBloodlustTimer; -        uint32 uiChainHealTimer; -        uint32 uiEarthShockTimer; -        uint32 uiLightningBoltTimer; -        uint32 uiEarthShieldTimer; - -        InstanceScript* instance; -          void Reset() override          {              Initialize(); +              if (instance->GetData(DATA_WAVE_COUNT) == 6)                  instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);              else if (instance->GetData(DATA_WAVE_COUNT) == 12)                  instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED); -            if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) +            if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS)              { -                if (!pGuard1->IsAlive()) -                    pGuard1->Respawn(); +                if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) +                    pGuard1->DespawnOrUnsummon(); +                if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) +                    pGuard2->DespawnOrUnsummon();              } -            if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) +            else              { -                if (!pGuard2->IsAlive()) -                    pGuard2->Respawn(); +                if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) +                { +                    if (!pGuard1->IsAlive()) +                        pGuard1->Respawn(); +                } +                if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) +                { +                    if (!pGuard2->IsAlive()) +                        pGuard2->Respawn(); +                }              }          } +        void JustReachedHome() override +        { +            if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) +                pGuard1->Respawn(); +             +            if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) +                pGuard2->Respawn(); +             +        } +          void AttackStart(Unit* who) override          {              if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) @@ -104,13 +126,13 @@ public:                  if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)))                  { -                    pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); +                    pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);                      if (!pGuard1->GetVictim() && pGuard1->AI())                          pGuard1->AI()->AttackStart(who);                  }                  if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)))                  { -                    pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); +                    pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);                      if (!pGuard2->GetVictim() && pGuard2->AI())                          pGuard2->AI()->AttackStart(who);                  } @@ -133,68 +155,13 @@ public:                  instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);              else if (instance->GetData(DATA_WAVE_COUNT) == 12)                  instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); -        } - -        void MoveInLineOfSight(Unit* /*who*/) override { } - -        void UpdateAI(uint32 diff) override -        { -            if (!UpdateVictim()) -                return; - -            //spam stormstrike in hc mode if spawns are dead -            if (IsHeroic()) -            { -                if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) -                { -                    if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) -                    { -                        if (!pGuard1->IsAlive() && !pGuard2->IsAlive()) -                            DoCastVictim(SPELL_STORMSTRIKE); -                    } -                } -            } - -            if (uiEarthShieldTimer <= diff) -            { -                DoCast(me, SPELL_EARTH_SHIELD); -                uiEarthShieldTimer = 20000; -            } else uiEarthShieldTimer -= diff; - -            if (uiChainHealTimer <= diff) -            { -                if (ObjectGuid TargetGUID = GetChainHealTargetGUID()) -                { -                    if (Creature* target = ObjectAccessor::GetCreature(*me, TargetGUID)) -                        DoCast(target, SPELL_CHAIN_HEAL); - -                    //If one of the adds is dead spawn heals faster -                    Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)); -                    Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)); -                    uiChainHealTimer = ((pGuard1 && !pGuard1->IsAlive()) || (pGuard2 && !pGuard2->IsAlive()) ? 3000 : 8000) + rand32() % 3000; -                } -            } else uiChainHealTimer -= diff; -            if (uiBloodlustTimer <= diff) -            { -                DoCast(me, SPELL_BLOODLUST); -                uiBloodlustTimer = urand(35000, 45000); -            } else uiBloodlustTimer -= diff; - -            if (uiEarthShockTimer <= diff) -            { -                DoCastVictim(SPELL_EARTH_SHOCK); -                uiEarthShockTimer = urand(8000, 13000); -            } else uiEarthShockTimer -= diff; - -            if (uiLightningBoltTimer <= diff) -            { -                if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) -                    DoCast(target, SPELL_LIGHTNING_BOLT); -                uiLightningBoltTimer = urand(18000, 24000); -            } else uiLightningBoltTimer -= diff; +            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_NPC); -            DoMeleeAttackIfReady(); +            events.ScheduleEvent(EVENT_EARTH_SHIELD, 20000); +            events.ScheduleEvent(EVENT_BLOODLUST, 15000); +            events.ScheduleEvent(EVENT_CHAIN_HEAL, 10000); +            events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 2000);          }          void JustDied(Unit* /*killer*/) override @@ -219,21 +186,115 @@ public:                  Talk(SAY_SLAY);          } -        ObjectGuid GetChainHealTargetGUID() +        void UpdateAI(uint32 diff) override          { -            if (HealthBelowPct(85)) -                return me->GetGUID(); +            if (!UpdateVictim()) +                return; -            Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)); -            if (pGuard1 && pGuard1->IsAlive() && !pGuard1->HealthAbovePct(75)) -                return pGuard1->GetGUID(); +            if (phase == 0) +                if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) +                { +                    if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) +                    { +                        if (!pGuard1->IsAlive() && !pGuard2->IsAlive()) +                        { +                            phase = 1; +                            DoCastVictim(SPELL_STORMSTRIKE); +                            DoCast(SPELL_WINDFURY); +                            events.Reset(); +                            events.ScheduleEvent(EVENT_EARTH_SHOCK, urand(2000, 8000)); +                            events.ScheduleEvent(EVENT_WINDFURY, urand(1500, 2000)); +                            events.ScheduleEvent(EVENT_STORMSTRIKE, urand(1500, 2000)); +                        } +                    } +                } + +            events.Update(diff); -            Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)); -            if (pGuard2 && pGuard2->IsAlive() && !pGuard2->HealthAbovePct(75)) -                return pGuard2->GetGUID(); +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; -            return ObjectGuid::Empty; +            if (breakBondsCd <= 0) +            { +                if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) +                { +                    if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) +                    { +                        if (pGuard1->IsAlive()) +                        { +                            if (pGuard1->HasAuraType(SPELL_AURA_MOD_STUN) || pGuard1->HasAuraType(SPELL_AURA_MOD_ROOT) +                                || pGuard1->HasAuraType(SPELL_AURA_MOD_CONFUSE) || pGuard1->HasAuraType(SPELL_AURA_MOD_PACIFY) +                                || pGuard1->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED)) +                            { +                                DoCast(SPELL_BREAK_BONDS); +                                breakBondsCd = 10000; +                                return; +                            } +                        } +                        if (pGuard2->IsAlive()) +                        { +                            if (pGuard2->HasAuraType(SPELL_AURA_MOD_STUN) || pGuard2->HasAuraType(SPELL_AURA_MOD_ROOT) +                                || pGuard2->HasAuraType(SPELL_AURA_MOD_CONFUSE) || pGuard2->HasAuraType(SPELL_AURA_MOD_PACIFY) +                                || pGuard2->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED)) +                            { +                                DoCast(SPELL_BREAK_BONDS); +                                breakBondsCd = 10000; +                                return; +                            } +                        } +                    } +                } +            } +            else +                breakBondsCd -= diff; + +            switch (uint32 eventId = events.ExecuteEvent()) +            { +                case EVENT_EARTH_SHIELD: +                    if (Unit* ally = DoSelectLowestHpFriendly(30.0f)) +                        DoCast(ally, SPELL_EARTH_SHIELD); +                    events.ScheduleEvent(EVENT_EARTH_SHIELD, 20000); +                    break; +                case EVENT_BLOODLUST: +                    DoCast(SPELL_BLOODLUST); +                    events.ScheduleEvent(EVENT_BLOODLUST, urand(35000, 45000)); +                    break; +                case EVENT_LIGHTNING_BOLT: +                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                        DoCast(target, SPELL_LIGHTNING_BOLT); +                    events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 2500); +                    break; +                case EVENT_CHAIN_HEAL: +                    if (Unit* ally = DoSelectLowestHpFriendly(40.0f)) +                        DoCast(ally, SPELL_CHAIN_HEAL); +                    { +                        Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)); +                        Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)); +                        events.ScheduleEvent(EVENT_CHAIN_HEAL, ((pGuard1 && !pGuard1->IsAlive()) || (pGuard2 && !pGuard2->IsAlive()) ? 3000 : 8000 + rand() % 3000)); +                    } +                    break; +                case EVENT_EARTH_SHOCK: +                    DoCastVictim(SPELL_EARTH_SHOCK); +                    events.ScheduleEvent(EVENT_EARTH_SHOCK, urand(8000, 13000)); +                    break; +                case EVENT_WINDFURY: +                    DoCast(SPELL_WINDFURY); +                    events.ScheduleEvent(EVENT_WINDFURY, urand(1500, 2000)); +                    break; +                case EVENT_STORMSTRIKE: +                    DoCastVictim(SPELL_STORMSTRIKE); +                    events.ScheduleEvent(EVENT_STORMSTRIKE, urand(1500, 2000)); +                    break; +            } + +            DoMeleeAttackIfReady();          } + +    private: +        EventMap events; +        InstanceScript* instance; +        uint8 phase; +        int32 breakBondsCd;      };      CreatureAI* GetAI(Creature* creature) const override @@ -278,6 +339,9 @@ public:          void Reset() override          {              Initialize(); + +            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);          }          void AttackStart(Unit* who) override diff --git a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp index 9be73febd52..2de6d1b576f 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp @@ -27,12 +27,16 @@ enum Spells      SPELL_WATER_BLAST                           = 54237,      SPELL_WATER_BOLT_VOLLEY                     = 54241,      SPELL_SPLASH                                = 59516, -    SPELL_WATER_GLOBULE                         = 54268 +    SPELL_BURST                                 = 54379, +    SPELL_WATER_GLOBULE                         = 54268, +    SPELL_MERGE                                 = 54269, +    SPELL_WATER_GLOBULE_VISUAL                  = 54260  };  enum IchoronCreatures  { -    NPC_ICHOR_GLOBULE                           = 29321 +    NPC_ICHOR_GLOBULE                           = 29321, +    NPC_ICHORON_SUMMON_TARGET                   = 29326  };  enum Yells @@ -49,25 +53,44 @@ enum Yells  enum Actions  {      ACTION_WATER_ELEMENT_HIT                    = 1, -    ACTION_WATER_ELEMENT_KILLED                 = 2  }; -/// @todo get those positions from spawn of creature 29326 -#define MAX_SPAWN_LOC 5 -static Position const SpawnLoc[MAX_SPAWN_LOC]= +enum IchoronEvents  { -    {1840.64f, 795.407f, 44.079f, 1.676f}, -    {1886.24f, 757.733f, 47.750f, 5.201f}, -    {1877.91f, 845.915f, 43.417f, 3.560f}, -    {1918.97f, 850.645f, 47.225f, 4.136f}, -    {1935.50f, 796.224f, 52.492f, 4.224f} +    EVENT_WATER_BLAST                           = 1, +    EVENT_WATER_BOLT_VOLLEY, +}; + +enum GlobuleEvents +{ +    EVENT_GLOBULE_MOVE                          = 1,  };  enum Misc  { +    DATA_GLOBULE_PATH                           = 0,      DATA_DEHYDRATION                            = 1  }; +Position globulePaths[10] = +{ +    // first target +    { 1861.357f, 804.039f, 44.008f, 6.268f }, +    { 1869.375f, 803.976f, 38.781f, 0.009f }, +    // second target +    { 1888.063f, 763.488f, 47.667f, 1.744f }, +    { 1882.865f, 776.385f, 38.824f, 1.882f }, +    // third target +    { 1935.140f, 817.752f, 52.181f, 1.885f }, +    { 1916.642f, 826.337f, 39.139f, 2.851f }, +    // fourth target +    { 1930.257f, 833.053f, 46.906f, 4.579f }, +    { 1916.642f, 826.337f, 39.139f, 2.851f }, +    // fifth target +    { 1878.248f, 841.883f, 43.334f, 4.717f }, +    { 1879.438f, 834.443f, 38.699f, 4.831f } +}; +  class boss_ichoron : public CreatureScript  {  public: @@ -78,33 +101,24 @@ public:          boss_ichoronAI(Creature* creature) : ScriptedAI(creature), m_waterElements(creature)          {              Initialize(); -            instance  = creature->GetInstanceScript(); +            instance = creature->GetInstanceScript();          }          void Initialize()          {              bIsExploded = false;              bIsFrenzy = false; +            bIsDrained = false;              dehydration = true; -            uiBubbleCheckerTimer = 1000; -            uiWaterBoltVolleyTimer = urand(10000, 15000); +            drainedTimer = 50; +            burstTimer = 15000;          } -        bool bIsExploded; -        bool bIsFrenzy; -        bool dehydration; - -        uint32 uiBubbleCheckerTimer; -        uint32 uiWaterBoltVolleyTimer; - -        InstanceScript* instance; - -        SummonList m_waterElements; -          void Reset() override          {              Initialize(); +            events.Reset();              me->SetVisible(true);              DespawnWaterElements(); @@ -131,6 +145,9 @@ public:                  instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);              else if (instance->GetData(DATA_WAVE_COUNT) == 12)                  instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + +            events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(10000, 15000)); +            events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000));          }          void AttackStart(Unit* who) override @@ -155,18 +172,16 @@ public:              switch (param)              {                  case ACTION_WATER_ELEMENT_HIT: -                    me->ModifyHealth(int32(me->CountPctFromMaxHealth(1))); - +                {                      if (bIsExploded)                          DoExplodeCompleted(); -                    dehydration = false; -                    break; -                case ACTION_WATER_ELEMENT_KILLED: -                    uint32 damage = me->CountPctFromMaxHealth(3); -                    me->ModifyHealth(-int32(damage)); -                    me->LowerPlayerDamageReq(damage); -                    break; +                    me->SetHealth(me->GetHealth() + me->CountPctFromMaxHealth(3)); +                     +                    if (dehydration) +                        dehydration = false; +                } +                break;              }          } @@ -180,6 +195,7 @@ public:          void DoExplodeCompleted()          {              bIsExploded = false; +            bIsDrained = false;              if (!HealthBelowPct(25))              { @@ -199,74 +215,24 @@ public:              return 0;          } -        void MoveInLineOfSight(Unit* /*who*/) override { } - -        void UpdateAI(uint32 uiDiff) override +        void MoveInLineOfSight(Unit* who) override          { -            if (!UpdateVictim()) +            if (!who->ToCreature())                  return; -            if (!bIsFrenzy && HealthBelowPct(25) && !bIsExploded) -            { -                Talk(SAY_ENRAGE); -                DoCast(me, SPELL_FRENZY, true); -                bIsFrenzy = true; -            } - -            if (!bIsFrenzy) -            { -                if (uiBubbleCheckerTimer <= uiDiff) -                { -                    if (!bIsExploded) -                    { -                        if (!me->HasAura(SPELL_PROTECTIVE_BUBBLE)) -                        { -                            Talk(SAY_SHATTER); -                            DoCast(me, SPELL_WATER_BLAST); // wrong target -                            DoCast(me, SPELL_DRAINED); -                            bIsExploded = true; -                            me->AttackStop(); -                            me->SetVisible(false); -                            for (uint8 i = 0; i < 10; i++) -                            { -                                int tmp = urand(0, MAX_SPAWN_LOC-1); -                                me->SummonCreature(NPC_ICHOR_GLOBULE, SpawnLoc[tmp], TEMPSUMMON_CORPSE_DESPAWN); -                            } -                        } -                    } -                    else -                    { -                        bool bIsWaterElementsAlive = false; -                        if (!m_waterElements.empty()) -                        { -                            for (SummonList::const_iterator itr = m_waterElements.begin(); itr != m_waterElements.end(); ++itr) -                                if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr)) -                                    if (temp->IsAlive()) -                                    { -                                        bIsWaterElementsAlive = true; -                                        break; -                                    } -                        } +            if (who->GetEntry() != NPC_ICHOR_GLOBULE) +                return; -                        if (!bIsWaterElementsAlive) -                            DoExplodeCompleted(); -                    } -                    uiBubbleCheckerTimer = 1000; -                } -                else uiBubbleCheckerTimer -= uiDiff; -            } +            if (!me->IsWithinDist(who, 4.0f, false)) +                return; -            if (!bIsExploded) -            { -                if (uiWaterBoltVolleyTimer <= uiDiff) -                { -                    DoCast(me, SPELL_WATER_BOLT_VOLLEY); -                    uiWaterBoltVolleyTimer = urand(10000, 15000); -                } -                else uiWaterBoltVolleyTimer -= uiDiff; +            if (who->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) +                return; -                DoMeleeAttackIfReady(); -            } +            who->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +            who->CastSpell(who, SPELL_MERGE); +            DoAction(ACTION_WATER_ELEMENT_HIT); +            who->ToCreature()->DespawnOrUnsummon(1000);          }          void JustDied(Unit* /*killer*/) override @@ -295,22 +261,23 @@ public:          void JustSummoned(Creature* summoned) override          { -            if (summoned) -            { -                summoned->SetSpeed(MOVE_RUN, 0.3f); -                summoned->GetMotionMaster()->MoveFollow(me, 0, 0); -                m_waterElements.Summon(summoned); -                instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID()); -            } +            summoned->SetSpeed(MOVE_RUN, 0.3f); +            m_waterElements.Summon(summoned); + +            instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID());          }          void SummonedCreatureDespawn(Creature* summoned) override          { -            if (summoned) +            m_waterElements.Despawn(summoned); + +            if (m_waterElements.empty() && bIsExploded)              { -                m_waterElements.Despawn(summoned); -                instance->SetGuidData(DATA_DEL_TRASH_MOB, summoned->GetGUID()); +                me->RemoveAllAuras(); +                DoExplodeCompleted();              } + +            instance->SetGuidData(DATA_DEL_TRASH_MOB, summoned->GetGUID());          }          void KilledUnit(Unit* victim) override @@ -318,6 +285,145 @@ public:              if (victim->GetTypeId() == TYPEID_PLAYER)                  Talk(SAY_SLAY);          } + +        void UpdateAI(uint32 diff) override +        { +            if (!UpdateVictim()) +                return; + +            if (!bIsFrenzy && HealthBelowPct(25) && !bIsExploded) +            { +                Talk(SAY_ENRAGE); +                DoCast(me, SPELL_FRENZY, true); +                bIsFrenzy = true; +            } + +            if (!bIsFrenzy) +            { +                if (!bIsExploded) +                { +                    if (!me->HasAura(SPELL_PROTECTIVE_BUBBLE)) +                    { +                        bIsExploded = true; +                        Talk(SAY_SHATTER); +                        DoCast(SPELL_BURST); +                        me->RemoveAllAuras(); +                        burstTimer = 15000; + +                        std::list<Creature*> summonTargets; +                        GetCreatureListWithEntryInGrid(summonTargets, me, NPC_ICHORON_SUMMON_TARGET, 200.0f); +                        std::list<Creature*>::iterator itr = summonTargets.begin(); + +                        for (uint8 i = 0; i < 10; i++) +                        { +                            std::advance(itr, urand(0, summonTargets.size() - 1)); // I take a random minion in the list +                            Position targetPos = (*itr)->GetRandomNearPosition(10.0f); +                            itr = summonTargets.begin(); +                            TempSummon* globule = me->SummonCreature(NPC_ICHOR_GLOBULE, targetPos, TEMPSUMMON_CORPSE_DESPAWN); +                            DoCast(globule, SPELL_WATER_GLOBULE_VISUAL); + +                            float minDistance = 1000.0f; +                            uint8 nextPath = 0; +                            // I move the globules to next position. the 10 positions are in couples, defined in globulePaths, so i have to increase by 2. +                            for (uint8 gpath = 0; gpath < 10; gpath += 2)  +                            { +                                if (globule->GetDistance(globulePaths[gpath]) < minDistance) +                                { +                                    minDistance = globule->GetDistance(globulePaths[gpath]); +                                    nextPath = gpath; +                                } +                            } + +                            globule->GetAI()->SetData(DATA_GLOBULE_PATH, nextPath); +                        } +                        return; +                    } + +                    if (me->HasUnitState(UNIT_STATE_CASTING)) +                        return; + +                    events.Update(diff); + +                    switch (uint32 eventId = events.ExecuteEvent()) +                    { +                        case EVENT_WATER_BLAST: +                            if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                                DoCast(target, SPELL_WATER_BLAST); +                            events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000)); +                            break; +                        case EVENT_WATER_BOLT_VOLLEY: +                            DoCast(SPELL_WATER_BOLT_VOLLEY); +                            events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(10000, 15000)); +                            break; +                    } + +                    DoMeleeAttackIfReady(); +                } +                else if (!bIsDrained) +                { +                    if (drainedTimer <= 0) +                    { +                        bIsDrained = true; +                        drainedTimer = 50; +                        uint32 damage = me->CountPctFromMaxHealth(30); +                        if (me->GetHealth() < damage)                             +                            me->SetHealth(me->CountPctFromMaxHealth(1)); +                        else +                        { +                            me->SetHealth(me->GetHealth() - damage); +                            me->LowerPlayerDamageReq(damage); +                        } +                        DoCast(SPELL_DRAINED); +                        me->SetVisible(false); +                        me->AttackStop(); +                    } +                    else +                        drainedTimer -= diff; +                } +                else if (bIsDrained) +                { +                    if (burstTimer <= 0) +                    { +                        DoExplodeCompleted(); +                    } +                    else +                        burstTimer -= diff; +                } +            } +            else +            { +                if (me->HasUnitState(UNIT_STATE_CASTING)) +                    return; + +                events.Update(diff); + +                switch (uint32 eventId = events.ExecuteEvent()) +                { +                case EVENT_WATER_BLAST: +                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                        DoCast(target, SPELL_WATER_BLAST); +                    events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000)); +                    break; +                case EVENT_WATER_BOLT_VOLLEY: +                    DoCast(SPELL_WATER_BOLT_VOLLEY); +                    events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(10000, 15000)); +                    break; +                } + +                DoMeleeAttackIfReady(); +            } +        } + +    private: +        InstanceScript* instance; +        SummonList m_waterElements; +        EventMap events; +        bool bIsExploded; +        bool bIsFrenzy; +        bool bIsDrained; +        bool dehydration; +        int32 drainedTimer; +        int32 burstTimer;      };      CreatureAI* GetAI(Creature* creature) const override @@ -335,54 +441,72 @@ public:      {          npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature)          { -            Initialize();              instance = creature->GetInstanceScript();          } -        void Initialize() +        void Reset() override          { -            uiRangeCheck_Timer = 1000; +            pathId = 0; +            events.Reset(); +            DoCast(SPELL_WATER_GLOBULE);          } -        InstanceScript* instance; - -        uint32 uiRangeCheck_Timer; - -        void Reset() override +        void AttackStart(Unit* /*who*/) override          { -            Initialize(); -            DoCast(me, SPELL_WATER_GLOBULE);          } -        void AttackStart(Unit* /*who*/) override +        void SetData(uint32 id, uint32 data) override          { +            if (id == DATA_GLOBULE_PATH) +            { +                pathId = data; +                me->GetMotionMaster()->MovePoint(0, globulePaths[pathId]); +            }          } -        void UpdateAI(uint32 uiDiff) override +        void MovementInform(uint32 type, uint32 id) override          { -            if (uiRangeCheck_Timer < uiDiff) +            if (type != POINT_MOTION_TYPE) +                return; + +            switch (id)              { -                if (Creature* ichoron = instance->GetCreature(DATA_ICHORON)) -                { -                    if (me->IsWithinDist(ichoron, 2.0f, false)) -                    { -                        if (ichoron->AI()) -                            ichoron->AI()->DoAction(ACTION_WATER_ELEMENT_HIT); -                        me->DespawnOrUnsummon(); -                    } -                } -                uiRangeCheck_Timer = 1000; +                case 0: +                    me->GetMotionMaster()->MovementExpired(); +                    events.ScheduleEvent(EVENT_GLOBULE_MOVE, 500); +                    break; +                case 1: +                    me->GetMotionMaster()->MovementExpired(); +                    if (Creature* ichoron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ICHORON))) +                        me->GetMotionMaster()->MoveFollow(ichoron, 0.0f, 0.0f); +                    break;              } -            else uiRangeCheck_Timer -= uiDiff;          } -        void JustDied(Unit* /*killer*/) override +        // on retail spell casted on a creature's death are not casted after death but keeping mob at 1 health, casting it and then letting the mob die. +        // this feature should be still implemented +        void DamageTaken(Unit* attacker, uint32 &damage) override          { -            DoCast(me, SPELL_SPLASH); -            if (Creature* ichoron = instance->GetCreature(DATA_ICHORON)) -                if (ichoron->AI()) -                    ichoron->AI()->DoAction(ACTION_WATER_ELEMENT_KILLED); +            int32 actualHp = me->GetHealth(); +            actualHp -= damage; + +            if (actualHp <= 0) +                DoCast(SPELL_SPLASH);          } + +        void UpdateAI(uint32 diff) override +        { +            events.Update(diff); + +            if (events.ExecuteEvent() == EVENT_GLOBULE_MOVE) +                me->GetMotionMaster()->MovePoint(1, globulePaths[pathId + 1]); + +        } + +    private: +        InstanceScript* instance; +        EventMap events; +        uint8 pathId;      };      CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp index 5040dccfa36..62ea86c04a4 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp @@ -24,7 +24,15 @@ enum Spells      SPELL_CAUTERIZING_FLAMES                    = 59466, // Only in heroic      SPELL_FIREBOLT                              = 54235,      SPELL_FLAME_BREATH                          = 54282, -    SPELL_LAVA_BURN                             = 54249 +    SPELL_LAVA_BURN                             = 54249, +}; + +enum LavanthorEvents +{ +    EVENT_CAUTERIZING_FLAMES = 1, +    EVENT_FIREBOLT, +    EVENT_FLAME_BREATH, +    EVENT_LAVA_BURN,  };  class boss_lavanthor : public CreatureScript @@ -36,32 +44,17 @@ public:      {          boss_lavanthorAI(Creature* creature) : ScriptedAI(creature)          { -            Initialize();              instance = creature->GetInstanceScript();          } -        void Initialize() -        { -            uiFireboltTimer = 1000; -            uiFlameBreathTimer = 5000; -            uiLavaBurnTimer = 10000; -            uiCauterizingFlamesTimer = 3000; -        } - -        uint32 uiFireboltTimer; -        uint32 uiFlameBreathTimer; -        uint32 uiLavaBurnTimer; -        uint32 uiCauterizingFlamesTimer; - -        InstanceScript* instance; -          void Reset() override          { -            Initialize();              if (instance->GetData(DATA_WAVE_COUNT) == 6)                  instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);              else if (instance->GetData(DATA_WAVE_COUNT) == 12)                  instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED); + +            events.Reset();          }          void EnterCombat(Unit* /*who*/) override @@ -72,11 +65,16 @@ public:                      EnterEvadeMode();                      return;                  } -              if (instance->GetData(DATA_WAVE_COUNT) == 6)                  instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);              else if (instance->GetData(DATA_WAVE_COUNT) == 12)                  instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + +            events.ScheduleEvent(EVENT_FIREBOLT, 1000); +            events.ScheduleEvent(EVENT_FLAME_BREATH, 5000); +            events.ScheduleEvent(EVENT_LAVA_BURN, 10000); +            if (IsHeroic()) +                events.ScheduleEvent(EVENT_CAUTERIZING_FLAMES, 3000);          }          void AttackStart(Unit* who) override @@ -93,39 +91,36 @@ public:              }          } -        void MoveInLineOfSight(Unit* /*who*/) override { } -          void UpdateAI(uint32 diff) override          {              if (!UpdateVictim())                  return; -            if (uiFireboltTimer <= diff) -            { -                DoCastVictim(SPELL_FIREBOLT); -                uiFireboltTimer = urand(5000, 13000); -            } else uiFireboltTimer -= diff; +            events.Update(diff); -            if (uiFlameBreathTimer <= diff) -            { -                DoCastVictim(SPELL_FLAME_BREATH); -                uiFlameBreathTimer = urand(10000, 15000); -            } else uiFlameBreathTimer -= diff; +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; -            if (uiLavaBurnTimer <= diff) +            switch (uint32 eventId = events.ExecuteEvent())              { -                if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true)) +            case EVENT_FIREBOLT: +                if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                    DoCast(target, SPELL_FIREBOLT); +                events.ScheduleEvent(EVENT_FIREBOLT, urand(5000, 13000)); +                break; +            case EVENT_FLAME_BREATH: +                DoCast(SPELL_FLAME_BREATH); +                events.ScheduleEvent(EVENT_FLAME_BREATH, urand(10000, 15000)); +                break; +            case EVENT_LAVA_BURN: +                if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))                      DoCast(target, SPELL_LAVA_BURN); -                uiLavaBurnTimer = urand(15000, 23000); -            } else uiLavaBurnTimer -= diff; - -            if (IsHeroic()) -            { -                if (uiCauterizingFlamesTimer <= diff) -                { -                    DoCastVictim(SPELL_CAUTERIZING_FLAMES); -                    uiCauterizingFlamesTimer = urand(10000, 16000); -                } else uiCauterizingFlamesTimer -= diff; +                events.ScheduleEvent(EVENT_LAVA_BURN, urand(15000, 23000)); +                break; +            case EVENT_CAUTERIZING_FLAMES: +                DoCast(SPELL_CAUTERIZING_FLAMES); +                events.ScheduleEvent(EVENT_CAUTERIZING_FLAMES, urand(10000, 16000)); +                break;              }              DoMeleeAttackIfReady(); @@ -144,6 +139,10 @@ public:                  instance->SetData(DATA_WAVE_COUNT, 13);              }          } + +    private: +        EventMap events; +        InstanceScript* instance;      };      CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp index 1c98806b127..df01b0d4a17 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp @@ -24,7 +24,18 @@ enum Spells      SPELL_CORROSIVE_SALIVA                     = 54527,      SPELL_OPTIC_LINK                           = 54396,      SPELL_RAY_OF_PAIN                          = 54438, // NYI missing spelldifficulty -    SPELL_RAY_OF_SUFFERING                     = 54442  // NYI missing spelldifficulty +    SPELL_RAY_OF_SUFFERING                     = 54442, // NYI missing spelldifficulty +     +    // Visual +    SPELL_OPTIC_LINK_LEVEL_1                   = 54393, +    SPELL_OPTIC_LINK_LEVEL_2                   = 54394, +    SPELL_OPTIC_LINK_LEVEL_3                   = 54395, +}; + +enum MoraggEvents +{ +    EVENT_CORROSIVE_SALIVA                      = 1, +    EVENT_OPTIC_LINK,  };  class boss_moragg : public CreatureScript @@ -36,24 +47,12 @@ public:      {          boss_moraggAI(Creature* creature) : ScriptedAI(creature)          { -            Initialize();              instance = creature->GetInstanceScript();          } -        void Initialize() -        { -            uiOpticLinkTimer = 10000; -            uiCorrosiveSalivaTimer = 5000; -        } - -        uint32 uiOpticLinkTimer; -        uint32 uiCorrosiveSalivaTimer; - -        InstanceScript* instance; -          void Reset() override          { -            Initialize(); +            events.Reset();              if (instance->GetData(DATA_WAVE_COUNT) == 6)                  instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED); @@ -74,6 +73,13 @@ public:                  instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);              else if (instance->GetData(DATA_WAVE_COUNT) == 12)                  instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + +            me->SetInCombatWithZone(); + +            DoCast(SPELL_RAY_OF_PAIN); +            DoCast(SPELL_RAY_OF_SUFFERING); +            events.ScheduleEvent(EVENT_OPTIC_LINK, 15000); +            events.ScheduleEvent(EVENT_CORROSIVE_SALIVA, 5000);          }          void AttackStart(Unit* who) override @@ -90,25 +96,28 @@ public:              }          } -        void MoveInLineOfSight(Unit* /*who*/) override { } -          void UpdateAI(uint32 diff) override          {              if (!UpdateVictim())                  return; -            if (uiOpticLinkTimer <= diff) -            { -                if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) -                    DoCast(target, SPELL_OPTIC_LINK); -                uiOpticLinkTimer = 15000; -            } else uiOpticLinkTimer -= diff; +            events.Update(diff); + +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; -            if (uiCorrosiveSalivaTimer <= diff) +            switch (uint32 eventId = events.ExecuteEvent())              { -                DoCastVictim(SPELL_CORROSIVE_SALIVA); -                uiCorrosiveSalivaTimer = 10000; -            } else uiCorrosiveSalivaTimer -= diff; +                case EVENT_OPTIC_LINK: +                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                        DoCast(target, SPELL_OPTIC_LINK); +                    events.ScheduleEvent(EVENT_OPTIC_LINK, 25000); +                    break; +                case EVENT_CORROSIVE_SALIVA: +                    DoCastVictim(SPELL_CORROSIVE_SALIVA); +                    events.ScheduleEvent(EVENT_CORROSIVE_SALIVA, 10000); +                    break; +            }              DoMeleeAttackIfReady();          } @@ -126,6 +135,10 @@ public:                  instance->SetData(DATA_WAVE_COUNT, 13);              }          } + +    private: +        EventMap events; +        InstanceScript* instance;      };      CreatureAI* GetAI(Creature* creature) const override @@ -134,7 +147,149 @@ public:      }  }; +class spell_moragg_ray_of_suffering : public SpellScriptLoader +{ +public: +    spell_moragg_ray_of_suffering() : SpellScriptLoader("spell_moragg_ray_of_suffering") { } + +    class spell_moragg_ray_of_suffering_AuraScript : public AuraScript +    { +        PrepareAuraScript(spell_moragg_ray_of_suffering_AuraScript); + +        void OnPeriodic(AuraEffect const* aurEff) +        { +            PreventDefaultAction(); +            std::list<HostileReference*> players = GetTarget()->ToCreature()->getThreatManager().getThreatList(); +            if (!players.empty()) +            { +                std::list<HostileReference*>::iterator itr = players.begin(); +                std::advance(itr, urand(0, players.size() - 1)); + +                uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; +                GetTarget()->CastCustomSpell(triggerSpell, SPELLVALUE_MAX_TARGETS, 1, (*itr)->getTarget(), TRIGGERED_FULL_MASK, NULL, aurEff); +            } +        } + +        void Register() override +        { +            OnEffectPeriodic += AuraEffectPeriodicFn(spell_moragg_ray_of_suffering_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); +        } +    }; + +    AuraScript* GetAuraScript() const override +    { +        return new spell_moragg_ray_of_suffering_AuraScript(); +    } +}; + +class spell_moragg_ray_of_pain : public SpellScriptLoader +{ +public: +    spell_moragg_ray_of_pain() : SpellScriptLoader("spell_moragg_ray_of_pain") { } + +    class spell_moragg_ray_of_pain_AuraScript : public AuraScript +    { +        PrepareAuraScript(spell_moragg_ray_of_pain_AuraScript); + +        void OnPeriodic(AuraEffect const* aurEff) +        { +            PreventDefaultAction(); +            std::list<HostileReference*> players = GetTarget()->ToCreature()->getThreatManager().getThreatList(); +            if (!players.empty()) +            { +                std::list<HostileReference*>::iterator itr = players.begin(); +                std::advance(itr, urand(0, players.size() - 1)); + +                uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; +                GetTarget()->CastCustomSpell(triggerSpell, SPELLVALUE_MAX_TARGETS, 1, (*itr)->getTarget(), TRIGGERED_FULL_MASK, NULL, aurEff); +            } +        } + +        void Register() override +        { +            OnEffectPeriodic += AuraEffectPeriodicFn(spell_moragg_ray_of_pain_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); +        } +    }; + +    AuraScript* GetAuraScript() const override +    { +        return new spell_moragg_ray_of_pain_AuraScript(); +    } +}; + +class spell_moragg_optic_link : public SpellScriptLoader +{ +public: +    spell_moragg_optic_link() : SpellScriptLoader("spell_moragg_optic_link") { } + +    class spell_moragg_optic_link_AuraScript : public AuraScript +    { +        PrepareAuraScript(spell_moragg_optic_link_AuraScript); + +        void OnPeriodic(AuraEffect const* aurEff) +        { +            switch (aurEff->GetTickNumber()) // Different visual based on tick +            { +                case 1: +                case 2: +                case 3: +                    GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_1, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); +                    break; +                case 4: +                case 5: +                case 6: +                case 7: +                    GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_1, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); +                    GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_2, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); +                    break; +                case 8: +                case 9: +                case 10: +                case 11: +                    GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_1, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); +                    GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_2, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); +                    GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_3, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); +                    break; +                default: +                    break; +            } +        } + +        void OnUpdate(AuraEffect* aurEff) +        { +            switch (aurEff->GetTickNumber()) +            { +                case 1: +                    aurEff->SetAmount(aurEff->GetAmount() + 250); // base amount is 500 +                    break; +                case 4: +                    aurEff->SetAmount(aurEff->GetAmount() * 2); // goes to 1500 +                    break; +                case 8: +                    aurEff->SetAmount(aurEff->GetAmount() * 2); // goes to 3000 +                    break; +                default: +                    break; +            } +        } + +        void Register() override +        { +            OnEffectPeriodic += AuraEffectPeriodicFn(spell_moragg_optic_link_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); +            OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_moragg_optic_link_AuraScript::OnUpdate, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); +        } +    }; + +    AuraScript* GetAuraScript() const override +    { +        return new spell_moragg_optic_link_AuraScript(); +    } +}; +  void AddSC_boss_moragg()  {      new boss_moragg(); +    new spell_moragg_ray_of_suffering(); +    new spell_moragg_ray_of_pain(); +    new spell_moragg_optic_link();  } diff --git a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp index d1efcb8ca7a..9deac82ca3a 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp @@ -25,21 +25,23 @@ enum Spells      SPELL_ARCANE_BARRAGE_VOLLEY                 = 54202,      SPELL_ARCANE_BUFFET                         = 54226,      SPELL_SUMMON_ETHEREAL_SPHERE_1              = 54102, -    SPELL_SUMMON_ETHEREAL_SPHERE_2              = 54137, +    SPELL_SUMMON_ETHEREAL_SPHERE_2              = 61337,      SPELL_SUMMON_ETHEREAL_SPHERE_3              = 54138  };  enum NPCs  {      NPC_ETHEREAL_SPHERE                         = 29271, -    //NPC_ETHEREAL_SPHERE2                      = 32582, // heroic only? +    NPC_ETHEREAL_SPHERE2                        = 32582  };  enum CreatureSpells  {      SPELL_ARCANE_POWER                          = 54160, +    H_SPELL_ARCANE_POWER                        = 59474,      SPELL_SUMMON_PLAYERS                        = 54164, -    SPELL_POWER_BALL_VISUAL                     = 54141 +    SPELL_POWER_BALL_VISUAL                     = 54141, +    SPELL_POWER_BALL_DAMAGE_TRIGGER             = 54207  };  enum Yells @@ -53,6 +55,17 @@ enum Yells      SAY_SUMMON_ENERGY                           = 6  }; +enum XevozzEvents +{ +    EVENT_ARCANE_BARRAGE                        = 1, +    EVENT_ARCANE_BUFFET, +    EVENT_SUMMON_SPHERE, +    EVENT_SUMMON_SPHERE_2, +    EVENT_RANGE_CHECK,  +    EVENT_SUMMON_PLAYERS, +    EVENT_DESPAWN_SPHERE +}; +  class boss_xevozz : public CreatureScript  {  public: @@ -62,23 +75,9 @@ public:      {          boss_xevozzAI(Creature* creature) : ScriptedAI(creature)          { -            Initialize(); -            instance  = creature->GetInstanceScript(); +            instance = creature->GetInstanceScript();          } -        void Initialize() -        { -            uiSummonEtherealSphere_Timer = urand(10000, 12000); -            uiArcaneBarrageVolley_Timer = urand(20000, 22000); -            uiArcaneBuffet_Timer = uiSummonEtherealSphere_Timer + urand(5000, 6000); -        } - -        InstanceScript* instance; - -        uint32 uiSummonEtherealSphere_Timer; -        uint32 uiArcaneBarrageVolley_Timer; -        uint32 uiArcaneBuffet_Timer; -          void Reset() override          {              if (instance->GetData(DATA_WAVE_COUNT) == 6) @@ -86,14 +85,15 @@ public:              else if (instance->GetData(DATA_WAVE_COUNT) == 12)                  instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED); -            Initialize();              DespawnSphere(); +            events.Reset();          }          void DespawnSphere()          {              std::list<Creature*> assistList;              GetCreatureListWithEntryInGrid(assistList, me, NPC_ETHEREAL_SPHERE, 150.0f); +            GetCreatureListWithEntryInGrid(assistList, me, NPC_ETHEREAL_SPHERE2, 150.0f);              if (assistList.empty())                  return; @@ -108,11 +108,7 @@ public:          void JustSummoned(Creature* summoned) override          {              summoned->SetSpeed(MOVE_RUN, 0.5f); -            if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) -            { -                summoned->AddThreat(target, 0.00f); -                summoned->AI()->AttackStart(target); -            } +            summoned->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f);          }          void AttackStart(Unit* who) override @@ -144,45 +140,10 @@ public:                  instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);              else if (instance->GetData(DATA_WAVE_COUNT) == 12)                  instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); -        } - -        void MoveInLineOfSight(Unit* /*who*/) override { } - -        void UpdateAI(uint32 diff) override -        { -            if (!UpdateVictim()) -                return; - -            if (uiArcaneBarrageVolley_Timer < diff) -            { -                DoCast(me, SPELL_ARCANE_BARRAGE_VOLLEY); -                uiArcaneBarrageVolley_Timer = urand(20000, 22000); -            } -            else uiArcaneBarrageVolley_Timer -= diff; - -            if (uiArcaneBuffet_Timer) -            { -                if (uiArcaneBuffet_Timer < diff) -                { -                    DoCastVictim(SPELL_ARCANE_BUFFET); -                    uiArcaneBuffet_Timer = 0; -                } -                else uiArcaneBuffet_Timer -= diff; -            } -            if (uiSummonEtherealSphere_Timer < diff) -            { -                Talk(SAY_SPAWN); -                DoCast(me, SPELL_SUMMON_ETHEREAL_SPHERE_1); -                if (IsHeroic()) // extra one for heroic -                    me->SummonCreature(NPC_ETHEREAL_SPHERE, me->GetPositionX() - 5 + rand32() % 10, me->GetPositionY() - 5 + rand32() % 10, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 40000); - -                uiSummonEtherealSphere_Timer = urand(45000, 47000); -                uiArcaneBuffet_Timer = urand(5000, 6000); -            } -            else uiSummonEtherealSphere_Timer -= diff; - -            DoMeleeAttackIfReady(); +            events.ScheduleEvent(EVENT_SUMMON_SPHERE, 5000); +            events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(8000, 10000)); +            events.ScheduleEvent(EVENT_ARCANE_BUFFET, urand(10000, 11000));          }          void JustDied(Unit* /*killer*/) override @@ -208,6 +169,63 @@ public:              if (victim->GetTypeId() == TYPEID_PLAYER)                  Talk(SAY_SLAY);          } + +        void SpellHit(Unit* who, const SpellInfo* spell) override +        { +            if (!who->ToCreature()) +                return; + +            if ((spell->Id == SPELL_ARCANE_POWER) || (spell->Id == H_SPELL_ARCANE_POWER)) +                Talk(SAY_SUMMON_ENERGY); +        } + +        void UpdateAI(uint32 uiDiff) override +        { +            if (!UpdateVictim()) +                return; + +            events.Update(uiDiff); + +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; + +            switch (uint32 eventId = events.ExecuteEvent()) +            { +                case EVENT_ARCANE_BARRAGE: +                    DoCast(SPELL_ARCANE_BARRAGE_VOLLEY); +                    events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(8000, 10000)); +                    break; +                case EVENT_ARCANE_BUFFET: +                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                        DoCast(target, SPELL_ARCANE_BUFFET); +                    events.ScheduleEvent(EVENT_ARCANE_BUFFET, urand(15000, 20000)); +                    break; +                case EVENT_SUMMON_SPHERE: +                    Talk(SAY_REPEAT_SUMMON); +                    DoCast(SPELL_SUMMON_ETHEREAL_SPHERE_1); +                    if (IsHeroic()) +                        events.ScheduleEvent(EVENT_SUMMON_SPHERE_2, 2500); +                    events.ScheduleEvent(EVENT_SUMMON_PLAYERS, urand(33000, 35000)); +                    events.ScheduleEvent(EVENT_SUMMON_SPHERE, urand(45000, 47000)); +                    break; +                case EVENT_SUMMON_SPHERE_2: +                    Talk(SAY_REPEAT_SUMMON); +                    DoCast(SPELL_SUMMON_ETHEREAL_SPHERE_2); +                    break; +                case EVENT_SUMMON_PLAYERS: +                    if (Creature* sphere = me->FindNearestCreature(NPC_ETHEREAL_SPHERE, 150.0f)) +                        sphere->GetAI()->DoAction(1); +                    else if (Creature* sphere = me->FindNearestCreature(NPC_ETHEREAL_SPHERE2, 150.0f)) +                        sphere->GetAI()->DoAction(1); +                    break; +            } + +            DoMeleeAttackIfReady(); +        } + +    private: +        InstanceScript* instance; +        EventMap events;      };      CreatureAI* GetAI(Creature* creature) const override @@ -225,72 +243,132 @@ public:      {          npc_ethereal_sphereAI(Creature* creature) : ScriptedAI(creature)          { -            Initialize(); -            instance   = creature->GetInstanceScript(); +            instance = creature->GetInstanceScript();          } -        void Initialize() +        void Reset() override          { -            uiSummonPlayers_Timer = urand(33000, 35000); -            uiRangeCheck_Timer = 1000; +            events.Reset(); +            DoCast(SPELL_POWER_BALL_VISUAL); +            DoCast(SPELL_POWER_BALL_DAMAGE_TRIGGER); +            arcanePower = false; +            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); +            me->setFaction(16); + +            events.ScheduleEvent(EVENT_DESPAWN_SPHERE, 40000); +            events.ScheduleEvent(EVENT_RANGE_CHECK, 1000);          } -        InstanceScript* instance; - -        uint32 uiSummonPlayers_Timer; -        uint32 uiRangeCheck_Timer; - -        void Reset() override +        void DoAction(int32 action) override          { -            Initialize(); +            DoCast(SPELL_SUMMON_PLAYERS);          }          void UpdateAI(uint32 diff) override          { -            if (!UpdateVictim()) -                return; +            events.Update(diff); -            if (!me->HasAura(SPELL_POWER_BALL_VISUAL)) -                DoCast(me, SPELL_POWER_BALL_VISUAL); +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; -            if (uiRangeCheck_Timer < diff) +            switch (uint32 eventId = events.ExecuteEvent())              { -                if (Creature* pXevozz = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_XEVOZZ))) -                { -                    float fDistance = me->GetDistance2d(pXevozz); -                    if (fDistance <= 3) -                        DoCast(pXevozz, SPELL_ARCANE_POWER); -                    else -                        DoCast(me, 35845); //Is it blizzlike? -                } -                uiRangeCheck_Timer = 1000; +                case EVENT_RANGE_CHECK: +                    if (Creature* xevozz = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_XEVOZZ))) +                    { +                        if (me->IsWithinDist(xevozz, 3.0f) && !arcanePower) +                        { +                            DoCast(SPELL_ARCANE_POWER); +                            arcanePower = true; +                            events.ScheduleEvent(EVENT_DESPAWN_SPHERE, 8000); +                        } +                    } +                    events.ScheduleEvent(EVENT_RANGE_CHECK, 1000); +                    break; +                case EVENT_DESPAWN_SPHERE: +                    me->DespawnOrUnsummon(); +                    break;              } -            else uiRangeCheck_Timer -= diff; +        } + +    private: +        InstanceScript* instance; +        EventMap events; +        bool arcanePower; +    }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return GetInstanceAI<npc_ethereal_sphereAI>(creature); +    } +}; + +class spell_xevozz_summon_players : public SpellScriptLoader +{ +public: +    spell_xevozz_summon_players() : SpellScriptLoader("spell_xevozz_summon_players") { } + +    class spell_xevozz_summon_players_SpellScript : public SpellScript +    { +        PrepareSpellScript(spell_xevozz_summon_players_SpellScript); + +        void HandleScript(SpellEffIndex effIndex) +        { +            Unit* target = GetHitUnit(); -            if (uiSummonPlayers_Timer < diff) +            if (target)              { -                DoCast(me, SPELL_SUMMON_PLAYERS); // not working right +                Position pos = GetOriginalCaster()->GetPosition(); -                Map* map = me->GetMap(); -                if (map && map->IsDungeon()) -                { -                    Map::PlayerList const &PlayerList = map->GetPlayers(); +                target->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); +            } +        } -                    if (!PlayerList.isEmpty()) -                        for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) -                            if (i->GetSource()->IsAlive()) -                                DoTeleportPlayer(i->GetSource(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), i->GetSource()->GetOrientation()); -                } +        void Register() override +        { +            OnEffectHitTarget += SpellEffectFn(spell_xevozz_summon_players_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); +        } +    }; -                uiSummonPlayers_Timer = urand(33000, 35000); +    SpellScript* GetSpellScript() const override +    { +        return new spell_xevozz_summon_players_SpellScript(); +    } +}; + +class spell_xevozz_summon_ethereal_sphere : public SpellScriptLoader +{ +public: +    spell_xevozz_summon_ethereal_sphere() : SpellScriptLoader("spell_xevozz_summon_ethereal_sphere") { } + +    class spell_xevozz_summon_ethereal_sphere_SpellScript : public SpellScript +    { +        PrepareSpellScript(spell_xevozz_summon_ethereal_sphere_SpellScript); + +        void HandleScript(SpellDestination& target) +        { +            Unit* caster = GetOriginalCaster(); +            Position pos; +            float distance = 0.0f; + +            while (distance < 20.0f) +            { +                pos = caster->GetRandomNearPosition(60.0f); +                distance = caster->GetDistance(pos);              } -            else uiSummonPlayers_Timer -= diff; + +            target.Relocate(pos); +        } + +        void Register() override +        { +            OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_xevozz_summon_ethereal_sphere_SpellScript::HandleScript, EFFECT_0, TARGET_DEST_DB);          }      }; -    CreatureAI* GetAI(Creature* creature) const override +    SpellScript* GetSpellScript() const override      { -        return GetInstanceAI<npc_ethereal_sphereAI>(creature); +        return new spell_xevozz_summon_ethereal_sphere_SpellScript();      }  }; @@ -298,4 +376,6 @@ void AddSC_boss_xevozz()  {      new boss_xevozz();      new npc_ethereal_sphere(); +    new spell_xevozz_summon_players(); +    new spell_xevozz_summon_ethereal_sphere();  } diff --git a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp index c29861f08a4..32dc18d2cf3 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp @@ -23,12 +23,8 @@ enum Spells  {      SPELL_SHROUD_OF_DARKNESS                    = 54524,      SPELL_SUMMON_VOID_SENTRY                    = 54369, -    SPELL_VOID_SHIFT                            = 54361 -}; - -enum Creatures -{ -    NPC_VOID_SENTRY                             = 29364 +    SPELL_VOID_SHIFT                            = 54361, +    SPELL_VOID_SHIFTED                          = 54343,  };  enum Yells @@ -46,6 +42,13 @@ enum Misc      DATA_VOID_DANCE                             = 2153  }; +enum ZuramatEvents +{ +    EVENT_VOID_SHIFT                            = 1, +    EVENT_SUMMON_VOID, +    EVENT_SHROUD_OF_DARKNESS +}; +  class boss_zuramat : public CreatureScript  {  public: @@ -53,26 +56,29 @@ public:      struct boss_zuramatAI : public ScriptedAI      { -        boss_zuramatAI(Creature* creature) : ScriptedAI(creature) +        boss_zuramatAI(Creature* creature) : ScriptedAI(creature), sentries(me)          { -            Initialize();              instance = creature->GetInstanceScript();          }          void Initialize()          { -            SpellShroudOfDarknessTimer = 22000; -            SpellVoidShiftTimer = 15000; -            SpellSummonVoidTimer = 12000; +            events.Reset();              voidDance = true;          } -        InstanceScript* instance; - -        uint32 SpellVoidShiftTimer; -        uint32 SpellSummonVoidTimer; -        uint32 SpellShroudOfDarknessTimer; -        bool voidDance; +        void DespawnSentries() +        { +            sentries.DespawnAll(); +            std::list<Creature*> sentries; +            GetCreatureListWithEntryInGrid(sentries, me, NPC_VOID_SENTRY_BALL, 200.0f); +            if (!sentries.empty()) +            { +                std::list<Creature*>::iterator itr = sentries.begin(); +                for (itr; itr != sentries.end(); ++itr) +                    (*itr)->DespawnOrUnsummon(); +            } +        }          void Reset() override          { @@ -82,6 +88,7 @@ public:                  instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);              Initialize(); +            DespawnSentries();          }          void AttackStart(Unit* who) override @@ -112,36 +119,17 @@ public:              if (instance->GetData(DATA_WAVE_COUNT) == 6)                  instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);              else if (instance->GetData(DATA_WAVE_COUNT) == 12) -                instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); -        } +                instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); -        void MoveInLineOfSight(Unit* /*who*/) override { } +            me->SetInCombatWithZone(); +            events.ScheduleEvent(EVENT_SHROUD_OF_DARKNESS, urand(18000, 20000)); +            events.ScheduleEvent(EVENT_VOID_SHIFT, 9000); +            events.ScheduleEvent(EVENT_SUMMON_VOID, 4000); +        } -        void UpdateAI(uint32 diff) override +        void JustSummoned(Creature* summon) override          { -            if (!UpdateVictim()) -                return; - -            if (SpellSummonVoidTimer <= diff) -            { -                DoCastVictim(SPELL_SUMMON_VOID_SENTRY, false); -                SpellSummonVoidTimer = 20000; -            } else SpellSummonVoidTimer -=diff; - -            if (SpellVoidShiftTimer <= diff) -            { -                 if (Unit* unit = SelectTarget(SELECT_TARGET_RANDOM, 0)) -                    DoCast(unit, SPELL_VOID_SHIFT); -                SpellVoidShiftTimer = 20000; -            } else SpellVoidShiftTimer -=diff; - -            if (SpellShroudOfDarknessTimer <= diff) -            { -                DoCastVictim(SPELL_SHROUD_OF_DARKNESS); -                SpellShroudOfDarknessTimer = 20000; -            } else SpellShroudOfDarknessTimer -=diff; - -            DoMeleeAttackIfReady(); +            sentries.Summon(summon);          }          void SummonedCreatureDies(Creature* summoned, Unit* /*who*/) override @@ -160,8 +148,12 @@ public:          void JustDied(Unit* /*killer*/) override          { +            instance->SetData(DATA_ZURAMAT, 1); +              Talk(SAY_DEATH); +            DespawnSentries(); +              if (instance->GetData(DATA_WAVE_COUNT) == 6)              {                  instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE); @@ -179,6 +171,43 @@ public:              if (victim->GetTypeId() == TYPEID_PLAYER)                  Talk(SAY_SLAY);          } + +        void UpdateAI(uint32 diff) override +        { +            //Return since we have no target +            if (!UpdateVictim()) +                return; + +            events.Update(diff); + +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; + +            switch (uint32 eventId = events.ExecuteEvent()) +            { +            case EVENT_SUMMON_VOID: +                DoCast(SPELL_SUMMON_VOID_SENTRY); +                events.ScheduleEvent(EVENT_SUMMON_VOID, urand(7000, 10000)); +                break; +            case EVENT_VOID_SHIFT: +                if (Unit* unit = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                    DoCast(unit, SPELL_VOID_SHIFT); +                events.ScheduleEvent(EVENT_VOID_SHIFT, 15000); +                break; +            case EVENT_SHROUD_OF_DARKNESS: +                DoCast(SPELL_SHROUD_OF_DARKNESS); +                events.ScheduleEvent(EVENT_SHROUD_OF_DARKNESS, urand(18000, 20000)); +                break; +            } + +            DoMeleeAttackIfReady(); +        } + +    private: +        InstanceScript* instance; +        EventMap events; +        SummonList sentries; +        bool voidDance;      };      CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp index 28c56a02255..e8ea47e09f3 100644 --- a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp @@ -145,6 +145,7 @@ public:              bCrystalActivated = false;              defenseless = true;              uiMainEventPhase = NOT_STARTED; +            zuramatDead = false;          }          ObjectGuid uiErekemGuard[2]; @@ -178,6 +179,7 @@ public:          bool bIsDoorSpellCast;          bool bCrystalActivated;          bool defenseless; +        bool zuramatDead;          std::list<uint8> NpcAtDoorCastingList; @@ -199,16 +201,21 @@ public:                      break;                  default:                      break; +                case NPC_VOID_SENTRY: +                    if (zuramatDead) +                    { +                        creature->DespawnOrUnsummon(); +                        zuramatDead = false; +                    } +                    break;              } -            /* -            BEWARE - SHIT.              if (creature->GetGUID() == uiFirstBoss || creature->GetGUID() == uiSecondBoss)              {                  creature->AllLootRemovedFromCorpse();                  creature->RemoveLootMode(1);              } -            */ +          }          void OnGameObjectCreate(GameObject* go) override @@ -314,6 +321,9 @@ public:                          uiRemoveNpc = 0; // might not have been reset after a wipe on a boss.                      }                      break; +                case DATA_ZURAMAT: +                    zuramatDead = true; +                    break;              }          } @@ -393,19 +403,23 @@ public:                      if (Creature* pGuard1 = instance->GetCreature(uiErekemGuard[0]))                      {                          if (bForceRespawn) +                        {                              pGuard1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); +                            pGuard1->GetMotionMaster()->MovePoint(0, BossStartMove21); +                        }                          else -                            pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); -                        pGuard1->GetMotionMaster()->MovePoint(0, BossStartMove21); +                            pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);                      }                      if (Creature* pGuard2 = instance->GetCreature(uiErekemGuard[1]))                      {                          if (bForceRespawn) -                            pGuard2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); +                        { +                            pGuard2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); +                            pGuard2->GetMotionMaster()->MovePoint(0, BossStartMove22); +                        }                          else -                            pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); -                        pGuard2->GetMotionMaster()->MovePoint(0, BossStartMove22); +                            pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);                      }                      break;                  case BOSS_ICHORON: @@ -448,6 +462,9 @@ public:                          boss->Respawn();                          boss->RemoveLootMode(1);                      } +                    else +                        boss->GetMotionMaster()->MoveTargetedHome(); +                      boss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);                      uiWaveCount = 0;                  } @@ -527,6 +544,7 @@ public:                      return false;              } +            zuramatDead = false;              return true;          } @@ -557,6 +575,7 @@ public:                  SetData(DATA_MAIN_DOOR, GO_STATE_ACTIVE);                  SetData(DATA_WAVE_COUNT, 0);                  uiMainEventPhase = NOT_STARTED; +                uiActivationTimer = 5000;                  for (int i = 0; i < 4; ++i)                      if (GameObject* crystal = instance->GetGameObject(uiActivationCrystal[i])) diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp index 8bcc80b5a84..1a5ec7ea0d7 100644 --- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp @@ -28,6 +28,7 @@  #define GOSSIP_START_EVENT  "Get your people to safety, we'll keep the Blue Dragonflight's forces at bay."  #define GOSSIP_ITEM_1       "Activate the crystals when we get in trouble, right"  #define GOSSIP_I_WANT_IN    "I'm not fighting, so send me in now!" +#define SAY_EVENT_LOCK      "I'm locking the door. Good luck, and thank you for doing this."  #define SPAWN_TIME          20000  enum PortalCreatures @@ -59,7 +60,7 @@ enum AzureSellbreakerSpells      SPELL_ARCANE_BLAST          = 58462,      SPELL_SLOW                  = 25603,      SPELL_CHAINS_OF_ICE         = 58464, -    SPELL_CONE_OF_COLD          = 58463 +    SPELL_CONE_OF_COLD          = 58463,  };  enum AzureBinderSpells @@ -67,7 +68,7 @@ enum AzureBinderSpells      SPELL_ARCANE_BARRAGE        = 58456,      SPELL_ARCANE_EXPLOSION      = 58455,      SPELL_FROST_NOVA            = 58458, -    SPELL_FROSTBOLT             = 58457 +    SPELL_FROSTBOLT             = 58457,  };  enum AzureMageSlayerSpells @@ -85,7 +86,7 @@ enum AzureCaptainSpells  enum AzureSorcerorSpells  {      SPELL_ARCANE_STREAM         = 60181, -    SPELL_MANA_DETONATION       = 60182 +    SPELL_MANA_DETONATION       = 60182,  };  enum AzureRaiderSpells @@ -114,7 +115,7 @@ enum TrashDoorSpell  enum Spells  {      SPELL_PORTAL_CHANNEL        = 58012, -    SPELL_CRYSTAL_ACTIVATION    = 57804, +    SPELL_CRYSTAL_ACTIVATION    = 57804, // visual effect      SPELL_ARCANE_SPHERE_PASSIVE = 44263  }; @@ -242,9 +243,19 @@ const float SaboteurFinalPos6[5][3] =      {1931.063354f, 848.468445f, 47.190434f}   }; -const Position MovePosition = {1806.955566f, 803.851807f, 44.363323f, 0.0f}; -const Position playerTeleportPosition = {1830.531006f, 803.939758f, 44.340508f, 6.281611f}; -const Position sinclariOutsidePosition = {1817.315674f, 804.060608f, 44.363998f, 0.0f}; +const Position PortalLocation[] = +{ +    { 1877.51f, 850.104f, 44.6599f, 4.7822f },     // WP 1 +    { 1936.07f, 803.198f, 53.3749f, 3.12414f },     // WP 3 +    { 1890.64f, 753.471f, 48.7224f, 1.71042f },     // WP 5 +}; + +uint64 preEventPortalGUID[3] = { 0 }; + +const Position MovePosition = { 1806.955566f, 803.851807f, 44.363323f, 0.0f }; +const Position playerTeleportPosition = { 1830.531006f, 803.939758f, 44.340508f, 6.281611f }; +const Position sinclariOutsidePosition = { 1820.429810f, 804.066040f, 44.363998f, 0.0f }; +const Position sinclariCrystalPosition = { 1828.868286f, 798.468811f, 44.363998f, 3.890467f };  class npc_sinclari_vh : public CreatureScript  { @@ -321,6 +332,13 @@ public:              me->SetReactState(REACT_AGGRESSIVE); +            if (TempSummon* summon = me->SummonCreature(NPC_TELEPORTATION_PORTAL, PortalLocation[0], TEMPSUMMON_MANUAL_DESPAWN)) +                preEventPortalGUID[0] = summon->GetGUID(); +            if (TempSummon* summon = me->SummonCreature(NPC_TELEPORTATION_PORTAL, PortalLocation[1], TEMPSUMMON_MANUAL_DESPAWN)) +                preEventPortalGUID[1] = summon->GetGUID(); +            if (TempSummon* summon = me->SummonCreature(NPC_TELEPORTATION_PORTAL, PortalLocation[2], TEMPSUMMON_MANUAL_DESPAWN)) +                preEventPortalGUID[2] = summon->GetGUID(); +              std::list<Creature*> GuardList;              me->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f);              if (!GuardList.empty()) @@ -347,25 +365,17 @@ public:                      switch (uiPhase)                      {                          case 1: -                            Talk(SAY_SINCLARI_1); -                            uiTimer = 4000; -                            uiPhase = 2; +                            me->SetWalk(true); +                            me->GetMotionMaster()->MovePoint(0, sinclariCrystalPosition); +                            uiTimer = 1000; +                            uiPhase = 6;                              break;                          case 2:                          { -                            std::list<Creature*> GuardList; -                            me->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); -                            if (!GuardList.empty()) -                                for (std::list<Creature*>::const_iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr) -                                { -                                    if (Creature* pGuard = *itr) -                                    { -                                        pGuard->SetWalk(false); -                                        pGuard->GetMotionMaster()->MovePoint(0, MovePosition); -                                    } -                                } -                            uiTimer = 6000; -                            uiPhase = 3; +                            me->SetFacingTo(me->GetOrientation() - 3.14f); +                            Talk(SAY_SINCLARI_1); +                            uiTimer = 1500; +                            uiPhase = 7;                              break;                          }                          case 3: @@ -378,7 +388,6 @@ public:                                      if (Creature* pGuard = *itr)                                      {                                          pGuard->SetVisible(false); -                                        pGuard->SetReactState(REACT_PASSIVE);                                      }                                  }                              uiTimer = 2000; @@ -391,11 +400,58 @@ public:                              uiPhase = 5;                              break;                          case 5: -                            instance->SetData(DATA_MAIN_EVENT_PHASE, IN_PROGRESS); +                            me->SetFacingTo(0.006673f); +                            me->Say(SAY_EVENT_LOCK, LANG_UNIVERSAL, me); // need to change to db say                              me->SetReactState(REACT_PASSIVE); +                            uiTimer = 3000; +                            uiPhase = 8; +                            break; +                        case 6: +                            me->GetMotionMaster()->MovementExpired(); +                            me->HandleEmoteCommand(EMOTE_STATE_USE_STANDING); +                            uiTimer = 2000; +                            uiPhase = 2; +                            break; +                        case 7: +                        { +                            std::list<Creature*> creatures; +                            GetCreatureListWithEntryInGrid(creatures, me, NPC_TELEPORTATION_PORTAL, 200.0f); +                            GetCreatureListWithEntryInGrid(creatures, me, NPC_AZURE_BINDER_1, 200.0f); +                            GetCreatureListWithEntryInGrid(creatures, me, NPC_AZURE_MAGE_SLAYER_1, 200.0f); +                            GetCreatureListWithEntryInGrid(creatures, me, NPC_AZURE_INVADER_1, 200.0f); +                            DoCast(SPELL_CRYSTAL_ACTIVATION); +                            if (!creatures.empty()) +                            { +                                for (std::list<Creature*>::iterator itr = creatures.begin(); itr != creatures.end(); ++itr) +                                    (*itr)->DisappearAndDie(); +                            } +                            uiTimer = 500; +                            uiPhase = 9; +                        } +                        break; +                        case 8: +                            instance->SetData(DATA_MAIN_EVENT_PHASE, IN_PROGRESS);                              uiTimer = 0;                              uiPhase = 0;                              break; +                        case 9: +                        { +                            std::list<Creature*> GuardList; +                            me->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); +                            if (!GuardList.empty()) +                                for (std::list<Creature*>::const_iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr) +                                { +                                    if (Creature* pGuard = *itr) +                                    { +                                        pGuard->SetReactState(REACT_PASSIVE); +                                        pGuard->SetWalk(false); +                                        pGuard->GetMotionMaster()->MovePoint(0, MovePosition); +                                    } +                                } +                            uiTimer = 4000; +                            uiPhase = 3; +                        } +                        break;                      }                  }                  else uiTimer -= uiDiff; @@ -548,6 +604,9 @@ public:              Initialize();              instance = creature->GetInstanceScript();              uiTypeOfMobsPortal = urand(0, 1);    // 0 - elite mobs   1 - portal guardian or portal keeper with regular mobs + +            if (instance->GetData(DATA_MAIN_EVENT_PHASE) == NOT_STARTED) +                uiTypeOfMobsPortal = 2;          }          void Initialize() @@ -575,10 +634,13 @@ public:          void UpdateAI(uint32 diff) override          { -            if (instance->GetData(DATA_REMOVE_NPC) == 1) +            if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS)              { -                me->DespawnOrUnsummon(); -                instance->SetData(DATA_REMOVE_NPC, 0); +                if (instance->GetData(DATA_REMOVE_NPC) == 1) +                { +                    me->DespawnOrUnsummon(); +                    instance->SetData(DATA_REMOVE_NPC, 0); +                }              }              uint8 uiWaveCount = instance->GetData(DATA_WAVE_COUNT); @@ -642,24 +704,39 @@ public:                          me->RemoveCorpse();                      }                      break; +                case 2: // Pre-event +                    if (uiSpawnTimer <= diff) +                    { +                        uint32 entry = RAND(NPC_AZURE_INVADER_1, NPC_AZURE_MAGE_SLAYER_1, NPC_AZURE_BINDER_1); +                        DoSummon(entry, me, 2.0f, 20000, TEMPSUMMON_DEAD_DESPAWN); +                        uiSpawnTimer = SPAWN_TIME; +                    } else uiSpawnTimer -= diff; +                    break;              }          }          void JustDied(Unit* /*killer*/) override          { -            instance->SetData(DATA_WAVE_COUNT, instance->GetData(DATA_WAVE_COUNT)+1); +            if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS) +                instance->SetData(DATA_WAVE_COUNT, instance->GetData(DATA_WAVE_COUNT) + 1);          }          void JustSummoned(Creature* summoned) override          { -            listOfMobs.Summon(summoned); -            instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID()); +            if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS) +            { +                listOfMobs.Summon(summoned); +                instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID()); +            }          }          void SummonedCreatureDies(Creature* summoned, Unit* /*killer*/) override          { -            listOfMobs.Despawn(summoned); -            instance->SetGuidData(DATA_DEL_TRASH_MOB, summoned->GetGUID()); +            if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS) +            { +                listOfMobs.Despawn(summoned); +                instance->SetGuidData(DATA_DEL_TRASH_MOB, summoned->GetGUID()); +            }          }      }; @@ -675,8 +752,39 @@ struct violet_hold_trashAI : public npc_escortAI      {          instance = creature->GetInstanceScript();          bHasGotMovingPoints = false; -        portalLocationID = instance->GetData(DATA_PORTAL_LOCATION); -        secondPortalRouteID = 0; + + +        if (instance->GetData(DATA_MAIN_EVENT_PHASE) == NOT_STARTED) +        { +            if (Creature* portal = me->FindNearestCreature(NPC_TELEPORTATION_PORTAL, 10.0f)) +            { +                uint64 portalGUID = portal->GetGUID(); +                for (uint8 i = 0; i < 3; i++) +                { +                    if (portalGUID == preEventPortalGUID[i]) +                    { +                        switch (i) +                        { +                        case 0: +                            portalLocationID = 0; +                            break; +                        case 1: +                            portalLocationID = 2; +                            break; +                        case 2: +                            portalLocationID = 4; +                            break; +                        } +                        break; +                    } +                } +            } +        } +        else +        { +            portalLocationID = instance->GetData(DATA_PORTAL_LOCATION); +            Reset(); +        }      }      public: @@ -691,7 +799,7 @@ struct violet_hold_trashAI : public npc_escortAI          {              case 0:                  if (waypointId == 5) -                   CreatureStartAttackDoor(); +                    CreatureStartAttackDoor();                  break;              case 1:                  if ((waypointId == 8 && secondPortalRouteID == 0) || (waypointId == 7 && secondPortalRouteID == 1)) @@ -699,7 +807,7 @@ struct violet_hold_trashAI : public npc_escortAI                  break;              case 2:                  if (waypointId == 7) -                   CreatureStartAttackDoor(); +                    CreatureStartAttackDoor();                  break;              case 3:                  if (waypointId == 8) @@ -1203,7 +1311,7 @@ public:                  if (uiConeOfColdTimer <= diff)                  { -                   DoCast(SPELL_CONE_OF_COLD); +                    DoCast(SPELL_CONE_OF_COLD);                      uiConeOfColdTimer = 5000;                  } else uiConeOfColdTimer -= diff;              } @@ -1391,6 +1499,33 @@ public:      }  }; +class spell_crystal_activation : public SpellScriptLoader +{ +public: +    spell_crystal_activation() : SpellScriptLoader("spell_crystal_activation") { } + +    class spell_crystal_activation_SpellScript : public SpellScript +    { +        PrepareSpellScript(spell_crystal_activation_SpellScript); + +        void HandleSendEvent(SpellEffIndex effIndex) +        { +            if (GetHitUnit()->GetEntry() == NPC_VIOLET_HOLD_GUARD) +                PreventHitDefaultEffect(effIndex); +        } + +        void Register() override +        { +            OnEffectHitTarget += SpellEffectFn(spell_crystal_activation_SpellScript::HandleSendEvent, EFFECT_0, SPELL_EFFECT_SEND_EVENT); +        } +    }; + +    SpellScript* GetSpellScript() const override +    { +        return new spell_crystal_activation_SpellScript(); +    } +}; +  void AddSC_violet_hold()  {      new npc_sinclari_vh(); @@ -1406,4 +1541,5 @@ void AddSC_violet_hold()      new npc_azure_saboteur();      new npc_violet_hold_arcane_sphere();      new go_activation_crystal(); +    new spell_crystal_activation();  } diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.h b/src/server/scripts/Northrend/VioletHold/violet_hold.h index 275a7467d83..e8da9576c13 100644 --- a/src/server/scripts/Northrend/VioletHold/violet_hold.h +++ b/src/server/scripts/Northrend/VioletHold/violet_hold.h @@ -101,7 +101,9 @@ enum CreaturesIds      NPC_SINCLARI                                = 30658,      NPC_SABOTEOUR                               = 31079,      NPC_VIOLET_HOLD_GUARD                       = 30659, -    NPC_DEFENSE_SYSTEM                          = 30837 +    NPC_DEFENSE_SYSTEM                          = 30837, +    NPC_VOID_SENTRY                             = 29364,  +    NPC_VOID_SENTRY_BALL                        = 29365  };  enum GameObjectIds | 
