aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game/CreatureEventAI.cpp398
-rw-r--r--src/game/CreatureEventAI.h132
-rw-r--r--src/game/CreatureEventAIMgr.cpp129
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)