aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game/Chat.cpp18
-rw-r--r--src/game/Chat.h4
-rw-r--r--src/game/CreatureEventAI.cpp413
-rw-r--r--src/game/CreatureEventAI.h224
-rw-r--r--src/game/CreatureEventAIMgr.cpp308
-rw-r--r--src/game/DBCfmt.h2
-rw-r--r--src/game/Level3.cpp35
-rw-r--r--src/game/ObjectMgr.cpp6
-rw-r--r--src/game/ObjectMgr.h2
-rw-r--r--src/game/SpellAuras.cpp21
-rw-r--r--src/game/SpellEffects.cpp14
-rw-r--r--src/game/SpellMgr.cpp4
-rw-r--r--src/shared/Util.h2
13 files changed, 620 insertions, 433 deletions
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index 9fe252154ed..3f10662f6ac 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -408,30 +408,34 @@ ChatCommand * ChatHandler::getCommandTable()
{ "all", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllCommand, "", NULL },
{ "all_achievement",SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllAchievementCommand,"", NULL },
{ "all_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllAreaCommand, "", NULL },
+ { "all_eventai", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllEventAICommand, "", NULL },
+ { "all_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllItemCommand, "", NULL },
+ { "all_locales", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLocalesCommand, "", NULL },
{ "all_loot", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLootCommand, "", NULL },
{ "all_npc", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllNpcCommand, "", NULL },
{ "all_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllQuestCommand, "", NULL },
{ "all_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllScriptsCommand, "", NULL },
{ "all_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllSpellCommand, "", NULL },
- { "all_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllItemCommand, "", NULL },
- { "all_locales", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLocalesCommand, "", NULL },
{ "config", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadConfigCommand, "", NULL },
{ "achievement_criteria_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAchievementCriteriaDataCommand, "", NULL },
{ "achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAchievementRewardCommand, "", NULL },
+ { "areatrigger_involvedrelation",SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestAreaTriggersCommand, "", NULL },
{ "areatrigger_tavern", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTavernCommand, "", NULL },
{ "areatrigger_teleport", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTeleportCommand, "", NULL },
{ "access_requirement", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAccessRequirementCommand, "", NULL },
- { "areatrigger_involvedrelation",SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestAreaTriggersCommand, "", NULL },
- { "event_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL },
{ "command", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommandCommand, "", NULL },
+ { "creature_ai_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAIScriptsCommand, "", NULL },
+ { "creature_ai_summons", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAISummonsCommand, "", NULL },
+ { "creature_ai_texts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAITextsCommand, "", NULL },
{ "creature_involvedrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand,"",NULL },
{ "creature_linked_respawn", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureLinkedRespawnCommand, "", NULL },
{ "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL },
{ "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL },
//{ "db_script_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDbScriptStringCommand, "", NULL },
{ "disenchant_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesDisenchantCommand, "", NULL },
+ { "event_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL },
{ "fishing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesFishingCommand, "", NULL },
{ "game_graveyard_zone", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameGraveyardZoneCommand, "", NULL },
{ "game_tele", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameTeleCommand, "", NULL },
@@ -453,15 +457,15 @@ ChatCommand * ChatHandler::getCommandTable()
{ "milling_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesMillingCommand, "", NULL },
{ "npc_gossip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcGossipCommand, "", NULL },
{ "npc_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcOptionCommand, "", NULL },
+ { "npc_spellclick_spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellClickSpellsCommand, "",NULL},
{ "npc_trainer", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL },
{ "npc_vendor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL },
{ "page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPageTextsCommand, "", NULL },
{ "pickpocketing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesPickpocketingCommand,"",NULL},
{ "points_of_interest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPointsOfInterestCommand, "",NULL},
- { "npc_spellclick_spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellClickSpellsCommand, "",NULL},
{ "prospecting_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesProspectingCommand,"", NULL },
- { "quest_mail_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesQuestMailCommand, "", NULL },
{ "quest_end_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestEndScriptsCommand, "", NULL },
+ { "quest_mail_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesQuestMailCommand, "", NULL },
{ "quest_start_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestStartScriptsCommand, "", NULL },
{ "quest_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestTemplateCommand, "", NULL },
{ "reference_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesReferenceCommand, "", NULL },
@@ -473,13 +477,13 @@ ChatCommand * ChatHandler::getCommandTable()
{ "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL },
{ "spell_required", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellRequiredCommand, "", NULL },
{ "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAreaCommand, "", NULL },
+ { "spell_bonus_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellBonusesCommand, "", NULL },
{ "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL },
{ "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL },
{ "spell_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSpellCommand, "", NULL },
{ "spell_linked_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLinkedSpellCommand, "", NULL },
{ "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL },
{ "spell_proc_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL },
- { "spell_bonus_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellBonusesCommand, "", NULL },
{ "spell_script_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptTargetCommand, "", NULL },
{ "spell_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptsCommand, "", NULL },
{ "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL },
diff --git a/src/game/Chat.h b/src/game/Chat.h
index fe0e197ee4b..1bef4db0d42 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -326,6 +326,7 @@ class ChatHandler
bool HandleReloadAllNpcCommand(const char* args);
bool HandleReloadAllQuestCommand(const char* args);
bool HandleReloadAllScriptsCommand(const char* args);
+ bool HandleReloadAllEventAICommand(const char* args);
bool HandleReloadAllSpellCommand(const char* args);
bool HandleReloadAllLocalesCommand(const char* args);
@@ -337,6 +338,9 @@ class ChatHandler
bool HandleReloadAreaTriggerTeleportCommand(const char* args);
bool HandleReloadAccessRequirementCommand(const char* args);
bool HandleReloadEventScriptsCommand(const char* args);
+ bool HandleReloadEventAITextsCommand(const char* args);
+ bool HandleReloadEventAISummonsCommand(const char* args);
+ bool HandleReloadEventAIScriptsCommand(const char* args);
bool HandleReloadCommandCommand(const char* args);
bool HandleReloadCreatureQuestRelationsCommand(const char* args);
bool HandleReloadCreatureQuestInvRelationsCommand(const char* args);
diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp
index 5c89e5d9022..1b412c3c314 100644
--- a/src/game/CreatureEventAI.cpp
+++ b/src/game/CreatureEventAI.cpp
@@ -41,6 +41,7 @@ int CreatureEventAI::Permissible(const Creature *creature)
CreatureEventAI::CreatureEventAI(Creature *c ) : CreatureAI(c)
{
+ // Need make copy for filter unneeded steps and safe in case table reload
CreatureEventAI_Event_Map::const_iterator CreatureEvents = CreatureEAI_Mgr.GetCreatureEventAIMap().find(m_creature->GetEntry());
if (CreatureEvents != CreatureEAI_Mgr.GetCreatureEventAIMap().end())
{
@@ -463,37 +464,35 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction
//Process actions
for (uint32 j = 0; j < MAX_ACTIONS; j++)
- ProcessAction(pHolder.Event.action[j].type, pHolder.Event.action[j].param1, pHolder.Event.action[j].param2, pHolder.Event.action[j].param3, rnd, pHolder.Event.event_id, pActionInvoker);
+ ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker);
return true;
}
-void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, uint32 param3, uint32 rnd, uint32 EventId, Unit* pActionInvoker)
+void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker)
{
- switch (type)
+ switch (action.type)
{
case ACTION_T_TEXT:
{
- if (!param1)
+ if (!action.text.TextId1)
return;
- uint32 temp = 0;
+ int32 temp = 0;
- if (param2 && param3)
+ if (action.text.TextId2 && action.text.TextId3)
{
switch( rand()%3 )
{
- case 0: temp = param1; break;
- case 2: temp = param2; break;
- case 3: temp = param3; break;
+ case 0: temp = action.text.TextId1; break;
+ case 2: temp = action.text.TextId2; break;
+ case 3: temp = action.text.TextId3; break;
}
- }else if ( param2 && urand(0,1) )
- {
- temp = param2;
- }else
- {
- temp = param1;
}
+ else if (action.text.TextId2 && urand(0,1))
+ temp = action.text.TextId2;
+ else
+ temp = action.text.TextId1;
if (temp)
{
@@ -519,12 +518,12 @@ void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, u
DoScriptText(temp, m_creature, target);
}
+ break;
}
- break;
case ACTION_T_SET_FACTION:
{
- if (param1)
- m_creature->setFaction(param1);
+ if (action.set_faction.factionId)
+ m_creature->setFaction(action.set_faction.factionId);
else
{
if (CreatureInfo const* ci = GetCreatureTemplateStore(m_creature->GetEntry()))
@@ -534,16 +533,16 @@ void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, u
m_creature->setFaction(ci->faction_A);
}
}
+ break;
}
- break;
case ACTION_T_MORPH_TO_ENTRY_OR_MODEL:
{
- if (param1 || param2)
+ if (action.morph.creatireId || action.morph.modelId)
{
//set model based on entry from creature_template
- if (param1)
+ if (action.morph.creatireId)
{
- if (CreatureInfo const* ci = GetCreatureTemplateStore(param1))
+ if (CreatureInfo const* ci = GetCreatureTemplateStore(action.morph.creatireId))
{
//use default display
if (ci->Modelid_A1)
@@ -552,72 +551,66 @@ void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, u
}
//if no param1, then use value from param2 (modelId)
else
- m_creature->SetDisplayId(param2);
+ m_creature->SetDisplayId(action.morph.modelId);
}
else
m_creature->DeMorph();
+ break;
}
- break;
case ACTION_T_SOUND:
- m_creature->PlayDirectSound(param1);
+ m_creature->PlayDirectSound(action.sound.soundId);
break;
case ACTION_T_EMOTE:
- m_creature->HandleEmoteCommand(param1);
+ m_creature->HandleEmoteCommand(action.emote.emoteId);
break;
case ACTION_T_RANDOM_SOUND:
{
- uint32 temp = GetRandActionParam(rnd, param1, param2, param3);
-
- if (temp != uint32(0xffffffff))
- m_creature->PlayDirectSound( temp );
+ int32 temp = GetRandActionParam(rnd, action.random_sound.soundId1, action.random_sound.soundId2, action.random_sound.soundId3);
+ if (temp >= 0)
+ m_creature->PlayDirectSound(temp);
+ break;
}
- break;
case ACTION_T_RANDOM_EMOTE:
{
- uint32 temp = GetRandActionParam(rnd, param1, param2, param3);
-
- if (temp != uint32(0xffffffff))
+ int32 temp = GetRandActionParam(rnd, action.random_emote.emoteId1, action.random_emote.emoteId2, action.random_emote.emoteId3);
+ if (temp >= 0)
m_creature->HandleEmoteCommand(temp);
+ break;
}
- break;
case ACTION_T_CAST:
{
- Unit* target = GetTargetByType(param2, pActionInvoker);
+ Unit* target = GetTargetByType(action.cast.target, pActionInvoker);
Unit* caster = m_creature;
if (!target)
return;
- //Cast is always triggered if target is forced to cast on self
- if (param3 & CAST_FORCE_TARGET_SELF)
- {
- param3 |= CAST_TRIGGERED;
+ if (action.cast.castFlags & CAST_FORCE_TARGET_SELF)
caster = target;
- }
//Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered
- bool canCast = !caster->IsNonMeleeSpellCasted(false) || (param3 & (CAST_TRIGGERED | CAST_INTURRUPT_PREVIOUS));
+ bool canCast = !caster->IsNonMeleeSpellCasted(false) || (action.cast.castFlags & (CAST_TRIGGERED | CAST_INTURRUPT_PREVIOUS));
// If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them
- if(param3 & CAST_AURA_NOT_PRESENT)
+ if(action.cast.castFlags & CAST_AURA_NOT_PRESENT)
{
- if(target->HasAura(param1))
+ if(target->HasAura(action.cast.spellId))
return;
}
if (canCast)
{
- const SpellEntry* tSpell = GetSpellStore()->LookupEntry(param1);
+ const SpellEntry* tSpell = GetSpellStore()->LookupEntry(action.cast.spellId);
//Verify that spell exists
if (tSpell)
{
//Check if cannot cast spell
- if (!(param3 & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST)) &&
- !CanCast(target, tSpell, (param3 & CAST_TRIGGERED)))
+ if (!(action.cast.castFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST)) &&
+ !CanCast(target, tSpell, (action.cast.castFlags & CAST_TRIGGERED)))
{
//Melee current victim if flag not set
- if (!(param3 & CAST_NO_MELEE_IF_OOM))
+ if (!(action.cast.castFlags & CAST_NO_MELEE_IF_OOM))
{
if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE)
{
@@ -632,111 +625,83 @@ void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, u
else
{
//Interrupt any previous spell
- if (caster->IsNonMeleeSpellCasted(false) && param3 & CAST_INTURRUPT_PREVIOUS)
+ if (caster->IsNonMeleeSpellCasted(false) && action.cast.castFlags & CAST_INTURRUPT_PREVIOUS)
caster->InterruptNonMeleeSpells(false);
- caster->CastSpell(target, param1, (param3 & CAST_TRIGGERED));
+ caster->CastSpell(target, action.cast.spellId, (action.cast.castFlags & CAST_TRIGGERED));
}
- }else
- sLog.outErrorDb("CreatureEventAI: event %d creature %d attempt to cast spell that doesn't exist %d", EventId, m_creature->GetEntry(), param1);
+ }
+ else
+ sLog.outErrorDb("CreatureEventAI: event %d creature %d attempt to cast spell that doesn't exist %d", EventId, m_creature->GetEntry(), action.cast.spellId);
}
+ break;
}
- break;
case ACTION_T_SUMMON:
{
- Unit* target = GetTargetByType(param2, pActionInvoker);
+ Unit* target = GetTargetByType(action.summon.target, pActionInvoker);
Creature* pCreature = NULL;
- if (param3)
- pCreature = m_creature->SummonCreature(param1, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, param3);
+ if (action.summon.duration)
+ pCreature = m_creature->SummonCreature(action.summon.creatured, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, action.summon.duration);
else
- pCreature = m_creature->SummonCreature(param1, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
+ pCreature = m_creature->SummonCreature(action.summon.creatured, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
if (!pCreature)
- {
-
- sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. Spawn event %d is on creature %d", param1, EventId, m_creature->GetEntry());
- }
- else if (param2 != TARGET_T_SELF && target)
+ sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. Spawn event %d is on creature %d", action.summon.creatured, EventId, m_creature->GetEntry());
+ else if (action.summon.target != TARGET_T_SELF && target)
pCreature->AI()->AttackStart(target);
+ break;
}
- break;
case ACTION_T_THREAT_SINGLE_PCT:
- {
- Unit* target = GetTargetByType(param2, pActionInvoker);
-
- if (target)
- m_creature->getThreatManager().modifyThreatPercent(target, param1);
- }
- break;
+ if (Unit* target = GetTargetByType(action.threat_single_pct.target, pActionInvoker))
+ m_creature->getThreatManager().modifyThreatPercent(target, action.threat_single_pct.percent);
+ break;
case ACTION_T_THREAT_ALL_PCT:
{
- Unit* Temp = NULL;
-
- std::list<HostilReference*>::iterator i = m_creature->getThreatManager().getThreatList().begin();
- for (; i != m_creature->getThreatManager().getThreatList().end(); ++i)
- {
- Temp = Unit::GetUnit(*m_creature,(*i)->getUnitGuid());
- if (Temp)
- m_creature->getThreatManager().modifyThreatPercent(Temp, param1);
- }
+ std::list<HostilReference*>& threatList = m_creature->getThreatManager().getThreatList();
+ for (std::list<HostilReference*>::iterator i = threatList.begin(); i != threatList.end(); ++i)
+ if(Unit* Temp = Unit::GetUnit(*m_creature,(*i)->getUnitGuid()))
+ m_creature->getThreatManager().modifyThreatPercent(Temp, action.threat_all_pct.percent);
+ break;
}
- break;
case ACTION_T_QUEST_EVENT:
- {
- Unit* target = GetTargetByType(param2, pActionInvoker);
-
- if (target && target->GetTypeId() == TYPEID_PLAYER)
- ((Player*)target)->AreaExploredOrEventHappens(param1);
- }
- break;
- case ACTION_T_CASTCREATUREGO:
- {
- Unit* target = GetTargetByType(param3, pActionInvoker);
-
- if (target && target->GetTypeId() == TYPEID_PLAYER)
- ((Player*)target)->CastedCreatureOrGO(param1, m_creature->GetGUID(), param2);
- }
- break;
+ if (Unit* target = GetTargetByType(action.quest_event.target, pActionInvoker))
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)target)->AreaExploredOrEventHappens(action.quest_event.questId);
+ break;
+ case ACTION_T_CAST_EVENT:
+ if (Unit* target = GetTargetByType(action.cast_event.target, pActionInvoker))
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)target)->CastedCreatureOrGO(action.cast_event.creatureId, m_creature->GetGUID(), action.cast_event.spellId);
+ break;
case ACTION_T_SET_UNIT_FIELD:
{
- Unit* target = GetTargetByType(param3, pActionInvoker);
+ Unit* target = GetTargetByType(action.set_unit_field.target, pActionInvoker);
- if (param1 < OBJECT_END || param1 >= UNIT_END)
+ // not allow modify important for integrity object fields
+ if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END)
return;
if (target)
- target->SetUInt32Value(param1, param2);
- }
- break;
- case ACTION_T_SET_UNIT_FLAG:
- {
- Unit* target = GetTargetByType(param2, pActionInvoker);
+ target->SetUInt32Value(action.set_unit_field.field, action.set_unit_field.value);
- if (target)
- target->SetFlag(UNIT_FIELD_FLAGS, param1);
+ break;
}
- break;
+ case ACTION_T_SET_UNIT_FLAG:
+ if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker))
+ target->SetFlag(UNIT_FIELD_FLAGS, action.unit_flag.value);
+ break;
case ACTION_T_REMOVE_UNIT_FLAG:
- {
- Unit* target = GetTargetByType(param2, pActionInvoker);
-
- if (target)
- target->RemoveFlag(UNIT_FIELD_FLAGS, param1);
- }
- break;
+ if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker))
+ target->RemoveFlag(UNIT_FIELD_FLAGS, action.unit_flag.value);
+ break;
case ACTION_T_AUTO_ATTACK:
- {
- if (param1)
- MeleeEnabled = true;
- else MeleeEnabled = false;
- }
- break;
+ MeleeEnabled = action.auto_attack.state != 0;
+ break;
case ACTION_T_COMBAT_MOVEMENT:
- {
- CombatMovementEnabled = param1;
+ CombatMovementEnabled = action.combat_movement.state != 0;
//Allow movement (create new targeted movement gen only if idle)
if (CombatMovementEnabled)
@@ -747,140 +712,113 @@ void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, u
{
m_creature->GetMotionMaster()->MoveIdle();
}
- }
- break;
+ break;
case ACTION_T_SET_PHASE:
- {
- Phase = param1;
- }
- break;
+ Phase = action.set_phase.phase;
+ break;
case ACTION_T_INC_PHASE:
{
- Phase += param1;
-
- if (Phase > 31)
+ int32 new_phase = int32(Phase)+action.set_inc_phase.step;
+ if (new_phase < 0)
+ {
+ sLog.outErrorDb( "CreatureEventAI: Event %d decrease Phase under 0. CreatureEntry = %d", EventId, m_creature->GetEntry());
+ Phase = 0;
+ }
+ else if (new_phase >= MAX_PHASE)
+ {
+ sLog.outErrorDb( "CreatureEventAI: Event %d incremented Phase above %u. Phase mask cannot be used with phases past %u. CreatureEntry = %d", EventId, MAX_PHASE-1, MAX_PHASE-1, m_creature->GetEntry());
+ Phase = MAX_PHASE-1;
+ }
+ else
+ Phase = new_phase;
- sLog.outErrorDb( "CreatureEventAI: Event %d incremented Phase above 31. Phase mask cannot be used with phases past 31. CreatureEntry = %d", EventId, m_creature->GetEntry());
+ break;
}
- break;
case ACTION_T_EVADE:
- {
EnterEvadeMode();
- }
- break;
+ break;
case ACTION_T_FLEE:
- {
- if(m_creature->HasAuraType(SPELL_AURA_PREVENTS_FLEEING))
- break;
- TimetoFleeLeft = 8000;
- m_creature->DoFleeToGetAssistance();
- IsFleeing = true;
- }
+ if(me->HasAuraType(SPELL_AURA_PREVENTS_FLEEING))
+ break;
+ TimetoFleeLeft = 8000;
+ me->DoFleeToGetAssistance();
+ IsFleeing = true;
break;
case ACTION_T_QUEST_EVENT_ALL:
- {
- Unit* Temp = NULL;
- if( pActionInvoker && pActionInvoker->GetTypeId() == TYPEID_PLAYER )
+ if (pActionInvoker && pActionInvoker->GetTypeId() == TYPEID_PLAYER)
{
- Temp = Unit::GetUnit(*m_creature,pActionInvoker->GetGUID());
- if( Temp )
- ((Player*)Temp)->GroupEventHappens(param1,m_creature);
+ if (Unit* Temp = Unit::GetUnit(*m_creature,pActionInvoker->GetGUID()))
+ if (Temp->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)Temp)->GroupEventHappens(action.quest_event_all.questId,m_creature);
}
- }
- break;
- case ACTION_T_CASTCREATUREGO_ALL:
+ break;
+ case ACTION_T_CAST_EVENT_ALL:
{
- Unit* Temp = NULL;
-
- std::list<HostilReference*>::iterator i = m_creature->getThreatManager().getThreatList().begin();
- for (; i != m_creature->getThreatManager().getThreatList().end(); ++i)
- {
- Temp = Unit::GetUnit(*m_creature,(*i)->getUnitGuid());
- if (Temp && Temp->GetTypeId() == TYPEID_PLAYER)
- ((Player*)Temp)->CastedCreatureOrGO(param1, m_creature->GetGUID(), param2);
- }
+ std::list<HostilReference*>& threatList = m_creature->getThreatManager().getThreatList();
+ for (std::list<HostilReference*>::iterator i = threatList.begin(); i != threatList.end(); ++i)
+ if (Unit* Temp = Unit::GetUnit(*m_creature,(*i)->getUnitGuid()))
+ if (Temp->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)Temp)->CastedCreatureOrGO(action.cast_event_all.creatureId, m_creature->GetGUID(), action.cast_event_all.spellId);
+ break;
}
- break;
case ACTION_T_REMOVEAURASFROMSPELL:
- {
- Unit* target = GetTargetByType(param1, pActionInvoker);
-
- if (target)
- target->RemoveAurasDueToSpell(param2);
- }
- break;
+ if (Unit* target = GetTargetByType(action.remove_aura.target, pActionInvoker))
+ target->RemoveAurasDueToSpell(action.remove_aura.spellId);
+ break;
case ACTION_T_RANGED_MOVEMENT:
- {
- AttackDistance = param1;
- AttackAngle = ((float)param2/180)*M_PI;
+ AttackDistance = action.ranged_movement.distance;
+ AttackAngle = ((float)action.ranged_movement.angle/180)*M_PI;
if (CombatMovementEnabled)
{
m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), AttackDistance, AttackAngle);
}
- }
- break;
+ break;
case ACTION_T_RANDOM_PHASE:
- {
- uint32 temp = GetRandActionParam(rnd, param1, param2, param3);
-
- Phase = temp;
- }
- break;
+ Phase = GetRandActionParam(rnd, action.random_phase.phase1, action.random_phase.phase2, action.random_phase.phase3);
+ break;
case ACTION_T_RANDOM_PHASE_RANGE:
- {
- if (param2 > param1)
- {
- Phase = param1 + (rnd % (param2 - param1));
- }
+ if (action.random_phase_range.phaseMax > action.random_phase_range.phaseMin)
+ Phase = action.random_phase_range.phaseMin + (rnd % (action.random_phase_range.phaseMax - action.random_phase_range.phaseMin));
else
sLog.outErrorDb( "CreatureEventAI: ACTION_T_RANDOM_PHASE_RANGE cannot have Param2 <= Param1. Divide by Zero. Event = %d. CreatureEntry = %d", EventId, m_creature->GetEntry());
- }
- break;
+ break;
case ACTION_T_SUMMON_ID:
{
- Unit* target = GetTargetByType(param2, pActionInvoker);
+ Unit* target = GetTargetByType(action.summon_id.target, pActionInvoker);
- //Duration
- Creature* pCreature = NULL;
-
- CreatureEventAI_Summon_Map::const_iterator i = CreatureEAI_Mgr.GetCreatureEventAISummonMap().find(param3);
+ CreatureEventAI_Summon_Map::const_iterator i = CreatureEAI_Mgr.GetCreatureEventAISummonMap().find(action.summon_id.spawnId);
if (i == CreatureEAI_Mgr.GetCreatureEventAISummonMap().end())
{
-
- sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", param1, param3, EventId, m_creature->GetEntry());
+ sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", action.summon_id.creatureId, action.summon_id.spawnId, EventId, m_creature->GetEntry());
return;
}
+ Creature* pCreature = NULL;
if ((*i).second.SpawnTimeSecs)
- pCreature = m_creature->SummonCreature(param1, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs);
- else pCreature = m_creature->SummonCreature(param1, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
+ pCreature = m_creature->SummonCreature(action.summon_id.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs);
+ else
+ pCreature = m_creature->SummonCreature(action.summon_id.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
if (!pCreature)
- {
-
- sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. EventId %d.Creature %d", param1, EventId, m_creature->GetEntry());
- }
- else if (param2 != TARGET_T_SELF && target)
+ sLog.outErrorDb( "CreatureEventAI: failed to spawn creature %u. EventId %d.Creature %d", action.summon_id.creatureId, EventId, m_creature->GetEntry());
+ else if (action.summon_id.target != TARGET_T_SELF && target)
pCreature->AI()->AttackStart(target);
+
+ break;
}
- break;
case ACTION_T_KILLED_MONSTER:
- {
//first attempt player who tapped creature
if (Player* pPlayer = m_creature->GetLootRecipient())
- pPlayer->RewardPlayerAndGroupAtEvent(param1, m_creature);
+ pPlayer->RewardPlayerAndGroupAtEvent(action.killed_monster.creatureId, m_creature);
else
{
//if not available, use pActionInvoker
- if (Unit* pTarget = GetTargetByType(param2, pActionInvoker))
- {
+ if (Unit* pTarget = GetTargetByType(action.killed_monster.target, pActionInvoker))
if (Player* pPlayer2 = pTarget->GetCharmerOrOwnerPlayerOrPlayerItself())
- pPlayer2->RewardPlayerAndGroupAtEvent(param1, m_creature);
- }
+ pPlayer2->RewardPlayerAndGroupAtEvent(action.killed_monster.creatureId, m_creature);
}
- }
- break;
+ break;
case ACTION_T_SET_INST_DATA:
{
InstanceData* pInst = (InstanceData*)m_creature->GetInstanceData();
@@ -890,12 +828,12 @@ void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, u
return;
}
- pInst->SetData(param1, param2);
+ pInst->SetData(action.set_inst_data.field, action.set_inst_data.value);
+ break;
}
- break;
case ACTION_T_SET_INST_DATA64:
{
- Unit* target = GetTargetByType(param2, pActionInvoker);
+ Unit* target = GetTargetByType(action.set_inst_data64.target, pActionInvoker);
if (!target)
{
sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data64 but Target == NULL. Creature %d", EventId, m_creature->GetEntry());
@@ -909,19 +847,19 @@ void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, u
return;
}
- pInst->SetData64(param1, target->GetGUID());
+ pInst->SetData64(action.set_inst_data64.field, target->GetGUID());
+ break;
}
- break;
case ACTION_T_UPDATE_TEMPLATE:
{
- if (m_creature->GetEntry() == param1)
+ if (m_creature->GetEntry() == action.update_template.creatureId)
{
sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_UPDATE_TEMPLATE call with param1 == current entry. Creature %d", EventId, m_creature->GetEntry());
return;
}
- m_creature->UpdateEntry(param1, param2 ? HORDE : ALLIANCE);
+ m_creature->UpdateEntry(action.update_template.creatureId, action.update_template.team ? HORDE : ALLIANCE);
}
break;
case ACTION_T_DIE:
@@ -950,13 +888,13 @@ void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, u
// TRINITY ONLY
case ACTION_T_SET_ACTIVE:
- me->setActive(param1 ? true : false);
+ me->setActive(action.raw.param1 ? true : false);
break;
case ACTION_T_SET_AGGRESSIVE:
- me->SetReactState(ReactStates(param1));
+ me->SetReactState(ReactStates(action.raw.param1));
break;
case ACTION_T_ATTACK_START_PULSE:
- AttackStart(me->SelectNearestTarget((float)param1));
+ AttackStart(me->SelectNearestTarget((float)action.raw.param1));
break;
case ACTION_T_SUMMON_GO:
{
@@ -964,16 +902,16 @@ void CreatureEventAI::ProcessAction(uint16 type, uint32 param1, uint32 param2, u
float x,y,z;
m_creature->GetPosition(x,y,z);
- pObject = m_creature->SummonGameObject(param1, x, y, z, 0, 0, 0, 0, 0, param2);
+ pObject = m_creature->SummonGameObject(action.raw.param1, x, y, z, 0, 0, 0, 0, 0, action.raw.param2);
if (!pObject)
{
- sLog.outErrorDb("TSCR: EventAI failed to spawn object %u. Spawn event %d is on creature %d", param1, EventId, m_creature->GetEntry());
+ sLog.outErrorDb("TSCR: EventAI failed to spawn object %u. Spawn event %d is on creature %d", action.raw.param1, EventId, m_creature->GetEntry());
}
break;
}
case ACTION_T_CALL_ASSISTANCE:
m_creature->SetNoCallAssistance(false);
- m_creature->CallAssistance(param1);
+ m_creature->CallAssistance(action.raw.param1);
break;
}
}
@@ -1346,15 +1284,20 @@ inline uint32 CreatureEventAI::GetRandActionParam(uint32 rnd, uint32 param1, uin
{
switch (rnd % 3)
{
- case 0:
- return param1;
- break;
- case 1:
- return param2;
- break;
- case 2:
- return param3;
- break;
+ case 0: return param1;
+ case 1: return param2;
+ case 2: return param3;
+ }
+ return 0;
+}
+
+inline int32 CreatureEventAI::GetRandActionParam(uint32 rnd, int32 param1, int32 param2, int32 param3)
+{
+ switch (rnd % 3)
+ {
+ case 0: return param1;
+ case 1: return param2;
+ case 2: return param3;
}
return 0;
}
@@ -1365,28 +1308,20 @@ inline Unit* CreatureEventAI::GetTargetByType(uint32 Target, Unit* pActionInvoke
{
case TARGET_T_SELF:
return m_creature;
- break;
case TARGET_T_HOSTILE:
return m_creature->getVictim();
- break;
case TARGET_T_HOSTILE_SECOND_AGGRO:
return SelectUnit(ATTACKING_TARGET_TOPAGGRO,1);
- break;
case TARGET_T_HOSTILE_LAST_AGGRO:
return SelectUnit(ATTACKING_TARGET_BOTTOMAGGRO,0);
- break;
case TARGET_T_HOSTILE_RANDOM:
return SelectUnit(ATTACKING_TARGET_RANDOM,0);
- break;
case TARGET_T_HOSTILE_RANDOM_NOT_TOP:
return SelectUnit(ATTACKING_TARGET_RANDOM,1);
- break;
case TARGET_T_ACTION_INVOKER:
return pActionInvoker;
- break;
default:
return NULL;
- break;
};
}
diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h
index 006cd7df08b..412a3b1919d 100644
--- a/src/game/CreatureEventAI.h
+++ b/src/game/CreatureEventAI.h
@@ -30,6 +30,7 @@ class WorldObject;
#define EVENT_UPDATE_TIME 500
#define SPELL_RUN_AWAY 8225
#define MAX_ACTIONS 3
+#define MAX_PHASE 32
enum EventAI_Type
{
@@ -78,7 +79,7 @@ enum EventAI_ActionType
ACTION_T_THREAT_SINGLE_PCT = 13, //*Threat%, Target
ACTION_T_THREAT_ALL_PCT = 14, //Threat%
ACTION_T_QUEST_EVENT = 15, //*QuestID, Target
- ACTION_T_CASTCREATUREGO = 16, //*QuestID, SpellId, Target
+ ACTION_T_CAST_EVENT = 16, //*QuestID, SpellId, Target - must be removed as hack?
ACTION_T_SET_UNIT_FIELD = 17, //*Field_Number, Value, Target
ACTION_T_SET_UNIT_FLAG = 18, //*Flags (may be more than one field OR'd together), Target
ACTION_T_REMOVE_UNIT_FLAG = 19, //*Flags (may be more than one field OR'd together), Target
@@ -89,7 +90,7 @@ enum EventAI_ActionType
ACTION_T_EVADE = 24, //No Params
ACTION_T_FLEE = 25, //No Params
ACTION_T_QUEST_EVENT_ALL = 26, //*QuestID
- ACTION_T_CASTCREATUREGO_ALL = 27, //*QuestId, SpellId
+ ACTION_T_CAST_EVENT_ALL = 27, //*QuestId, SpellId
ACTION_T_REMOVEAURASFROMSPELL = 28, //*Target, Spellid
ACTION_T_RANGED_MOVEMENT = 29, //Distance, Angle
ACTION_T_RANDOM_PHASE = 30, //PhaseId1, PhaseId2, PhaseId3
@@ -171,6 +172,202 @@ struct StringTextData
// Text Maps
typedef UNORDERED_MAP<int32, StringTextData> CreatureEventAI_TextMap;
+struct CreatureEventAI_Action
+{
+ EventAI_ActionType type: 16;
+ union
+ {
+ // ACTION_T_TEXT = 1
+ struct
+ {
+ int32 TextId1;
+ int32 TextId2;
+ int32 TextId3;
+ } text;
+ // ACTION_T_SET_FACTION = 2
+ struct
+ {
+ uint32 factionId; // faction or 0 for default)
+ } set_faction;
+ // ACTION_T_MORPH_TO_ENTRY_OR_MODEL = 3
+ struct
+ {
+ uint32 creatireId; // set one from fields (or 0 for both to demorph)
+ uint32 modelId;
+ } morph;
+ // ACTION_T_SOUND = 4
+ struct
+ {
+ uint32 soundId;
+ } sound;
+ // ACTION_T_EMOTE = 5
+ struct
+ {
+ uint32 emoteId;
+ } emote;
+ // ACTION_T_RANDOM_SOUND = 9
+ struct
+ {
+ int32 soundId1; // (-1 in any field means no output if randomed that field)
+ int32 soundId2;
+ int32 soundId3;
+ } random_sound;
+ // ACTION_T_RANDOM_EMOTE = 10
+ struct
+ {
+ int32 emoteId1; // (-1 in any field means no output if randomed that field)
+ int32 emoteId2;
+ int32 emoteId3;
+ } random_emote;
+ // ACTION_T_CAST = 11
+ struct
+ {
+ uint32 spellId;
+ uint32 target;
+ uint32 castFlags;
+ } cast;
+ // ACTION_T_SUMMON = 12
+ struct
+ {
+ uint32 creatured;
+ uint32 target;
+ uint32 duration;
+ } summon;
+ // ACTION_T_THREAT_SINGLE_PCT = 13
+ struct
+ {
+ int32 percent;
+ uint32 target;
+ } threat_single_pct;
+ // ACTION_T_THREAT_ALL_PCT = 14
+ struct
+ {
+ int32 percent;
+ } threat_all_pct;
+ // ACTION_T_QUEST_EVENT = 15
+ struct
+ {
+ uint32 questId;
+ uint32 target;
+ } quest_event;
+ // ACTION_T_CAST_EVENT = 16
+ struct
+ {
+ uint32 creatureId;
+ uint32 spellId;
+ uint32 target;
+ } cast_event;
+ // ACTION_T_SET_UNIT_FIELD = 17
+ struct
+ {
+ uint32 field;
+ uint32 value;
+ uint32 target;
+ } set_unit_field;
+ // ACTION_T_SET_UNIT_FLAG = 18, // value provided mask bits that will be set
+ // ACTION_T_REMOVE_UNIT_FLAG = 19, // value provided mask bits that will be clear
+ struct
+ {
+ uint32 value;
+ uint32 target;
+ } unit_flag;
+ // ACTION_T_AUTO_ATTACK = 20
+ struct
+ {
+ uint32 state; // 0 = stop attack, anything else means continue attacking
+ } auto_attack;
+ // ACTION_T_COMBAT_MOVEMENT = 21
+ struct
+ {
+ uint32 state; // 0 = stop combat based movement, anything else continue attacking
+ } combat_movement;
+ // ACTION_T_SET_PHASE = 22
+ struct
+ {
+ uint32 phase;
+ } set_phase;
+ // ACTION_T_INC_PHASE = 23
+ struct
+ {
+ int32 step;
+ } set_inc_phase;
+ // ACTION_T_QUEST_EVENT_ALL = 26
+ struct
+ {
+ uint32 questId;
+ } quest_event_all;
+ // ACTION_T_CAST_EVENT_ALL = 27
+ struct
+ {
+ uint32 creatureId;
+ uint32 spellId;
+ } cast_event_all;
+ // ACTION_T_REMOVEAURASFROMSPELL = 28
+ struct
+ {
+ uint32 target;
+ uint32 spellId;
+ } remove_aura;
+ // ACTION_T_RANGED_MOVEMENT = 29
+ struct
+ {
+ uint32 distance;
+ int32 angle;
+ } ranged_movement;
+ // ACTION_T_RANDOM_PHASE = 30
+ struct
+ {
+ uint32 phase1;
+ uint32 phase2;
+ uint32 phase3;
+ } random_phase;
+ // ACTION_T_RANDOM_PHASE_RANGE = 31
+ struct
+ {
+ uint32 phaseMin;
+ uint32 phaseMax;
+ } random_phase_range;
+ // ACTION_T_SUMMON_ID = 32
+ struct
+ {
+ uint32 creatureId;
+ uint32 target;
+ uint32 spawnId;
+ } summon_id;
+ // ACTION_T_KILLED_MONSTER = 33
+ struct
+ {
+ uint32 creatureId;
+ uint32 target;
+ } killed_monster;
+ // ACTION_T_SET_INST_DATA = 34
+ struct
+ {
+ uint32 field;
+ uint32 value;
+ } set_inst_data;
+ // ACTION_T_SET_INST_DATA64 = 35
+ struct
+ {
+ uint32 field;
+ uint32 target;
+ } set_inst_data64;
+ // ACTION_T_UPDATE_TEMPLATE = 36, //*Entry, Team
+ struct
+ {
+ uint32 creatureId;
+ uint32 team;
+ } update_template;
+ // RAW
+ struct
+ {
+ uint32 param1;
+ uint32 param2;
+ uint32 param3;
+ } raw;
+ };
+};
+
struct CreatureEventAI_Event
{
uint32 event_id;
@@ -204,25 +401,7 @@ struct CreatureEventAI_Event
int32 event_param4_s;
};
- struct _action
- {
- EventAI_ActionType type: 16;
- union
- {
- uint32 param1;
- int32 param1_s;
- };
- union
- {
- uint32 param2;
- int32 param2_s;
- };
- union
- {
- uint32 param3;
- int32 param3_s;
- };
- }action[MAX_ACTIONS];
+ CreatureEventAI_Action action[MAX_ACTIONS];
};
//Event_Map
typedef UNORDERED_MAP<uint32, std::vector<CreatureEventAI_Event> > CreatureEventAI_Event_Map;
@@ -275,8 +454,9 @@ class TRINITY_DLL_SPEC CreatureEventAI : public CreatureAI
static int Permissible(const Creature *);
bool ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker = NULL);
- void ProcessAction(uint16 type, uint32 param1, uint32 param2, uint32 param3, uint32 rnd, uint32 EventId, Unit* pActionInvoker);
+ void ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker);
inline uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3);
+ inline int32 GetRandActionParam(uint32 rnd, int32 param1, int32 param2, int32 param3);
inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker);
inline Unit* SelectUnit(AttackingTarget target, uint32 position);
diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp
index 01c92ade6db..a8e3f04db71 100644
--- a/src/game/CreatureEventAIMgr.cpp
+++ b/src/game/CreatureEventAIMgr.cpp
@@ -388,251 +388,252 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
continue;
}
- temp.action[j].type = EventAI_ActionType(action_type);
- temp.action[j].param1 = fields[11+(j*4)].GetUInt32();
- temp.action[j].param2 = fields[12+(j*4)].GetUInt32();
- temp.action[j].param3 = fields[13+(j*4)].GetUInt32();
+ CreatureEventAI_Action& action = temp.action[j];
+
+ action.type = EventAI_ActionType(action_type);
+ action.raw.param1 = fields[11+(j*4)].GetUInt32();
+ action.raw.param2 = fields[12+(j*4)].GetUInt32();
+ action.raw.param3 = fields[13+(j*4)].GetUInt32();
//Report any errors in actions
- switch (temp.action[j].type)
+ switch (action.type)
{
case ACTION_T_NONE:
break;
case ACTION_T_TEXT:
{
- if (temp.action[j].param1_s < 0)
+ if (action.text.TextId1 < 0)
{
- if (m_CreatureEventAI_TextMap.find(temp.action[j].param1_s) == m_CreatureEventAI_TextMap.end())
+ if (m_CreatureEventAI_TextMap.find(action.text.TextId1) == m_CreatureEventAI_TextMap.end())
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 refrences non-existing entry in texts table.", i, j+1);
}
- if (temp.action[j].param2_s < 0)
+ if (action.text.TextId2 < 0)
{
- if (m_CreatureEventAI_TextMap.find(temp.action[j].param2_s) == m_CreatureEventAI_TextMap.end())
+ if (m_CreatureEventAI_TextMap.find(action.text.TextId2) == m_CreatureEventAI_TextMap.end())
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 refrences non-existing entry in texts table.", i, j+1);
- if (!temp.action[j].param1_s)
+ if (!action.text.TextId1)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u has param2, but param1 is not set. Required for randomized text.", i, j+1);
}
- if (temp.action[j].param3_s < 0)
+ if (action.text.TextId3 < 0)
{
- if (m_CreatureEventAI_TextMap.find(temp.action[j].param3_s) == m_CreatureEventAI_TextMap.end())
+ if (m_CreatureEventAI_TextMap.find(action.text.TextId3) == m_CreatureEventAI_TextMap.end())
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 refrences non-existing entry in texts table.", i, j+1);
- if (!temp.action[j].param1_s || !temp.action[j].param2_s)
+ if (!action.text.TextId1 || !action.text.TextId2)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u has param3, but param1 and/or param2 is not set. Required for randomized text.", i, j+1);
}
break;
}
case ACTION_T_SET_FACTION:
- if (temp.action[j].param1 !=0 && !sFactionStore.LookupEntry(temp.action[j].param1))
+ if (action.set_faction.factionId !=0 && !sFactionStore.LookupEntry(action.set_faction.factionId))
{
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant FactionId %u.", i, j+1, temp.action[j].param1);
- temp.action[j].param1 = 0;
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent FactionId %u.", i, j+1, action.set_faction.factionId);
+ action.set_faction.factionId = 0;
}
break;
case ACTION_T_MORPH_TO_ENTRY_OR_MODEL:
- if (temp.action[j].param1 !=0 || temp.action[j].param2 !=0)
+ if (action.morph.creatireId !=0 || action.morph.modelId !=0)
{
- if (temp.action[j].param1 && !sCreatureStorage.LookupEntry<CreatureInfo>(temp.action[j].param1))
+ if (action.morph.creatireId && !sCreatureStorage.LookupEntry<CreatureInfo>(action.morph.creatireId))
{
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Creature entry %u.", i, j+1, temp.action[j].param1);
- temp.action[j].param1 = 0;
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Creature entry %u.", i, j+1, action.morph.creatireId);
+ action.morph.creatireId = 0;
}
- if (temp.action[j].param2 && !sCreatureDisplayInfoStore.LookupEntry(temp.action[j].param2))
+ if (action.morph.modelId)
{
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant ModelId %u.", i, j+1, temp.action[j].param2);
- temp.action[j].param2 = 0;
+ if (action.morph.creatireId)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u have unused ModelId %u with also set creature id %u.", i, j+1, action.morph.modelId,action.morph.creatireId);
+ action.morph.modelId = 0;
+ }
+ else if (!sCreatureDisplayInfoStore.LookupEntry(action.morph.modelId))
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant ModelId %u.", i, j+1, action.morph.modelId);
+ action.morph.modelId = 0;
+ }
}
+
+ break;
}
- break;
case ACTION_T_SOUND:
- if (!sSoundEntriesStore.LookupEntry(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i, j+1, temp.action[j].param1);
- break;
- case ACTION_T_RANDOM_SOUND:
- if (!sSoundEntriesStore.LookupEntry(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 uses non-existant SoundID %u.", i, j+1, temp.action[j].param1);
- if (temp.action[j].param2_s >= 0 && !sSoundEntriesStore.LookupEntry(temp.action[j].param2))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 uses non-existant SoundID %u.", i, j+1, temp.action[j].param2);
- if (temp.action[j].param3_s >= 0 && !sSoundEntriesStore.LookupEntry(temp.action[j].param3))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 uses non-existant SoundID %u.", i, j+1, temp.action[j].param3);
+ if (!sSoundEntriesStore.LookupEntry(action.sound.soundId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i, j+1, action.sound.soundId);
break;
case ACTION_T_EMOTE:
- if (!sEmotesStore.LookupEntry(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (EmoteId: %u) are not valid.", i, j+1, temp.action[j].param1);
+ if (!sEmotesStore.LookupEntry(action.emote.emoteId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (EmoteId: %u) are not valid.", i, j+1, action.emote.emoteId);
+ break;
+ case ACTION_T_RANDOM_SOUND:
+ if (!sSoundEntriesStore.LookupEntry(action.random_sound.soundId1))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 uses non-existant SoundID %u.", i, j+1, action.random_sound.soundId1);
+ if (action.random_sound.soundId2 >= 0 && !sSoundEntriesStore.LookupEntry(action.random_sound.soundId2))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 uses non-existant SoundID %u.", i, j+1, action.random_sound.soundId2);
+ if (action.random_sound.soundId3 >= 0 && !sSoundEntriesStore.LookupEntry(action.random_sound.soundId3))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 uses non-existant SoundID %u.", i, j+1, action.random_sound.soundId3);
break;
case ACTION_T_RANDOM_EMOTE:
- if (!sEmotesStore.LookupEntry(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (EmoteId: %u) are not valid.", i, j+1, temp.action[j].param1);
- if (temp.action[j].param2_s >= 0 && !sEmotesStore.LookupEntry(temp.action[j].param2))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 (EmoteId: %u) are not valid.", i, j+1, temp.action[j].param2);
- if (temp.action[j].param3_s >= 0 && !sEmotesStore.LookupEntry(temp.action[j].param3))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 (EmoteId: %u) are not valid.", i, j+1, temp.action[j].param3);
+ if (!sEmotesStore.LookupEntry(action.random_emote.emoteId1))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (EmoteId: %u) are not valid.", i, j+1, action.random_emote.emoteId1);
+ if (action.random_emote.emoteId2 >= 0 && !sEmotesStore.LookupEntry(action.random_emote.emoteId2))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 (EmoteId: %u) are not valid.", i, j+1, action.random_emote.emoteId2);
+ if (action.random_emote.emoteId3 >= 0 && !sEmotesStore.LookupEntry(action.random_emote.emoteId3))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 (EmoteId: %u) are not valid.", i, j+1, action.random_emote.emoteId3);
break;
case ACTION_T_CAST:
{
- const SpellEntry *spell = sSpellStore.LookupEntry(temp.action[j].param1);
+ const SpellEntry *spell = sSpellStore.LookupEntry(action.cast.spellId);
if (!spell)
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param1);
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent SpellID %u.", i, j+1, action.cast.spellId);
else
{
if (spell->RecoveryTime > 0 && temp.event_flags & EFLAG_REPEATABLE)
{
//output as debug for now, also because there's no general rule all spells have RecoveryTime
if (temp.event_param3 < spell->RecoveryTime)
- 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,temp.action[j].param1, spell->RecoveryTime, temp.event_param3);
+ 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);
}
}
- if (temp.action[j].param2 >= TARGET_T_END)
+ //Cast is always triggered if target is forced to cast on self
+ if (action.cast.castFlags & CAST_FORCE_TARGET_SELF)
+ action.cast.castFlags |= CAST_TRIGGERED;
+
+ if (action.cast.target >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
break;
}
- case ACTION_T_REMOVEAURASFROMSPELL:
- {
- if (!sSpellStore.LookupEntry(temp.action[j].param2))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
+ case ACTION_T_SUMMON:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.summon.creatured))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent creature entry %u.", i, j+1, action.summon.creatured);
- if (temp.action[j].param1 >= TARGET_T_END)
+ if (action.summon.target >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
break;
- }
+ case ACTION_T_THREAT_SINGLE_PCT:
+ if (std::abs(action.threat_single_pct.percent) > 100)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses invalid percent value %u.", i, j+1, action.threat_single_pct.percent);
+ if (action.threat_single_pct.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_THREAT_ALL_PCT:
+ if (std::abs(action.threat_all_pct.percent) > 100)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses invalid percent value %u.", i, j+1, action.threat_all_pct.percent);
+ break;
case ACTION_T_QUEST_EVENT:
- {
- if (Quest const* qid = objmgr.GetQuestTemplate(temp.action[j].param1))
+ if (Quest const* qid = objmgr.GetQuestTemplate(action.quest_event.questId))
{
if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, temp.action[j].param1);
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, action.quest_event.questId);
}
else
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1);
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent Quest entry %u.", i, j+1, action.quest_event.questId);
- if (temp.action[j].param2 >= TARGET_T_END)
+ if (action.quest_event.target >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
break;
- }
+ case ACTION_T_CAST_EVENT:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.cast_event.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent creature entry %u.", i, j+1, action.cast_event.creatureId);
+ if (!sSpellStore.LookupEntry(action.cast_event.spellId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent SpellID %u.", i, j+1, action.cast_event.spellId);
+ if (action.cast_event.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_SET_UNIT_FIELD:
+ if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (UNIT_FIELD*). Index out of range for intended use.", i, j+1);
+ if (action.set_unit_field.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_SET_UNIT_FLAG:
+ case ACTION_T_REMOVE_UNIT_FLAG:
+ if (action.unit_flag.target >= TARGET_T_END)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+ case ACTION_T_SET_PHASE:
+ if (action.set_phase.phase >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ break;
+ case ACTION_T_INC_PHASE:
+ if (action.set_inc_phase.step == 0)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u is incrementing phase by 0. Was this intended?", i, j+1);
+ else if (std::abs(action.set_inc_phase.step) > MAX_PHASE-1)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u is change phase by too large for any use %i.", i, j+1, action.set_inc_phase.step);
+ break;
case ACTION_T_QUEST_EVENT_ALL:
- {
- if (Quest const* qid = objmgr.GetQuestTemplate(temp.action[j].param1))
+ if (Quest const* qid = objmgr.GetQuestTemplate(action.quest_event_all.questId))
{
if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, temp.action[j].param1);
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, action.quest_event_all.questId);
}
else
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1);
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent Quest entry %u.", i, j+1, action.quest_event_all.questId);
break;
- }
- case ACTION_T_CASTCREATUREGO:
- {
- if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
-
- if (!sSpellStore.LookupEntry(temp.action[j].param2))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
-
- if (temp.action[j].param3 >= TARGET_T_END)
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
- break;
- }
- case ACTION_T_CASTCREATUREGO_ALL:
- {
- if (!objmgr.GetQuestTemplate(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1);
-
- if (!sSpellStore.LookupEntry(temp.action[j].param2))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
+ case ACTION_T_CAST_EVENT_ALL:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.cast_event_all.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent creature entry %u.", i, j+1, action.cast_event_all.creatureId);
+ if (!sSpellStore.LookupEntry(action.cast_event_all.spellId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent SpellID %u.", i, j+1, action.cast_event_all.spellId);
break;
- }
-
- //2nd param target
- case ACTION_T_SUMMON_ID:
- {
- if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
-
- if (m_CreatureEventAI_Summon_Map.find(temp.action[j].param3) == m_CreatureEventAI_Summon_Map.end())
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u summons missing CreatureEventAI_Summon %u", i, j+1, temp.action[j].param3);
-
- if (temp.action[j].param2 >= TARGET_T_END)
+ case ACTION_T_REMOVEAURASFROMSPELL:
+ if (!sSpellStore.LookupEntry(action.remove_aura.spellId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existent SpellID %u.", i, j+1, action.remove_aura.spellId);
+ if (action.remove_aura.target >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
break;
- }
- case ACTION_T_KILLED_MONSTER:
- {
- if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
-
- if (temp.action[j].param2 >= TARGET_T_END)
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ case ACTION_T_RANDOM_PHASE: //PhaseId1, PhaseId2, PhaseId3
+ if (action.random_phase.phase1 >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase1 >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ if (action.random_phase.phase2 >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase2 >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ if (action.random_phase.phase3 >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase3 >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
break;
- }
- case ACTION_T_SUMMON:
- {
- if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
-
- if (temp.action[j].param2 >= TARGET_T_END)
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ case ACTION_T_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax
+ if (action.random_phase_range.phaseMin >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phaseMin >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ if (action.random_phase_range.phaseMin >= MAX_PHASE)
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phaseMax >= %u. Phase mask cannot be used past phase %u.", i, j+1, MAX_PHASE, MAX_PHASE-1);
+ if (action.random_phase_range.phaseMin >= action.random_phase_range.phaseMax)
+ {
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phaseMax <= phaseMin.", i, j+1);
+ std::swap(action.random_phase_range.phaseMin,action.random_phase_range.phaseMax);
+ // equal case processed at call
+ }
break;
- }
- case ACTION_T_THREAT_SINGLE_PCT:
- case ACTION_T_SET_UNIT_FLAG:
- case ACTION_T_REMOVE_UNIT_FLAG:
- if (temp.action[j].param2 >= TARGET_T_END)
+ case ACTION_T_SUMMON_ID:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.summon_id.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, action.summon_id.creatureId);
+ if (action.summon_id.target >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
+ if (m_CreatureEventAI_Summon_Map.find(action.summon_id.spawnId) == m_CreatureEventAI_Summon_Map.end())
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u summons missing CreatureEventAI_Summon %u", i, j+1, action.summon_id.spawnId);
break;
- //3rd param target
- case ACTION_T_SET_UNIT_FIELD:
- if (temp.action[j].param1 < OBJECT_END || temp.action[j].param1 >= UNIT_END)
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (UNIT_FIELD*). Index out of range for intended use.", i, j+1);
- if (temp.action[j].param3 >= TARGET_T_END)
+ case ACTION_T_KILLED_MONSTER:
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.killed_monster.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, action.killed_monster.creatureId);
+ if (action.killed_monster.target >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
break;
-
- case ACTION_T_SET_PHASE:
- if (temp.action[j].param1 > 31)
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase > 31. Phase mask cannot be used past phase 31.", i, j+1);
- break;
-
- case ACTION_T_INC_PHASE:
- if (!temp.action[j].param1)
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u is incrementing phase by 0. Was this intended?", i, j+1);
- break;
-
case ACTION_T_SET_INST_DATA:
- {
if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1);
-
- if (temp.action[j].param2 > 4/*SPECIAL*/)
+ if (action.set_inst_data.value > 4/*SPECIAL*/)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set instance data above encounter state 4. Custom case?", i, j+1);
-
break;
- }
case ACTION_T_SET_INST_DATA64:
- {
if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1);
-
- if (temp.action[j].param2 >= TARGET_T_END)
+ if (action.set_inst_data64.target >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
-
break;
- }
case ACTION_T_UPDATE_TEMPLATE:
- {
- if (!sCreatureStorage.LookupEntry<CreatureInfo>(temp.action[j].param1))
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
- break;
- }
-
- case ACTION_T_THREAT_ALL_PCT:
- if (abs(temp.action[j].param1_s) > 100)
- sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses invalid percent value %u.", i, j+1, temp.action[j].param1);
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.update_template.creatureId))
+ sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, action.update_template.creatureId);
break;
-
case ACTION_T_EVADE: //No Params
case ACTION_T_FLEE: //No Params
case ACTION_T_DIE: //No Params
@@ -642,11 +643,6 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
case ACTION_T_RANGED_MOVEMENT: //Distance, Angle
break;
- case ACTION_T_RANDOM_PHASE: //PhaseId1, PhaseId2, PhaseId3
- case ACTION_T_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax
- // check not implemented
- break;
-
case ACTION_T_RANDOM_SAY:
case ACTION_T_RANDOM_YELL:
case ACTION_T_RANDOM_TEXTEMOTE:
diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h
index 170fd25dd9f..e7980c31a27 100644
--- a/src/game/DBCfmt.h
+++ b/src/game/DBCfmt.h
@@ -106,4 +106,4 @@ const char WorldMapAreaEntryfmt[]="xinxffffix";
const char WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxxxx";
const char WorldSafeLocsEntryfmt[]="nifffxxxxxxxxxxxxxxxxx";
-#endif \ No newline at end of file
+#endif
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index ac90a065315..cd25640a185 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -53,6 +53,7 @@
#include "InstanceSaveMgr.h"
#include "InstanceData.h"
#include "AuctionHouseBot.h"
+#include "CreatureEventAIMgr.h"
bool ChatHandler::HandleAHBotOptionsCommand(const char* args)
{
@@ -531,6 +532,7 @@ bool ChatHandler::HandleReloadAllCommand(const char*)
HandleReloadAllAchievementCommand("");
HandleReloadAllAreaCommand("");
+ HandleReloadAllEventAICommand("");
HandleReloadAllLootCommand("");
HandleReloadAllNpcCommand("");
HandleReloadAllQuestCommand("");
@@ -612,6 +614,14 @@ bool ChatHandler::HandleReloadAllScriptsCommand(const char*)
return true;
}
+bool ChatHandler::HandleReloadAllEventAICommand(const char*)
+{
+ HandleReloadEventAITextsCommand("a");
+ HandleReloadEventAISummonsCommand("a");
+ HandleReloadEventAIScriptsCommand("a");
+ return true;
+}
+
bool ChatHandler::HandleReloadAllSpellCommand(const char*)
{
HandleReloadSkillDiscoveryTemplateCommand("a");
@@ -1135,6 +1145,31 @@ bool ChatHandler::HandleReloadWpScriptsCommand(const char* arg)
return true;
}
+bool ChatHandler::HandleReloadEventAITextsCommand(const char* arg)
+{
+
+ sLog.outString( "Re-Loading Texts from `creature_ai_texts`...");
+ CreatureEAI_Mgr.LoadCreatureEventAI_Texts();
+ SendGlobalSysMessage("DB table `creature_ai_texts` reloaded.");
+ return true;
+}
+
+bool ChatHandler::HandleReloadEventAISummonsCommand(const char* arg)
+{
+ sLog.outString( "Re-Loading Summons from `creature_ai_summons`...");
+ CreatureEAI_Mgr.LoadCreatureEventAI_Summons();
+ SendGlobalSysMessage("DB table `creature_ai_summons` reloaded.");
+ return true;
+}
+
+bool ChatHandler::HandleReloadEventAIScriptsCommand(const char* arg)
+{
+ sLog.outString( "Re-Loading Scripts from `creature_ai_scripts`...");
+ CreatureEAI_Mgr.LoadCreatureEventAI_Scripts();
+ SendGlobalSysMessage("DB table `creature_ai_scripts` reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleReloadQuestEndScriptsCommand(const char* arg)
{
if(sWorld.IsScriptScheduled())
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 3ed60018ecc..02da82cb5fb 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -6851,11 +6851,7 @@ bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 mi
for(TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();)
{
if (itr->first >= start_value && itr->first < end_value)
- {
- TrinityStringLocaleMap::iterator itr2 = itr;
- ++itr;
- mTrinityStringLocaleMap.erase(itr2);
- }
+ mTrinityStringLocaleMap.erase(itr++);
else
++itr;
}
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index 33915398c91..136429a41d5 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -154,7 +154,7 @@ typedef UNORDERED_MAP<uint32,ItemLocale> ItemLocaleMap;
typedef UNORDERED_MAP<uint32,QuestLocale> QuestLocaleMap;
typedef UNORDERED_MAP<uint32,NpcTextLocale> NpcTextLocaleMap;
typedef UNORDERED_MAP<uint32,PageTextLocale> PageTextLocaleMap;
-typedef UNORDERED_MAP<uint32,TrinityStringLocale> TrinityStringLocaleMap;
+typedef UNORDERED_MAP<int32,TrinityStringLocale> TrinityStringLocaleMap;
typedef UNORDERED_MAP<uint32,NpcOptionLocale> NpcOptionLocaleMap;
typedef UNORDERED_MAP<uint32,PointOfInterestLocale> PointOfInterestLocaleMap;
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 097073cd96a..59059756fbc 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -2346,6 +2346,27 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
if(caster)
caster->CastSpell(caster,13138,true,NULL,this);
return;
+ case 28832: // Mark of Korth'azz
+ case 28833: // Mark of Blaumeux
+ case 28834: // Mark of Rivendare
+ case 28835: // Mark of Zeliek
+ {
+ int8 stack = GetParentAura()->GetStackAmount();
+ int32 damage;
+ switch(stack)
+ {
+ case 1: return;
+ case 2: damage = 500; break;
+ case 3: damage = 1000; break;
+ case 4: damage = 1500; break;
+ case 5: damage = 4000; break;
+ case 6: damage = 12000; break;
+ default:damage = 20000 + 1000 * (stack - 7); break;
+ }
+ if(caster)
+ caster->CastCustomSpell(28836, SPELLVALUE_BASE_POINT0, damage, m_target);
+ return;
+ }
case 34026: // kill command
{
Unit * pet = m_target->GetGuardianPet();
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 47ef23ad855..c28e992adde 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -337,6 +337,17 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
switch(m_spellInfo->Id) // better way to check unknown
{
+ // Positive/Negative Charge
+ case 28062:
+ case 39090:
+ case 28085:
+ case 39093:
+ if(m_triggeredByAuraSpell && unitTarget->HasAura(m_triggeredByAuraSpell->Id))
+ {
+ damage = 0;
+ m_caster->CastSpell(m_caster, (m_spellInfo->Id == 28062 || m_spellInfo->Id == 39090) ? 29659 : 29660, true);
+ }
+ break;
// percent from health with min
case 25599: // Thundercrash
{
@@ -1011,6 +1022,9 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastSpell(unitTarget,29294,true);
return;
}
+ // Polarity Shift
+ case 28089: spell_id = roll_chance_i(50) ? 28059 : 28084; break;
+ case 39096: spell_id = roll_chance_i(50) ? 39088 : 39091; break;
case 29200: // Purify Helboar Meat
{
if( m_caster->GetTypeId() != TYPEID_PLAYER )
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 5de2f843c87..4c83d286620 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -3198,7 +3198,9 @@ void SpellMgr::LoadSpellCustomAttr()
case 45150: // Meteor Slash
mSpellCustomAttr[i] |= SPELL_ATTR_CU_SHARE_DAMAGE;
break;
- case 27820:
+ case 27820: // Mana Detonation
+ case 28062: case 39090: // Positive/Negative Charge
+ case 28085: case 39093:
mSpellCustomAttr[i] |= SPELL_ATTR_CU_EXCLUDE_SELF;
break;
case 44978: case 45001: case 45002: // Wild Magic
diff --git a/src/shared/Util.h b/src/shared/Util.h
index adfbdad620a..ddbf968b2c2 100644
--- a/src/shared/Util.h
+++ b/src/shared/Util.h
@@ -92,7 +92,7 @@ inline void ApplyModFloatVar(float& var, float val, bool apply)
inline void ApplyPercentModFloatVar(float& var, float val, bool apply)
{
- if (!apply && val == -100.0f)
+ if (val == -100.0f) // prevent set var to zero
val = -99.99f;
var *= (apply?(100.0f+val)/100.0f : 100.0f / (100.0f+val));
}