2010-10-27 21:01:47 +02:00
/*
2017-01-01 16:21:30 +01:00
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
2010-10-27 21:01:47 +02:00
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DatabaseEnv.h"
#include "ObjectMgr.h"
#include "ObjectDefines.h"
#include "GridDefines.h"
#include "GridNotifiers.h"
2016-06-15 06:44:36 +02:00
#include "InstanceScript.h"
2010-10-27 21:01:47 +02:00
#include "SpellMgr.h"
#include "Cell.h"
2011-12-11 16:22:18 +01:00
#include "GameEventMgr.h"
2012-03-01 23:45:07 +01:00
#include "CreatureTextMgr.h"
2013-09-02 17:48:17 +02:00
#include "SpellInfo.h"
2010-10-27 21:01:47 +02:00
#include "SmartScriptMgr.h"
2016-03-11 17:11:05 +01:00
SmartWaypointMgr * SmartWaypointMgr :: instance ()
{
static SmartWaypointMgr instance ;
return & instance ;
}
2010-10-27 21:01:47 +02:00
void SmartWaypointMgr :: LoadFromDB ()
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2014-05-01 10:10:13 +02:00
for ( std :: unordered_map < uint32 , WPPath *>:: iterator itr = waypoint_map . begin (); itr != waypoint_map . end (); ++ itr )
2012-03-24 18:42:35 +01:00
{
for ( WPPath :: iterator pathItr = itr -> second -> begin (); pathItr != itr -> second -> end (); ++ pathItr )
delete pathItr -> second ;
delete itr -> second ;
}
2010-10-27 21:01:47 +02:00
waypoint_map . clear ();
2011-12-31 20:14:38 +01:00
PreparedStatement * stmt = WorldDatabase . GetPreparedStatement ( WORLD_SEL_SMARTAI_WP );
2010-10-27 21:01:47 +02:00
PreparedQueryResult result = WorldDatabase . Query ( stmt );
if ( ! result )
{
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "server.loading" , ">> Loaded 0 SmartAI Waypoint Paths. DB table `waypoints` is empty." );
2012-08-03 15:54:54 +02:00
2010-10-27 21:01:47 +02:00
return ;
}
uint32 count = 0 ;
uint32 total = 0 ;
2010-12-19 17:06:33 +01:00
uint32 last_entry = 0 ;
uint32 last_id = 1 ;
2010-10-27 21:01:47 +02:00
do
{
2011-03-27 12:54:42 +02:00
Field * fields = result -> Fetch ();
2010-10-27 21:01:47 +02:00
uint32 entry = fields [ 0 ]. GetUInt32 ();
uint32 id = fields [ 1 ]. GetUInt32 ();
2011-04-29 20:47:02 +02:00
float x , y , z ;
2010-10-27 21:01:47 +02:00
x = fields [ 2 ]. GetFloat ();
y = fields [ 3 ]. GetFloat ();
z = fields [ 4 ]. GetFloat ();
2010-12-13 22:37:56 +01:00
2010-10-27 21:01:47 +02:00
if ( last_entry != entry )
{
2012-02-23 13:01:16 +01:00
waypoint_map [ entry ] = new WPPath ();
2010-10-27 21:01:47 +02:00
last_id = 1 ;
2012-02-23 13:01:16 +01:00
count ++ ;
2010-10-27 21:01:47 +02:00
}
2011-11-26 01:53:44 +01:00
2010-10-27 21:01:47 +02:00
if ( last_id != id )
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartWaypointMgr::LoadFromDB: Path entry %u, unexpected point id %u, expected %u." , entry , id , last_id );
2011-11-26 01:53:44 +01:00
2010-10-27 21:01:47 +02:00
last_id ++ ;
2012-02-23 13:01:16 +01:00
( * waypoint_map [ entry ])[ id ] = new WayPoint ( id , x , y , z );
2010-10-27 21:01:47 +02:00
last_entry = entry ;
total ++ ;
2010-12-19 17:06:33 +01:00
}
while ( result -> NextRow ());
2010-10-27 21:01:47 +02:00
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "server.loading" , ">> Loaded %u SmartAI waypoint paths (total %u waypoints) in %u ms" , count , total , GetMSTimeDiffToNow ( oldMSTime ));
2010-10-27 21:01:47 +02:00
}
2012-03-24 18:42:35 +01:00
SmartWaypointMgr ::~ SmartWaypointMgr ()
{
2014-05-01 10:10:13 +02:00
for ( std :: unordered_map < uint32 , WPPath *>:: iterator itr = waypoint_map . begin (); itr != waypoint_map . end (); ++ itr )
2012-03-24 18:42:35 +01:00
{
for ( WPPath :: iterator pathItr = itr -> second -> begin (); pathItr != itr -> second -> end (); ++ pathItr )
delete pathItr -> second ;
delete itr -> second ;
}
}
2016-03-11 17:11:05 +01:00
SmartAIMgr * SmartAIMgr :: instance ()
{
static SmartAIMgr instance ;
return & instance ;
}
2010-10-27 21:01:47 +02:00
void SmartAIMgr :: LoadSmartAIFromDB ()
{
2013-12-11 18:53:05 +01:00
LoadHelperStores ();
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2010-10-27 21:01:47 +02:00
for ( uint8 i = 0 ; i < SMART_SCRIPT_TYPE_MAX ; i ++ )
mEventMap [ i ]. clear (); //Drop Existing SmartAI List
2011-12-31 20:14:38 +01:00
PreparedStatement * stmt = WorldDatabase . GetPreparedStatement ( WORLD_SEL_SMART_SCRIPTS );
2010-10-27 21:01:47 +02:00
PreparedQueryResult result = WorldDatabase . Query ( stmt );
if ( ! result )
{
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "server.loading" , ">> Loaded 0 SmartAI scripts. DB table `smartai_scripts` is empty." );
2010-10-27 21:01:47 +02:00
return ;
}
2010-12-19 17:06:33 +01:00
uint32 count = 0 ;
2010-10-27 21:01:47 +02:00
do
{
Field * fields = result -> Fetch ();
SmartScriptHolder temp ;
2014-10-26 02:57:28 +02:00
temp . entryOrGuid = fields [ 0 ]. GetInt64 ();
2011-02-20 19:11:42 +00:00
SmartScriptType source_type = ( SmartScriptType ) fields [ 1 ]. GetUInt8 ();
2010-10-27 21:01:47 +02:00
if ( source_type >= SMART_SCRIPT_TYPE_MAX )
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: invalid source_type (%u), skipped loading." , uint32 ( source_type ));
2010-10-27 21:01:47 +02:00
continue ;
}
if ( temp . entryOrGuid >= 0 )
{
2011-09-29 12:43:05 +02:00
switch ( source_type )
2010-10-27 21:01:47 +02:00
{
case SMART_SCRIPT_TYPE_CREATURE :
{
2014-10-04 16:19:25 +02:00
CreatureTemplate const * creatureInfo = sObjectMgr -> GetCreatureTemplate (( uint32 ) temp . entryOrGuid );
if ( ! creatureInfo )
2010-10-27 21:01:47 +02:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: Creature entry (%u) does not exist, skipped loading." , uint32 ( temp . entryOrGuid ));
2010-10-27 21:01:47 +02:00
continue ;
}
2014-10-04 16:19:25 +02:00
if ( creatureInfo -> AIName != "SmartAI" )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: Creature entry (%u) is not using SmartAI, skipped loading." , uint32 ( temp . entryOrGuid ));
continue ;
}
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_SCRIPT_TYPE_GAMEOBJECT :
{
2014-10-04 16:19:25 +02:00
GameObjectTemplate const * gameObjectInfo = sObjectMgr -> GetGameObjectTemplate (( uint32 ) temp . entryOrGuid );
if ( ! gameObjectInfo )
2010-10-27 21:01:47 +02:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: GameObject entry (%u) does not exist, skipped loading." , uint32 ( temp . entryOrGuid ));
2010-10-27 21:01:47 +02:00
continue ;
}
2014-10-04 16:19:25 +02:00
if ( gameObjectInfo -> AIName != "SmartGameObjectAI" )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: GameObject entry (%u) is not using SmartGameObjectAI, skipped loading." , uint32 ( temp . entryOrGuid ));
continue ;
}
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_SCRIPT_TYPE_AREATRIGGER :
{
if ( ! sAreaTriggerStore . LookupEntry (( uint32 ) temp . entryOrGuid ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: AreaTrigger entry (%u) does not exist, skipped loading." , uint32 ( temp . entryOrGuid ));
2010-10-27 21:01:47 +02:00
continue ;
}
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_SCRIPT_TYPE_TIMED_ACTIONLIST :
break ; //nothing to check, really
2010-10-27 21:01:47 +02:00
default :
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: not yet implemented source_type %u" , ( uint32 ) source_type );
2010-10-27 21:01:47 +02:00
continue ;
}
2011-10-30 13:12:39 +00:00
}
else
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
CreatureData const * creature = sObjectMgr -> GetCreatureData ( uint64 ( - temp . entryOrGuid ));
2014-10-04 16:19:25 +02:00
if ( ! creature )
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: Creature guid (" SI64FMTD ") does not exist, skipped loading." , - temp . entryOrGuid );
2010-10-27 21:01:47 +02:00
continue ;
}
2014-10-04 16:19:25 +02:00
CreatureTemplate const * creatureInfo = sObjectMgr -> GetCreatureTemplate ( creature -> id );
if ( ! creatureInfo )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: Creature entry (%u) guid (" SI64FMTD ") does not exist, skipped loading." , creature -> id , - temp . entryOrGuid );
2014-10-04 16:19:25 +02:00
continue ;
}
if ( creatureInfo -> AIName != "SmartAI" )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: Creature entry (%u) guid (" SI64FMTD ") is not using SmartAI, skipped loading." , creature -> id , - temp . entryOrGuid );
2014-10-04 16:19:25 +02:00
continue ;
}
2010-10-27 21:01:47 +02:00
}
2011-10-30 13:12:39 +00:00
2010-10-27 21:01:47 +02:00
temp . source_type = source_type ;
2011-02-20 19:11:42 +00:00
temp . event_id = fields [ 2 ]. GetUInt16 ();
temp . link = fields [ 3 ]. GetUInt16 ();
temp . event . type = ( SMART_EVENT ) fields [ 4 ]. GetUInt8 ();
temp . event . event_phase_mask = fields [ 5 ]. GetUInt8 ();
temp . event . event_chance = fields [ 6 ]. GetUInt8 ();
2016-09-02 23:14:50 +02:00
temp . event . event_flags = fields [ 7 ]. GetUInt16 ();
2010-10-27 21:01:47 +02:00
temp . event . raw . param1 = fields [ 8 ]. GetUInt32 ();
temp . event . raw . param2 = fields [ 9 ]. GetUInt32 ();
temp . event . raw . param3 = fields [ 10 ]. GetUInt32 ();
temp . event . raw . param4 = fields [ 11 ]. GetUInt32 ();
2011-02-20 19:11:42 +00:00
temp . action . type = ( SMART_ACTION ) fields [ 12 ]. GetUInt8 ();
2010-10-27 21:01:47 +02:00
temp . action . raw . param1 = fields [ 13 ]. GetUInt32 ();
temp . action . raw . param2 = fields [ 14 ]. GetUInt32 ();
temp . action . raw . param3 = fields [ 15 ]. GetUInt32 ();
temp . action . raw . param4 = fields [ 16 ]. GetUInt32 ();
temp . action . raw . param5 = fields [ 17 ]. GetUInt32 ();
temp . action . raw . param6 = fields [ 18 ]. GetUInt32 ();
2011-02-20 19:11:42 +00:00
temp . target . type = ( SMARTAI_TARGETS ) fields [ 19 ]. GetUInt8 ();
2010-10-27 21:01:47 +02:00
temp . target . raw . param1 = fields [ 20 ]. GetUInt32 ();
temp . target . raw . param2 = fields [ 21 ]. GetUInt32 ();
temp . target . raw . param3 = fields [ 22 ]. GetUInt32 ();
temp . target . x = fields [ 23 ]. GetFloat ();
temp . target . y = fields [ 24 ]. GetFloat ();
temp . target . z = fields [ 25 ]. GetFloat ();
temp . target . o = fields [ 26 ]. GetFloat ();
//check target
if ( ! IsTargetValid ( temp ))
continue ;
// check all event and action params
if ( ! IsEventValid ( temp ))
continue ;
// creature entry / guid not found in storage, create empty event list for it and increase counters
if ( mEventMap [ source_type ]. find ( temp . entryOrGuid ) == mEventMap [ source_type ]. end ())
{
2010-12-19 17:06:33 +01:00
++ count ;
2010-10-27 21:01:47 +02:00
SmartAIEventList eventList ;
mEventMap [ source_type ][ temp . entryOrGuid ] = eventList ;
}
// store the new event
mEventMap [ source_type ][ temp . entryOrGuid ]. push_back ( temp );
2010-12-19 17:06:33 +01:00
}
while ( result -> NextRow ());
2010-10-27 21:01:47 +02:00
2014-10-11 18:52:01 +02:00
// Post Loading Validation
for ( uint8 i = 0 ; i < SMART_SCRIPT_TYPE_MAX ; ++ i )
2014-10-02 21:11:20 +02:00
{
2014-10-11 18:52:01 +02:00
for ( SmartAIEventMap :: iterator itr = mEventMap [ i ]. begin (); itr != mEventMap [ i ]. end (); ++ itr )
2014-10-02 21:11:20 +02:00
{
2014-10-11 18:52:01 +02:00
for ( SmartScriptHolder const & e : itr -> second )
2014-10-02 21:11:20 +02:00
{
2014-10-11 18:52:01 +02:00
if ( e . link )
2014-10-02 21:11:20 +02:00
{
2014-10-11 18:52:01 +02:00
if ( ! FindLinkedEvent ( itr -> second , e . link ))
2014-10-02 21:11:20 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: Entry " SI64FMTD " SourceType %u, Event %u, Link Event %u not found or invalid." ,
2014-10-11 18:52:01 +02:00
e . entryOrGuid , e . GetScriptType (), e . event_id , e . link );
2014-10-02 21:11:20 +02:00
}
2014-10-11 18:52:01 +02:00
}
2014-10-02 22:24:59 +02:00
2014-10-11 18:52:01 +02:00
if ( e . GetEventType () == SMART_EVENT_LINK )
{
if ( ! FindLinkedSourceEvent ( itr -> second , e . event_id ))
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr::LoadSmartAIFromDB: Entry " SI64FMTD " SourceType %u, Event %u, Link Source Event not found or invalid. Event will never trigger." ,
2014-10-11 18:52:01 +02:00
e . entryOrGuid , e . GetScriptType (), e . event_id );
}
2014-10-02 21:11:20 +02:00
}
}
}
}
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "server.loading" , ">> Loaded %u SmartAI scripts in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
2012-08-03 14:20:18 +02:00
2013-12-11 18:53:05 +01:00
UnLoadHelperStores ();
2010-10-27 21:01:47 +02:00
}
2011-05-12 10:40:53 +02:00
bool SmartAIMgr :: IsTargetValid ( SmartScriptHolder const & e )
2010-10-27 21:01:47 +02:00
{
2014-10-11 05:33:08 +02:00
if ( std :: abs ( e . target . o ) > 2 * float ( M_PI ))
2014-10-27 21:56:12 +00:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u has abs(`target.o` = %f) > 2*PI (orientation is expressed in radians)" ,
2014-10-11 18:56:58 +02:00
e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . target . o );
2014-10-11 05:33:08 +02:00
2010-10-27 21:01:47 +02:00
if ( e . GetActionType () == SMART_ACTION_INSTALL_AI_TEMPLATE )
2011-10-30 13:12:39 +00:00
return true ; // AI template has special handling
2014-10-11 18:52:01 +02:00
2010-10-27 21:01:47 +02:00
switch ( e . GetTargetType ())
{
case SMART_TARGET_CREATURE_DISTANCE :
case SMART_TARGET_CREATURE_RANGE :
2011-10-30 13:12:39 +00:00
{
if ( e . target . unitDistance . creature && ! sObjectMgr -> GetCreatureTemplate ( e . target . unitDistance . creature ))
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2011-10-30 13:12:39 +00:00
return false ;
2010-10-27 21:01:47 +02:00
}
2011-10-30 13:12:39 +00:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_GAMEOBJECT_DISTANCE :
case SMART_TARGET_GAMEOBJECT_RANGE :
2011-10-30 13:12:39 +00:00
{
if ( e . target . goDistance . entry && ! sObjectMgr -> GetGameObjectTemplate ( e . target . goDistance . entry ))
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2011-10-30 13:12:39 +00:00
return false ;
2010-10-27 21:01:47 +02:00
}
2011-10-30 13:12:39 +00:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_CREATURE_GUID :
2011-10-30 13:12:39 +00:00
{
2011-12-27 20:23:55 -05:00
if ( e . target . unitGUID . entry && ! IsCreatureValid ( e , e . target . unitGUID . entry ))
return false ;
2011-10-30 13:12:39 +00:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_GAMEOBJECT_GUID :
2011-10-30 13:12:39 +00:00
{
2012-02-18 16:52:08 +01:00
if ( e . target . goGUID . entry && ! IsGameObjectValid ( e , e . target . goGUID . entry ))
2011-12-27 20:23:55 -05:00
return false ;
2011-10-30 13:12:39 +00:00
break ;
}
case SMART_TARGET_PLAYER_DISTANCE :
case SMART_TARGET_CLOSEST_PLAYER :
{
if ( e . target . playerDistance . dist == 0 )
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u has maxDist 0 as target_param1, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2011-10-30 13:12:39 +00:00
return false ;
2010-10-27 21:01:47 +02:00
}
2011-10-30 13:12:39 +00:00
break ;
}
2010-10-27 21:01:47 +02:00
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 :
2012-01-22 01:49:53 +01:00
case SMART_TARGET_INVOKER_PARTY :
2010-10-27 21:01:47 +02:00
case SMART_TARGET_POSITION :
case SMART_TARGET_NONE :
2010-10-31 14:21:35 +01:00
case SMART_TARGET_ACTION_INVOKER_VEHICLE :
2010-11-07 18:02:33 +01:00
case SMART_TARGET_OWNER_OR_SUMMONER :
2010-11-20 12:42:10 +01:00
case SMART_TARGET_THREAT_LIST :
2011-10-30 13:12:39 +00:00
case SMART_TARGET_CLOSEST_GAMEOBJECT :
case SMART_TARGET_CLOSEST_CREATURE :
2013-08-07 19:59:06 +01:00
case SMART_TARGET_CLOSEST_ENEMY :
2013-08-15 01:22:22 +01:00
case SMART_TARGET_CLOSEST_FRIENDLY :
2011-12-27 20:23:55 -05:00
case SMART_TARGET_STORED :
2016-08-19 14:25:23 +02:00
case SMART_TARGET_LOOT_RECIPIENTS :
2010-10-27 21:01:47 +02:00
break ;
default :
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Not handled target_type(%u), Entry " SI64FMTD " SourceType %u Event %u Action %u, skipped." , e . GetTargetType (), e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2010-10-27 21:01:47 +02:00
return false ;
}
return true ;
}
2011-08-18 14:55:27 -03:00
bool SmartAIMgr :: IsEventValid ( SmartScriptHolder & e )
2010-10-27 21:01:47 +02:00
{
if ( e . event . type >= SMART_EVENT_END )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: EntryOrGuid " SI64FMTD " using event(%u) has invalid event type (%u), skipped." , e . entryOrGuid , e . event_id , e . GetEventType ());
2010-10-27 21:01:47 +02:00
return false ;
}
2014-10-11 18:52:01 +02:00
2010-11-03 14:10:16 +01:00
// 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 ]))
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: EntryOrGuid " SI64FMTD ", event type %u can not be used for Script type %u" , e . entryOrGuid , e . GetEventType (), e . GetScriptType ());
2010-10-27 21:01:47 +02:00
return false ;
}
2014-10-11 18:52:01 +02:00
2012-05-20 16:13:52 +01:00
if ( e . action . type <= 0 || e . action . type >= SMART_ACTION_END )
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: EntryOrGuid " SI64FMTD " using event(%u) has invalid action type (%u), skipped." , e . entryOrGuid , e . event_id , e . GetActionType ());
2010-10-27 21:01:47 +02:00
return false ;
}
2014-10-11 18:52:01 +02:00
2010-10-27 21:01:47 +02:00
if ( e . event . event_phase_mask > SMART_EVENT_PHASE_ALL )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: EntryOrGuid " SI64FMTD " using event(%u) has invalid phase mask (%u), skipped." , e . entryOrGuid , e . event_id , e . event . event_phase_mask );
2010-10-27 21:01:47 +02:00
return false ;
}
2014-10-11 18:52:01 +02:00
2012-05-20 16:13:52 +01:00
if ( e . event . event_flags > SMART_EVENT_FLAGS_ALL )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: EntryOrGuid " SI64FMTD " using event(%u) has invalid event flags (%u), skipped." , e . entryOrGuid , e . event_id , e . event . event_flags );
2012-05-20 16:13:52 +01:00
return false ;
}
2014-10-11 18:52:01 +02:00
if ( e . link && e . link == e . event_id )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: EntryOrGuid " SI64FMTD " SourceType %u, Event %u, Event is linking self (infinite loop), skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id );
2014-10-11 18:52:01 +02:00
return false ;
}
2010-11-03 14:10:16 +01:00
if ( e . GetScriptType () == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST )
2010-10-27 21:01:47 +02:00
{
2010-11-03 14:10:16 +01:00
e . event . type = SMART_EVENT_UPDATE_OOC ; //force default OOC, can change when calling the script!
2012-03-28 20:00:29 +08:00
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 ;
2010-11-03 14:10:16 +01:00
}
else
{
2014-10-11 18:52:01 +02:00
switch ( e . GetEventType ())
2010-11-03 14:10:16 +01:00
{
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 :
2012-03-28 20:00:29 +08:00
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 ;
2010-11-03 14:10:16 +01:00
break ;
case SMART_EVENT_SPELLHIT :
case SMART_EVENT_SPELLHIT_TARGET :
if ( e . event . spellHit . spell )
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( e . event . spellHit . spell );
if ( ! spellInfo )
2010-11-03 14:10:16 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-11-03 14:10:16 +01:00
return false ;
}
2011-08-20 20:31:31 -03:00
if ( e . event . spellHit . school && ( e . event . spellHit . school & spellInfo -> SchoolMask ) != spellInfo -> SchoolMask )
2010-11-03 14:10:16 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-11-03 14:10:16 +01:00
return false ;
}
2010-10-27 21:01:47 +02:00
}
2012-03-28 20:00:29 +08:00
if ( ! IsMinMaxValid ( e , e . event . spellHit . cooldownMin , e . event . spellHit . cooldownMax ))
return false ;
2010-11-03 14:10:16 +01:00
break ;
case SMART_EVENT_OOC_LOS :
case SMART_EVENT_IC_LOS :
2012-03-28 20:00:29 +08:00
if ( ! IsMinMaxValid ( e , e . event . los . cooldownMin , e . event . los . cooldownMax ))
return false ;
2010-11-03 14:10:16 +01:00
break ;
case SMART_EVENT_RESPAWN :
if ( e . event . respawn . type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && ! sMapStore . LookupEntry ( e . event . respawn . map ))
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
return false ;
}
2016-02-02 19:13:04 +01:00
if ( e . event . respawn . type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && ! sAreaTableStore . LookupEntry ( e . event . respawn . area ))
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
return false ;
}
break ;
2010-11-03 14:10:16 +01:00
case SMART_EVENT_FRIENDLY_HEALTH :
2013-09-01 10:49:29 +02:00
if ( ! NotNULL ( e , e . event . friendlyHealth . radius ))
2012-03-28 20:00:29 +08:00
return false ;
2013-09-01 10:49:29 +02:00
if ( ! IsMinMaxValid ( e , e . event . friendlyHealth . repeatMin , e . event . friendlyHealth . repeatMax ))
2012-03-28 20:00:29 +08:00
return false ;
2010-11-03 14:10:16 +01:00
break ;
case SMART_EVENT_FRIENDLY_IS_CC :
2012-03-28 20:00:29 +08:00
if ( ! IsMinMaxValid ( e , e . event . friendlyCC . repeatMin , e . event . friendlyCC . repeatMax ))
return false ;
2010-11-03 14:10:16 +01:00
break ;
case SMART_EVENT_FRIENDLY_MISSING_BUFF :
2010-10-27 21:01:47 +02:00
{
2012-03-28 20:00:29 +08:00
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 ;
2010-10-27 21:01:47 +02:00
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_EVENT_KILL :
2012-03-28 20:00:29 +08:00
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 ;
2010-11-03 14:10:16 +01:00
break ;
2013-10-22 15:59:32 +02:00
case SMART_EVENT_VICTIM_CASTING :
2013-09-01 10:49:29 +02:00
if ( e . event . targetCasting . spellId > 0 && ! sSpellMgr -> GetSpellInfo ( e . event . targetCasting . spellId ))
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2013-09-01 10:49:29 +02:00
return false ;
}
if ( ! IsMinMaxValid ( e , e . event . targetCasting . repeatMin , e . event . targetCasting . repeatMax ))
return false ;
break ;
2010-11-03 14:10:16 +01:00
case SMART_EVENT_PASSENGER_BOARDED :
case SMART_EVENT_PASSENGER_REMOVED :
2012-03-28 20:00:29 +08:00
if ( ! IsMinMaxValid ( e , e . event . minMax . repeatMin , e . event . minMax . repeatMax ))
return false ;
2010-11-03 14:10:16 +01:00
break ;
case SMART_EVENT_SUMMON_DESPAWNED :
case SMART_EVENT_SUMMONED_UNIT :
2012-03-28 20:00:29 +08:00
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 ;
2010-11-03 14:10:16 +01:00
break ;
case SMART_EVENT_ACCEPTED_QUEST :
case SMART_EVENT_REWARD_QUEST :
2011-10-24 23:21:34 +01:00
if ( e . event . quest . quest && ! IsQuestValid ( e , e . event . quest . quest ))
return false ;
2010-11-03 14:10:16 +01:00
break ;
case SMART_EVENT_RECEIVE_EMOTE :
2010-10-27 21:01:47 +02:00
{
2012-03-28 20:00:29 +08:00
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 ;
2010-10-27 21:01:47 +02:00
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_EVENT_HAS_AURA :
case SMART_EVENT_TARGET_BUFFED :
2010-10-27 21:01:47 +02:00
{
2012-03-28 20:00:29 +08:00
if ( ! IsSpellValid ( e , e . event . aura . spell ))
return false ;
if ( ! IsMinMaxValid ( e , e . event . aura . repeatMin , e . event . aura . repeatMax ))
return false ;
2010-11-03 14:10:16 +01:00
break ;
}
case SMART_EVENT_TRANSPORT_ADDCREATURE :
2012-06-17 21:50:01 +01:00
{
if ( e . event . transportAddCreature . creature && ! IsCreatureValid ( e , e . event . transportAddCreature . creature ))
return false ;
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_EVENT_MOVEMENTINFORM :
2012-06-17 21:50:01 +01:00
{
2016-09-14 23:53:37 +02:00
if ( e . event . movementInform . type >= MAX_MOTION_TYPE )
2010-11-03 14:10:16 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2012-06-17 21:50:01 +01:00
return false ;
2010-10-27 21:01:47 +02:00
}
2012-06-17 21:50:01 +01:00
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_EVENT_DATA_SET :
2012-06-17 21:50:01 +01:00
{
if ( ! IsMinMaxValid ( e , e . event . dataSet . cooldownMin , e . event . dataSet . cooldownMax ))
return false ;
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_EVENT_AREATRIGGER_ONTRIGGER :
2012-06-17 21:50:01 +01:00
{
if ( e . event . areatrigger . id && ! IsAreaTriggerValid ( e , e . event . areatrigger . id ))
return false ;
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_EVENT_TEXT_OVER :
2014-10-11 18:52:01 +02:00
if ( ! IsTextValid ( e , e . event . textOver . textGroupID ))
2012-06-17 21:50:01 +01:00
return false ;
break ;
2010-11-17 23:24:21 +01:00
case SMART_EVENT_DUMMY_EFFECT :
2012-06-17 21:50:01 +01:00
{
2012-03-28 20:00:29 +08:00
if ( ! IsSpellValid ( e , e . event . dummy . spell ))
return false ;
if ( e . event . dummy . effIndex > EFFECT_2 )
return false ;
2010-11-17 23:24:21 +01:00
break ;
2012-06-17 21:50:01 +01:00
}
2011-04-14 00:30:32 -03:00
case SMART_EVENT_IS_BEHIND_TARGET :
2012-06-17 21:50:01 +01:00
{
2011-04-14 00:30:32 -03:00
if ( ! IsMinMaxValid ( e , e . event . behindTarget . cooldownMin , e . event . behindTarget . cooldownMax ))
return false ;
break ;
2012-06-17 21:50:01 +01:00
}
2011-12-11 16:22:18 +01:00
case SMART_EVENT_GAME_EVENT_START :
case SMART_EVENT_GAME_EVENT_END :
2012-06-17 21:50:01 +01:00
{
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 :
{
2012-06-19 00:07:20 +02:00
if ( e . event . doAction . eventId > EVENT_CHARGE )
2011-12-11 16:22:18 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2012-06-17 21:50:01 +01:00
return false ;
2011-12-11 16:22:18 +01:00
}
2012-06-17 21:50:01 +01:00
break ;
}
2013-08-15 01:18:10 +01:00
case SMART_EVENT_FRIENDLY_HEALTH_PCT :
2013-09-01 10:49:29 +02:00
if ( ! IsMinMaxValid ( e , e . event . friendlyHealthPct . repeatMin , e . event . friendlyHealthPct . repeatMax ))
2013-08-15 01:18:10 +01:00
return false ;
2013-09-01 10:49:29 +02:00
if ( e . event . friendlyHealthPct . maxHpPct > 100 || e . event . friendlyHealthPct . minHpPct > 100 )
2013-08-15 01:18:10 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u has pct value above 100, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2013-08-15 01:18:10 +01:00
return false ;
}
switch ( e . GetTargetType ())
{
case SMART_TARGET_CREATURE_RANGE :
case SMART_TARGET_CREATURE_GUID :
case SMART_TARGET_CREATURE_DISTANCE :
case SMART_TARGET_CLOSEST_CREATURE :
case SMART_TARGET_CLOSEST_PLAYER :
case SMART_TARGET_PLAYER_RANGE :
case SMART_TARGET_PLAYER_DISTANCE :
break ;
default :
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses invalid target_type %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . GetTargetType ());
2013-08-15 01:18:10 +01:00
return false ;
}
break ;
2014-03-17 16:58:10 -04:00
case SMART_EVENT_DISTANCE_CREATURE :
if ( e . event . distance . guid == 0 && e . event . distance . entry == 0 )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE did not provide creature guid or entry, skipped." );
return false ;
}
if ( e . event . distance . guid != 0 && e . event . distance . entry != 0 )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE provided both an entry and guid, skipped." );
return false ;
}
if ( e . event . distance . guid != 0 && ! sObjectMgr -> GetCreatureData ( e . event . distance . guid ))
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature guid %u, skipped." , e . event . distance . guid );
return false ;
}
if ( e . event . distance . entry != 0 && ! sObjectMgr -> GetCreatureTemplate ( e . event . distance . entry ))
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature entry %u, skipped." , e . event . distance . entry );
return false ;
}
break ;
case SMART_EVENT_DISTANCE_GAMEOBJECT :
if ( e . event . distance . guid == 0 && e . event . distance . entry == 0 )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT did not provide gameobject guid or entry, skipped." );
return false ;
}
if ( e . event . distance . guid != 0 && e . event . distance . entry != 0 )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT provided both an entry and guid, skipped." );
return false ;
}
if ( e . event . distance . guid != 0 && ! sObjectMgr -> GetGOData ( e . event . distance . guid ))
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject guid %u, skipped." , e . event . distance . guid );
return false ;
}
if ( e . event . distance . entry != 0 && ! sObjectMgr -> GetGameObjectTemplate ( e . event . distance . entry ))
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject entry %u, skipped." , e . event . distance . entry );
return false ;
}
break ;
2015-04-02 18:02:34 +02:00
case SMART_EVENT_COUNTER_SET :
if ( ! IsMinMaxValid ( e , e . event . counter . cooldownMin , e . event . counter . cooldownMax ))
return false ;
if ( e . event . counter . id == 0 )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid counter id %u, skipped." , e . event . counter . id );
return false ;
}
if ( e . event . counter . value == 0 )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid value %u, skipped." , e . event . counter . value );
return false ;
}
break ;
2014-10-11 18:52:01 +02:00
case SMART_EVENT_LINK :
2012-01-06 11:09:01 -05:00
case SMART_EVENT_GO_STATE_CHANGED :
2012-06-11 11:10:46 +02:00
case SMART_EVENT_GO_EVENT_INFORM :
2010-11-03 14:10:16 +01:00
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 :
2010-11-17 23:24:21 +01:00
case SMART_EVENT_FOLLOW_COMPLETED :
2012-06-19 00:07:20 +02:00
case SMART_EVENT_ON_SPELLCLICK :
2010-11-03 14:10:16 +01:00
break ;
2010-12-13 22:37:56 +01:00
default :
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Not handled event_type(%u), Entry " SI64FMTD " SourceType %u Event %u Action %u, skipped." , e . GetEventType (), e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2010-11-03 14:10:16 +01:00
return false ;
}
2010-10-27 21:01:47 +02:00
}
2010-11-03 14:10:16 +01:00
2010-10-27 21:01:47 +02:00
switch ( e . GetActionType ())
{
2014-10-03 16:02:11 +02:00
case SMART_ACTION_TALK :
2014-10-11 18:52:01 +02:00
case SMART_ACTION_SIMPLE_TALK :
if ( ! IsTextValid ( e , e . action . talk . textGroupID ))
return false ;
2014-10-03 16:02:11 +02:00
break ;
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_FACTION :
2011-08-26 05:15:38 +01:00
if ( e . action . faction . factionID && ! sFactionTemplateStore . LookupEntry ( e . action . faction . factionID ))
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
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 )
{
2011-04-28 22:57:08 +02:00
if ( e . action . morphOrMount . creature > 0 && ! sObjectMgr -> GetCreatureTemplate ( e . action . morphOrMount . creature ))
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
return false ;
}
if ( e . action . morphOrMount . model )
{
if ( e . action . morphOrMount . creature )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u has ModelID set with also set CreatureId, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2010-10-27 21:01:47 +02:00
return false ;
}
else if ( ! sCreatureDisplayInfoStore . LookupEntry ( e . action . morphOrMount . model ))
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
return false ;
}
}
}
break ;
case SMART_ACTION_SOUND :
2011-10-24 23:21:34 +01:00
if ( ! IsSoundValid ( e , e . action . sound . sound ))
return false ;
2010-10-27 21:01:47 +02:00
break ;
case SMART_ACTION_SET_EMOTE_STATE :
case SMART_ACTION_PLAY_EMOTE :
2012-03-28 20:00:29 +08:00
if ( ! IsEmoteValid ( e , e . action . emote . emote ))
return false ;
2010-10-27 21:01:47 +02:00
break ;
case SMART_ACTION_FAIL_QUEST :
2016-08-19 23:01:03 +02:00
case SMART_ACTION_OFFER_QUEST :
2012-03-28 20:00:29 +08:00
if ( ! e . action . quest . quest || ! IsQuestValid ( e , e . action . quest . quest ))
return false ;
2010-10-27 21:01:47 +02:00
break ;
2010-11-19 20:23:08 +01:00
case SMART_ACTION_ACTIVATE_TAXI :
{
if ( ! sTaxiPathStore . LookupEntry ( e . action . taxi . id ))
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-11-19 20:23:08 +01:00
return false ;
}
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_RANDOM_EMOTE :
2012-03-28 20:00:29 +08:00
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 ;
2010-10-27 21:01:47 +02:00
break ;
2016-01-26 03:26:41 +00:00
case SMART_ACTION_RANDOM_SOUND :
2016-01-26 03:37:07 +00:00
{
if ( std :: all_of ( e . action . randomSound . sounds . begin (), e . action . randomSound . sounds . end (), []( uint32 sound ) { return sound == 0 ; }))
2016-01-26 03:26:41 +00:00
{
2016-04-02 19:22:30 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u does not have any non-zero sound" ,
2016-01-26 03:37:07 +00:00
e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
return false ;
2016-01-26 03:26:41 +00:00
}
2016-01-26 03:37:07 +00:00
for ( uint32 sound : e . action . randomSound . sounds )
if ( sound && ! IsSoundValid ( e , sound ))
return false ;
2016-01-26 03:26:41 +00:00
break ;
2016-01-26 03:37:07 +00:00
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_CAST :
2014-09-30 18:55:51 +02:00
{
if ( ! IsSpellValid ( e , e . action . cast . spell ))
return false ;
2015-02-08 19:40:03 +01:00
SpellInfo const * spellInfo = sSpellMgr -> AssertSpellInfo ( e . action . cast . spell );
2014-11-22 17:18:16 +01:00
for ( SpellEffectInfo const * effect : spellInfo -> GetEffectsForDifficulty ( DIFFICULTY_NONE ))
2014-09-30 18:55:51 +02:00
{
2014-11-22 17:18:16 +01:00
if ( effect && ( effect -> IsEffect ( SPELL_EFFECT_KILL_CREDIT ) || effect -> IsEffect ( SPELL_EFFECT_KILL_CREDIT2 )))
2014-09-30 18:55:51 +02:00
{
2014-11-22 17:18:16 +01:00
if ( effect -> TargetA . GetTarget () == TARGET_UNIT_CASTER )
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u Effect: SPELL_EFFECT_KILL_CREDIT: (SpellId: %u targetA: %u - targetB: %u) has invalid target for this Action" ,
2014-11-22 17:18:16 +01:00
e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . cast . spell , effect -> TargetA . GetTarget (), effect -> TargetB . GetTarget ());
2014-09-30 18:55:51 +02:00
}
}
break ;
}
case SMART_ACTION_ADD_AURA :
2010-11-06 23:18:04 +01:00
case SMART_ACTION_INVOKER_CAST :
2012-03-28 20:00:29 +08:00
if ( ! IsSpellValid ( e , e . action . cast . spell ))
return false ;
2010-10-27 21:01:47 +02:00
break ;
case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS :
case SMART_ACTION_CALL_GROUPEVENTHAPPENS :
2010-12-22 21:25:23 +01:00
if ( Quest const * qid = sObjectMgr -> GetQuestTemplate ( e . action . quest . quest ))
2010-10-27 21:01:47 +02:00
{
2012-08-18 21:08:21 +01:00
if ( ! qid -> HasSpecialFlag ( QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT ))
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
return false ;
}
}
else
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
return false ;
}
break ;
case SMART_ACTION_SET_EVENT_PHASE :
if ( e . action . setEventPhase . phase >= SMART_EVENT_PHASE_MAX )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
return false ;
}
break ;
case SMART_ACTION_INC_EVENT_PHASE :
if ( ! e . action . incEventPhase . inc && ! e . action . incEventPhase . dec )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u is incrementing phase by 0, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2010-10-27 21:01:47 +02:00
return false ;
}
else if ( e . action . incEventPhase . inc > SMART_EVENT_PHASE_MAX || e . action . incEventPhase . dec > SMART_EVENT_PHASE_MAX )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u attempts to increment phase by too large value, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2010-10-27 21:01:47 +02:00
return false ;
}
break ;
case SMART_ACTION_REMOVEAURASFROMSPELL :
2012-06-02 14:28:24 +01:00
if ( e . action . removeAura . spell != 0 && ! IsSpellValid ( e , e . action . removeAura . spell ))
2012-03-28 20:00:29 +08:00
return false ;
2010-10-27 21:01:47 +02:00
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 )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u attempts to set invalid phase, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2010-10-27 21:01:47 +02:00
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 )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u attempts to set invalid phase, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2010-10-27 21:01:47 +02:00
return false ;
}
2014-01-21 19:56:43 +01:00
2012-03-28 20:00:29 +08:00
if ( ! IsMinMaxValid ( e , e . action . randomPhaseRange . phaseMin , e . action . randomPhaseRange . phaseMax ))
return false ;
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_ACTION_SUMMON_CREATURE :
2013-12-11 18:53:05 +01:00
{
2012-03-28 20:00:29 +08:00
if ( ! IsCreatureValid ( e , e . action . summonCreature . creature ))
return false ;
2013-09-05 16:16:23 +02:00
2013-12-11 18:53:05 +01:00
CacheSpellContainerBounds sBounds = GetSummonCreatureSpellContainerBounds ( e . action . summonCreature . creature );
for ( CacheSpellContainer :: const_iterator itr = sBounds . first ; itr != sBounds . second ; ++ itr )
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u creature summon: There is a summon spell for creature entry %u (SpellId: %u, effect: %u)" ,
2013-12-11 18:53:05 +01:00
e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . summonCreature . creature , itr -> second . first , itr -> second . second );
2013-09-05 16:16:23 +02:00
2011-09-19 14:41:21 +02:00
if ( e . action . summonCreature . type < TEMPSUMMON_TIMED_OR_DEAD_DESPAWN || e . action . summonCreature . type > TEMPSUMMON_MANUAL_DESPAWN )
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses incorrect TempSummonType %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . summonCreature . type );
2010-10-27 21:01:47 +02:00
return false ;
}
break ;
2013-12-11 18:53:05 +01:00
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_CALL_KILLEDMONSTER :
2013-12-11 18:53:05 +01:00
{
2012-03-28 20:00:29 +08:00
if ( ! IsCreatureValid ( e , e . action . killedMonster . creature ))
return false ;
2013-09-02 17:48:17 +02:00
2013-12-11 18:53:05 +01:00
CacheSpellContainerBounds sBounds = GetKillCreditSpellContainerBounds ( e . action . killedMonster . creature );
for ( CacheSpellContainer :: const_iterator itr = sBounds . first ; itr != sBounds . second ; ++ itr )
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u Kill Credit: There is a killcredit spell for creatureEntry %u (SpellId: %u effect: %u)" ,
2013-12-11 18:53:05 +01:00
e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . killedMonster . creature , itr -> second . first , itr -> second . second );
2013-09-02 17:48:17 +02:00
2013-07-08 18:01:41 +02:00
if ( e . GetTargetType () == SMART_TARGET_POSITION )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses incorrect TargetType %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . GetTargetType ());
2013-07-08 18:01:41 +02:00
return false ;
}
2010-10-27 21:01:47 +02:00
break ;
2013-12-11 18:53:05 +01:00
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_UPDATE_TEMPLATE :
2013-12-13 09:45:58 +01:00
if ( ! IsCreatureValid ( e , e . action . updateTemplate . creature ))
2012-03-28 20:00:29 +08:00
return false ;
2010-10-27 21:01:47 +02:00
break ;
case SMART_ACTION_SET_SHEATH :
if ( e . action . setSheath . sheath && e . action . setSheath . sheath >= MAX_SHEATH_STATE )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
return false ;
}
break ;
case SMART_ACTION_SET_REACT_STATE :
{
if ( e . action . react . state > REACT_AGGRESSIVE )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Creature " SI64FMTD " Event %u Action %u uses invalid React State %u, skipped." , e . entryOrGuid , e . event_id , e . GetActionType (), e . action . react . state );
2010-10-27 21:01:47 +02:00
return false ;
}
break ;
}
case SMART_ACTION_SUMMON_GO :
2013-12-11 18:53:05 +01:00
{
2012-03-28 20:00:29 +08:00
if ( ! IsGameObjectValid ( e , e . action . summonGO . entry ))
return false ;
2013-09-05 16:16:23 +02:00
2013-12-11 18:53:05 +01:00
CacheSpellContainerBounds sBounds = GetSummonGameObjectSpellContainerBounds ( e . action . summonGO . entry );
for ( CacheSpellContainer :: const_iterator itr = sBounds . first ; itr != sBounds . second ; ++ itr )
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u gameobject summon: There is a summon spell for gameobject entry %u (SpellId: %u, effect: %u)" ,
2014-09-21 17:45:31 +02:00
e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . summonGO . entry , itr -> second . first , itr -> second . second );
2010-10-27 21:01:47 +02:00
break ;
2013-12-11 18:53:05 +01:00
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_REMOVE_ITEM :
2012-03-28 20:00:29 +08:00
if ( ! IsItemValid ( e , e . action . item . entry ))
return false ;
if ( ! NotNULL ( e , e . action . item . count ))
return false ;
2010-10-27 21:01:47 +02:00
break ;
2014-09-21 17:45:31 +02:00
case SMART_ACTION_ADD_ITEM :
{
if ( ! IsItemValid ( e , e . action . item . entry ))
return false ;
if ( ! NotNULL ( e , e . action . item . count ))
return false ;
2014-10-11 18:52:01 +02:00
CacheSpellContainerBounds sBounds = GetCreateItemSpellContainerBounds ( e . action . item . entry );
2014-09-21 17:45:31 +02:00
for ( CacheSpellContainer :: const_iterator itr = sBounds . first ; itr != sBounds . second ; ++ itr )
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u Create Item: There is a create item spell for item %u (SpellId: %u effect: %u)" ,
2014-10-11 18:52:01 +02:00
e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . item . entry , itr -> second . first , itr -> second . second );
2014-09-21 17:45:31 +02:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_TELEPORT :
if ( ! sMapStore . LookupEntry ( e . action . teleport . mapID ))
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " 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 );
2010-10-27 21:01:47 +02:00
return false ;
}
2015-04-02 18:02:34 +02:00
break ;
case SMART_ACTION_SET_COUNTER :
if ( e . action . setCounter . counterId == 0 )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses wrong counterId %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . setCounter . counterId );
return false ;
}
if ( e . action . setCounter . value == 0 )
{
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses wrong value %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . setCounter . value );
return false ;
}
2010-10-27 21:01:47 +02:00
break ;
case SMART_ACTION_INSTALL_AI_TEMPLATE :
if ( e . action . installTtemplate . id >= SMARTAI_TEMPLATE_END )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Creature " SI64FMTD " Event %u Action %u uses non-existent AI template id %u, skipped." , e . entryOrGuid , e . event_id , e . GetActionType (), e . action . installTtemplate . id );
2010-10-27 21:01:47 +02:00
return false ;
}
break ;
case SMART_ACTION_WP_STOP :
2012-03-28 20:00:29 +08:00
if ( e . action . wpStop . quest && ! IsQuestValid ( e , e . action . wpStop . quest ))
return false ;
2010-10-27 21:01:47 +02:00
break ;
case SMART_ACTION_WP_START :
{
2010-12-22 21:25:23 +01:00
if ( ! sSmartWaypointMgr -> GetPath ( e . action . wpStart . pathID ))
2010-11-16 00:13:47 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Creature " SI64FMTD " Event %u Action %u uses non-existent WaypointPath id %u, skipped." , e . entryOrGuid , e . event_id , e . GetActionType (), e . action . wpStart . pathID );
2010-11-16 00:13:47 +01:00
return false ;
}
2012-03-28 20:00:29 +08:00
if ( e . action . wpStart . quest && ! IsQuestValid ( e , e . action . wpStart . quest ))
return false ;
2010-10-27 21:01:47 +02:00
if ( e . action . wpStart . reactState > REACT_AGGRESSIVE )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Creature " SI64FMTD " Event %u Action %u uses invalid React State %u, skipped." , e . entryOrGuid , e . event_id , e . GetActionType (), e . action . wpStart . reactState );
2010-10-27 21:01:47 +02:00
return false ;
}
break ;
}
case SMART_ACTION_CREATE_TIMED_EVENT :
{
2012-03-28 20:00:29 +08:00
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 ;
2010-10-27 21:01:47 +02:00
break ;
}
2014-02-09 16:09:09 +01:00
case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST :
{
if ( ! IsMinMaxValid ( e , e . action . randTimedActionList . entry1 , e . action . randTimedActionList . entry2 ))
return false ;
break ;
}
2013-08-10 14:13:17 +02:00
case SMART_ACTION_SET_POWER :
case SMART_ACTION_ADD_POWER :
case SMART_ACTION_REMOVE_POWER :
if ( e . action . power . powerType > MAX_POWERS )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent Power %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . power . powerType );
2013-08-10 14:13:17 +02:00
return false ;
}
break ;
2013-08-30 01:16:12 +02:00
case SMART_ACTION_GAME_EVENT_STOP :
{
uint32 eventId = e . action . gameEventStop . id ;
GameEventMgr :: GameEventDataMap const & events = sGameEventMgr -> GetEventMap ();
if ( eventId < 1 || eventId >= events . size ())
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent event, eventId %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . gameEventStop . id );
2013-08-30 01:16:12 +02:00
return false ;
}
GameEventData const & eventData = events [ eventId ];
if ( ! eventData . isValid ())
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent event, eventId %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . gameEventStop . id );
2013-08-30 01:16:12 +02:00
return false ;
}
break ;
}
case SMART_ACTION_GAME_EVENT_START :
{
uint32 eventId = e . action . gameEventStart . id ;
GameEventMgr :: GameEventDataMap const & events = sGameEventMgr -> GetEventMap ();
if ( eventId < 1 || eventId >= events . size ())
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent event, eventId %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . gameEventStart . id );
2013-08-30 01:16:12 +02:00
return false ;
}
GameEventData const & eventData = events [ eventId ];
if ( ! eventData . isValid ())
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent event, eventId %u, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . gameEventStart . id );
2013-08-30 01:16:12 +02:00
return false ;
}
break ;
}
2014-03-31 17:31:21 +02:00
case SMART_ACTION_EQUIP :
{
if ( e . GetScriptType () == SMART_SCRIPT_TYPE_CREATURE )
{
int8 equipId = ( int8 ) e . action . equip . entry ;
2017-02-19 10:58:08 +01:00
if ( equipId && ! sObjectMgr -> GetEquipmentInfo ( e . entryOrGuid , equipId ))
2014-03-31 17:31:21 +02:00
{
2017-02-19 10:58:08 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id %u for creature " SI64FMTD ", skipped." , equipId , e . entryOrGuid );
return false ;
2014-03-31 17:31:21 +02:00
}
}
break ;
}
2016-06-14 13:29:51 -03:00
case SMART_ACTION_SET_INST_DATA :
{
if ( e . action . setInstanceData . type > 1 )
{
2016-06-15 06:44:36 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses invalid data type %u (value range 0-1), skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . setInstanceData . type );
2016-06-14 13:29:51 -03:00
return false ;
}
else if ( e . action . setInstanceData . type == 1 )
{
if ( e . action . setInstanceData . data > TO_BE_DECIDED )
{
2016-06-15 06:44:36 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses invalid boss state %u (value range 0-5), skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), e . action . setInstanceData . data );
2016-06-14 13:29:51 -03:00
return false ;
}
}
break ;
}
2014-06-05 13:05:29 -05:00
case SMART_ACTION_SET_INGAME_PHASE_ID :
{
uint32 phaseId = e . action . ingamePhaseId . id ;
uint32 apply = e . action . ingamePhaseId . apply ;
if ( apply != 0 && apply != 1 )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid apply value %u (Should be 0 or 1) for creature " SI64FMTD ", skipped" , apply , e . entryOrGuid );
2014-06-05 13:05:29 -05:00
return false ;
}
2016-02-06 17:53:37 +01:00
if ( ! sPhaseStore . LookupEntry ( phaseId ))
2014-06-05 13:05:29 -05:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid phaseid %u for creature " SI64FMTD ", skipped" , phaseId , e . entryOrGuid );
2014-06-05 13:05:29 -05:00
return false ;
}
break ;
}
case SMART_ACTION_SET_INGAME_PHASE_GROUP :
{
2014-06-06 12:08:42 -05:00
uint32 phaseGroup = e . action . ingamePhaseGroup . groupId ;
2014-06-05 13:05:29 -05:00
uint32 apply = e . action . ingamePhaseGroup . apply ;
if ( apply != 0 && apply != 1 )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid apply value %u (Should be 0 or 1) for creature " SI64FMTD ", skipped" , apply , e . entryOrGuid );
2014-06-05 13:05:29 -05:00
return false ;
}
2015-03-06 18:52:58 +01:00
if ( sDB2Manager . GetPhasesForGroup ( phaseGroup ). empty ())
2014-06-05 13:05:29 -05:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid phase group id %u for creature " SI64FMTD ", skipped" , phaseGroup , e . entryOrGuid );
2014-06-05 13:05:29 -05:00
return false ;
}
break ;
}
2014-08-31 01:17:34 +02:00
case SMART_ACTION_START_CLOSEST_WAYPOINT :
2010-10-27 21:01:47 +02:00
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 :
2015-07-24 22:54:15 +02:00
case SMART_ACTION_COMBAT_STOP :
2010-10-27 21:01:47 +02:00
case SMART_ACTION_DIE :
case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE :
case SMART_ACTION_SET_ACTIVE :
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_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_SET_VISIBILITY :
case SMART_ACTION_WP_PAUSE :
case SMART_ACTION_SET_FLY :
case SMART_ACTION_SET_RUN :
2011-08-21 00:07:38 -03:00
case SMART_ACTION_SET_SWIM :
2010-10-27 21:01:47 +02:00
case SMART_ACTION_FORCE_DESPAWN :
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_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 :
2012-12-29 22:26:40 +01:00
case SMART_ACTION_SET_RANGED_MOVEMENT :
2010-11-03 14:10:16 +01:00
case SMART_ACTION_CALL_TIMED_ACTIONLIST :
case SMART_ACTION_SET_NPC_FLAG :
case SMART_ACTION_ADD_NPC_FLAG :
case SMART_ACTION_REMOVE_NPC_FLAG :
2010-11-07 18:34:04 +01:00
case SMART_ACTION_CROSS_CAST :
2010-11-07 22:10:11 +01:00
case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST :
2010-11-20 13:23:29 +01:00
case SMART_ACTION_RANDOM_MOVE :
2011-02-07 09:35:14 -07:00
case SMART_ACTION_SET_UNIT_FIELD_BYTES_1 :
2011-02-07 10:15:54 -07:00
case SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1 :
2011-02-15 00:29:33 -03:00
case SMART_ACTION_INTERRUPT_SPELL :
2011-03-02 16:50:09 +01:00
case SMART_ACTION_SEND_GO_CUSTOM_ANIM :
2011-06-12 17:50:23 +02:00
case SMART_ACTION_SET_DYNAMIC_FLAG :
case SMART_ACTION_ADD_DYNAMIC_FLAG :
case SMART_ACTION_REMOVE_DYNAMIC_FLAG :
2011-07-02 07:52:03 +02:00
case SMART_ACTION_JUMP_TO_POS :
2011-10-23 12:55:17 +01:00
case SMART_ACTION_SEND_GOSSIP_MENU :
2012-01-22 10:02:31 -05:00
case SMART_ACTION_GO_SET_LOOT_STATE :
case SMART_ACTION_SEND_TARGET_TO_TARGET :
2012-09-08 00:55:47 +01:00
case SMART_ACTION_SET_HOME_POS :
2012-09-17 13:56:12 -04:00
case SMART_ACTION_SET_HEALTH_REGEN :
2013-02-02 18:18:27 +01:00
case SMART_ACTION_SET_ROOT :
2013-02-16 18:41:55 +00:00
case SMART_ACTION_SET_GO_FLAG :
case SMART_ACTION_ADD_GO_FLAG :
case SMART_ACTION_REMOVE_GO_FLAG :
2013-03-09 02:03:37 +01:00
case SMART_ACTION_SUMMON_CREATURE_GROUP :
2016-07-15 18:37:17 +02:00
case SMART_ACTION_MOVE_OFFSET :
2016-03-03 23:16:59 +01:00
case SMART_ACTION_SET_CORPSE_DELAY :
2016-08-19 14:53:53 +02:00
case SMART_ACTION_DISABLE_EVADE :
2010-10-27 21:01:47 +02:00
break ;
default :
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry " SI64FMTD " SourceType %u Event %u, skipped." , e . GetActionType (), e . GetEventType (), e . entryOrGuid , e . GetScriptType (), e . event_id );
2010-10-27 21:01:47 +02:00
return false ;
}
return true ;
}
2014-10-11 18:52:01 +02:00
bool SmartAIMgr :: IsTextValid ( SmartScriptHolder const & e , uint32 id )
2010-10-27 21:01:47 +02:00
{
2014-10-11 18:52:01 +02:00
if ( e . GetScriptType () != SMART_SCRIPT_TYPE_CREATURE )
return true ;
2010-10-27 21:01:47 +02:00
uint32 entry = 0 ;
2014-10-03 20:05:19 +02:00
2014-10-11 18:52:01 +02:00
if ( e . GetEventType () == SMART_EVENT_TEXT_OVER )
2014-10-07 21:49:50 +02:00
{
2014-10-11 18:52:01 +02:00
entry = e . event . textOver . creatureEntry ;
2014-10-07 21:49:50 +02:00
}
2014-10-03 20:05:19 +02:00
else
{
2014-10-11 18:52:01 +02:00
switch ( e . GetTargetType ())
2010-10-27 21:01:47 +02:00
{
2014-10-11 18:52:01 +02:00
case SMART_TARGET_CREATURE_DISTANCE :
case SMART_TARGET_CREATURE_RANGE :
case SMART_TARGET_CLOSEST_CREATURE :
return true ; // ignore
default :
if ( e . entryOrGuid < 0 )
{
2015-07-19 21:54:48 +01:00
ObjectGuid :: LowType guid = ObjectGuid :: LowType ( - e . entryOrGuid );
CreatureData const * data = sObjectMgr -> GetCreatureData ( guid );
2014-10-11 18:52:01 +02:00
if ( ! data )
{
2015-07-19 21:54:48 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u using non-existent Creature guid " UI64FMTD ", skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), guid );
2014-10-11 18:52:01 +02:00
return false ;
}
else
entry = data -> id ;
}
else
entry = uint32 ( e . entryOrGuid );
break ;
2010-10-27 21:01:47 +02:00
}
}
2014-10-03 20:05:19 +02:00
2010-12-22 21:25:23 +01:00
if ( ! entry || ! sCreatureTextMgr -> TextExist ( entry , uint8 ( id )))
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartAIMgr: Entry " SI64FMTD "SourceType %u Event %u Action %u using non-existent Text id %d, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType (), id );
2010-10-27 21:01:47 +02:00
return false ;
}
2014-10-03 20:05:19 +02:00
2010-10-27 21:01:47 +02:00
return true ;
2014-10-03 20:05:19 +02:00
}
2013-12-11 18:53:05 +01:00
void SmartAIMgr :: LoadHelperStores ()
{
uint32 oldMSTime = getMSTime ();
SpellInfo const * spellInfo = NULL ;
for ( uint32 i = 0 ; i < sSpellMgr -> GetSpellInfoStoreSize (); ++ i )
{
spellInfo = sSpellMgr -> GetSpellInfo ( i );
if ( ! spellInfo )
continue ;
2014-11-22 17:18:16 +01:00
for ( SpellEffectInfo const * effect : spellInfo -> GetEffectsForDifficulty ( DIFFICULTY_NONE ))
2013-12-11 18:53:05 +01:00
{
2014-11-22 17:18:16 +01:00
if ( ! effect )
continue ;
if ( effect -> IsEffect ( SPELL_EFFECT_SUMMON ))
SummonCreatureSpellStore . insert ( std :: make_pair ( uint32 ( effect -> MiscValue ), std :: make_pair ( i , SpellEffIndex ( effect -> EffectIndex ))));
2013-12-11 18:53:05 +01:00
2014-11-22 17:18:16 +01:00
else if ( effect -> IsEffect ( SPELL_EFFECT_SUMMON_OBJECT_WILD ))
SummonGameObjectSpellStore . insert ( std :: make_pair ( uint32 ( effect -> MiscValue ), std :: make_pair ( i , SpellEffIndex ( effect -> EffectIndex ))));
2013-12-11 18:53:05 +01:00
2014-11-22 17:18:16 +01:00
else if ( effect -> IsEffect ( SPELL_EFFECT_KILL_CREDIT ) || effect -> IsEffect ( SPELL_EFFECT_KILL_CREDIT2 ))
KillCreditSpellStore . insert ( std :: make_pair ( uint32 ( effect -> MiscValue ), std :: make_pair ( i , SpellEffIndex ( effect -> EffectIndex ))));
2014-09-21 17:45:31 +02:00
2014-11-22 17:18:16 +01:00
else if ( effect -> IsEffect ( SPELL_EFFECT_CREATE_ITEM ))
CreateItemSpellStore . insert ( std :: make_pair ( uint32 ( effect -> ItemType ), std :: make_pair ( i , SpellEffIndex ( effect -> EffectIndex ))));
2013-12-11 18:53:05 +01:00
}
}
TC_LOG_INFO ( "server.loading" , ">> Loaded SmartAIMgr Helpers in %u ms" , GetMSTimeDiffToNow ( oldMSTime ));
}
void SmartAIMgr :: UnLoadHelperStores ()
{
SummonCreatureSpellStore . clear ();
SummonGameObjectSpellStore . clear ();
KillCreditSpellStore . clear ();
2014-09-21 17:45:31 +02:00
CreateItemSpellStore . clear ();
2013-12-11 18:53:05 +01:00
}
CacheSpellContainerBounds SmartAIMgr :: GetSummonCreatureSpellContainerBounds ( uint32 creatureEntry ) const
{
return SummonCreatureSpellStore . equal_range ( creatureEntry );
}
CacheSpellContainerBounds SmartAIMgr :: GetSummonGameObjectSpellContainerBounds ( uint32 gameObjectEntry ) const
{
return SummonGameObjectSpellStore . equal_range ( gameObjectEntry );
}
CacheSpellContainerBounds SmartAIMgr :: GetKillCreditSpellContainerBounds ( uint32 killCredit ) const
{
return KillCreditSpellStore . equal_range ( killCredit );
}
2014-09-21 17:45:31 +02:00
2014-10-11 18:52:01 +02:00
CacheSpellContainerBounds SmartAIMgr :: GetCreateItemSpellContainerBounds ( uint32 itemId ) const
2014-09-21 17:45:31 +02:00
{
return CreateItemSpellStore . equal_range ( itemId );
}