bool SmartAIMgr::IsTargetValid(SmartScriptHolder e) { if (e.GetActionType() == SMART_ACTION_INSTALL_AI_TEMPLATE) return true; //AI template has special handling switch (e.GetTargetType()) { case SMART_TARGET_CREATURE_DISTANCE: case SMART_TARGET_CREATURE_RANGE: { if (e.target.unitDistance.creature && !sCreatureStorage.LookupEntry<CreatureInfo>(e.target.unitDistance.creature)) { sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Creature entry %u as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.unitDistance.creature); return false; } break; } case SMART_TARGET_GAMEOBJECT_DISTANCE: case SMART_TARGET_GAMEOBJECT_RANGE: { if (e.target.goDistance.entry && !sGOStorage.LookupEntry<GameObjectInfo>(e.target.goDistance.entry)) { sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent GameObject entry %u as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.goDistance.entry); return false; } break; } case SMART_TARGET_CREATURE_GUID: { if (e.target.unitGUID.entry && !IsCreatureValid(e, e.target.unitGUID.entry)) return false; break; } case SMART_TARGET_GAMEOBJECT_GUID: { if (e.target.goGUID.entry && !IsGameObjectValid(e, e.target.goGUID.entry)) return false; break; } case SMART_TARGET_PLAYER_RANGE: case SMART_TARGET_PLAYER_DISTANCE: case SMART_TARGET_SELF: case SMART_TARGET_VICTIM: case SMART_TARGET_HOSTILE_SECOND_AGGRO: case SMART_TARGET_HOSTILE_LAST_AGGRO: case SMART_TARGET_HOSTILE_RANDOM: case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP: case SMART_TARGET_ACTION_INVOKER: case SMART_TARGET_POSITION: case SMART_TARGET_NONE: case SMART_TARGET_CLOSEST_CREATURE: case SMART_TARGET_CLOSEST_GAMEOBJECT: case SMART_TARGET_CLOSEST_PLAYER: case SMART_TARGET_ACTION_INVOKER_VEHICLE: case SMART_TARGET_OWNER_OR_SUMMONER: case SMART_TARGET_THREAT_LIST: break; default: sLog->outErrorDb("SmartAIMgr: Not handled target_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetTargetType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } return true; }
bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) { if (e.event.type >= SMART_EVENT_END) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: EntryOrGuid %d using event(%u) has invalid event type (%u), skipped.", e.entryOrGuid, e.event_id, e.GetEventType()); return false; } // in SMART_SCRIPT_TYPE_TIMED_ACTIONLIST all event types are overriden by core if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && !(SmartAIEventMask[e.event.type][1] & SmartAITypeMask[e.GetScriptType()][1])) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: EntryOrGuid %d, event type %u can not be used for Script type %u", e.entryOrGuid, e.GetEventType(), e.GetScriptType()); return false; } if (e.action.type <= 0 || e.action.type >= SMART_ACTION_END) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: EntryOrGuid %d using event(%u) has invalid action type (%u), skipped.", e.entryOrGuid, e.event_id, e.GetActionType()); return false; } if (e.event.event_phase_mask > SMART_EVENT_PHASE_ALL) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: EntryOrGuid %d using event(%u) has invalid phase mask (%u), skipped.", e.entryOrGuid, e.event_id, e.event.event_phase_mask); return false; } if (e.event.event_flags > SMART_EVENT_FLAGS_ALL) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: EntryOrGuid %d using event(%u) has invalid event flags (%u), skipped.", e.entryOrGuid, e.event_id, e.event.event_flags); return false; } if (e.GetScriptType() == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST) { e.event.type = SMART_EVENT_UPDATE_OOC;//force default OOC, can change when calling the script! if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max)) return false; if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax)) return false; } else { uint32 type = e.event.type; switch (type) { case SMART_EVENT_UPDATE: case SMART_EVENT_UPDATE_IC: case SMART_EVENT_UPDATE_OOC: case SMART_EVENT_HEALT_PCT: case SMART_EVENT_MANA_PCT: case SMART_EVENT_TARGET_HEALTH_PCT: case SMART_EVENT_TARGET_MANA_PCT: case SMART_EVENT_RANGE: case SMART_EVENT_DAMAGED: case SMART_EVENT_DAMAGED_TARGET: case SMART_EVENT_RECEIVE_HEAL: if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max)) return false; if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax)) return false; break; case SMART_EVENT_SPELLHIT: case SMART_EVENT_SPELLHIT_TARGET: if (e.event.spellHit.spell) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.event.spellHit.spell); if (!spellInfo) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); return false; } if (e.event.spellHit.school && (e.event.spellHit.school & spellInfo->SchoolMask) != spellInfo->SchoolMask) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses Spell entry %u with invalid school mask, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); return false; } } if (!IsMinMaxValid(e, e.event.spellHit.cooldownMin, e.event.spellHit.cooldownMax)) return false; break; case SMART_EVENT_OOC_LOS: case SMART_EVENT_IC_LOS: if (!IsMinMaxValid(e, e.event.los.cooldownMin, e.event.los.cooldownMax)) return false; break; case SMART_EVENT_RESPAWN: if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && !sMapStore.LookupEntry(e.event.respawn.map)) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map); return false; } if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area)) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area); return false; } break; case SMART_EVENT_FRIENDLY_HEALTH: if (!NotNULL(e, e.event.friendlyHealt.radius)) return false; if (!IsMinMaxValid(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax)) return false; break; case SMART_EVENT_FRIENDLY_IS_CC: if (!IsMinMaxValid(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax)) return false; break; case SMART_EVENT_FRIENDLY_MISSING_BUFF: { if (!IsSpellValid(e, e.event.missingBuff.spell)) return false; if (!NotNULL(e, e.event.missingBuff.radius)) return false; if (!IsMinMaxValid(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax)) return false; break; } case SMART_EVENT_KILL: if (!IsMinMaxValid(e, e.event.kill.cooldownMin, e.event.kill.cooldownMax)) return false; if (e.event.kill.creature && !IsCreatureValid(e, e.event.kill.creature)) return false; break; case SMART_EVENT_TARGET_CASTING: case SMART_EVENT_PASSENGER_BOARDED: case SMART_EVENT_PASSENGER_REMOVED: if (!IsMinMaxValid(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax)) return false; break; case SMART_EVENT_SUMMON_DESPAWNED: case SMART_EVENT_SUMMONED_UNIT: if (e.event.summoned.creature && !IsCreatureValid(e, e.event.summoned.creature)) return false; if (!IsMinMaxValid(e, e.event.summoned.cooldownMin, e.event.summoned.cooldownMax)) return false; break; case SMART_EVENT_ACCEPTED_QUEST: case SMART_EVENT_REWARD_QUEST: if (e.event.quest.quest && !IsQuestValid(e, e.event.quest.quest)) return false; break; case SMART_EVENT_RECEIVE_EMOTE: { if (e.event.emote.emote && !IsTextEmoteValid(e, e.event.emote.emote)) return false; if (!IsMinMaxValid(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax)) return false; break; } case SMART_EVENT_HAS_AURA: case SMART_EVENT_TARGET_BUFFED: { if (!IsSpellValid(e, e.event.aura.spell)) return false; if (!IsMinMaxValid(e, e.event.aura.repeatMin, e.event.aura.repeatMax)) return false; break; } case SMART_EVENT_TRANSPORT_ADDCREATURE: { if (e.event.transportAddCreature.creature && !IsCreatureValid(e, e.event.transportAddCreature.creature)) return false; break; } case SMART_EVENT_MOVEMENTINFORM: { if (e.event.movementInform.type > NULL_MOTION_TYPE) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Motion type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.movementInform.type); return false; } break; } case SMART_EVENT_DATA_SET: { if (!IsMinMaxValid(e, e.event.dataSet.cooldownMin, e.event.dataSet.cooldownMax)) return false; break; } case SMART_EVENT_AREATRIGGER_ONTRIGGER: { if (e.event.areatrigger.id && !IsAreaTriggerValid(e, e.event.areatrigger.id)) return false; break; } case SMART_EVENT_TEXT_OVER: //if (e.event.textOver.textGroupID && !IsTextValid(e, e.event.textOver.textGroupID)) return false;// 0 is a valid text group! break; case SMART_EVENT_LINK: { if (e.link && e.link == e.event_id) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u, Event %u, Link Event is linking self (infinite loop), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id); return false; } break; } case SMART_EVENT_DUMMY_EFFECT: { if (!IsSpellValid(e, e.event.dummy.spell)) return false; if (e.event.dummy.effIndex > EFFECT_2) return false; break; } case SMART_EVENT_IS_BEHIND_TARGET: { if (!IsMinMaxValid(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax)) return false; break; } case SMART_EVENT_GAME_EVENT_START: case SMART_EVENT_GAME_EVENT_END: { GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap(); if (e.event.gameEvent.gameEventId >= events.size() || !events[e.event.gameEvent.gameEventId].isValid()) return false; break; } case SMART_EVENT_ACTION_DONE: { if (e.event.doAction.eventId > EVENT_CHARGE) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid event id %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.doAction.eventId); return false; } break; } case SMART_EVENT_GO_STATE_CHANGED: case SMART_EVENT_GO_EVENT_INFORM: case SMART_EVENT_TIMED_EVENT_TRIGGERED: case SMART_EVENT_INSTANCE_PLAYER_ENTER: case SMART_EVENT_TRANSPORT_RELOCATE: case SMART_EVENT_CHARMED: case SMART_EVENT_CHARMED_TARGET: case SMART_EVENT_CORPSE_REMOVED: case SMART_EVENT_AI_INIT: case SMART_EVENT_TRANSPORT_ADDPLAYER: case SMART_EVENT_TRANSPORT_REMOVE_PLAYER: case SMART_EVENT_AGGRO: case SMART_EVENT_DEATH: case SMART_EVENT_EVADE: case SMART_EVENT_REACHED_HOME: case SMART_EVENT_RESET: case SMART_EVENT_QUEST_ACCEPTED: case SMART_EVENT_QUEST_OBJ_COPLETETION: case SMART_EVENT_QUEST_COMPLETION: case SMART_EVENT_QUEST_REWARDED: case SMART_EVENT_QUEST_FAIL: case SMART_EVENT_JUST_SUMMONED: case SMART_EVENT_WAYPOINT_START: case SMART_EVENT_WAYPOINT_REACHED: case SMART_EVENT_WAYPOINT_PAUSED: case SMART_EVENT_WAYPOINT_RESUMED: case SMART_EVENT_WAYPOINT_STOPPED: case SMART_EVENT_WAYPOINT_ENDED: case SMART_EVENT_GOSSIP_SELECT: case SMART_EVENT_GOSSIP_HELLO: case SMART_EVENT_JUST_CREATED: case SMART_EVENT_FOLLOW_COMPLETED: case SMART_EVENT_ON_SPELLCLICK: break; default: sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Not handled event_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } } switch (e.GetActionType()) { case SMART_ACTION_SET_FACTION: if (e.action.faction.factionID && !sFactionTemplateStore.LookupEntry(e.action.faction.factionID)) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Faction %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.faction.factionID); return false; } break; case SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: case SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL: if (e.action.morphOrMount.creature || e.action.morphOrMount.model) { if (e.action.morphOrMount.creature > 0 && !sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature)) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Creature entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.morphOrMount.creature); return false; } if (e.action.morphOrMount.model) { if (e.action.morphOrMount.creature) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u has ModelID set with also set CreatureId, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } else if (!sCreatureDisplayInfoStore.LookupEntry(e.action.morphOrMount.model)) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Model id %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.morphOrMount.model); return false; } } } break; case SMART_ACTION_SOUND: if (!IsSoundValid(e, e.action.sound.sound)) return false; if (e.action.sound.range > TEXT_RANGE_WORLD) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Text Range %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.sound.range); return false; } break; case SMART_ACTION_SET_EMOTE_STATE: case SMART_ACTION_PLAY_EMOTE: if (!IsEmoteValid(e, e.action.emote.emote)) return false; break; case SMART_ACTION_FAIL_QUEST: case SMART_ACTION_ADD_QUEST: if (!e.action.quest.quest || !IsQuestValid(e, e.action.quest.quest)) return false; break; case SMART_ACTION_ACTIVATE_TAXI: { if (!sTaxiPathStore.LookupEntry(e.action.taxi.id)) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Taxi path ID %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.taxi.id); return false; } break; } case SMART_ACTION_RANDOM_EMOTE: if (e.action.randomEmote.emote1 && !IsEmoteValid(e, e.action.randomEmote.emote1)) return false; if (e.action.randomEmote.emote2 && !IsEmoteValid(e, e.action.randomEmote.emote2)) return false; if (e.action.randomEmote.emote3 && !IsEmoteValid(e, e.action.randomEmote.emote3)) return false; if (e.action.randomEmote.emote4 && !IsEmoteValid(e, e.action.randomEmote.emote4)) return false; if (e.action.randomEmote.emote5 && !IsEmoteValid(e, e.action.randomEmote.emote5)) return false; if (e.action.randomEmote.emote6 && !IsEmoteValid(e, e.action.randomEmote.emote6)) return false; break; case SMART_ACTION_ADD_AURA: case SMART_ACTION_CAST: case SMART_ACTION_INVOKER_CAST: if (!IsSpellValid(e, e.action.cast.spell)) return false; break; case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: case SMART_ACTION_CALL_GROUPEVENTHAPPENS: if (Quest const* qid = sObjectMgr->GetQuestTemplate(e.action.quest.quest)) { if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u SpecialFlags for Quest entry %u does not include FLAGS_EXPLORATION_OR_EVENT(2), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest); return false; } } else { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Quest entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest); return false; } break; case SMART_ACTION_SEND_CASTCREATUREORGO: if (!IsQuestValid(e, e.action.castCreatureOrGO.quest)) return false; if (!IsSpellValid(e, e.action.castCreatureOrGO.spell)) return false; break; case SMART_ACTION_SET_EVENT_PHASE: if (e.action.setEventPhase.phase >= SMART_EVENT_PHASE_MAX) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set phase %u. Phase mask cannot be used past phase %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setEventPhase.phase, SMART_EVENT_PHASE_MAX-1); return false; } break; case SMART_ACTION_INC_EVENT_PHASE: if (!e.action.incEventPhase.inc && !e.action.incEventPhase.dec) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u is incrementing phase by 0, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } else if (e.action.incEventPhase.inc > SMART_EVENT_PHASE_MAX || e.action.incEventPhase.dec > SMART_EVENT_PHASE_MAX) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to increment phase by too large value, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } break; case SMART_ACTION_CALL_CASTEDCREATUREORGO: if (!IsCreatureValid(e, e.action.castedCreatureOrGO.creature)) return false; if (!IsSpellValid(e, e.action.castedCreatureOrGO.spell)) return false; break; case SMART_ACTION_REMOVEAURASFROMSPELL: if (e.action.removeAura.spell != 0 && !IsSpellValid(e, e.action.removeAura.spell)) return false; break; case SMART_ACTION_RANDOM_PHASE: { if (e.action.randomPhase.phase1 >= SMART_EVENT_PHASE_MAX || e.action.randomPhase.phase2 >= SMART_EVENT_PHASE_MAX || e.action.randomPhase.phase3 >= SMART_EVENT_PHASE_MAX || e.action.randomPhase.phase4 >= SMART_EVENT_PHASE_MAX || e.action.randomPhase.phase5 >= SMART_EVENT_PHASE_MAX || e.action.randomPhase.phase6 >= SMART_EVENT_PHASE_MAX) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } } break; case SMART_ACTION_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax { if (e.action.randomPhaseRange.phaseMin >= SMART_EVENT_PHASE_MAX || e.action.randomPhaseRange.phaseMax >= SMART_EVENT_PHASE_MAX) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } if (!IsMinMaxValid(e, e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax)) return false; break; } case SMART_ACTION_SUMMON_CREATURE: if (!IsCreatureValid(e, e.action.summonCreature.creature)) return false; if (e.action.summonCreature.type < TEMPSUMMON_TIMED_OR_DEAD_DESPAWN || e.action.summonCreature.type > TEMPSUMMON_MANUAL_DESPAWN) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses incorrect TempSummonType %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonCreature.type); return false; } break; case SMART_ACTION_CALL_KILLEDMONSTER: if (!IsCreatureValid(e, e.action.killedMonster.creature)) return false; break; case SMART_ACTION_UPDATE_TEMPLATE: if (e.action.updateTemplate.creature && !IsCreatureValid(e, e.action.updateTemplate.creature)) return false; break; case SMART_ACTION_SET_SHEATH: if (e.action.setSheath.sheath && e.action.setSheath.sheath >= MAX_SHEATH_STATE) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses incorrect Sheath state %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setSheath.sheath); return false; } break; case SMART_ACTION_SET_REACT_STATE: { if (e.action.react.state > REACT_AGGRESSIVE) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Creature %d Event %u Action %u uses invalid React State %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.react.state); return false; } break; } case SMART_ACTION_SUMMON_GO: if (!IsGameObjectValid(e, e.action.summonGO.entry)) return false; break; case SMART_ACTION_ADD_ITEM: case SMART_ACTION_REMOVE_ITEM: if (!IsItemValid(e, e.action.item.entry)) return false; if (!NotNULL(e, e.action.item.count)) return false; break; case SMART_ACTION_TELEPORT: if (!sMapStore.LookupEntry(e.action.teleport.mapID)) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.teleport.mapID); return false; } break; case SMART_ACTION_INSTALL_AI_TEMPLATE: if (e.action.installTtemplate.id >= SMARTAI_TEMPLATE_END) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Creature %d Event %u Action %u uses non-existent AI template id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.installTtemplate.id); return false; } break; case SMART_ACTION_WP_STOP: if (e.action.wpStop.quest && !IsQuestValid(e, e.action.wpStop.quest)) return false; break; case SMART_ACTION_WP_START: { if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID)) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Creature %d Event %u Action %u uses non-existent WaypointPath id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.pathID); return false; } if (e.action.wpStart.quest && !IsQuestValid(e, e.action.wpStart.quest)) return false; if (e.action.wpStart.reactState > REACT_AGGRESSIVE) { sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Creature %d Event %u Action %u uses invalid React State %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.reactState); return false; } break; } case SMART_ACTION_CREATE_TIMED_EVENT: { if (!IsMinMaxValid(e, e.action.timeEvent.min, e.action.timeEvent.max)) return false; if (!IsMinMaxValid(e, e.action.timeEvent.repeatMin, e.action.timeEvent.repeatMax)) return false; break; } case SMART_ACTION_SET_BASE_RATE_XP: case SMART_ACTION_FOLLOW: case SMART_ACTION_SET_ORIENTATION: case SMART_ACTION_STORE_TARGET_LIST: case SMART_ACTION_EVADE: case SMART_ACTION_FLEE_FOR_ASSIST: case SMART_ACTION_DIE: case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: case SMART_ACTION_SET_ACTIVE: case SMART_ACTION_STORE_VARIABLE_DECIMAL: case SMART_ACTION_WP_RESUME: case SMART_ACTION_KILL_UNIT: case SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL: case SMART_ACTION_RESET_GOBJECT: case SMART_ACTION_ATTACK_START: case SMART_ACTION_THREAT_ALL_PCT: case SMART_ACTION_THREAT_SINGLE_PCT: case SMART_ACTION_SET_INST_DATA: case SMART_ACTION_SET_INST_DATA64: case SMART_ACTION_AUTO_ATTACK: case SMART_ACTION_ALLOW_COMBAT_MOVEMENT: case SMART_ACTION_CALL_FOR_HELP: case SMART_ACTION_SET_DATA: case SMART_ACTION_MOVE_FORWARD: case SMART_ACTION_SET_VISIBILITY: case SMART_ACTION_WP_PAUSE: case SMART_ACTION_SET_FLY: case SMART_ACTION_SET_RUN: case SMART_ACTION_SET_SWIM: case SMART_ACTION_FORCE_DESPAWN: case SMART_ACTION_SET_INGAME_PHASE_MASK: case SMART_ACTION_SET_UNIT_FLAG: case SMART_ACTION_REMOVE_UNIT_FLAG: case SMART_ACTION_PLAYMOVIE: case SMART_ACTION_MOVE_TO_POS: case SMART_ACTION_RESPAWN_TARGET: case SMART_ACTION_CLOSE_GOSSIP: case SMART_ACTION_EQUIP: case SMART_ACTION_TRIGGER_TIMED_EVENT: case SMART_ACTION_REMOVE_TIMED_EVENT: case SMART_ACTION_OVERRIDE_SCRIPT_BASE_OBJECT: case SMART_ACTION_RESET_SCRIPT_BASE_OBJECT: case SMART_ACTION_ACTIVATE_GOBJECT: case SMART_ACTION_CALL_SCRIPT_RESET: case SMART_ACTION_SET_RANGED_MOVEMENT: case SMART_ACTION_CALL_TIMED_ACTIONLIST: case SMART_ACTION_SET_NPC_FLAG: case SMART_ACTION_ADD_NPC_FLAG: case SMART_ACTION_REMOVE_NPC_FLAG: case SMART_ACTION_TALK: case SMART_ACTION_SIMPLE_TALK: case SMART_ACTION_CROSS_CAST: case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: case SMART_ACTION_RANDOM_MOVE: case SMART_ACTION_SET_UNIT_FIELD_BYTES_1: case SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1: case SMART_ACTION_INTERRUPT_SPELL: case SMART_ACTION_SEND_GO_CUSTOM_ANIM: case SMART_ACTION_SET_DYNAMIC_FLAG: case SMART_ACTION_ADD_DYNAMIC_FLAG: case SMART_ACTION_REMOVE_DYNAMIC_FLAG: case SMART_ACTION_JUMP_TO_POS: case SMART_ACTION_SEND_GOSSIP_MENU: case SMART_ACTION_GO_SET_LOOT_STATE: case SMART_ACTION_SEND_TARGET_TO_TARGET: case SMART_ACTION_SET_HOME_POS: case SMART_ACTION_SET_HEALTH_REGEN: case SMART_ACTION_SET_ROOT: case SMART_ACTION_SET_GO_FLAG: case SMART_ACTION_ADD_GO_FLAG: case SMART_ACTION_REMOVE_GO_FLAG: case SMART_ACTION_SUMMON_CREATURE_GROUP: break; default: sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id); return false; } return true; }
bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e) { if (e.GetActionType() == SMART_ACTION_INSTALL_AI_TEMPLATE) return true; // AI template has special handling switch (e.GetTargetType()) { case SMART_TARGET_CREATURE_DISTANCE: case SMART_TARGET_CREATURE_RANGE: { if (e.target.unitDistance.creature && !sObjectMgr->GetCreatureTemplate(e.target.unitDistance.creature)) { IC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Creature entry %u as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.unitDistance.creature); return false; } break; } case SMART_TARGET_GAMEOBJECT_DISTANCE: case SMART_TARGET_GAMEOBJECT_RANGE: { if (e.target.goDistance.entry && !sObjectMgr->GetGameObjectTemplate(e.target.goDistance.entry)) { IC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent GameObject entry %u as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.goDistance.entry); return false; } break; } case SMART_TARGET_CREATURE_GUID: { if (e.target.unitGUID.entry && !IsCreatureValid(e, e.target.unitGUID.entry)) return false; break; } case SMART_TARGET_GAMEOBJECT_GUID: { if (e.target.goGUID.entry && !IsGameObjectValid(e, e.target.goGUID.entry)) return false; break; } case SMART_TARGET_PLAYER_DISTANCE: case SMART_TARGET_CLOSEST_PLAYER: { if (e.target.playerDistance.dist == 0) { IC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u has maxDist 0 as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } break; } case SMART_TARGET_PLAYER_RANGE: case SMART_TARGET_SELF: case SMART_TARGET_VICTIM: case SMART_TARGET_HOSTILE_SECOND_AGGRO: case SMART_TARGET_HOSTILE_LAST_AGGRO: case SMART_TARGET_HOSTILE_RANDOM: case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP: case SMART_TARGET_ACTION_INVOKER: case SMART_TARGET_INVOKER_PARTY: case SMART_TARGET_POSITION: case SMART_TARGET_NONE: //case SMART_TARGET_ACTION_INVOKER_VEHICLE: case SMART_TARGET_OWNER_OR_SUMMONER: case SMART_TARGET_THREAT_LIST: case SMART_TARGET_CLOSEST_GAMEOBJECT: case SMART_TARGET_CLOSEST_CREATURE: case SMART_TARGET_CLOSEST_ENEMY: case SMART_TARGET_CLOSEST_FRIENDLY: case SMART_TARGET_STORED: break; default: IC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled target_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetTargetType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } return true; }