void UpdateAI(const uint32 uiDiff)
    {
        if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
            return;

        if (m_uiHealTimer < uiDiff)
        {
            if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f))
            {
                if (DoCastSpellIfCan(pTarget, SPELL_FLASH_HEAL) == CAST_OK)
                    m_uiHealTimer = urand(15000, 20000);
            }
        }
        else
            m_uiHealTimer -= uiDiff;

        if (m_uiRenewTimer < uiDiff)
        {
            if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f))
            {
                if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_RENEW : SPELL_RENEW_H) == CAST_OK)
                    m_uiRenewTimer = urand(5000, 10000);
            }
        }
        else
            m_uiRenewTimer -= uiDiff;

        if (m_uiShieldTimer < uiDiff)
        {
            if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHIELD : SPELL_SHIELD_H) == CAST_OK)
                m_uiShieldTimer = urand(30000, 35000);
        }
        else
            m_uiShieldTimer -= uiDiff;

        if (m_uiDispelTimer < uiDiff)
        {
            Unit* pTarget = NULL;
            std::list<Creature*> lTempList = DoFindFriendlyCC(50.0f);

            if (!lTempList.empty())
                pTarget = *(lTempList.begin());
            else
                pTarget = DoSelectLowestHpFriendly(50.0f);

            if (pTarget)
            {
                if (DoCastSpellIfCan(pTarget, SPELL_DISPEL_MAGIC) == CAST_OK)
                    m_uiDispelTimer = urand(12000, 15000);
            }
        }
        else
            m_uiDispelTimer -= uiDiff;

        // Use the Medallion if CC - only on heroic. Not sure how many times they are allowed to use it.
        if (!m_bIsRegularMode && m_uiMedallionTimer)
        {
            if (m_creature->isFrozen() || m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT))
            {
                if (m_uiMedallionTimer <= uiDiff)
                {
                    if (DoCastSpellIfCan(m_creature, SPELL_MEDALLION, CAST_TRIGGERED) == CAST_OK)
                        m_uiMedallionTimer = 0;
                }
                else
                    m_uiMedallionTimer -= uiDiff;
            }
        }

        if (m_uiSWPainTimer < uiDiff)
        {
            if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0))
            {
                if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOW_WORD_PAIN : SPELL_SHADOW_WORD_PAIN_H) == CAST_OK)
                    m_uiSWPainTimer = 10000;
            }
        }
        else
            m_uiSWPainTimer -= uiDiff;

        if (m_uiScreamTimer < uiDiff)
        {
            if (DoCastSpellIfCan(m_creature, SPELL_SCREAM) == CAST_OK)
                m_uiScreamTimer = urand(15000, 20000);
        }
        else
            m_uiScreamTimer -= uiDiff;

        DoMeleeAttackIfReady();
    }
