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; }
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; }