bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& holder, Unit* actionInvoker /*=NULL*/)
{
    if (!holder.Enabled || holder.Time)
        return false;

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

    CreatureEventAI_Event const& event = holder.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
        holder.UpdateRepeatTimer(me, event.timer.repeatMin, event.timer.repeatMax);
        break;
    case EVENT_T_TIMER_OOC:
        if (me->isInCombat())
            return false;

        //Repeat Timers
        holder.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
        holder.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
        holder.UpdateRepeatTimer(me, event.percent_range.repeatMin, event.percent_range.repeatMax);
        break;
    }
    case EVENT_T_AGGRO:
        break;
    case EVENT_T_KILL:
        //Repeat Timers
        holder.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
        holder.UpdateRepeatTimer(me, event.spell_hit.repeatMin, event.spell_hit.repeatMax);
        break;
    case EVENT_T_RANGE:
        //Repeat Timers
        holder.UpdateRepeatTimer(me, event.range.repeatMin, event.range.repeatMax);
        break;
    case EVENT_T_OOC_LOS:
        //Repeat Timers
        holder.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
        holder.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
        holder.UpdateRepeatTimer(me, event.target_casting.repeatMin, event.target_casting.repeatMax);
        break;
    case EVENT_T_FRIENDLY_HP:
    {
        if (!me->isInCombat())
            return false;

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

        actionInvoker = unit;

        //Repeat Timers
        holder.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
        actionInvoker = *(pList.begin());

        //Repeat Timers
        holder.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
        actionInvoker = *(pList.begin());

        //Repeat Timers
        holder.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 (!actionInvoker || actionInvoker->GetTypeId() != TYPEID_UNIT)
            return false;

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

        //Repeat Timers
        holder.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
        holder.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
        holder.UpdateRepeatTimer(me, event.buffed.repeatMin, event.buffed.repeatMax);
        break;
    }
    case EVENT_T_TARGET_BUFFED:
    {
        //Prevent event from occuring on no unit
        if (!actionInvoker)
            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 = actionInvoker->GetAura(event.buffed.spellId);
        if (!aura || aura->GetStackAmount() < event.buffed.amount)
            return false;

        //Repeat Timers
        holder.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(), holder.Event.event_id, holder.Event.event_type);
        break;
    }

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

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

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

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

    return true;
}
Esempio n. 2
0
bool GuardianAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker, Creature* pAIEventSender /*=nullptr*/)
{
    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))
    {
        if (!IsTimerBasedEvent(pHolder.Event.event_type))
            DEBUG_FILTER_LOG(LOG_FILTER_EVENT_AI_DEV, "CreatureEventAI: Event %u skipped because of phasemask %u. Current phase %u", pHolder.Event.event_id, pHolder.Event.event_inverse_phase_mask, m_Phase);
        return false;
    }

    if (!IsTimerBasedEvent(pHolder.Event.event_type))
        LOG_PROCESS_EVENT;

    CreatureEventAI_Event const& event = pHolder.Event;

    // Check event conditions based on the event type, also reset events
    switch (event.event_type)
    {
        case EVENT_T_FRIENDLY_HP:
        {
            Unit* pUnit = DoSelectLowestHpFriendly((float)event.friendly_hp.radius, event.friendly_hp.hpDeficit, false);
            if (!pUnit)
                return false;

            pActionInvoker = pUnit;

            LOG_PROCESS_EVENT;
            // Repeat Timers
            pHolder.UpdateRepeatTimer(m_creature, event.friendly_hp.repeatMin, event.friendly_hp.repeatMax);
            break;
        }
        default:
            return CreatureEventAI::ProcessEvent(pHolder, pActionInvoker, pAIEventSender);
    }

    // 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, normal case
    if (!(pHolder.Event.event_flags & EFLAG_RANDOM_ACTION))
    {
        for (uint32 j = 0; j < MAX_ACTIONS; ++j)
            ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker, pAIEventSender);
    }
    // Process actions, random case
    else
    {
        // amount of real actions
        uint32 count = 0;
        for (uint32 j = 0; j < MAX_ACTIONS; ++j)
            if (pHolder.Event.action[j].type != ACTION_T_NONE)
                ++count;

        if (count)
        {
            // select action number from found amount
            uint32 idx = rnd % count;

            // find selected action, skipping not used
            uint32 j = 0;
            for (; ; ++j)
            {
                if (pHolder.Event.action[j].type != ACTION_T_NONE)
                {
                    if (!idx)
                        break;
                    --idx;
                }
            }

            ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker, pAIEventSender);
        }
    }
    return true;
}