Example #2
0
bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder,	Unit* pActionInvoker /*=NULL*/)
{
    if (!pHolder.Enabled || pHolder.Time)
        return false;

    //Check the inverse phase mask (event doesn't trigger if current phase bit is set in mask)
    if (pHolder.Event.event_inverse_phase_mask & (1 << m_Phase))
        return false;

    CreatureEventAI_Event const& event = pHolder.Event;

    //Check event conditions based on the event type, also reset events
    switch (event.event_type)
    {
    case EVENT_T_TIMER:
        if (!me->isInCombat())
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.timer.repeatMin, event.timer.repeatMax);
        break;
    case EVENT_T_TIMER_OOC:
        if (me->isInCombat())
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.timer.repeatMin, event.timer.repeatMax);
        break;
    case EVENT_T_HP: {
        if (!me->isInCombat() || !me->GetMaxHealth())
            return false;

        uint32 perc = uint32(me->GetHealthPct());

        if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.percent_range.repeatMin, event.percent_range.repeatMax);
        break;
    }
    case EVENT_T_MANA:
    {
        if (!me->isInCombat() || !me->GetMaxPower(POWER_MANA))
            return false;

        uint32 perc = (me->GetPower(POWER_MANA) * 100) / me->GetMaxPower(POWER_MANA);

        if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.percent_range.repeatMin, event.percent_range.repeatMax);
        break;
    }
    case EVENT_T_AGGRO:
        break;
    case EVENT_T_KILL:
        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.kill.repeatMin, event.kill.repeatMax);
        break;
    case EVENT_T_DEATH:
    case EVENT_T_EVADE:
        break;
    case EVENT_T_SPELLHIT:
        //Spell hit is special case, param1 and param2 handled within CreatureEventAI::SpellHit

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.spell_hit.repeatMin, event.spell_hit.repeatMax);
        break;
    case EVENT_T_RANGE:
        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.range.repeatMin, event.range.repeatMax);
        break;
    case EVENT_T_OOC_LOS:
        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.ooc_los.repeatMin, event.ooc_los.repeatMax);
        break;
    case EVENT_T_RESET:
    case EVENT_T_SPAWNED:
        break;
    case EVENT_T_TARGET_HP: {
        if (!me->isInCombat() || !me->getVictim() || !me->getVictim()->GetMaxHealth())
            return false;

        uint32 perc = uint32(me->getVictim()->GetHealthPct());

        if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.percent_range.repeatMin, event.percent_range.repeatMax);
        break;
    }
    case EVENT_T_TARGET_CASTING:
        if (!me->isInCombat() || !me->getVictim() || !me->getVictim()->IsNonMeleeSpellCasted(false, false, true))
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.target_casting.repeatMin, event.target_casting.repeatMax);
        break;
    case EVENT_T_FRIENDLY_HP:
    {
        if (!me->isInCombat())
            return false;

        Unit* pUnit = DoSelectLowestHpFriendly((float) event.friendly_hp.radius, event.friendly_hp.hpDeficit);
        if (!pUnit)
            return false;

        pActionInvoker = pUnit;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.friendly_hp.repeatMin, event.friendly_hp.repeatMax);
        break;
    }
    case EVENT_T_FRIENDLY_IS_CC:
    {
        if (!me->isInCombat())
            return false;

        std::list<Creature*> pList;
        DoFindFriendlyCC(pList, (float) event.friendly_is_cc.radius);

        //List is empty
        if (pList.empty())
            return false;

        //We don't really care about the whole list, just return first available
        pActionInvoker = *(pList.begin());

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.friendly_is_cc.repeatMin, event.friendly_is_cc.repeatMax);
        break;
    }
    case EVENT_T_FRIENDLY_MISSING_BUFF:
    {
        std::list<Creature*> pList;
        DoFindFriendlyMissingBuff(pList, (float) event.friendly_buff.radius, event.friendly_buff.spellId);

        //List is empty
        if (pList.empty())
            return false;

        //We don't really care about the whole list, just return first available
        pActionInvoker = *(pList.begin());

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.friendly_buff.repeatMin, event.friendly_buff.repeatMax);
        break;
    }
    case EVENT_T_SUMMONED_UNIT:
    {
        //Prevent event from occuring on no unit or non creatures
        if (!pActionInvoker || pActionInvoker->GetTypeId() != TYPEID_UNIT)
            return false;

        //Creature id doesn't match up
        if (pActionInvoker->ToCreature()->GetEntry() != event.summon_unit.creatureId)
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.summon_unit.repeatMin, event.summon_unit.repeatMax);
        break;
    }
    case EVENT_T_TARGET_MANA:
    {
        if (!me->isInCombat() || !me->getVictim() || !me->getVictim()->GetMaxPower(POWER_MANA))
            return false;

        uint32 perc = (me->getVictim()->GetPower(POWER_MANA) * 100) / me->getVictim()->GetMaxPower(POWER_MANA);

        if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.percent_range.repeatMin, event.percent_range.repeatMax);
        break;
    }
    case EVENT_T_REACHED_HOME:
    case EVENT_T_RECEIVE_EMOTE:
        break;
    case EVENT_T_BUFFED:
    {
        //Note: checked only aura for effect 0, if need check aura for effect 1/2 then
        // possible way: pack in event.buffed.amount 2 uint16 (ammount+effectIdx)
        Aura const * aura = me->GetAura(event.buffed.spellId);
        if (!aura || aura->GetStackAmount() < event.buffed.amount)
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.buffed.repeatMin, event.buffed.repeatMax);
        break;
    }
    case EVENT_T_TARGET_BUFFED: {
        //Prevent event from occuring on no unit
        if (!pActionInvoker)
            return false;

        //Note: checked only aura for effect 0, if need check aura for effect 1/2 then
        // possible way: pack in event.buffed.amount 2 uint16 (ammount+effectIdx)
        Aura const * aura = pActionInvoker->GetAura(event.buffed.spellId);
        if (!aura || aura->GetStackAmount() < event.buffed.amount)
            return false;

        //Repeat Timers
        pHolder.UpdateRepeatTimer(me, event.buffed.repeatMin, event.buffed.repeatMax);
        break;
    }
    default:
        sLog->outErrorDb("CreatureEventAI: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", me->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type);
        break;
    }

    //Disable non-repeatable events
    if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE))
        pHolder.Enabled = false;

    //Store random here so that all random actions match up
    uint32 rnd = rand();

    //Return if chance for event is not met
    if (pHolder.Event.event_chance <= rnd % 100)
        return false;

    //Process actions
    for (uint8 j = 0; j < MAX_ACTIONS; ++j)
        ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker);

    return true;
}
Example #3
0
    void UpdateAI(const uint32 uiDiff) override
    {
        if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
            return;

        switch (m_uiPhase)
        {
            case PHASE_FAKE_DEATH:
                if (m_uiResurrectTimer < uiDiff)
                {
                    if (!m_pInstance)
                        return;

                    if (m_pInstance->GetData(TYPE_THEKAL) != SPECIAL || m_pInstance->GetData(TYPE_ZATH) != SPECIAL)
                    {
                        DoCastSpellIfCan(m_creature, SPELL_RESURRECT);
                        m_pInstance->SetData(TYPE_LORKHAN, IN_PROGRESS);
                    }

                    m_uiPhase = PHASE_WAITING;
                }
                else
                    m_uiResurrectTimer -= uiDiff;

            // no break needed here
            case PHASE_WAITING:
                return;

            case PHASE_NORMAL:
                if (m_uiDispelTimer < uiDiff)
                {
                    std::list<Creature*> pList = DoFindFriendlyCC(30.0f);

                    Creature* dispelTarget = nullptr;

                    if (!pList.empty())
                        for (std::list<Creature*>::iterator itr = pList.begin(); itr != pList.end(); ++itr)
                        {
                            dispelTarget = (*itr);
                            break;
                        }

                    if (!dispelTarget && (m_creature->isInRoots() || m_creature->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED)))
                        dispelTarget = m_creature;

                    if (dispelTarget && (DoCastSpellIfCan(dispelTarget, SPELL_DISPEL_MAGIC) == CAST_OK))
                        m_uiDispelTimer = urand(15000, 20000);
                }
                else
                    m_uiDispelTimer -= uiDiff;

                // Lightning_Shield_Timer
                if (m_uiLightningShieldTimer < uiDiff)
                {
                    if (DoCastSpellIfCan(m_creature, SPELL_LIGHTNING_SHIELD) == CAST_OK)
                        m_uiLightningShieldTimer = 61000;
                }
                else
                    m_uiLightningShieldTimer -= uiDiff;

                // Casting Greatheal to Thekal or Zath if they are in meele range.
                // TODO - why this range check?
                if (m_uiGreatHealTimer < uiDiff)
                {
                    if (m_pInstance)
                    {
                        Creature* pThekal = m_pInstance->GetSingleCreatureFromStorage(NPC_THEKAL);
                        Creature* pZath = m_pInstance->GetSingleCreatureFromStorage(NPC_ZATH);

                        switch (urand(0, 1))
                        {
                            case 0:
                                if (pThekal && m_creature->IsWithinDistInMap(pThekal, 3 * ATTACK_DISTANCE))
                                    DoCastSpellIfCan(pThekal, SPELL_GREAT_HEAL);
                                break;
                            case 1:
                                if (pZath && m_creature->IsWithinDistInMap(pZath, 3 * ATTACK_DISTANCE))
                                    DoCastSpellIfCan(pZath, SPELL_GREAT_HEAL);
                                break;
                        }
                    }

                    m_uiGreatHealTimer = urand(15000, 20000);
                }
                else
                    m_uiGreatHealTimer -= uiDiff;

                // Disarm_Timer
                if (m_uiDisarmTimer < uiDiff)
                {
                    if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DISARM) == CAST_OK)
                        m_uiDisarmTimer = urand(15000, 25000);
                }
                else
                    m_uiDisarmTimer -= uiDiff;

                break;
        }

        DoMeleeAttackIfReady();
    }
