diff options
author | megamage <none@none> | 2009-05-19 15:38:36 -0500 |
---|---|---|
committer | megamage <none@none> | 2009-05-19 15:38:36 -0500 |
commit | 74206e4b6acb921806f19f52fc8cefa4e8a2ae52 (patch) | |
tree | bc78d99e483347f49e63819603d958b114f0076c /src | |
parent | ca4c3eb8477536f7d3c5e4d0f629748fc6e4fcbb (diff) |
[7852] Use union of per-event type structures, more checks at creature event ai loading. Author: VladimirMangos
Including:
* Fixed check for EVENT_T_SPELLHIT school field. Add check at loading. Note: this event expect before and now schol _mask_ in param2.
* In EVENT_T_RECEIVE_EMOTE use original player condition check code instead copy of related code.
--HG--
branch : trunk
Diffstat (limited to 'src')
-rw-r--r-- | src/game/CreatureEventAI.cpp | 398 | ||||
-rw-r--r-- | src/game/CreatureEventAI.h | 132 | ||||
-rw-r--r-- | src/game/CreatureEventAIMgr.cpp | 129 |
3 files changed, 259 insertions, 400 deletions
diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index 1b412c3c314..116ff6d0cd3 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -32,6 +32,22 @@ #include "WorldPacket.h" #include "InstanceData.h" +bool CreatureEventAIHolder::UpdateRepeatTimer( Creature* creature, uint32 repeatMin, uint32 repeatMax ) +{ + if (repeatMin == repeatMax) + Time = repeatMin; + else if (repeatMax > repeatMin) + Time = urand(repeatMin, repeatMax); + else + { + sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", creature->GetEntry(), Event.event_id, Event.event_type); + Enabled = false; + return false; + } + + return true; +} + int CreatureEventAI::Permissible(const Creature *creature) { if( creature->GetAIName() == "EventAI" ) @@ -109,53 +125,25 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction if (pHolder.Event.event_chance <= rnd % 100) return false; - uint32 param1 = pHolder.Event.event_param1; - uint32 param2 = pHolder.Event.event_param2; - uint32 param3 = pHolder.Event.event_param3; - uint32 param4 = pHolder.Event.event_param4; + CreatureEventAI_Event const& event = pHolder.Event; //Check event conditions based on the event type, also reset events - switch (pHolder.Event.event_type) + switch (event.event_type) { case EVENT_T_TIMER: - { if (!m_creature->isInCombat()) return false; //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; + pHolder.UpdateRepeatTimer(m_creature,event.timer.repeatMin,event.timer.repeatMax); + break; case EVENT_T_TIMER_OOC: - { if (m_creature->isInCombat()) return false; //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; + pHolder.UpdateRepeatTimer(m_creature,event.timer.repeatMin,event.timer.repeatMax); + break; case EVENT_T_HP: { if (!m_creature->isInCombat() || !m_creature->GetMaxHealth()) @@ -163,24 +151,13 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction uint32 perc = (m_creature->GetHealth()*100) / m_creature->GetMaxHealth(); - if (perc > param1 || perc < param2) + if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin) return false; //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } + pHolder.UpdateRepeatTimer(m_creature,event.percent_range.repeatMin,event.percent_range.repeatMax); + break; } - break; case EVENT_T_MANA: { if (!m_creature->isInCombat() || !m_creature->GetMaxPower(POWER_MANA)) @@ -188,109 +165,38 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction uint32 perc = (m_creature->GetPower(POWER_MANA)*100) / m_creature->GetMaxPower(POWER_MANA); - if (perc > param1 || perc < param2) + if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin) return false; //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } + pHolder.UpdateRepeatTimer(m_creature,event.percent_range.repeatMin,event.percent_range.repeatMax); + break; } - break; case EVENT_T_AGGRO: - { - } - break; + break; case EVENT_T_KILL: - { //Repeat Timers - if (param1 == param2) - { - pHolder.Time = param1; - - }else if (param2 > param1) - pHolder.Time = urand(param1, param2); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } + pHolder.UpdateRepeatTimer(m_creature,event.kill.repeatMin,event.kill.repeatMax); + break; case EVENT_T_DEATH: - { - } - break; case EVENT_T_EVADE: - { - } - break; + break; case EVENT_T_SPELLHIT: - { //Spell hit is special case, param1 and param2 handled within CreatureEventAI::SpellHit //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; + pHolder.UpdateRepeatTimer(m_creature,event.spell_hit.repeatMin,event.spell_hit.repeatMax); + break; case EVENT_T_RANGE: - { //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; + pHolder.UpdateRepeatTimer(m_creature,event.range.repeatMin,event.range.repeatMax); + break; case EVENT_T_OOC_LOS: - { //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; + pHolder.UpdateRepeatTimer(m_creature,event.ooc_los.repeatMin,event.ooc_los.repeatMax); + break; case EVENT_T_SPAWNED: - { - } - break; + break; case EVENT_T_TARGET_HP: { if (!m_creature->isInCombat() || !m_creature->getVictim() || !m_creature->getVictim()->GetMaxHealth()) @@ -298,78 +204,42 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction uint32 perc = (m_creature->getVictim()->GetHealth()*100) / m_creature->getVictim()->GetMaxHealth(); - if (perc > param1 || perc < param2) + if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin) return false; //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } + pHolder.UpdateRepeatTimer(m_creature,event.percent_range.repeatMin,event.percent_range.repeatMax); + break; } - break; case EVENT_T_TARGET_CASTING: - { if (!m_creature->isInCombat() || !m_creature->getVictim() || !m_creature->getVictim()->IsNonMeleeSpellCasted(false, false, true)) return false; //Repeat Timers - if (param1 == param2) - { - pHolder.Time = param1; - - }else if (param2 > param1) - pHolder.Time = urand(param1, param2); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } - } - break; + pHolder.UpdateRepeatTimer(m_creature,event.target_casting.repeatMin,event.target_casting.repeatMax); + break; case EVENT_T_FRIENDLY_HP: { if (!m_creature->isInCombat()) return false; - Unit* pUnit = DoSelectLowestHpFriendly(param2, param1); - + Unit* pUnit = DoSelectLowestHpFriendly(event.friendly_hp.radius, event.friendly_hp.hpDeficit); if (!pUnit) return false; pActionInvoker = pUnit; //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } + pHolder.UpdateRepeatTimer(m_creature,event.friendly_hp.repeatMin,event.friendly_hp.repeatMax); + break; } - break; case EVENT_T_FRIENDLY_IS_CC: { if (!m_creature->isInCombat()) return false; std::list<Creature*> pList; - DoFindFriendlyCC(pList, param2); + DoFindFriendlyCC(pList, event.friendly_is_cc.radius); //List is empty if (pList.empty()) @@ -379,23 +249,13 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction pActionInvoker = *(pList.begin()); //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } + pHolder.UpdateRepeatTimer(m_creature,event.friendly_is_cc.repeatMin,event.friendly_is_cc.repeatMax); + break; } - break; case EVENT_T_FRIENDLY_MISSING_BUFF: { std::list<Creature*> pList; - DoFindFriendlyMissingBuff(pList, param2, param1); + DoFindFriendlyMissingBuff(pList, event.friendly_buff.radius, event.friendly_buff.spellId); //List is empty if (pList.empty()) @@ -405,20 +265,9 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction pActionInvoker = *(pList.begin()); //Repeat Timers - if (param3 == param4) - { - pHolder.Time = param3; - - }else if (param4 > param3) - pHolder.Time = urand(param3, param4); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } + pHolder.UpdateRepeatTimer(m_creature,event.friendly_buff.repeatMin,event.friendly_buff.repeatMax); + break; } - break; case EVENT_T_SUMMONED_UNIT: { //Prevent event from occuring on no unit or non creatures @@ -426,34 +275,31 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction return false; //Creature id doesn't match up - if (param1 && ((Creature*)pActionInvoker)->GetEntry() != param1) + if (((Creature*)pActionInvoker)->GetEntry() != event.summon_unit.creatureId) return false; //Repeat Timers - if (param2 == param3) - { - pHolder.Time = param2; - - }else if (param3 > param2) - pHolder.Time = urand(param2, param3); - else - { - - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); - pHolder.Enabled = false; - } + pHolder.UpdateRepeatTimer(m_creature,event.summon_unit.repeatMin,event.summon_unit.repeatMax); } break; - case EVENT_T_REACHED_HOME: + case EVENT_T_TARGET_MANA: { + if (!m_creature->isInCombat() || !m_creature->getVictim() || !m_creature->getVictim()->GetMaxPower(POWER_MANA)) + return false; + + uint32 perc = (m_creature->getVictim()->GetPower(POWER_MANA)*100) / m_creature->getVictim()->GetMaxPower(POWER_MANA); + + if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin) + return false; + + //Repeat Timers + pHolder.UpdateRepeatTimer(m_creature,event.percent_range.repeatMin,event.percent_range.repeatMax); + break; } - break; + case EVENT_T_REACHED_HOME: case EVENT_T_RECEIVE_EMOTE: - { - } - break; + break; default: - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); break; } @@ -946,25 +792,16 @@ void CreatureEventAI::Reset() //Reset all events to enabled for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) { - switch ((*i).Event.event_type) + CreatureEventAI_Event const& event = (*i).Event; + switch (event.event_type) { //Reset all out of combat timers case EVENT_T_TIMER_OOC: { - if ((*i).Event.event_param2 == (*i).Event.event_param1) - { - (*i).Time = (*i).Event.event_param1; - (*i).Enabled = true; - } - else if ((*i).Event.event_param2 > (*i).Event.event_param1) - { - (*i).Time = urand((*i).Event.event_param1, (*i).Event.event_param2); + if ((*i).UpdateRepeatTimer(m_creature,event.timer.initialMin,event.timer.initialMax)) (*i).Enabled = true; - } - else - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has InitialMax < InitialMin. Event disabled.", m_creature->GetEntry(), (*i).Event.event_id, (*i).Event.event_type); + break; } - break; //default: //TODO: enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void EnterCombat() //(*i).Enabled = true; @@ -1052,7 +889,8 @@ void CreatureEventAI::EnterCombat(Unit *enemy) { for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) { - switch ((*i).Event.event_type) + CreatureEventAI_Event const& event = (*i).Event; + switch (event.event_type) { case EVENT_T_AGGRO: (*i).Enabled = true; @@ -1060,18 +898,8 @@ void CreatureEventAI::EnterCombat(Unit *enemy) break; //Reset all in combat timers case EVENT_T_TIMER: - if ((*i).Event.event_param2 == (*i).Event.event_param1) - { - (*i).Time = (*i).Event.event_param1; + if ((*i).UpdateRepeatTimer(m_creature,event.timer.initialMin,event.timer.initialMax)) (*i).Enabled = true; - } - else if ((*i).Event.event_param2 > (*i).Event.event_param1) - { - (*i).Time = urand((*i).Event.event_param1, (*i).Event.event_param2); - (*i).Enabled = true; - } - else - sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has InitialMax < InitialMin. Event disabled.", m_creature->GetEntry(), (*i).Event.event_id, (*i).Event.event_type); break; //All normal events need to be re-enabled and their time set to 0 default: @@ -1117,14 +945,14 @@ void CreatureEventAI::MoveInLineOfSight(Unit *who) if ((*itr).Event.event_type == EVENT_T_OOC_LOS) { //can trigger if closer than fMaxAllowedRange - float fMaxAllowedRange = (*itr).Event.event_param2; + float fMaxAllowedRange = (*itr).Event.ooc_los.maxRange; //if range is ok and we are actually in LOS if (m_creature->IsWithinDistInMap(who, fMaxAllowedRange) && m_creature->IsWithinLOSInMap(who)) { //if friendly event&&who is not hostile OR hostile event&&who is hostile - if (((*itr).Event.event_param1 && !m_creature->IsHostileTo(who)) || - ((!(*itr).Event.event_param1) && m_creature->IsHostileTo(who))) + if (((*itr).Event.ooc_los.noHostile && !m_creature->IsHostileTo(who)) || + ((!(*itr).Event.ooc_los.noHostile) && m_creature->IsHostileTo(who))) ProcessEvent(*itr, who); } } @@ -1145,17 +973,11 @@ void CreatureEventAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell) return; for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i) - { if ((*i).Event.event_type == EVENT_T_SPELLHIT) - { //If spell id matches (or no spell id) & if spell school matches (or no spell school) - if (!(*i).Event.event_param1 || pSpell->Id == (*i).Event.event_param1) - { - if ((*i).Event.event_param2_s == -1 || pSpell->SchoolMask == (*i).Event.event_param2) + if (!(*i).Event.spell_hit.spellId || pSpell->Id == (*i).Event.spell_hit.spellId) + if (pSpell->SchoolMask & (*i).Event.spell_hit.schoolMask) ProcessEvent(*i, pUnit); - } - } - } } void CreatureEventAI::UpdateAI(const uint32 diff) @@ -1227,8 +1049,7 @@ void CreatureEventAI::UpdateAI(const uint32 diff) case EVENT_T_RANGE: if (me->getVictim()) if (m_creature->IsInMap(m_creature->getVictim())) - if (m_creature->IsInRange(m_creature->getVictim(), - (float)(*i).Event.event_param1,(float)(*i).Event.event_param2)) + if (m_creature->IsInRange(m_creature->getVictim(),(float)(*i).Event.range.minDist,(float)(*i).Event.range.maxDist)) ProcessEvent(*i); break; } @@ -1495,60 +1316,11 @@ void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote) { if ((*itr).Event.event_type == EVENT_T_RECEIVE_EMOTE) { - if ((*itr).Event.event_param1 != text_emote) + if ((*itr).Event.receive_emote.emoteId != text_emote) return; - bool bProcess = false; - - switch((*itr).Event.event_param2) - { - //enum ConditionType - case CONDITION_NONE: // 0 0 - bProcess = true; - break; - case CONDITION_AURA: // spell_id effindex - if (pPlayer->HasAuraEffect((*itr).Event.event_param3,(*itr).Event.event_param4)) - bProcess = true; - break; - case CONDITION_ITEM: // item_id count - if (pPlayer->HasItemCount((*itr).Event.event_param3,(*itr).Event.event_param4)) - bProcess = true; - break; - case CONDITION_ITEM_EQUIPPED: // item_id count - if (pPlayer->HasItemOrGemWithIdEquipped((*itr).Event.event_param3,(*itr).Event.event_param4)) - bProcess = true; - break; - case CONDITION_ZONEID: // zone_id 0 - if (pPlayer->GetZoneId() == (*itr).Event.event_param3) - bProcess = true; - break; - case CONDITION_REPUTATION_RANK: // faction_id min_rank - if (pPlayer->GetReputationRank((*itr).Event.event_param3) >= (*itr).Event.event_param4) - bProcess = true; - break; - case CONDITION_TEAM: // player_team 0, (469 - Alliance 67 - Horde) - if (pPlayer->GetTeam() == (*itr).Event.event_param3) - bProcess = true; - break; - case CONDITION_SKILL: // skill_id min skill_value - if (pPlayer->HasSkill((*itr).Event.event_param3) && pPlayer->GetSkillValue((*itr).Event.event_param3) >= (*itr).Event.event_param4) - bProcess = true; - break; - case CONDITION_QUESTREWARDED: // quest_id 0 - if (pPlayer->GetQuestRewardStatus((*itr).Event.event_param3)) - bProcess = true; - break; - case CONDITION_QUESTTAKEN: // quest_id 0, for condition true while quest active. - if (pPlayer->GetQuestStatus((*itr).Event.event_param3) == QUEST_STATUS_INCOMPLETE) - bProcess = true; - break; - case CONDITION_ACTIVE_EVENT: // event_id 0 - if (IsHolidayActive(HolidayIds((*itr).Event.event_param3))) - bProcess = true; - break; - } - - if (bProcess) + PlayerCondition pcon((*itr).Event.receive_emote.condition,(*itr).Event.receive_emote.conditionValue1,(*itr).Event.receive_emote.conditionValue2); + if (pcon.Meets(pPlayer)) { sLog.outDebug("CreatureEventAI: ReceiveEmote CreatureEventAI: Condition ok, processing"); ProcessEvent(*itr, pPlayer); diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h index 412a3b1919d..8baa551ec6a 100644 --- a/src/game/CreatureEventAI.h +++ b/src/game/CreatureEventAI.h @@ -44,7 +44,7 @@ enum EventAI_Type EVENT_T_EVADE = 7, // NONE EVENT_T_SPELLHIT = 8, // SpellID, School, RepeatMin, RepeatMax EVENT_T_RANGE = 9, // MinDist, MaxDist, RepeatMin, RepeatMax - EVENT_T_OOC_LOS = 10, // NoHostile, NoFriendly, RepeatMin, RepeatMax + EVENT_T_OOC_LOS = 10, // NoHostile, MaxRnage, RepeatMin, RepeatMax EVENT_T_SPAWNED = 11, // NONE EVENT_T_TARGET_HP = 12, // HPMax%, HPMin%, RepeatMin, RepeatMax EVENT_T_TARGET_CASTING = 13, // RepeatMin, RepeatMax @@ -382,23 +382,116 @@ struct CreatureEventAI_Event union { - uint32 event_param1; - int32 event_param1_s; - }; - union - { - uint32 event_param2; - int32 event_param2_s; - }; - union - { - uint32 event_param3; - int32 event_param3_s; - }; - union - { - uint32 event_param4; - int32 event_param4_s; + // EVENT_T_TIMER = 0 + // EVENT_T_TIMER_OOC = 1 + struct + { + uint32 initialMin; + uint32 initialMax; + uint32 repeatMin; + uint32 repeatMax; + } timer; + // EVENT_T_HP = 2 + // EVENT_T_MANA = 3 + // EVENT_T_TARGET_HP = 12 + // EVENT_T_TARGET_MANA = 18 + struct + { + uint32 percentMax; + uint32 percentMin; + uint32 repeatMin; + uint32 repeatMax; + } percent_range; + // EVENT_T_KILL = 5 + struct + { + uint32 repeatMin; + uint32 repeatMax; + } kill; + // EVENT_T_SPELLHIT = 8 + struct + { + uint32 spellId; + uint32 schoolMask; // -1 (==0xffffffff) is ok value for full mask, or must be more limited mask like (0 < 1) = 1 for normal/physical school + uint32 repeatMin; + uint32 repeatMax; + } spell_hit; + // EVENT_T_RANGE = 9 + struct + { + uint32 minDist; + uint32 maxDist; + uint32 repeatMin; + uint32 repeatMax; + } range; + // EVENT_T_OOC_LOS = 10 + struct + { + uint32 noHostile; + uint32 maxRange; + uint32 repeatMin; + uint32 repeatMax; + } ooc_los; + // EVENT_T_TARGET_CASTING = 13 + struct + { + uint32 repeatMin; + uint32 repeatMax; + } target_casting; + // EVENT_T_FRIENDLY_HP = 14 + struct + { + uint32 hpDeficit; + uint32 radius; + uint32 repeatMin; + uint32 repeatMax; + } friendly_hp; + // EVENT_T_FRIENDLY_IS_CC = 15 + struct + { + uint32 dispelType; // unused ? + uint32 radius; + uint32 repeatMin; + uint32 repeatMax; + } friendly_is_cc; + // EVENT_T_FRIENDLY_MISSING_BUFF = 16 + struct + { + uint32 spellId; + uint32 radius; + uint32 repeatMin; + uint32 repeatMax; + } friendly_buff; + // EVENT_T_SUMMONED_UNIT = 17 + struct + { + uint32 creatureId; + uint32 repeatMin; + uint32 repeatMax; + } summon_unit; + // EVENT_T_QUEST_ACCEPT = 19 + // EVENT_T_QUEST_COMPLETE = 20 + struct + { + uint32 questId; + } quest; + // EVENT_T_RECEIVE_EMOTE = 22 + struct + { + uint32 emoteId; + uint32 condition; + uint32 conditionValue1; + uint32 conditionValue2; + } receive_emote; + + // RAW + struct + { + uint32 param1; + uint32 param2; + uint32 param3; + uint32 param4; + } raw; }; CreatureEventAI_Action action[MAX_ACTIONS]; @@ -427,6 +520,9 @@ struct CreatureEventAIHolder CreatureEventAI_Event Event; uint32 Time; bool Enabled; + + // helper + bool UpdateRepeatTimer(Creature* creature, uint32 repeatMin, uint32 repeatMax); }; class TRINITY_DLL_SPEC CreatureEventAI : public CreatureAI diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp index a8e3f04db71..a5f7395d68d 100644 --- a/src/game/CreatureEventAIMgr.cpp +++ b/src/game/CreatureEventAIMgr.cpp @@ -205,10 +205,10 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() temp.event_inverse_phase_mask = fields[3].GetUInt32(); temp.event_chance = fields[4].GetUInt8(); temp.event_flags = fields[5].GetUInt8(); - temp.event_param1 = fields[6].GetUInt32(); - temp.event_param2 = fields[7].GetUInt32(); - temp.event_param3 = fields[8].GetUInt32(); - temp.event_param4 = fields[9].GetUInt32(); + temp.raw.param1 = fields[6].GetUInt32(); + temp.raw.param2 = fields[7].GetUInt32(); + temp.raw.param3 = fields[8].GetUInt32(); + temp.raw.param4 = fields[9].GetUInt32(); //Creature does not exist in database if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.creature_id)) @@ -232,87 +232,97 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() { case EVENT_T_TIMER: case EVENT_T_TIMER_OOC: - { - if (temp.event_param2 < temp.event_param1) + if (temp.timer.initialMax < temp.timer.initialMin) sLog.outErrorDb("CreatureEventAI: Creature %u are using timed event(%u) with param2 < param1 (InitialMax < InitialMin). Event will never repeat.", temp.creature_id, i); - - if (temp.event_param4 < temp.event_param3) + if (temp.timer.repeatMax < temp.timer.repeatMin) sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); - break; - } - case EVENT_T_HP: case EVENT_T_MANA: case EVENT_T_TARGET_HP: - { - if (temp.event_param2 > 100) + case EVENT_T_TARGET_MANA: + if (temp.percent_range.percentMax > 100) sLog.outErrorDb("CreatureEventAI: Creature %u are using percentage event(%u) with param2 (MinPercent) > 100. Event will never trigger! ", temp.creature_id, i); - if (temp.event_param1 <= temp.event_param2) + if (temp.percent_range.percentMax <= temp.percent_range.percentMin) sLog.outErrorDb("CreatureEventAI: Creature %u are using percentage event(%u) with param1 <= param2 (MaxPercent <= MinPercent). Event will never trigger! ", temp.creature_id, i); - if (temp.event_flags & EFLAG_REPEATABLE && !temp.event_param3 && !temp.event_param4) + if (temp.event_flags & EFLAG_REPEATABLE && !temp.percent_range.repeatMin && !temp.percent_range.repeatMax) { sLog.outErrorDb("CreatureEventAI: Creature %u has param3 and param4=0 (RepeatMin/RepeatMax) but cannot be repeatable without timers. Removing EFLAG_REPEATABLE for event %u.", temp.creature_id, i); temp.event_flags &= ~EFLAG_REPEATABLE; } break; - } - case EVENT_T_SPELLHIT: - { - if (temp.event_param1) + if (temp.spell_hit.spellId) { - SpellEntry const* pSpell = sSpellStore.LookupEntry(temp.event_param1); + SpellEntry const* pSpell = sSpellStore.LookupEntry(temp.spell_hit.spellId); if (!pSpell) { - sLog.outErrorDb("CreatureEventAI: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.event_param1, i); + sLog.outErrorDb("CreatureEventAI: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.spell_hit.spellId, i); continue; } - if (temp.event_param2_s != -1 && temp.event_param2 != pSpell->SchoolMask) - sLog.outErrorDb("CreatureEventAI: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", temp.creature_id, temp.event_param1, i); + if ((temp.spell_hit.schoolMask & pSpell->SchoolMask) != pSpell->SchoolMask) + sLog.outErrorDb("CreatureEventAI: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", temp.creature_id, temp.spell_hit.schoolMask, i); } - //TODO: fix this system with SPELL_SCHOOL_MASK. Current complicate things, using int32(-1) instead of just 0 - //SPELL_SCHOOL_MASK_NONE = 0 and does not exist, thus it can not ever trigger or be used in SpellHit() - if (temp.event_param2_s != -1 && temp.event_param2_s > SPELL_SCHOOL_MASK_ALL) - sLog.outErrorDb("CreatureEventAI: Creature %u is using invalid SpellSchoolMask(%u) defined in event %u.", temp.creature_id, temp.event_param2, i); + if (!temp.spell_hit.schoolMask) + sLog.outErrorDb("CreatureEventAI: Creature %u is using invalid SpellSchoolMask(%u) defined in event %u.", temp.creature_id, temp.spell_hit.schoolMask, i); - if (temp.event_param4 < temp.event_param3) + if (temp.spell_hit.repeatMax < temp.spell_hit.repeatMin) sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); break; - } - case EVENT_T_RANGE: + if (temp.range.maxDist < temp.range.minDist) + sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (MaxDist < MinDist). Event will never repeat.", temp.creature_id, i); + if (temp.range.repeatMax < temp.range.repeatMin) + sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + break; case EVENT_T_OOC_LOS: + if (temp.ooc_los.repeatMax < temp.ooc_los.repeatMin) + sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + break; case EVENT_T_FRIENDLY_HP: + if (temp.friendly_hp.repeatMax < temp.friendly_hp.repeatMin) + sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + break; case EVENT_T_FRIENDLY_IS_CC: + if (temp.friendly_is_cc.repeatMax < temp.friendly_is_cc.repeatMin) + sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + break; case EVENT_T_FRIENDLY_MISSING_BUFF: { - //Disabled check for now. Check code related to events and adjust accordingly before enable. - //Events should have min/max or alternative set to a static value. - /*if (!temp.event_param3 && !temp.event_param4) + SpellEntry const* pSpell = sSpellStore.LookupEntry(temp.spell_hit.spellId); + if (!pSpell) { - sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) without param3/param4 (RepeatMin/RepeatMax). Using minimum values.", temp.creature_id, i); - temp.event_param3 = 2500; - temp.event_param4 = 2500; - }*/ - - if (temp.event_param4 < temp.event_param3) + sLog.outErrorDb("CreatureEventAI: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.spell_hit.spellId, i); + continue; + } + if (temp.friendly_buff.repeatMax < temp.friendly_buff.repeatMin) sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); break; } - case EVENT_T_KILL: + if (temp.kill.repeatMax < temp.kill.repeatMin) + sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + break; case EVENT_T_TARGET_CASTING: - { - if (temp.event_param2 < temp.event_param1) + if (temp.target_casting.repeatMax < temp.target_casting.repeatMin) sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); - break; - } + case EVENT_T_SUMMONED_UNIT: + if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.summon_unit.creatureId)) + sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with not existed creature template id (%u) in param1, skipped.", temp.creature_id, i, temp.summon_unit.creatureId); + if (temp.summon_unit.repeatMax < temp.summon_unit.repeatMin) + sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); + break; + case EVENT_T_QUEST_ACCEPT: + case EVENT_T_QUEST_COMPLETE: + if (!objmgr.GetQuestTemplate(temp.quest.questId)) + sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with not existed qyest id (%u) in param1, skipped.", temp.creature_id, i, temp.quest.questId); + sLog.outErrorDb("CreatureEventAI: Creature %u using not implemented event (%u) in event %u.", temp.creature_id, temp.event_id, i); + continue; case EVENT_T_AGGRO: case EVENT_T_DEATH: @@ -331,21 +341,15 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() case EVENT_T_RECEIVE_EMOTE: { - if (!sEmotesTextStore.LookupEntry(temp.event_param1)) + if (!sEmotesTextStore.LookupEntry(temp.receive_emote.emoteId)) { - sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param1 (EmoteTextId: %u) are not valid.",temp.creature_id, i, temp.event_param1); + sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param1 (EmoteTextId: %u) are not valid.",temp.creature_id, i, temp.receive_emote.emoteId); continue; } - if (temp.event_param2 == CONDITION_AD_COMMISSION_AURA || temp.event_param2 == CONDITION_NO_AURA) + if (!PlayerCondition::IsValid(ConditionType(temp.receive_emote.condition), temp.receive_emote.conditionValue1, temp.receive_emote.conditionValue2)) { - sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param2 (Condition: %u) are not implemented for EventAI.",temp.creature_id, i, temp.event_param2); - continue; - } - - if (!PlayerCondition::IsValid(ConditionType(temp.event_param2), temp.event_param3, temp.event_param4)) - { - sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param2 (Condition: %u) are not valid.",temp.creature_id, i, temp.event_param2); + sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param2 (Condition: %u) are not valid.",temp.creature_id, i, temp.receive_emote.condition); continue; } @@ -358,21 +362,6 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() break; } - case EVENT_T_SUMMONED_UNIT: - { - if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.event_param1)) - sLog.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with not existed creature template id (%u) in param1, skipped.", temp.creature_id, i, temp.event_param1); - - if (temp.event_param3 < temp.event_param2) - sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param3 < param2 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); - - break; - } - - case EVENT_T_QUEST_ACCEPT: - case EVENT_T_QUEST_COMPLETE: - sLog.outErrorDb("CreatureEventAI: Creature %u using not implemented event (%u) in event %u.", temp.creature_id, temp.event_id, i); - continue; default: sLog.outErrorDb("CreatureEventAI: Creature %u using not checked at load event (%u) in event %u. Need check code update?", temp.creature_id, temp.event_id, i); break; @@ -486,6 +475,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() const SpellEntry *spell = sSpellStore.LookupEntry(action.cast.spellId); if (!spell) sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent SpellID %u.", i, j+1, action.cast.spellId); + /* FIXME: temp.raw.param3 not have event tipes with recovery time in it.... else { if (spell->RecoveryTime > 0 && temp.event_flags & EFLAG_REPEATABLE) @@ -495,6 +485,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() sLog.outDebug("CreatureEventAI: Event %u Action %u uses SpellID %u but cooldown is longer(%u) than minumum defined in event param3(%u).", i, j+1,action.cast.spellId, spell->RecoveryTime, temp.event_param3); } } + */ //Cast is always triggered if target is forced to cast on self if (action.cast.castFlags & CAST_FORCE_TARGET_SELF) |