diff options
-rw-r--r-- | src/game/CreatureEventAI.cpp | 412 | ||||
-rw-r--r-- | src/game/CreatureEventAI.h | 224 | ||||
-rw-r--r-- | src/game/CreatureEventAIMgr.cpp | 308 |
3 files changed, 527 insertions, 417 deletions
diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index 3b8df3419da..1b412c3c314 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -464,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) { @@ -520,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())) @@ -535,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) @@ -553,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) { @@ -633,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) @@ -748,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(); @@ -891,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()); @@ -910,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: @@ -951,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: { @@ -965,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; } } @@ -1347,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; } @@ -1366,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: |