Example #4
0
    void UpdateAI(const uint32 uiDiff)
    {
        if (!m_creature->SelectHostileTarget() || !m_creature->getVictim())
            return;

        if (m_uiArcaneTorrentTimer < uiDiff)
        {
            if (IsEnemyPlayerInRangeForSpell(SPELL_ARCANE_TORRENT))
            {
                DoCastSpellIfCan(m_creature, SPELL_ARCANE_TORRENT);
                m_uiArcaneTorrentTimer = 60000;
            }
            else
                m_uiArcaneTorrentTimer = 1000;
        }
        else
            m_uiArcaneTorrentTimer -= uiDiff;

        if (m_uiFlashHealTimer < uiDiff)
        {
            //this will fail if we previously was following target and pTarget is now different than before
            if (Unit* pTarget = DoSelectLowestHpFriendly(RANGE_FRIENDLY_TARGET*2, 30000))
            {
                if (pTarget->IsWithinDistInMap(m_creature, RANGE_FRIENDLY_TARGET))
                {
                    DoCastSpellIfCan(pTarget, SPELL_FLASH_HEAL);

                    //if not already chasing, start chase
                    if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
                        m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), 20.0f);
                }
                else
                {
                    //if chasing, start follow target instead
                    if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
                    {
                        m_creature->GetMotionMaster()->MovementExpired();
                        m_creature->GetMotionMaster()->MoveFollow(pTarget, 20.0f, 0.0f);
                    }
                }
            }

            m_uiFlashHealTimer = 2500;
        }
        else
            m_uiFlashHealTimer -= uiDiff;

        if (m_uiDispelMagicTimer < uiDiff)
        {
            Unit* pTarget = NULL;
            std::list<Creature*> lTempList = DoFindFriendlyCC(RANGE_FRIENDLY_TARGET);

            if (!lTempList.empty())
                pTarget = *(lTempList.begin());
            else
                pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0);

            if (pTarget)
                DoCastSpellIfCan(pTarget, SPELL_DISPEL_MAGIC);

            m_uiDispelMagicTimer = 12000;
        }
        else
            m_uiDispelMagicTimer -= uiDiff;

        DoMeleeAttackIfReady();
    }
    bool UpdateCompanionAI(const uint32 uiDiff)
    {
        if (m_uiGoblinDragonGunTimer < uiDiff)
        {
            if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_GOBLIN_DRAGON_GUN : SPELL_GOBLIN_DRAGON_GUN_H) == CAST_OK)
                m_uiGoblinDragonGunTimer = urand(10000, 20000);
        }
        else
            m_uiGoblinDragonGunTimer -= uiDiff;

        if (m_uiRocketLaunchTimer < uiDiff)
        {
            if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0))
            {
                if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_ROCKET_LAUNCH : SPELL_ROCKET_LAUNCH_H) == CAST_OK)
                    m_uiRocketLaunchTimer = 9000;
            }
        }
        else
            m_uiRocketLaunchTimer -= uiDiff;

        if (m_uiFelIronBombTimer < uiDiff)
        {
            if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0))
            {
                if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FEL_IRON_BOMB : SPELL_FEL_IRON_BOMB_H) == CAST_OK)
                    m_uiFelIronBombTimer = 15000;
            }
        }
        else
            m_uiFelIronBombTimer -= uiDiff;

        if (m_uiRecombobulateTimer < uiDiff)
        {
            // Note: this should be casted only on Polyformed targets
            Unit* pTarget = NULL;
            std::list<Creature*> lTempList = DoFindFriendlyCC(50.0f);

            if (!lTempList.empty())
                pTarget = *(lTempList.begin());
            else
                pTarget = DoSelectLowestHpFriendly(50.0f);

            if (pTarget)
            {
                if (DoCastSpellIfCan(pTarget, SPELL_RECOMBOBULATE) == CAST_OK)
                    m_uiRecombobulateTimer = 2000;
            }
        }
        else
            m_uiRecombobulateTimer -= uiDiff;

        if (m_uiHighExplosiveSheepTimer < uiDiff)
        {
            if (DoCastSpellIfCan(m_creature, SPELL_HIGH_EXPLOSIVE_SHEEP) == CAST_OK)
                m_uiHighExplosiveSheepTimer = 65000;
        }
        else
            m_uiHighExplosiveSheepTimer -= uiDiff;

        return true;
    }