2010-10-27 21:01:47 +02:00
/*
2020-01-02 06:44:10 +01:00
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
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/>.
*/
2017-05-18 23:52:58 +02:00
#include "SmartScript.h"
2012-11-20 12:30:30 +01:00
#include "CellImpl.h"
2014-09-13 20:41:31 +02:00
#include "ChatTextBuilder.h"
2017-05-18 23:52:58 +02:00
#include "Creature.h"
2012-11-20 12:30:30 +01:00
#include "CreatureTextMgr.h"
2017-06-04 01:00:45 +02:00
#include "CreatureTextMgrImpl.h"
#include "DB2Stores.h"
2017-05-18 23:52:58 +02:00
#include "GameEventMgr.h"
#include "GameObject.h"
2017-05-28 16:34:44 +02:00
#include "GossipDef.h"
2010-10-27 21:01:47 +02:00
#include "GridNotifiersImpl.h"
2017-06-04 01:00:45 +02:00
#include "Group.h"
2010-10-27 21:01:47 +02:00
#include "InstanceScript.h"
2012-11-20 12:30:30 +01:00
#include "Language.h"
2017-05-18 23:52:58 +02:00
#include "Log.h"
#include "Map.h"
2017-06-04 01:00:45 +02:00
#include "MotionMaster.h"
2017-05-18 23:52:58 +02:00
#include "ObjectAccessor.h"
2017-05-28 16:34:44 +02:00
#include "ObjectMgr.h"
2018-01-28 11:37:20 +01:00
#include "PhasingHandler.h"
2017-05-18 23:52:58 +02:00
#include "Random.h"
2010-10-27 21:01:47 +02:00
#include "SmartAI.h"
2017-05-18 23:52:58 +02:00
#include "SpellAuras.h"
2017-06-04 01:00:45 +02:00
#include "SpellMgr.h"
#include "TemporarySummon.h"
2011-08-03 12:28:42 +02:00
#include "Vehicle.h"
2017-08-12 01:40:25 +02:00
#include "WaypointDefines.h"
2010-10-27 21:01:47 +02:00
SmartScript :: SmartScript ()
{
2016-08-05 12:41:56 +02:00
go = nullptr ;
me = nullptr ;
trigger = nullptr ;
2017-03-17 21:21:35 +01:00
sceneTemplate = nullptr ;
2010-10-27 21:01:47 +02:00
mEventPhase = 0 ;
mPathId = 0 ;
mTextTimer = 0 ;
mLastTextID = 0 ;
mUseTextTimer = false ;
2011-09-20 17:56:47 +02:00
mTalkerEntry = 0 ;
2010-10-27 21:01:47 +02:00
mTemplate = SMARTAI_TEMPLATE_BASIC ;
2012-08-30 22:44:33 +01:00
mScriptType = SMART_SCRIPT_TYPE_CREATURE ;
2014-02-08 21:57:28 +01:00
isProcessingTimedActionList = false ;
2011-03-27 12:54:11 +02:00
}
SmartScript ::~ SmartScript ()
{
2010-10-27 21:01:47 +02:00
}
2020-08-14 17:06:03 +02:00
bool SmartScript :: IsSmart ( Creature * c /*= nullptr*/ )
2017-05-18 23:52:58 +02:00
{
bool smart = true ;
if ( c && c -> GetAIName () != "SmartAI" )
smart = false ;
if ( ! me || me -> GetAIName () != "SmartAI" )
smart = false ;
if ( ! smart )
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Action target Creature (GUID: " UI64FMTD " Entry: %u) is not using SmartAI, action called by Creature (GUID: " UI64FMTD " Entry: %u) skipped to prevent crash." , uint64 ( c ? c -> GetSpawnId () : UI64LIT ( 0 )), c ? c -> GetEntry () : 0 , uint64 ( me ? me -> GetSpawnId () : UI64LIT ( 0 )), me ? me -> GetEntry () : 0 );
return smart ;
}
2020-08-14 17:06:03 +02:00
bool SmartScript :: IsSmartGO ( GameObject * g /*= nullptr*/ )
2017-05-18 23:52:58 +02:00
{
bool smart = true ;
if ( g && g -> GetAIName () != "SmartGameObjectAI" )
smart = false ;
if ( ! go || go -> GetAIName () != "SmartGameObjectAI" )
smart = false ;
if ( ! smart )
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Action target GameObject (GUID: " UI64FMTD " Entry: %u) is not using SmartGameObjectAI, action called by GameObject (GUID: " UI64FMTD " Entry: %u) skipped to prevent crash." , uint64 ( g ? g -> GetSpawnId () : UI64LIT ( 0 )), g ? g -> GetEntry () : 0 , uint64 ( go ? go -> GetSpawnId () : UI64LIT ( 0 )), go ? go -> GetEntry () : 0 );
return smart ;
}
void SmartScript :: StoreCounter ( uint32 id , uint32 value , uint32 reset )
{
2017-02-17 21:33:18 +01:00
CounterMap :: iterator itr = mCounterList . find ( id );
2017-05-18 23:52:58 +02:00
if ( itr != mCounterList . end ())
{
if ( reset == 0 )
2017-02-17 21:33:18 +01:00
itr -> second += value ;
else
itr -> second = value ;
2017-05-18 23:52:58 +02:00
}
2017-02-17 21:33:18 +01:00
else
mCounterList . insert ( std :: make_pair ( id , value ));
2017-05-18 23:52:58 +02:00
2017-02-17 21:33:18 +01:00
ProcessEventsFor ( SMART_EVENT_COUNTER_SET , nullptr , id );
2017-05-18 23:52:58 +02:00
}
2017-02-17 21:33:18 +01:00
uint32 SmartScript :: GetCounterValue ( uint32 id ) const
2017-05-18 23:52:58 +02:00
{
2017-02-17 21:33:18 +01:00
CounterMap :: const_iterator itr = mCounterList . find ( id );
2017-05-18 23:52:58 +02:00
if ( itr != mCounterList . end ())
return itr -> second ;
return 0 ;
}
GameObject * SmartScript :: FindGameObjectNear ( WorldObject * searchObject , ObjectGuid :: LowType guid ) const
{
auto bounds = searchObject -> GetMap () -> GetGameObjectBySpawnIdStore (). equal_range ( guid );
if ( bounds . first == bounds . second )
return nullptr ;
return bounds . first -> second ;
}
Creature * SmartScript :: FindCreatureNear ( WorldObject * searchObject , ObjectGuid :: LowType guid ) const
{
auto bounds = searchObject -> GetMap () -> GetCreatureBySpawnIdStore (). equal_range ( guid );
if ( bounds . first == bounds . second )
return nullptr ;
auto creatureItr = std :: find_if ( bounds . first , bounds . second , []( Map :: CreatureBySpawnIdContainer :: value_type const & pair )
{
return pair . second -> IsAlive ();
});
return creatureItr != bounds . second ? creatureItr -> second : bounds . first -> second ;
}
2010-10-27 21:01:47 +02:00
void SmartScript :: OnReset ()
{
ResetBaseObject ();
for ( SmartAIEventList :: iterator i = mEvents . begin (); i != mEvents . end (); ++ i )
{
2012-04-05 12:09:37 -05:00
if ( ! (( * i ). event . event_flags & SMART_EVENT_FLAG_DONT_RESET ))
{
InitTimer (( * i ));
( * i ). runOnce = false ;
}
2010-10-27 21:01:47 +02:00
}
ProcessEventsFor ( SMART_EVENT_RESET );
2014-09-14 16:14:12 +02:00
mLastInvoker . Clear ();
2015-04-02 18:02:34 +02:00
mCounterList . clear ();
2010-10-27 21:01:47 +02:00
}
2017-05-18 23:52:58 +02:00
void SmartScript :: ResetBaseObject ()
{
WorldObject * lookupRoot = me ;
if ( ! lookupRoot )
lookupRoot = go ;
if ( lookupRoot )
{
if ( ! meOrigGUID . IsEmpty ())
{
if ( Creature * m = ObjectAccessor :: GetCreature ( * lookupRoot , meOrigGUID ))
{
me = m ;
2020-08-14 17:06:03 +02:00
go = nullptr ;
2017-05-18 23:52:58 +02:00
}
}
2020-09-04 13:38:24 +02:00
2017-05-18 23:52:58 +02:00
if ( ! goOrigGUID . IsEmpty ())
{
if ( GameObject * o = ObjectAccessor :: GetGameObject ( * lookupRoot , goOrigGUID ))
{
2020-08-14 17:06:03 +02:00
me = nullptr ;
2017-05-18 23:52:58 +02:00
go = o ;
}
}
}
goOrigGUID . Clear ();
meOrigGUID . Clear ();
}
2020-09-04 13:38:24 +02:00
void SmartScript :: ProcessEventsFor ( SMART_EVENT e , Unit * unit , uint32 var0 , uint32 var1 , bool bvar , SpellInfo const * spell , GameObject * gob , std :: string const & varString )
2010-10-27 21:01:47 +02:00
{
for ( SmartAIEventList :: iterator i = mEvents . begin (); i != mEvents . end (); ++ i )
{
2014-10-11 18:52:01 +02:00
SMART_EVENT eventType = SMART_EVENT ( i -> GetEventType ());
2010-11-16 14:08:12 +01:00
if ( eventType == SMART_EVENT_LINK ) //special handling
2010-10-27 21:01:47 +02:00
continue ;
2010-12-13 22:37:56 +01:00
2017-06-10 19:17:41 -03:00
if ( eventType == e )
2015-10-25 13:20:28 +01:00
if ( sConditionMgr -> IsObjectMeetingSmartEventConditions ( i -> entryOrGuid , i -> event_id , i -> source_type , unit , GetBaseObject ()))
2017-03-17 21:21:35 +01:00
ProcessEvent ( * i , unit , var0 , var1 , bvar , spell , gob , varString );
2010-10-27 21:01:47 +02:00
}
}
2020-09-04 13:38:24 +02:00
void SmartScript :: ProcessAction ( SmartScriptHolder & e , Unit * unit , uint32 var0 , uint32 var1 , bool bvar , SpellInfo const * spell , GameObject * gob , std :: string const & varString )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
// calc random
2010-10-27 21:01:47 +02:00
if ( e . GetEventType () != SMART_EVENT_LINK && e . event . event_chance < 100 && e . event . event_chance )
{
2016-10-10 19:05:28 -03:00
if ( ! roll_chance_i ( e . event . event_chance ))
2010-10-27 21:01:47 +02:00
return ;
}
e . runOnce = true ; //used for repeat check
2010-11-04 19:56:39 +01:00
if ( unit )
2011-02-21 22:23:43 +01:00
mLastInvoker = unit -> GetGUID ();
2010-11-04 19:56:39 +01:00
2011-02-21 22:23:43 +01:00
if ( Unit * tempInvoker = GetLastInvoker ())
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: Invoker: %s (%s)" , tempInvoker -> GetName (). c_str (), tempInvoker -> GetGUID (). ToString (). c_str ());
2011-02-21 01:15:14 +01:00
2017-06-03 10:21:06 +02:00
ObjectVector targets ;
GetTargets ( targets , e , unit );
2010-10-27 21:01:47 +02:00
switch ( e . GetActionType ())
{
case SMART_ACTION_TALK :
2011-03-26 23:45:23 +01:00
{
2017-02-17 21:33:18 +01:00
Creature * talker = e . target . type == 0 ? me : nullptr ;
2016-08-05 12:41:56 +02:00
Unit * talkTarget = nullptr ;
2015-08-14 22:50:28 +02:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-11-01 11:00:53 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ) && ! target -> ToCreature () -> IsPet ()) // Prevented sending text to pets.
2010-11-01 11:00:53 +01:00
{
2017-06-03 10:21:06 +02:00
if ( e . action . talk . useTalkTarget )
2011-10-30 14:26:49 +00:00
{
2017-02-17 21:33:18 +01:00
talker = me ;
2017-06-03 10:21:06 +02:00
talkTarget = target -> ToCreature ();
2011-10-30 14:26:49 +00:00
}
2017-06-03 10:21:06 +02:00
else
talker = target -> ToCreature ();
break ;
}
else if ( IsPlayer ( target ))
{
talker = me ;
talkTarget = target -> ToPlayer ();
break ;
2010-11-01 11:00:53 +01:00
}
2010-11-05 19:38:43 +01:00
}
2011-10-30 14:26:49 +00:00
2017-02-17 21:33:18 +01:00
if ( ! talkTarget )
talkTarget = GetLastInvoker ();
2012-06-12 22:22:18 +02:00
if ( ! talker )
break ;
2011-09-20 17:56:47 +02:00
mTalkerEntry = talker -> GetEntry ();
2011-03-26 23:45:23 +01:00
mLastTextID = e . action . talk . textGroupID ;
mTextTimer = e . action . talk . duration ;
mUseTextTimer = true ;
2013-12-23 14:23:49 +01:00
sCreatureTextMgr -> SendChat ( talker , uint8 ( e . action . talk . textGroupID ), talkTarget );
2014-10-27 22:52:19 +00:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_TALK: talker: %s (%s), textGuid: %s" ,
2014-10-22 21:22:04 +02:00
talker -> GetName (). c_str (), talker -> GetGUID (). ToString (). c_str (), talkTarget ? talkTarget -> GetGUID (). ToString (). c_str () : "Empty" );
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-05 19:38:43 +01:00
case SMART_ACTION_SIMPLE_TALK :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-11-05 19:38:43 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
2020-08-14 17:06:03 +02:00
sCreatureTextMgr -> SendChat ( target -> ToCreature (), uint8 ( e . action . talk . textGroupID ), IsPlayer ( GetLastInvoker ()) ? GetLastInvoker () : nullptr );
2017-06-03 10:21:06 +02:00
else if ( IsPlayer ( target ) && me )
2010-11-05 19:38:43 +01:00
{
2017-06-03 10:21:06 +02:00
Unit * templastInvoker = GetLastInvoker ();
2020-08-14 17:06:03 +02:00
sCreatureTextMgr -> SendChat ( me , uint8 ( e . action . talk . textGroupID ), IsPlayer ( templastInvoker ) ? templastInvoker : nullptr , CHAT_MSG_ADDON , LANG_ADDON , TEXT_RANGE_NORMAL , 0 , TEAM_OTHER , false , target -> ToPlayer ());
2010-11-05 19:38:43 +01:00
}
2017-06-03 10:21:06 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_SIMPLE_TALK: talker: %s (%s), textGroupId: %u" ,
target -> GetName (). c_str (), target -> GetGUID (). ToString (). c_str (), uint8 ( e . action . talk . textGroupID ));
2010-11-01 11:00:53 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_PLAY_EMOTE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-11-02 13:13:54 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2011-06-15 17:33:06 +02:00
{
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> HandleEmoteCommand ( e . action . emote . emote );
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_PLAY_EMOTE: target: %s (%s), emote: %u" ,
target -> GetName (). c_str (), target -> GetGUID (). ToString (). c_str (), e . action . emote . emote );
2011-06-15 17:33:06 +02:00
}
2010-11-02 13:13:54 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SOUND :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-11-02 13:13:54 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
target -> PlayDirectSound ( e . action . sound . sound , e . action . sound . onlySelf ? target -> ToPlayer () : nullptr );
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_SOUND: target: %s (%s), sound: %u, onlyself: %u" ,
target -> GetName (). c_str (), target -> GetGUID (). ToString (). c_str (), e . action . sound . sound , e . action . sound . onlySelf );
2011-03-26 23:45:23 +01:00
}
2010-11-02 13:13:54 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_FACTION :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( e . action . faction . factionID )
2010-11-02 13:13:54 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetFaction ( e . action . faction . factionID );
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry %u, %s set faction to %u" ,
target -> GetEntry (), target -> GetGUID (). ToString (). c_str (), e . action . faction . factionID );
}
else
{
if ( CreatureTemplate const * ci = sObjectMgr -> GetCreatureTemplate ( target -> ToCreature () -> GetEntry ()))
2010-11-02 13:13:54 +01:00
{
2017-06-03 10:21:06 +02:00
if ( target -> ToCreature () -> GetFaction () != ci -> faction )
2010-11-02 13:13:54 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetFaction ( ci -> faction );
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry %u, %s set faction to %u" ,
target -> GetEntry (), target -> GetGUID (). ToString (). c_str (), ci -> faction );
2010-11-02 13:13:54 +01:00
}
}
}
2010-10-27 21:01:47 +02:00
}
}
break ;
}
case SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsCreature ( target ))
2010-11-02 13:13:54 +01:00
continue ;
2010-12-13 22:37:56 +01:00
2010-11-02 13:13:54 +01:00
if ( e . action . morphOrMount . creature || e . action . morphOrMount . model )
2010-10-27 21:01:47 +02:00
{
2010-11-02 13:13:54 +01:00
//set model based on entry from creature_template
if ( e . action . morphOrMount . creature )
2010-10-27 21:01:47 +02:00
{
2011-04-28 22:57:08 +02:00
if ( CreatureTemplate const * ci = sObjectMgr -> GetCreatureTemplate ( e . action . morphOrMount . creature ))
2010-11-02 13:13:54 +01:00
{
2018-11-07 20:23:30 +01:00
CreatureModel const * model = ObjectMgr :: ChooseDisplayId ( ci );
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetDisplayId ( model -> CreatureDisplayID , model -> DisplayScale );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry %u, %s set displayid to %u" ,
2017-06-03 10:21:06 +02:00
target -> GetEntry (), target -> GetGUID (). ToString (). c_str (), model -> CreatureDisplayID );
2010-11-02 13:13:54 +01:00
}
2010-10-27 21:01:47 +02:00
}
2010-11-02 13:13:54 +01:00
//if no param1, then use value from param2 (modelId)
else
2011-02-21 01:15:14 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetDisplayId ( e . action . morphOrMount . model );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry %u, %s set displayid to %u" ,
2017-06-03 10:21:06 +02:00
target -> GetEntry (), target -> GetGUID (). ToString (). c_str (), e . action . morphOrMount . model );
2011-02-21 01:15:14 +01:00
}
2010-10-27 21:01:47 +02:00
}
else
2011-02-21 01:15:14 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> DeMorph ();
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry %u, %s demorphs." ,
2017-06-03 10:21:06 +02:00
target -> GetEntry (), target -> GetGUID (). ToString (). c_str ());
2011-02-21 01:15:14 +01:00
}
2010-10-27 21:01:47 +02:00
}
break ;
}
case SMART_ACTION_FAIL_QUEST :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-11-02 13:13:54 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsPlayer ( target ))
2011-02-21 01:15:14 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToPlayer () -> FailQuest ( e . action . quest . quest );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_FAIL_QUEST: Player %s fails quest %u" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), e . action . quest . quest );
2011-02-21 01:15:14 +01:00
}
2010-11-02 13:13:54 +01:00
}
2010-10-27 21:01:47 +02:00
break ;
}
2016-08-19 23:01:03 +02:00
case SMART_ACTION_OFFER_QUEST :
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-11-02 13:13:54 +01:00
{
2017-06-03 10:21:06 +02:00
if ( Player * player = target -> ToPlayer ())
2013-12-17 11:10:23 +01:00
{
2016-08-19 23:01:03 +02:00
if ( Quest const * q = sObjectMgr -> GetQuestTemplate ( e . action . questOffer . questID ))
2011-02-21 01:15:14 +01:00
{
2016-08-19 23:01:03 +02:00
if ( me && e . action . questOffer . directAdd == 0 )
{
2017-06-03 10:21:06 +02:00
if ( player -> CanTakeQuest ( q , true ))
{
if ( WorldSession * session = player -> GetSession ())
2016-08-19 23:01:03 +02:00
{
PlayerMenu menu ( session );
2017-11-28 00:04:03 +01:00
menu . SendQuestGiverQuestDetails ( q , me -> GetGUID (), true , false );
2017-06-03 10:21:06 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player %s - offering quest %u" , player -> GetGUID (). ToString (). c_str (), e . action . questOffer . questID );
2016-08-19 23:01:03 +02:00
}
2017-06-03 10:21:06 +02:00
}
2016-08-19 23:01:03 +02:00
}
else
{
2017-06-03 10:21:06 +02:00
player -> AddQuestAndCheckCompletion ( q , nullptr );
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player %s - quest %u added" ,
player -> GetGUID (). ToString (). c_str (), e . action . questOffer . questID );
2016-08-19 23:01:03 +02:00
}
2011-02-21 01:15:14 +01:00
}
2013-12-17 11:10:23 +01:00
}
2010-11-02 13:13:54 +01:00
}
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_ACTION_SET_REACT_STATE :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2013-12-17 11:10:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsCreature ( target ))
2013-12-17 11:10:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetReactState ( ReactStates ( e . action . react . state ));
2013-12-17 11:10:23 +01:00
}
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_ACTION_RANDOM_EMOTE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
std :: vector < uint32 > emotes ;
2020-06-25 12:15:21 +02:00
std :: copy_if ( std :: begin ( e . action . randomEmote . emotes ), std :: end ( e . action . randomEmote . emotes ),
2017-06-03 10:21:06 +02:00
std :: back_inserter ( emotes ), []( uint32 emote ) { return emote != 0 ; });
2011-06-15 17:33:06 +02:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
uint32 emote = Trinity :: Containers :: SelectRandomContainerElement ( emotes );
target -> ToUnit () -> HandleEmoteCommand ( emote );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_EMOTE: Creature %s handle random emote %u" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), emote );
2010-10-27 21:01:47 +02:00
}
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_THREAT_ALL_PCT :
{
2011-02-21 01:15:14 +01:00
if ( ! me )
2012-01-22 20:36:01 -05:00
break ;
2011-02-21 01:15:14 +01:00
2017-07-03 17:49:54 +02:00
for ( auto * ref : me -> GetThreatManager (). GetModifiableThreatList ())
2011-03-26 23:45:23 +01:00
{
2017-07-01 20:18:02 +02:00
ref -> ModifyThreatByPercent ( std :: max < int32 > ( - 100 , int32 ( e . action . threatPCT . threatINC ) - int32 ( e . action . threatPCT . threatDEC )));
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_THREAT_ALL_PCT: Creature %s modify threat for %s, value %i" ,
me -> GetGUID (). ToString (). c_str (), ref -> GetVictim () -> GetGUID (). ToString (). c_str (), int32 ( e . action . threatPCT . threatINC ) - int32 ( e . action . threatPCT . threatDEC ));
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_ACTION_THREAT_SINGLE_PCT :
{
2011-02-21 01:15:14 +01:00
if ( ! me )
2012-01-22 20:36:01 -05:00
break ;
2011-02-21 01:15:14 +01:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2011-02-21 01:15:14 +01:00
{
2017-07-01 20:18:02 +02:00
me -> GetThreatManager (). ModifyThreatByPercent ( target -> ToUnit (), std :: max < int32 > ( - 100 , int32 ( e . action . threatPCT . threatINC ) - int32 ( e . action . threatPCT . threatDEC )));
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_THREAT_SINGLE_PCT: Creature %s modify threat for %s, value %i" ,
2017-07-01 20:18:02 +02:00
me -> GetGUID (). ToString (). c_str (), target -> GetGUID (). ToString (). c_str (), int32 ( e . action . threatPCT . threatINC ) - int32 ( e . action . threatPCT . threatDEC ));
2011-02-21 01:15:14 +01:00
}
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2012-11-17 14:57:20 -05:00
// Special handling for vehicles
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
if ( Vehicle * vehicle = target -> ToUnit () -> GetVehicleKit ())
2012-11-17 14:57:20 -05:00
for ( SeatMap :: iterator it = vehicle -> Seats . begin (); it != vehicle -> Seats . end (); ++ it )
2017-06-03 10:21:06 +02:00
if ( Player * player = ObjectAccessor :: GetPlayer ( * target , it -> second . Passenger . Guid ))
2012-11-17 14:57:20 -05:00
player -> AreaExploredOrEventHappens ( e . action . quest . quest );
2012-11-19 01:00:47 +00:00
2017-06-03 10:21:06 +02:00
if ( IsPlayer ( target ))
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToPlayer () -> AreaExploredOrEventHappens ( e . action . quest . quest );
2014-08-19 11:50:39 +02:00
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: %s credited quest %u" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), e . action . quest . quest );
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_CAST :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( targets . empty ())
2012-01-22 20:36:01 -05:00
break ;
2011-02-21 01:15:14 +01:00
2017-06-03 10:21:06 +02:00
if ( e . action . cast . targetsLimit > 0 && targets . size () > e . action . cast . targetsLimit )
Trinity :: Containers :: RandomResize ( targets , e . action . cast . targetsLimit );
2017-02-17 21:33:18 +01:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
// may be nullptr
2017-02-17 21:33:18 +01:00
if ( go )
2017-06-03 10:21:06 +02:00
go -> CastSpell ( target -> ToUnit (), e . action . cast . spell );
2017-02-17 21:33:18 +01:00
2017-06-03 10:21:06 +02:00
if ( ! IsUnit ( target ))
2013-10-11 16:57:28 +02:00
continue ;
2017-06-03 10:21:06 +02:00
if ( ! ( e . action . cast . castFlags & SMARTCAST_AURA_NOT_PRESENT ) || ! target -> ToUnit () -> HasAura ( e . action . cast . spell ))
2011-03-26 23:45:23 +01:00
{
2016-08-19 15:23:19 +02:00
TriggerCastFlags triggerFlag = TRIGGERED_NONE ;
if ( e . action . cast . castFlags & SMARTCAST_TRIGGERED )
{
if ( e . action . cast . triggerFlags )
triggerFlag = TriggerCastFlags ( e . action . cast . triggerFlags );
else
triggerFlag = TRIGGERED_FULL_MASK ;
}
2014-06-14 20:12:38 +02:00
if ( me )
2013-12-03 20:53:33 -03:30
{
2016-08-19 15:23:19 +02:00
if ( e . action . cast . castFlags & SMARTCAST_INTERRUPT_PREVIOUS )
2014-06-14 20:12:38 +02:00
me -> InterruptNonMeleeSpells ( false );
2013-12-03 20:53:33 -03:30
2016-08-19 15:23:19 +02:00
if ( e . action . cast . castFlags & SMARTCAST_COMBAT_MOVE )
2014-06-14 20:12:38 +02:00
{
// If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed
// unless target is outside spell range, out of mana, or LOS.
2013-12-03 20:53:33 -03:30
2017-06-03 10:21:06 +02:00
bool allowMove = false ;
2020-06-12 01:29:18 +02:00
SpellInfo const * spellInfo = sSpellMgr -> AssertSpellInfo ( e . action . cast . spell , me -> GetMap () -> GetDifficultyID ());
2017-05-21 23:18:43 +02:00
std :: vector < SpellPowerCost > costs = spellInfo -> CalcPowerCost ( me , spellInfo -> GetSchoolMask ());
2015-03-08 13:31:57 +01:00
bool hasPower = true ;
2017-05-21 23:18:43 +02:00
for ( SpellPowerCost const & cost : costs )
2015-03-08 13:31:57 +01:00
{
if ( cost . Power == POWER_HEALTH )
{
2015-03-22 13:47:55 +01:00
if ( me -> GetHealth () <= uint32 ( cost . Amount ))
2015-03-08 13:31:57 +01:00
{
hasPower = false ;
break ;
}
}
else
{
if ( me -> GetPower ( cost . Power ) < cost . Amount )
{
hasPower = false ;
break ;
}
}
}
2013-12-03 20:53:33 -03:30
2017-06-03 10:21:06 +02:00
if ( me -> GetDistance ( target ) > spellInfo -> GetMaxRange ( true ) ||
me -> GetDistance ( target ) < spellInfo -> GetMinRange ( true ) ||
! me -> IsWithinLOSInMap ( target ) || ! hasPower )
allowMove = true ;
2013-12-03 20:53:33 -03:30
2017-06-03 10:21:06 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> SetCombatMove ( allowMove );
2014-06-14 19:55:25 +02:00
}
2013-12-03 20:53:33 -03:30
2017-06-03 10:21:06 +02:00
me -> CastSpell ( target -> ToUnit (), e . action . cast . spell , triggerFlag );
2014-06-14 19:55:25 +02:00
}
2014-06-14 20:12:38 +02:00
else if ( go )
2017-06-03 10:21:06 +02:00
go -> CastSpell ( target -> ToUnit (), e . action . cast . spell , triggerFlag );
2013-12-03 20:53:33 -03:30
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_CAST:: %s casts spell %u on target %s with castflags %u" ,
2017-06-03 10:21:06 +02:00
( me ? me -> GetGUID () : go -> GetGUID ()). ToString (). c_str (), e . action . cast . spell , target -> GetGUID (). ToString (). c_str (), e . action . cast . castFlags );
2011-03-26 23:45:23 +01:00
}
2013-10-11 16:57:28 +02:00
else
2017-06-03 10:21:06 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "Spell %u not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (%s) already has the aura ", e.action.cast.spell, target->GetGUID().ToString().c_str()) ;
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-06 23:18:04 +01:00
case SMART_ACTION_INVOKER_CAST :
2011-03-26 23:45:23 +01:00
{
2017-02-05 23:42:31 +01:00
Unit * tempLastInvoker = GetLastInvoker ( unit );
2011-03-26 23:45:23 +01:00
if ( ! tempLastInvoker )
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
if ( targets . empty ())
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
if ( e . action . cast . targetsLimit > 0 && targets . size () > e . action . cast . targetsLimit )
Trinity :: Containers :: RandomResize ( targets , e . action . cast . targetsLimit );
2017-02-17 21:33:18 +01:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-11-06 23:18:04 +01:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsUnit ( target ))
2013-10-11 16:57:28 +02:00
continue ;
2011-02-21 01:15:14 +01:00
2017-06-03 10:21:06 +02:00
if ( ! ( e . action . cast . castFlags & SMARTCAST_AURA_NOT_PRESENT ) || ! target -> ToUnit () -> HasAura ( e . action . cast . spell ))
2013-11-11 11:03:32 +01:00
{
2016-08-19 15:23:19 +02:00
if ( e . action . cast . castFlags & SMARTCAST_INTERRUPT_PREVIOUS )
2013-11-11 11:03:32 +01:00
tempLastInvoker -> InterruptNonMeleeSpells ( false );
2013-10-11 16:57:28 +02:00
2016-08-19 15:23:19 +02:00
TriggerCastFlags triggerFlag = TRIGGERED_NONE ;
if ( e . action . cast . castFlags & SMARTCAST_TRIGGERED )
{
if ( e . action . cast . triggerFlags )
triggerFlag = TriggerCastFlags ( e . action . cast . triggerFlags );
else
triggerFlag = TRIGGERED_FULL_MASK ;
}
2017-06-03 10:21:06 +02:00
tempLastInvoker -> CastSpell ( target -> ToUnit (), e . action . cast . spell , triggerFlag );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker %s casts spell %u on target %s with castflags %u" ,
2017-06-03 10:21:06 +02:00
tempLastInvoker -> GetGUID (). ToString (). c_str (), e . action . cast . spell , target -> GetGUID (). ToString (). c_str (), e . action . cast . castFlags );
2013-11-11 11:03:32 +01:00
}
else
2017-06-03 10:21:06 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "Spell %u not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (%s) already has the aura ", e.action.cast.spell, target->GetGUID().ToString().c_str()) ;
2010-11-06 23:18:04 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_ADD_AURA :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> AddAura ( e . action . cast . spell , target -> ToUnit ());
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_ADD_AURA: Adding aura %u to %s" ,
2017-06-03 10:21:06 +02:00
e . action . cast . spell , target -> GetGUID (). ToString (). c_str ());
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_ACTIVATE_GOBJECT :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsGameObject ( target ))
2011-03-26 23:45:23 +01:00
{
// Activate
2017-06-03 10:21:06 +02:00
target -> ToGameObject () -> SetLootState ( GO_READY );
target -> ToGameObject () -> UseDoorOrButton ( 0 , false , unit );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. %s (entry: %u) activated" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), target -> GetEntry ());
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_RESET_GOBJECT :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsGameObject ( target ))
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToGameObject () -> ResetDoorOrButton ();
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_RESET_GOBJECT. %s (entry: %u) reset" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), target -> GetEntry ());
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_EMOTE_STATE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> SetEmoteState ( Emote ( e . action . emote . emote ));
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_SET_EMOTE_STATE. %s set emotestate to %u" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), e . action . emote . emote );
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_UNIT_FLAG :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2011-03-26 23:45:23 +01:00
{
2013-05-26 13:22:21 -02:30
if ( ! e . action . unitFlag . type )
{
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> AddUnitFlag ( UnitFlags ( e . action . unitFlag . flag ));
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_SET_UNIT_FLAG. %s added flag %u to UNIT_FIELD_FLAGS" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), e . action . unitFlag . flag );
2013-05-26 13:22:21 -02:30
}
else
{
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> AddUnitFlag2 ( UnitFlags2 ( e . action . unitFlag . flag ));
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_SET_UNIT_FLAG. %s added flag %u to UNIT_FIELD_FLAGS_2" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), e . action . unitFlag . flag );
2013-05-26 13:22:21 -02:30
}
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_REMOVE_UNIT_FLAG :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2011-03-26 23:45:23 +01:00
{
2013-05-26 13:22:21 -02:30
if ( ! e . action . unitFlag . type )
{
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> RemoveUnitFlag ( UnitFlags ( e . action . unitFlag . flag ));
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_REMOVE_UNIT_FLAG. %s removed flag %u to UNIT_FIELD_FLAGS" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), e . action . unitFlag . flag );
2013-05-26 13:22:21 -02:30
}
else
{
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> RemoveUnitFlag2 ( UnitFlags2 ( e . action . unitFlag . flag ));
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_REMOVE_UNIT_FLAG. %s removed flag %u to UNIT_FIELD_FLAGS_2" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), e . action . unitFlag . flag );
2013-05-26 13:22:21 -02:30
}
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_AUTO_ATTACK :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-02-21 01:15:14 +01:00
2014-08-09 00:10:34 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> SetAutoAttack ( e . action . autoAttack . attack != 0 );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_AUTO_ATTACK: %s bool on = %u" ,
me -> GetGUID (). ToString (). c_str (), e . action . autoAttack . attack );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_ALLOW_COMBAT_MOVEMENT :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-02-21 01:15:14 +01:00
2014-07-17 15:42:57 +02:00
bool move = e . action . combatMove . move != 0 ;
2014-08-09 00:10:34 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> SetCombatMove ( move );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_ALLOW_COMBAT_MOVEMENT: %s bool on = %u" ,
me -> GetGUID (). ToString (). c_str (), e . action . combatMove . move );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_EVENT_PHASE :
2011-03-26 23:45:23 +01:00
{
2011-06-15 17:33:06 +02:00
if ( ! GetBaseObject ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2011-03-26 23:45:23 +01:00
SetPhase ( e . action . setEventPhase . phase );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_SET_EVENT_PHASE: %s set event phase %u" ,
GetBaseObject () -> GetGUID (). ToString (). c_str (), e . action . setEventPhase . phase );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_INC_EVENT_PHASE :
2011-03-26 23:45:23 +01:00
{
2011-06-15 17:33:06 +02:00
if ( ! GetBaseObject ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2011-03-26 23:45:23 +01:00
IncPhase ( e . action . incEventPhase . inc );
DecPhase ( e . action . incEventPhase . dec );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_INC_EVENT_PHASE: %s inc event phase by %u, "
"decrease by %u" , GetBaseObject () -> GetGUID (). ToString (). c_str (), e . action . incEventPhase . inc , e . action . incEventPhase . dec );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_EVADE :
2011-03-26 23:45:23 +01:00
{
if ( ! me )
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
me -> AI () -> EnterEvadeMode ();
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_EVADE: %s EnterEvadeMode" , me -> GetGUID (). ToString (). c_str ());
2013-09-01 18:01:59 +01:00
break ;
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_FLEE_FOR_ASSIST :
2011-03-26 23:45:23 +01:00
{
if ( ! me )
2012-01-22 20:36:01 -05:00
break ;
2011-02-21 01:15:14 +01:00
2011-03-26 23:45:23 +01:00
me -> DoFleeToGetAssistance ();
2016-09-02 23:14:50 +02:00
2017-02-17 21:33:18 +01:00
if ( e . action . fleeAssist . withEmote )
2012-03-01 22:26:05 +01:00
{
2018-01-14 18:48:01 +01:00
Trinity :: BroadcastTextBuilder builder ( me , CHAT_MSG_MONSTER_EMOTE , BROADCAST_TEXT_FLEE_FOR_ASSIST , me -> getGender ());
2014-12-23 00:06:36 +01:00
CreatureTextMgr :: SendChatPacket ( me , builder , CHAT_MSG_MONSTER_EMOTE );
2012-03-01 22:26:05 +01:00
}
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_FLEE_FOR_ASSIST: %s DoFleeToGetAssistance" , me -> GetGUID (). ToString (). c_str ());
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_CALL_GROUPEVENTHAPPENS :
2011-03-26 23:45:23 +01:00
{
2012-11-21 12:36:00 +01:00
if ( ! unit )
break ;
2017-02-17 21:33:18 +01:00
// If invoker was pet or charm
Player * player = unit -> GetCharmerOrOwnerPlayerOrPlayerItself ();
if ( player && GetBaseObject ())
2010-10-27 21:01:47 +02:00
{
2017-02-17 21:33:18 +01:00
player -> GroupEventHappens ( e . action . quest . quest , GetBaseObject ());
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: %s, group credit for quest %u" ,
unit -> GetGUID (). ToString (). c_str (), e . action . quest . quest );
2010-10-27 21:01:47 +02:00
}
2012-11-21 12:36:00 +01:00
2012-11-17 14:57:20 -05:00
// Special handling for vehicles
if ( Vehicle * vehicle = unit -> GetVehicleKit ())
for ( SeatMap :: iterator it = vehicle -> Seats . begin (); it != vehicle -> Seats . end (); ++ it )
2017-02-05 23:42:31 +01:00
if ( Player * player = ObjectAccessor :: GetPlayer ( * unit , it -> second . Passenger . Guid ))
2012-11-17 14:57:20 -05:00
player -> GroupEventHappens ( e . action . quest . quest , GetBaseObject ());
2011-03-26 23:45:23 +01:00
break ;
}
2015-07-24 22:54:15 +02:00
case SMART_ACTION_COMBAT_STOP :
{
if ( ! me )
break ;
me -> CombatStop ( true );
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_COMBAT_STOP: %s CombatStop" , me -> GetGUID (). ToString (). c_str ());
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_REMOVEAURASFROMSPELL :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsUnit ( target ))
2011-03-26 23:45:23 +01:00
continue ;
2011-02-21 01:15:14 +01:00
2013-11-11 11:03:32 +01:00
if ( e . action . removeAura . spell )
2014-11-02 17:30:44 +01:00
{
if ( e . action . removeAura . charges )
{
2017-06-03 10:21:06 +02:00
if ( Aura * aur = target -> ToUnit () -> GetAura ( e . action . removeAura . spell ))
2014-11-03 17:25:56 +01:00
aur -> ModCharges ( - static_cast < int32 > ( e . action . removeAura . charges ), AURA_REMOVE_BY_EXPIRE );
2014-11-02 17:30:44 +01:00
}
else
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> RemoveAurasDueToSpell ( e . action . removeAura . spell );
2014-11-02 17:30:44 +01:00
}
2013-11-11 11:03:32 +01:00
else
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> RemoveAllAuras ();
2012-06-02 14:28:24 +01:00
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_REMOVEAURASFROMSPELL: %s, spell %u" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), e . action . removeAura . spell );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_FOLLOW :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-02-21 01:15:14 +01:00
2017-06-03 10:21:06 +02:00
if ( targets . empty ())
2013-12-17 10:12:23 +01:00
{
2017-02-17 21:33:18 +01:00
ENSURE_AI ( SmartAI , me -> AI ()) -> StopFollow ( false );
2012-01-22 20:36:01 -05:00
break ;
2013-12-17 10:12:23 +01:00
}
2011-02-21 01:15:14 +01:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2010-10-27 21:01:47 +02:00
{
2017-02-17 21:33:18 +01:00
float angle = e . action . follow . angle > 6 ? ( e . action . follow . angle * M_PI / 180.0f ) : e . action . follow . angle ;
2017-06-03 10:21:06 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> SetFollow ( target -> ToUnit (), float ( e . action . follow . dist ) + 0.1f , angle , e . action . follow . credit , e . action . follow . entry , e . action . follow . creditType );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_FOLLOW: %s following target %s" ,
2017-06-03 10:21:06 +02:00
me -> GetGUID (). ToString (). c_str (), target -> GetGUID (). ToString (). c_str ());
2011-05-11 21:19:22 +02:00
break ;
2010-10-27 21:01:47 +02:00
}
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_RANDOM_PHASE :
2011-03-26 23:45:23 +01:00
{
2011-06-15 17:33:06 +02:00
if ( ! GetBaseObject ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2017-06-03 10:21:06 +02:00
std :: vector < uint32 > phases ;
2020-06-25 12:15:21 +02:00
std :: copy_if ( std :: begin ( e . action . randomPhase . phases ), std :: end ( e . action . randomPhase . phases ),
2017-06-03 10:21:06 +02:00
std :: back_inserter ( phases ), []( uint32 phase ) { return phase != 0 ; });
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
uint32 phase = Trinity :: Containers :: SelectRandomContainerElement ( phases );
2011-03-26 23:45:23 +01:00
SetPhase ( phase );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE: %s sets event phase to %u" ,
GetBaseObject () -> GetGUID (). ToString (). c_str (), phase );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_RANDOM_PHASE_RANGE :
2011-03-26 23:45:23 +01:00
{
2011-06-15 17:33:06 +02:00
if ( ! GetBaseObject ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2011-03-26 23:45:23 +01:00
uint32 phase = urand ( e . action . randomPhaseRange . phaseMin , e . action . randomPhaseRange . phaseMax );
SetPhase ( phase );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE_RANGE: %s sets event phase to %u" ,
GetBaseObject () -> GetGUID (). ToString (). c_str (), phase );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_CALL_KILLEDMONSTER :
2011-03-26 23:45:23 +01:00
{
2013-09-01 13:44:08 +02:00
if ( e . target . type == SMART_TARGET_NONE || e . target . type == SMART_TARGET_SELF ) // Loot recipient and his group members
2013-07-08 18:01:41 +02:00
{
if ( ! me )
break ;
2011-02-21 01:15:14 +01:00
2013-07-08 18:01:41 +02:00
if ( Player * player = me -> GetLootRecipient ())
{
player -> RewardPlayerAndGroupAtEvent ( e . action . killedMonster . creature , player );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: %s, Killcredit: %u" ,
player -> GetGUID (). ToString (). c_str (), e . action . killedMonster . creature );
2013-07-08 18:01:41 +02:00
}
}
else // Specific target type
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsPlayer ( target ))
2013-07-08 18:01:41 +02:00
{
2017-06-03 10:21:06 +02:00
target -> ToPlayer () -> KilledMonsterCredit ( e . action . killedMonster . creature );
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: %s, Killcredit: %u" ,
2017-06-03 10:21:06 +02:00
target -> GetGUID (). ToString (). c_str (), e . action . killedMonster . creature );
2013-08-06 23:16:03 +01:00
}
2017-06-03 10:21:06 +02:00
else if ( IsUnit ( target )) // Special handling for vehicles
if ( Vehicle * vehicle = target -> ToUnit () -> GetVehicleKit ())
2015-07-21 00:33:36 +02:00
for ( SeatMap :: iterator seatItr = vehicle -> Seats . begin (); seatItr != vehicle -> Seats . end (); ++ seatItr )
2017-06-03 10:21:06 +02:00
if ( Player * player = ObjectAccessor :: GetPlayer ( * target , seatItr -> second . Passenger . Guid ))
2013-07-08 18:01:41 +02:00
player -> KilledMonsterCredit ( e . action . killedMonster . creature );
2010-10-27 21:01:47 +02:00
}
}
2011-03-26 23:45:23 +01:00
break ;
}
case SMART_ACTION_SET_INST_DATA :
{
WorldObject * obj = GetBaseObject ();
if ( ! obj )
obj = unit ;
2011-02-21 01:15:14 +01:00
2011-03-26 23:45:23 +01:00
if ( ! obj )
2012-01-22 20:36:01 -05:00
break ;
2011-02-21 01:15:14 +01:00
2011-06-15 17:33:06 +02:00
InstanceScript * instance = obj -> GetInstanceScript ();
if ( ! instance )
2011-03-26 23:45:23 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Event %u attempt to set instance data without instance script. EntryOrGuid " SI64FMTD "" , e . GetEventType (), e . entryOrGuid );
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
}
2011-02-21 01:15:14 +01:00
2016-06-14 13:29:51 -03:00
switch ( e . action . setInstanceData . type )
{
case 0 :
instance -> SetData ( e . action . setInstanceData . field , e . action . setInstanceData . data );
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: SetData Field: %u, data: %u" ,
e . action . setInstanceData . field , e . action . setInstanceData . data );
break ;
case 1 :
instance -> SetBossState ( e . action . setInstanceData . field , static_cast < EncounterState > ( e . action . setInstanceData . data ));
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: SetBossState BossId: %u, State: %u (%s)" ,
2017-08-27 13:35:03 +02:00
e . action . setInstanceData . field , e . action . setInstanceData . data , InstanceScript :: GetBossStateName ( e . action . setInstanceData . data ));
2016-06-14 13:29:51 -03:00
break ;
default : // Static analysis
break ;
}
2011-03-26 23:45:23 +01:00
break ;
}
case SMART_ACTION_SET_INST_DATA64 :
{
WorldObject * obj = GetBaseObject ();
if ( ! obj )
obj = unit ;
2011-02-21 01:15:14 +01:00
2011-03-26 23:45:23 +01:00
if ( ! obj )
2012-01-22 20:36:01 -05:00
break ;
2010-12-13 22:37:56 +01:00
2011-06-15 17:33:06 +02:00
InstanceScript * instance = obj -> GetInstanceScript ();
if ( ! instance )
2011-03-26 23:45:23 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Event %u attempt to set instance data without instance script. EntryOrGuid " SI64FMTD "" , e . GetEventType (), e . entryOrGuid );
2012-01-22 20:36:01 -05:00
break ;
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
if ( targets . empty ())
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
instance -> SetGuidData ( e . action . setInstanceData64 . field , targets . front () -> GetGUID ());
2014-09-16 19:47:10 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: %u, data: %s" ,
2017-06-03 10:21:06 +02:00
e . action . setInstanceData64 . field , targets . front () -> GetGUID (). ToString (). c_str ());
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_UPDATE_TEMPLATE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2017-02-28 16:39:59 -03:00
if ( IsCreature ( target ))
target -> ToCreature () -> UpdateEntry ( e . action . updateTemplate . creature , target -> ToCreature () -> GetCreatureData (), e . action . updateTemplate . updateLevel != 0 );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_DIE :
2011-03-26 23:45:23 +01:00
{
if ( me && ! me -> isDead ())
2010-10-27 21:01:47 +02:00
{
2015-12-07 20:06:02 +01:00
me -> KillSelf ();
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_DIE: %s" , me -> GetGUID (). ToString (). c_str ());
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
{
if ( IsCreature ( target ))
2017-02-17 21:33:18 +01:00
{
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetInCombatWithZone ();
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature %s, target: %s" , me -> GetGUID (). ToString (). c_str (), target -> GetGUID (). ToString (). c_str ());
2017-02-17 21:33:18 +01:00
}
2017-06-03 10:21:06 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_CALL_FOR_HELP :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
{
if ( IsCreature ( target ))
2013-01-10 15:09:12 +00:00
{
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> CallForHelp ( float ( e . action . callHelp . range ));
2017-02-17 21:33:18 +01:00
if ( e . action . callHelp . withEmote )
{
Trinity :: BroadcastTextBuilder builder ( me , CHAT_MSG_MONSTER_EMOTE , BROADCAST_TEXT_CALL_FOR_HELP , me -> getGender ());
sCreatureTextMgr -> SendChatPacket ( me , builder , CHAT_MSG_MONSTER_EMOTE );
}
2017-06-03 10:21:06 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature %s, target: %s" , me -> GetGUID (). ToString (). c_str (), target -> GetGUID (). ToString (). c_str ());
2013-01-10 15:09:12 +00:00
}
2017-06-03 10:21:06 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_SHEATH :
2011-03-26 23:45:23 +01:00
{
if ( me )
2010-10-27 21:01:47 +02:00
{
2011-03-26 23:45:23 +01:00
me -> SetSheath ( SheathState ( e . action . setSheath . sheath ));
2014-10-22 21:22:04 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction: SMART_ACTION_SET_SHEATH: %s, State: %u" ,
me -> GetGUID (). ToString (). c_str (), e . action . setSheath . sheath );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_FORCE_DESPAWN :
2011-03-26 23:45:23 +01:00
{
2017-02-06 19:28:44 -03:00
// there should be at least a world update tick before despawn, to avoid breaking linked actions
int32 const respawnDelay = std :: max < int32 > ( e . action . forceDespawn . delay , 1 );
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2017-02-06 19:28:44 -03:00
{
2017-06-03 10:21:06 +02:00
if ( Creature * creature = target -> ToCreature ())
2017-02-06 19:28:44 -03:00
{
2017-06-03 10:21:06 +02:00
if ( SmartAI * smartAI = CAST_AI ( SmartAI , creature -> AI ()))
2017-02-06 19:28:44 -03:00
{
smartAI -> SetDespawnTime ( respawnDelay );
smartAI -> StartDespawn ();
}
else
2017-06-03 10:21:06 +02:00
creature -> DespawnOrUnsummon ( respawnDelay );
2017-02-06 19:28:44 -03:00
}
2017-07-16 18:16:48 +02:00
else if ( GameObject * goTarget = target -> ToGameObject ())
goTarget -> SetRespawnTime ( respawnDelay );
2017-02-06 19:28:44 -03:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2014-06-05 13:05:29 -05:00
case SMART_ACTION_SET_INGAME_PHASE_ID :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2018-01-28 11:37:20 +01:00
{
if ( e . action . ingamePhaseId . apply == 1 )
2017-06-03 10:21:06 +02:00
PhasingHandler :: AddPhase ( target , e . action . ingamePhaseId . id , true );
2018-01-28 11:37:20 +01:00
else
2017-06-03 10:21:06 +02:00
PhasingHandler :: RemovePhase ( target , e . action . ingamePhaseId . id , true );
2018-01-28 11:37:20 +01:00
}
2014-06-05 13:05:29 -05:00
break ;
}
case SMART_ACTION_SET_INGAME_PHASE_GROUP :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2018-01-28 11:37:20 +01:00
{
if ( e . action . ingamePhaseGroup . apply == 1 )
2017-06-03 10:21:06 +02:00
PhasingHandler :: AddPhaseGroup ( target , e . action . ingamePhaseGroup . groupId , true );
2018-01-28 11:37:20 +01:00
else
2017-06-03 10:21:06 +02:00
PhasingHandler :: RemovePhaseGroup ( target , e . action . ingamePhaseGroup . groupId , true );
2018-01-28 11:37:20 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsUnit ( target ))
2011-06-12 02:30:32 +02:00
continue ;
2011-06-15 17:33:06 +02:00
2011-03-26 23:45:23 +01:00
if ( e . action . morphOrMount . creature || e . action . morphOrMount . model )
2010-10-27 21:01:47 +02:00
{
2011-03-26 23:45:23 +01:00
if ( e . action . morphOrMount . creature > 0 )
2010-10-27 21:01:47 +02:00
{
2011-04-28 22:57:08 +02:00
if ( CreatureTemplate const * cInfo = sObjectMgr -> GetCreatureTemplate ( e . action . morphOrMount . creature ))
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> Mount ( ObjectMgr :: ChooseDisplayId ( cInfo ) -> CreatureDisplayID );
2010-10-27 21:01:47 +02:00
}
else
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> Mount ( e . action . morphOrMount . model );
2010-10-27 21:01:47 +02:00
}
else
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> Dismount ();
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
case SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
2017-02-17 21:33:18 +01:00
{
2017-06-03 10:21:06 +02:00
SmartAI * ai = CAST_AI ( SmartAI , target -> ToCreature () -> AI ());
2017-02-17 21:33:18 +01:00
if ( ! ai )
continue ;
if ( e . action . invincHP . percent )
2017-06-03 10:21:06 +02:00
ai -> SetInvincibilityHpLevel ( target -> ToCreature () -> CountPctFromMaxHealth ( e . action . invincHP . percent ));
2017-02-17 21:33:18 +01:00
else
ai -> SetInvincibilityHpLevel ( e . action . invincHP . minHP );
}
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2019-08-22 13:45:11 +02:00
case SMART_ACTION_SET_DATA :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2019-08-22 13:45:11 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
target -> ToCreature () -> AI () -> SetData ( e . action . setData . field , e . action . setData . data );
else if ( IsGameObject ( target ))
target -> ToGameObject () -> AI () -> SetData ( e . action . setData . field , e . action . setData . data );
2019-08-22 13:45:11 +02:00
}
break ;
}
2016-07-15 18:37:17 +02:00
case SMART_ACTION_MOVE_OFFSET :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2016-07-15 18:37:17 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsCreature ( target ))
continue ;
2011-06-15 17:33:06 +02:00
2017-06-03 10:21:06 +02:00
if ( ! ( e . event . event_flags & SMART_EVENT_FLAG_WHILE_CHARMED ) && IsCharmedCreature ( target ))
continue ;
2016-09-02 23:14:50 +02:00
2017-06-03 10:21:06 +02:00
Position pos = target -> GetPosition ();
2016-07-15 18:37:17 +02:00
2017-06-03 10:21:06 +02:00
// Use forward/backward/left/right cartesian plane movement
float x , y , z , o ;
o = pos . GetOrientation ();
x = pos . GetPositionX () + ( std :: cos ( o - ( M_PI / 2 )) * e . target . x ) + ( std :: cos ( o ) * e . target . y );
y = pos . GetPositionY () + ( std :: sin ( o - ( M_PI / 2 )) * e . target . x ) + ( std :: sin ( o ) * e . target . y );
z = pos . GetPositionZ () + e . target . z ;
target -> ToCreature () -> GetMotionMaster () -> MovePoint ( SMART_RANDOM_POINT , x , y , z );
2016-07-15 18:37:17 +02:00
}
2015-07-30 00:45:48 +02:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_VISIBILITY :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsUnit ( target ))
target -> ToUnit () -> SetVisible ( e . action . visibility . state ? true : false );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_ACTIVE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
target -> setActive ( e . action . active . state ? true : false );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_ATTACK_START :
2011-03-26 23:45:23 +01:00
{
if ( ! me )
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
if ( targets . empty ())
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
2017-02-17 21:33:18 +01:00
// attack random target
2017-06-03 10:21:06 +02:00
if ( Unit * target = Trinity :: Containers :: SelectRandomContainerElement ( targets ) -> ToUnit ())
2017-02-17 21:33:18 +01:00
me -> AI () -> AttackStart ( target );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SUMMON_CREATURE :
2011-03-26 23:45:23 +01:00
{
2017-03-17 21:21:35 +01:00
WorldObject * summoner = GetBaseObjectOrUnit ( unit );
if ( ! summoner )
break ;
2017-06-03 10:21:06 +02:00
float x , y , z , o ;
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
target -> GetPosition ( x , y , z , o );
x += e . target . x ;
y += e . target . y ;
z += e . target . z ;
o += e . target . o ;
if ( Creature * summon = summoner -> SummonCreature ( e . action . summonCreature . creature , x , y , z , o , ( TempSummonType ) e . action . summonCreature . type , e . action . summonCreature . duration ))
if ( e . action . summonCreature . attackInvoker )
summon -> AI () -> AttackStart ( target -> ToUnit ());
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
if ( e . GetTargetType () != SMART_TARGET_POSITION )
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
2017-03-17 21:21:35 +01:00
if ( Creature * summon = summoner -> SummonCreature ( e . action . summonCreature . creature , e . target . x , e . target . y , e . target . z , e . target . o , ( TempSummonType ) e . action . summonCreature . type , e . action . summonCreature . duration ))
2011-03-26 23:45:23 +01:00
if ( unit && e . action . summonCreature . attackInvoker )
summon -> AI () -> AttackStart ( unit );
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SUMMON_GO :
2011-03-26 23:45:23 +01:00
{
2017-03-17 21:21:35 +01:00
WorldObject * summoner = GetBaseObjectOrUnit ( unit );
if ( ! summoner )
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
Position pos = target -> GetPositionWithOffset ( Position ( e . target . x , e . target . y , e . target . z , e . target . o ));
summoner -> SummonGameObject ( e . action . summonGO . entry , pos , QuaternionData :: fromEulerAnglesZYX ( pos . GetOrientation (), 0.f , 0.f ), e . action . summonGO . despawnTime );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
if ( e . GetTargetType () != SMART_TARGET_POSITION )
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
2017-06-04 01:00:45 +02:00
summoner -> SummonGameObject ( e . action . summonGO . entry , Position ( e . target . x , e . target . y , e . target . z , e . target . o ), QuaternionData :: fromEulerAnglesZYX ( e . target . o , 0.f , 0.f ), e . action . summonGO . despawnTime );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_KILL_UNIT :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsUnit ( target ))
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> KillSelf ();
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_INSTALL_AI_TEMPLATE :
2011-03-26 23:45:23 +01:00
{
InstallTemplate ( e );
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_ADD_ITEM :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsPlayer ( target ))
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
target -> ToPlayer () -> AddItem ( e . action . item . entry , e . action . item . count );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_REMOVE_ITEM :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsPlayer ( target ))
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
target -> ToPlayer () -> DestroyItemCount ( e . action . item . entry , e . action . item . count , true );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_STORE_TARGET_LIST :
2011-03-26 23:45:23 +01:00
{
StoreTargetList ( targets , e . action . storeTargets . id );
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_TELEPORT :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsPlayer ( target ))
target -> ToPlayer () -> TeleportTo ( e . action . teleport . mapID , e . target . x , e . target . y , e . target . z , e . target . o );
else if ( IsCreature ( target ))
target -> ToCreature () -> NearTeleportTo ( e . target . x , e . target . y , e . target . z , e . target . o );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2017-02-17 21:33:18 +01:00
case SMART_ACTION_SET_DISABLE_GRAVITY :
{
if ( ! IsSmart ())
break ;
ENSURE_AI ( SmartAI , me -> AI ()) -> SetDisableGravity ( e . action . setDisableGravity . disable != 0 );
break ;
}
case SMART_ACTION_SET_CAN_FLY :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2017-02-17 21:33:18 +01:00
ENSURE_AI ( SmartAI , me -> AI ()) -> SetCanFly ( e . action . setFly . fly != 0 );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_RUN :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2014-08-09 00:10:34 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> SetRun ( e . action . setRun . run != 0 );
2011-03-26 23:45:23 +01:00
break ;
}
2011-08-21 00:07:38 -03:00
case SMART_ACTION_SET_SWIM :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2014-08-09 00:10:34 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> SetSwim ( e . action . setSwim . swim != 0 );
2011-03-26 23:45:23 +01:00
break ;
}
2015-04-02 18:02:34 +02:00
case SMART_ACTION_SET_COUNTER :
{
2017-06-03 10:21:06 +02:00
if ( ! targets . empty ())
2015-05-02 15:35:07 +02:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2015-05-02 15:35:07 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
2015-05-02 15:35:07 +02:00
{
2017-06-03 10:21:06 +02:00
if ( SmartAI * ai = CAST_AI ( SmartAI , target -> ToCreature () -> AI ()))
2015-05-02 15:35:07 +02:00
ai -> GetScript () -> StoreCounter ( e . action . setCounter . counterId , e . action . setCounter . value , e . action . setCounter . reset );
else
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartAI, skipping" );
}
2017-06-03 10:21:06 +02:00
else if ( IsGameObject ( target ))
2015-05-02 15:35:07 +02:00
{
2017-06-03 10:21:06 +02:00
if ( SmartGameObjectAI * ai = CAST_AI ( SmartGameObjectAI , target -> ToGameObject () -> AI ()))
2015-05-02 15:35:07 +02:00
ai -> GetScript () -> StoreCounter ( e . action . setCounter . counterId , e . action . setCounter . value , e . action . setCounter . reset );
else
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartGameObjectAI, skipping" );
}
}
}
else
StoreCounter ( e . action . setCounter . counterId , e . action . setCounter . value , e . action . setCounter . reset );
2015-04-02 18:02:34 +02:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_WP_START :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2014-07-17 15:42:57 +02:00
bool run = e . action . wpStart . run != 0 ;
2011-03-26 23:45:23 +01:00
uint32 entry = e . action . wpStart . pathID ;
2014-07-17 15:42:57 +02:00
bool repeat = e . action . wpStart . repeat != 0 ;
2017-02-17 21:33:18 +01:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2017-02-17 21:33:18 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsPlayer ( target ))
2017-02-17 21:33:18 +01:00
{
2017-06-03 10:21:06 +02:00
StoreTargetList ( targets , SMART_ESCORT_TARGETS );
break ;
2017-02-17 21:33:18 +01:00
}
}
2011-03-26 23:45:23 +01:00
me -> SetReactState (( ReactStates ) e . action . wpStart . reactState );
2014-08-09 00:10:34 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> StartPath ( run , entry , repeat , unit );
2011-03-26 23:45:23 +01:00
uint32 quest = e . action . wpStart . quest ;
uint32 DespawnTime = e . action . wpStart . despawnTime ;
2014-08-09 00:10:34 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> mEscortQuestID = quest ;
ENSURE_AI ( SmartAI , me -> AI ()) -> SetDespawnTime ( DespawnTime );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_WP_PAUSE :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2011-03-26 23:45:23 +01:00
uint32 delay = e . action . wpPause . delay ;
2014-08-09 00:10:34 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> PausePath ( delay , e . GetEventType () == SMART_EVENT_WAYPOINT_REACHED ? false : true );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_WP_STOP :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2011-03-26 23:45:23 +01:00
uint32 DespawnTime = e . action . wpStop . despawnTime ;
uint32 quest = e . action . wpStop . quest ;
2014-07-17 15:42:57 +02:00
bool fail = e . action . wpStop . fail != 0 ;
2014-08-09 00:10:34 +02:00
ENSURE_AI ( SmartAI , me -> AI ()) -> StopPath ( DespawnTime , quest , fail );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_WP_RESUME :
2011-03-26 23:45:23 +01:00
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2017-02-17 21:33:18 +01:00
ENSURE_AI ( SmartAI , me -> AI ()) -> SetWPPauseTimer ( 0 );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_SET_ORIENTATION :
2011-03-26 23:45:23 +01:00
{
if ( ! me )
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
if ( e . GetTargetType () == SMART_TARGET_SELF )
2013-10-26 17:06:50 +02:00
me -> SetFacingTo (( me -> GetTransport () ? me -> GetTransportHomePosition () : me -> GetHomePosition ()). GetOrientation ());
2011-03-26 23:45:23 +01:00
else if ( e . GetTargetType () == SMART_TARGET_POSITION )
2012-01-14 15:34:41 +01:00
me -> SetFacingTo ( e . target . o );
2017-06-03 10:21:06 +02:00
else if ( ! targets . empty ())
me -> SetFacingToObject ( targets . front ());
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_PLAYMOVIE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsPlayer ( target ))
2011-03-26 23:45:23 +01:00
continue ;
2011-03-27 12:54:42 +02:00
2017-06-03 10:21:06 +02:00
target -> ToPlayer () -> SendMovieStart ( e . action . movie . entry );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
case SMART_ACTION_MOVE_TO_POS :
{
if ( ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-06-15 17:33:06 +02:00
2016-08-05 12:41:56 +02:00
WorldObject * target = nullptr ;
2011-12-30 19:01:22 +01:00
2017-02-17 21:33:18 +01:00
/*if (e.GetTargetType() == SMART_TARGET_CREATURE_RANGE || e.GetTargetType() == SMART_TARGET_CREATURE_GUID ||
2011-12-30 19:01:22 +01:00
e.GetTargetType() == SMART_TARGET_CREATURE_DISTANCE || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_RANGE ||
e.GetTargetType() == SMART_TARGET_GAMEOBJECT_GUID || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_DISTANCE ||
2011-12-27 20:37:42 -05:00
e.GetTargetType() == SMART_TARGET_CLOSEST_CREATURE || e.GetTargetType() == SMART_TARGET_CLOSEST_GAMEOBJECT ||
2013-08-07 19:59:06 +01:00
e.GetTargetType() == SMART_TARGET_OWNER_OR_SUMMONER || e.GetTargetType() == SMART_TARGET_ACTION_INVOKER ||
2017-02-17 21:33:18 +01:00
e.GetTargetType() == SMART_TARGET_CLOSEST_ENEMY || e.GetTargetType() == SMART_TARGET_CLOSEST_FRIENDLY)*/
2011-12-27 20:25:50 -05:00
{
2017-06-03 10:21:06 +02:00
// we want to move to random element
if ( ! targets . empty ())
target = Trinity :: Containers :: SelectRandomContainerElement ( targets );
2011-12-27 20:25:50 -05:00
}
2012-03-03 23:41:29 +01:00
if ( ! target )
2013-10-16 18:37:29 +02:00
{
2017-06-04 01:00:45 +02:00
Position dest ( e . target . x , e . target . y , e . target . z );
2013-10-16 18:37:29 +02:00
if ( e . action . MoveToPos . transport )
if ( TransportBase * trans = me -> GetDirectTransport ())
2017-06-04 01:00:45 +02:00
trans -> CalculatePassengerPosition ( dest . m_positionX , dest . m_positionY , dest . m_positionZ );
2013-10-16 18:37:29 +02:00
2017-06-04 01:00:45 +02:00
me -> GetMotionMaster () -> MovePoint ( e . action . MoveToPos . pointId , dest , e . action . MoveToPos . disablePathfinding == 0 );
2013-10-16 18:37:29 +02:00
}
2011-12-27 20:25:50 -05:00
else
2017-01-21 22:10:07 +01:00
{
float x , y , z ;
target -> GetPosition ( x , y , z );
if ( e . action . MoveToPos . ContactDistance > 0 )
target -> GetContactPoint ( me , x , y , z , e . action . MoveToPos . ContactDistance );
2017-02-17 21:33:18 +01:00
me -> GetMotionMaster () -> MovePoint ( e . action . MoveToPos . pointId , x + e . target . x , y + e . target . y , z + e . target . z , e . action . MoveToPos . disablePathfinding == 0 );
2017-01-21 22:10:07 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_RESPAWN_TARGET :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
target -> ToCreature () -> Respawn ();
else if ( IsGameObject ( target ))
2017-02-17 21:33:18 +01:00
{
// do not modify respawndelay of already spawned gameobjects
2017-06-03 10:21:06 +02:00
if ( target -> ToGameObject () -> isSpawnedByDefault ())
target -> ToGameObject () -> Respawn ();
2017-02-17 21:33:18 +01:00
else
2017-06-03 10:21:06 +02:00
target -> ToGameObject () -> SetRespawnTime ( e . action . RespawnTarget . goRespawnTime );
2017-02-17 21:33:18 +01:00
}
2010-10-27 21:01:47 +02:00
}
break ;
}
case SMART_ACTION_CLOSE_GOSSIP :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsPlayer ( target ))
target -> ToPlayer () -> PlayerTalkClass -> SendCloseGossip ();
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_EQUIP :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( Creature * npc = target -> ToCreature ())
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
std :: array < EquipmentItem , MAX_EQUIPMENT_ITEMS > slot ;
if ( int8 equipId = static_cast < int8 > ( e . action . equip . entry ))
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
EquipmentInfo const * eInfo = sObjectMgr -> GetEquipmentInfo ( npc -> GetEntry (), equipId );
if ( ! eInfo )
2010-11-06 23:08:33 +01:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id %u for creature %u" , equipId , npc -> GetEntry ());
2013-09-01 18:01:59 +01:00
break ;
2010-11-06 23:08:33 +01:00
}
2013-05-17 21:30:02 +02:00
2013-02-18 12:24:18 +00:00
npc -> SetCurrentEquipmentId ( equipId );
2017-06-03 10:21:06 +02:00
std :: copy ( std :: begin ( eInfo -> Items ), std :: end ( eInfo -> Items ), std :: begin ( slot ));
2011-03-26 23:45:23 +01:00
}
else
{
2020-06-25 12:15:21 +02:00
slot [ 0 ]. ItemId = e . action . equip . slot1 ;
slot [ 1 ]. ItemId = e . action . equip . slot2 ;
slot [ 2 ]. ItemId = e . action . equip . slot3 ;
2010-10-27 21:01:47 +02:00
}
2017-06-03 10:21:06 +02:00
for ( uint32 i = 0 ; i < MAX_EQUIPMENT_ITEMS ; ++ i )
if ( ! e . action . equip . mask || ( e . action . equip . mask & ( 1 << i )))
npc -> SetVirtualItem ( 0 , slot [ i ]. ItemId , slot [ i ]. AppearanceModId , slot [ i ]. ItemVisual );
2010-10-27 21:01:47 +02:00
}
}
2011-03-26 23:45:23 +01:00
break ;
}
case SMART_ACTION_CREATE_TIMED_EVENT :
{
2013-09-22 22:08:38 +02:00
SmartEvent ne = SmartEvent ();
2011-03-26 23:45:23 +01:00
ne . type = ( SMART_EVENT ) SMART_EVENT_UPDATE ;
ne . event_chance = e . action . timeEvent . chance ;
if ( ! ne . event_chance ) ne . event_chance = 100 ;
ne . minMaxRepeat . min = e . action . timeEvent . min ;
ne . minMaxRepeat . max = e . action . timeEvent . max ;
ne . minMaxRepeat . repeatMin = e . action . timeEvent . repeatMin ;
ne . minMaxRepeat . repeatMax = e . action . timeEvent . repeatMax ;
2011-05-12 10:40:53 +02:00
ne . event_flags = 0 ;
2011-03-26 23:45:23 +01:00
if ( ! ne . minMaxRepeat . repeatMin && ! ne . minMaxRepeat . repeatMax )
ne . event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE ;
2013-09-22 22:08:38 +02:00
SmartAction ac = SmartAction ();
2011-03-26 23:45:23 +01:00
ac . type = ( SMART_ACTION ) SMART_ACTION_TRIGGER_TIMED_EVENT ;
ac . timeEvent . id = e . action . timeEvent . id ;
2013-09-22 22:08:38 +02:00
SmartScriptHolder ev = SmartScriptHolder ();
2011-03-26 23:45:23 +01:00
ev . event = ne ;
ev . event_id = e . action . timeEvent . id ;
ev . target = e . target ;
ev . action = ac ;
InitTimer ( ev );
mStoredEvents . push_back ( ev );
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_TRIGGER_TIMED_EVENT :
2016-08-05 12:41:56 +02:00
ProcessEventsFor (( SMART_EVENT ) SMART_EVENT_TIMED_EVENT_TRIGGERED , nullptr , e . action . timeEvent . id );
2017-02-17 21:33:18 +01:00
// remove this event if not repeatable
if ( e . event . event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE )
mRemIDs . push_back ( e . action . timeEvent . id );
2011-03-26 23:45:23 +01:00
break ;
2010-10-27 21:01:47 +02:00
case SMART_ACTION_REMOVE_TIMED_EVENT :
2011-03-26 23:45:23 +01:00
mRemIDs . push_back ( e . action . timeEvent . id );
break ;
2010-10-27 21:01:47 +02:00
case SMART_ACTION_OVERRIDE_SCRIPT_BASE_OBJECT :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
2010-10-27 21:01:47 +02:00
{
2014-09-14 16:14:12 +02:00
if ( ! meOrigGUID && me )
meOrigGUID = me -> GetGUID ();
if ( ! goOrigGUID && go )
goOrigGUID = go -> GetGUID ();
2016-08-05 12:41:56 +02:00
go = nullptr ;
2017-06-03 10:21:06 +02:00
me = target -> ToCreature ();
2011-05-12 10:40:53 +02:00
break ;
2011-03-26 23:45:23 +01:00
}
2017-06-03 10:21:06 +02:00
else if ( IsGameObject ( target ))
2011-03-26 23:45:23 +01:00
{
2014-09-14 16:14:12 +02:00
if ( ! meOrigGUID && me )
meOrigGUID = me -> GetGUID ();
if ( ! goOrigGUID && go )
goOrigGUID = go -> GetGUID ();
2017-06-03 10:21:06 +02:00
go = target -> ToGameObject ();
2016-08-05 12:41:56 +02:00
me = nullptr ;
2011-05-12 10:40:53 +02:00
break ;
2010-10-27 21:01:47 +02:00
}
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_ACTION_RESET_SCRIPT_BASE_OBJECT :
ResetBaseObject ();
break ;
case SMART_ACTION_CALL_SCRIPT_RESET :
2016-10-29 23:44:03 +02:00
SetPhase ( 0 );
2010-10-27 21:01:47 +02:00
OnReset ();
break ;
2012-05-29 12:19:46 +02:00
case SMART_ACTION_SET_RANGED_MOVEMENT :
{
2012-05-29 12:29:10 +02:00
if ( ! IsSmart ())
break ;
2012-06-23 12:15:52 +02:00
float attackDistance = float ( e . action . setRangedMovement . distance );
2014-08-21 16:56:11 +02:00
float attackAngle = float ( e . action . setRangedMovement . angle ) / 180.0f * float ( M_PI );
2012-05-29 12:19:46 +02:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( Creature * creature = target -> ToCreature ())
if ( IsSmart ( creature ) && creature -> GetVictim ())
if ( ENSURE_AI ( SmartAI , creature -> AI ()) -> CanCombatMove ())
creature -> GetMotionMaster () -> MoveChase ( creature -> GetVictim (), attackDistance , attackAngle );
2012-05-29 12:29:10 +02:00
2012-05-29 12:19:46 +02:00
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_ACTION_CALL_TIMED_ACTIONLIST :
2011-03-26 23:45:23 +01:00
{
if ( e . GetTargetType () == SMART_TARGET_NONE )
2010-11-03 14:10:16 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Entry " SI64FMTD " SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database." , e . entryOrGuid , e . GetScriptType (), e . GetEventType (), e . GetActionType ());
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
}
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( Creature * creature = target -> ToCreature ())
2010-12-07 18:31:34 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsSmart ( creature ))
ENSURE_AI ( SmartAI , creature -> AI ()) -> SetScript9 ( e , e . action . timedActionList . id , GetLastInvoker ());
}
2017-07-16 18:16:48 +02:00
else if ( GameObject * goTarget = target -> ToGameObject ())
2017-06-03 10:21:06 +02:00
{
2017-07-16 18:16:48 +02:00
if ( IsSmartGO ( goTarget ))
ENSURE_AI ( SmartGameObjectAI , goTarget -> AI ()) -> SetScript9 ( e , e . action . timedActionList . id , GetLastInvoker ());
2010-12-07 18:31:34 +01:00
}
2010-11-03 14:10:16 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_ACTION_SET_NPC_FLAG :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsCreature ( target ))
target -> ToUnit () -> SetNpcFlags ( NPCFlags ( e . action . unitFlag . flag ));
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_ACTION_ADD_NPC_FLAG :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsCreature ( target ))
target -> ToUnit () -> AddNpcFlag ( NPCFlags ( e . action . unitFlag . flag ));
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-03 14:10:16 +01:00
case SMART_ACTION_REMOVE_NPC_FLAG :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsCreature ( target ))
target -> ToUnit () -> RemoveNpcFlag ( NPCFlags ( e . action . unitFlag . flag ));
2011-03-26 23:45:23 +01:00
break ;
}
case SMART_ACTION_CROSS_CAST :
{
2017-06-03 10:21:06 +02:00
if ( targets . empty ())
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
ObjectVector casters ;
GetTargets ( casters , CreateSmartEvent ( SMART_EVENT_UPDATE_IC , 0 , 0 , 0 , 0 , 0 , 0 , SMART_ACTION_NONE , 0 , 0 , 0 , 0 , 0 , 0 , ( SMARTAI_TARGETS ) e . action . crossCast . targetType , e . action . crossCast . targetParam1 , e . action . crossCast . targetParam2 , e . action . crossCast . targetParam3 , 0 ), unit );
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * caster : casters )
2010-11-07 18:34:04 +01:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsUnit ( caster ))
2013-10-11 16:57:28 +02:00
continue ;
2017-06-03 10:21:06 +02:00
Unit * casterUnit = caster -> ToUnit ();
2013-11-11 11:03:32 +01:00
2013-10-11 16:57:28 +02:00
bool interruptedSpell = false ;
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-11-07 18:34:04 +01:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsUnit ( target ))
2013-10-11 16:57:28 +02:00
continue ;
2010-11-07 18:34:04 +01:00
2017-06-03 10:21:06 +02:00
if ( ! ( e . action . crossCast . castFlags & SMARTCAST_AURA_NOT_PRESENT ) || ! target -> ToUnit () -> HasAura ( e . action . crossCast . spell ))
2012-02-18 19:00:48 -05:00
{
2016-08-19 15:23:19 +02:00
if ( ! interruptedSpell && e . action . crossCast . castFlags & SMARTCAST_INTERRUPT_PREVIOUS )
2012-02-18 19:00:48 -05:00
{
2017-06-03 10:21:06 +02:00
casterUnit -> InterruptNonMeleeSpells ( false );
2013-10-11 16:57:28 +02:00
interruptedSpell = true ;
2012-02-18 19:00:48 -05:00
}
2013-10-11 16:57:28 +02:00
2017-06-03 10:21:06 +02:00
casterUnit -> CastSpell ( target -> ToUnit (), e . action . crossCast . spell , ( e . action . crossCast . castFlags & SMARTCAST_TRIGGERED ) != 0 );
2012-02-18 19:00:48 -05:00
}
2013-10-11 16:57:28 +02:00
else
2017-06-03 10:21:06 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "Spell %u not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (%s) already has the aura ", e.action.crossCast.spell, target->GetGUID().ToString().c_str()) ;
2010-11-07 18:34:04 +01:00
}
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-07 22:10:11 +01:00
case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
std :: vector < uint32 > actionLists ;
2020-06-25 12:15:21 +02:00
std :: copy_if ( std :: begin ( e . action . randTimedActionList . actionLists ), std :: end ( e . action . randTimedActionList . actionLists ),
2017-06-03 10:21:06 +02:00
std :: back_inserter ( actionLists ), []( uint32 actionList ) { return actionList != 0 ; });
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
uint32 id = Trinity :: Containers :: SelectRandomContainerElement ( actionLists );
2011-03-26 23:45:23 +01:00
if ( e . GetTargetType () == SMART_TARGET_NONE )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Entry " SI64FMTD " SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database." , e . entryOrGuid , e . GetScriptType (), e . GetEventType (), e . GetActionType ());
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
}
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( Creature * creature = target -> ToCreature ())
2010-12-07 18:31:34 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsSmart ( creature ))
ENSURE_AI ( SmartAI , creature -> AI ()) -> SetScript9 ( e , id , GetLastInvoker ());
}
2017-07-16 18:16:48 +02:00
else if ( GameObject * goTarget = target -> ToGameObject ())
2017-06-03 10:21:06 +02:00
{
2017-07-16 18:16:48 +02:00
if ( IsSmartGO ( goTarget ))
ENSURE_AI ( SmartGameObjectAI , goTarget -> AI ()) -> SetScript9 ( e , id , GetLastInvoker ());
2010-12-07 18:31:34 +01:00
}
2010-11-07 22:10:11 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-07 22:10:11 +01:00
case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
uint32 id = urand ( e . action . randTimedActionList . actionLists [ 0 ], e . action . randTimedActionList . actionLists [ 1 ]);
2011-03-26 23:45:23 +01:00
if ( e . GetTargetType () == SMART_TARGET_NONE )
2010-11-07 22:10:11 +01:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Entry " SI64FMTD " SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database." , e . entryOrGuid , e . GetScriptType (), e . GetEventType (), e . GetActionType ());
2012-01-22 20:36:01 -05:00
break ;
2011-03-26 23:45:23 +01:00
}
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
if ( Creature * creature = target -> ToCreature ())
2010-12-07 18:31:34 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsSmart ( creature ))
ENSURE_AI ( SmartAI , creature -> AI ()) -> SetScript9 ( e , id , GetLastInvoker ());
}
2017-07-16 18:16:48 +02:00
else if ( GameObject * goTarget = target -> ToGameObject ())
2017-06-03 10:21:06 +02:00
{
2017-07-16 18:16:48 +02:00
if ( IsSmartGO ( goTarget ))
ENSURE_AI ( SmartGameObjectAI , goTarget -> AI ()) -> SetScript9 ( e , id , GetLastInvoker ());
2010-12-07 18:31:34 +01:00
}
2010-11-07 22:10:11 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-19 20:23:08 +01:00
case SMART_ACTION_ACTIVATE_TAXI :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsPlayer ( target ))
target -> ToPlayer () -> ActivateTaxiPathTo ( e . action . taxi . id );
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-20 13:23:29 +01:00
case SMART_ACTION_RANDOM_MOVE :
2011-03-26 23:45:23 +01:00
{
2013-09-21 11:21:29 +02:00
bool foundTarget = false ;
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2010-11-20 13:23:29 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature (( target )))
2011-03-26 23:45:23 +01:00
{
2013-09-21 11:21:29 +02:00
foundTarget = true ;
2011-03-26 23:45:23 +01:00
if ( e . action . moveRandom . distance )
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> GetMotionMaster () -> MoveRandom ( float ( e . action . moveRandom . distance ));
2011-03-26 23:45:23 +01:00
else
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> GetMotionMaster () -> MoveIdle ();
2011-03-26 23:45:23 +01:00
}
2010-11-20 13:23:29 +01:00
}
2011-03-26 23:45:23 +01:00
2013-09-21 11:21:29 +02:00
if ( ! foundTarget && me && IsCreature ( me ))
{
if ( e . action . moveRandom . distance )
2017-06-03 10:21:06 +02:00
me -> GetMotionMaster () -> MoveRandom ( float ( e . action . moveRandom . distance ));
2013-09-21 11:21:29 +02:00
else
me -> GetMotionMaster () -> MoveIdle ();
}
2011-03-26 23:45:23 +01:00
break ;
}
2011-02-07 09:35:14 -07:00
case SMART_ACTION_SET_UNIT_FIELD_BYTES_1 :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsUnit ( target ))
2019-06-03 20:40:34 +02:00
{
switch ( e . action . setunitByte . type )
{
case 0 :
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> SetStandState ( UnitStandStateType ( e . action . setunitByte . byte1 ));
2019-06-03 20:40:34 +02:00
break ;
case 1 :
// pet talent points
break ;
case 2 :
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> AddVisFlags ( UnitVisFlags ( e . action . setunitByte . byte1 ));
2019-06-03 20:40:34 +02:00
break ;
case 3 :
// this is totally wrong to maintain compatibility with existing scripts
// TODO: fix with animtier overhaul
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> SetAnimTier ( UnitBytes1_Flags ( target -> ToUnit () -> m_unitData -> AnimTier | e . action . setunitByte . byte1 ), false );
2019-06-03 20:40:34 +02:00
break ;
}
}
2011-03-26 23:45:23 +01:00
break ;
}
2011-02-07 10:15:54 -07:00
case SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1 :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsUnit ( target ))
2019-06-03 20:40:34 +02:00
{
switch ( e . action . setunitByte . type )
{
case 0 :
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> SetStandState ( UNIT_STAND_STATE_STAND );
2019-06-03 20:40:34 +02:00
break ;
case 1 :
// pet talent points
break ;
case 2 :
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> RemoveVisFlags ( UnitVisFlags ( e . action . setunitByte . byte1 ));
2019-06-03 20:40:34 +02:00
break ;
case 3 :
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> SetAnimTier ( UnitBytes1_Flags ( target -> ToUnit () -> m_unitData -> AnimTier & ~ e . action . setunitByte . byte1 ), false );
2019-06-03 20:40:34 +02:00
break ;
}
}
2011-03-26 23:45:23 +01:00
break ;
}
2011-02-15 00:29:33 -03:00
case SMART_ACTION_INTERRUPT_SPELL :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsUnit ( target ))
target -> ToUnit () -> InterruptNonMeleeSpells ( e . action . interruptSpellCasting . withDelayed != 0 , e . action . interruptSpellCasting . spell_id , e . action . interruptSpellCasting . withInstant != 0 );
2011-03-26 23:45:23 +01:00
break ;
}
2011-03-02 16:50:09 +01:00
case SMART_ACTION_SEND_GO_CUSTOM_ANIM :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsGameObject ( target ))
target -> ToGameObject () -> SendCustomAnim ( e . action . sendGoCustomAnim . anim );
2011-03-26 23:45:23 +01:00
break ;
}
2011-06-12 17:50:23 +02:00
case SMART_ACTION_SET_DYNAMIC_FLAG :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
target -> SetDynamicFlags ( e . action . unitFlag . flag );
2011-06-12 17:50:23 +02:00
break ;
}
case SMART_ACTION_ADD_DYNAMIC_FLAG :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
target -> AddDynamicFlag ( e . action . unitFlag . flag );
2011-06-12 17:50:23 +02:00
break ;
}
case SMART_ACTION_REMOVE_DYNAMIC_FLAG :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
target -> RemoveDynamicFlag ( e . action . unitFlag . flag );
2011-06-12 17:50:23 +02:00
break ;
}
2011-07-02 07:52:03 +02:00
case SMART_ACTION_JUMP_TO_POS :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( Creature * creature = target -> ToCreature ())
creature -> GetMotionMaster () -> MoveJump ( e . target . x , e . target . y , e . target . z , 0.0f , float ( e . action . jump . speedxy ), float ( e . action . jump . speedz )); // @todo add optional jump orientation support?
2011-07-02 07:52:03 +02:00
break ;
}
2012-01-06 11:09:01 -05:00
case SMART_ACTION_GO_SET_LOOT_STATE :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsGameObject ( target ))
target -> ToGameObject () -> SetLootState (( LootState ) e . action . setGoLootState . state );
2012-01-06 11:09:01 -05:00
break ;
}
2016-12-27 19:00:57 +01:00
case SMART_ACTION_GO_SET_GO_STATE :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsGameObject ( target ))
target -> ToGameObject () -> SetGoState (( GOState ) e . action . goState . state );
2016-12-27 19:00:57 +01:00
break ;
}
2012-01-22 07:54:32 -05:00
case SMART_ACTION_SEND_TARGET_TO_TARGET :
{
2017-06-04 16:43:36 -03:00
WorldObject * ref = GetBaseObject ();
if ( ! ref )
ref = unit ;
if ( ! ref )
break ;
ObjectVector const * storedTargets = GetStoredTargetVector ( e . action . sendTargetToTarget . id , * ref );
2012-04-05 22:13:20 +02:00
if ( ! storedTargets )
2013-09-01 18:01:59 +01:00
break ;
2012-04-05 22:13:20 +02:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2012-01-22 07:54:32 -05:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
2012-01-22 16:56:55 +01:00
{
2017-06-03 10:21:06 +02:00
if ( SmartAI * ai = CAST_AI ( SmartAI , target -> ToCreature () -> AI ()))
ai -> GetScript () -> StoreTargetList ( ObjectVector ( * storedTargets ), e . action . sendTargetToTarget . id ); // store a copy of target list
2012-01-22 16:56:55 +01:00
else
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartAI, skipping" );
2012-01-22 16:56:55 +01:00
}
2017-06-03 10:21:06 +02:00
else if ( IsGameObject ( target ))
2012-01-22 16:56:55 +01:00
{
2017-06-03 10:21:06 +02:00
if ( SmartGameObjectAI * ai = CAST_AI ( SmartGameObjectAI , target -> ToGameObject () -> AI ()))
ai -> GetScript () -> StoreTargetList ( ObjectVector ( * storedTargets ), e . action . sendTargetToTarget . id ); // store a copy of target list
2012-01-22 16:56:55 +01:00
else
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartGameObjectAI, skipping" );
2012-01-22 16:56:55 +01:00
}
2012-01-22 07:54:32 -05:00
}
break ;
}
2011-10-23 12:55:17 +01:00
case SMART_ACTION_SEND_GOSSIP_MENU :
{
2017-05-27 03:56:09 -03:00
if ( ! GetBaseObject () || ! IsSmart ())
2012-01-22 20:36:01 -05:00
break ;
2011-10-31 02:01:17 +01:00
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId %d, gossipNpcTextId %d" ,
2011-12-06 12:37:05 +01:00
e . action . sendGossipMenu . gossipMenuId , e . action . sendGossipMenu . gossipNpcTextId );
2011-10-23 12:55:17 +01:00
2017-05-27 03:56:09 -03:00
// override default gossip
if ( me )
ENSURE_AI ( SmartAI , me -> AI ()) -> SetGossipReturn ( true );
else if ( go )
ENSURE_AI ( SmartGameObjectAI , go -> AI ()) -> SetGossipReturn ( true );
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2013-09-01 13:56:35 +02:00
{
2017-06-03 10:21:06 +02:00
if ( Player * player = target -> ToPlayer ())
2011-10-23 12:55:17 +01:00
{
if ( e . action . sendGossipMenu . gossipMenuId )
player -> PrepareGossipMenu ( GetBaseObject (), e . action . sendGossipMenu . gossipMenuId , true );
else
2017-05-28 16:34:44 +02:00
player -> PlayerTalkClass -> ClearMenus ();
2011-10-23 12:55:17 +01:00
2017-05-28 16:34:44 +02:00
player -> PlayerTalkClass -> SendGossipMenu ( e . action . sendGossipMenu . gossipNpcTextId , GetBaseObject () -> GetGUID ());
2011-10-23 12:55:17 +01:00
}
2013-09-01 13:56:35 +02:00
}
2011-10-23 12:55:17 +01:00
break ;
}
2012-09-08 00:55:47 +01:00
case SMART_ACTION_SET_HOME_POS :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2013-09-01 13:56:35 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
2013-02-02 19:06:47 +01:00
{
if ( e . GetTargetType () == SMART_TARGET_SELF )
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetHomePosition ( me -> GetPositionX (), me -> GetPositionY (), me -> GetPositionZ (), me -> GetOrientation ());
2013-02-02 19:06:47 +01:00
else if ( e . GetTargetType () == SMART_TARGET_POSITION )
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetHomePosition ( e . target . x , e . target . y , e . target . z , e . target . o );
2013-09-01 13:56:35 +02:00
else if ( e . GetTargetType () == SMART_TARGET_CREATURE_RANGE || e . GetTargetType () == SMART_TARGET_CREATURE_GUID ||
e . GetTargetType () == SMART_TARGET_CREATURE_DISTANCE || e . GetTargetType () == SMART_TARGET_GAMEOBJECT_RANGE ||
e . GetTargetType () == SMART_TARGET_GAMEOBJECT_GUID || e . GetTargetType () == SMART_TARGET_GAMEOBJECT_DISTANCE ||
e . GetTargetType () == SMART_TARGET_CLOSEST_CREATURE || e . GetTargetType () == SMART_TARGET_CLOSEST_GAMEOBJECT ||
e . GetTargetType () == SMART_TARGET_OWNER_OR_SUMMONER || e . GetTargetType () == SMART_TARGET_ACTION_INVOKER ||
e . GetTargetType () == SMART_TARGET_CLOSEST_ENEMY || e . GetTargetType () == SMART_TARGET_CLOSEST_FRIENDLY )
{
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetHomePosition ( target -> GetPositionX (), target -> GetPositionY (), target -> GetPositionZ (), target -> GetOrientation ());
2013-09-01 13:56:35 +02:00
}
2013-02-02 19:06:47 +01:00
else
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is invalid, skipping" );
2013-02-02 19:06:47 +01:00
}
2013-09-01 13:56:35 +02:00
}
2013-02-02 19:06:47 +01:00
break ;
2012-09-08 00:55:47 +01:00
}
2012-09-17 13:56:12 -04:00
case SMART_ACTION_SET_HEALTH_REGEN :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsCreature ( target ))
2017-08-21 20:28:18 +02:00
target -> ToCreature () -> SetRegenerateHealth ( e . action . setHealthRegen . regenHealth != 0 );
2012-09-17 21:17:48 +02:00
break ;
2012-09-17 13:56:12 -04:00
}
2013-02-02 18:18:27 +01:00
case SMART_ACTION_SET_ROOT :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsCreature ( target ))
target -> ToCreature () -> SetControlled ( e . action . setRoot . root != 0 , UNIT_STATE_ROOT );
2013-02-02 18:18:27 +01:00
break ;
}
2013-02-16 18:41:55 +00:00
case SMART_ACTION_SET_GO_FLAG :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsGameObject ( target ))
target -> ToGameObject () -> SetFlags ( GameObjectFlags ( e . action . goFlag . flag ));
2013-02-16 18:41:55 +00:00
break ;
}
case SMART_ACTION_ADD_GO_FLAG :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsGameObject ( target ))
target -> ToGameObject () -> AddFlag ( GameObjectFlags ( e . action . goFlag . flag ));
2013-02-16 18:41:55 +00:00
break ;
}
case SMART_ACTION_REMOVE_GO_FLAG :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsGameObject ( target ))
target -> ToGameObject () -> RemoveFlag ( GameObjectFlags ( e . action . goFlag . flag ));
2013-02-16 18:41:55 +00:00
break ;
}
2013-03-09 02:03:37 +01:00
case SMART_ACTION_SUMMON_CREATURE_GROUP :
{
std :: list < TempSummon *> summonList ;
GetBaseObject () -> SummonCreatureGroup ( e . action . creatureGroup . group , & summonList );
2017-06-03 10:21:06 +02:00
for ( TempSummon * summon : summonList )
2013-03-09 02:03:37 +01:00
if ( unit && e . action . creatureGroup . attackInvoker )
2017-06-03 10:21:06 +02:00
summon -> AI () -> AttackStart ( unit );
2013-03-09 02:03:37 +01:00
break ;
}
2013-08-10 14:13:17 +02:00
case SMART_ACTION_SET_POWER :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsUnit ( target ))
target -> ToUnit () -> SetPower ( Powers ( e . action . power . powerType ), e . action . power . newPower );
2013-08-10 14:13:17 +02:00
break ;
}
case SMART_ACTION_ADD_POWER :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsUnit ( target ))
target -> ToUnit () -> SetPower ( Powers ( e . action . power . powerType ), target -> ToUnit () -> GetPower ( Powers ( e . action . power . powerType )) + e . action . power . newPower );
2013-08-10 14:13:17 +02:00
break ;
}
case SMART_ACTION_REMOVE_POWER :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
if ( IsUnit ( target ))
target -> ToUnit () -> SetPower ( Powers ( e . action . power . powerType ), target -> ToUnit () -> GetPower ( Powers ( e . action . power . powerType )) - e . action . power . newPower );
2013-08-10 14:13:17 +02:00
break ;
}
2013-08-30 01:16:12 +02:00
case SMART_ACTION_GAME_EVENT_STOP :
{
uint32 eventId = e . action . gameEventStop . id ;
if ( ! sGameEventMgr -> IsActiveEvent ( eventId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_STOP, inactive event (id: %u)" , eventId );
2013-09-01 18:01:59 +01:00
break ;
2013-08-30 01:16:12 +02:00
}
sGameEventMgr -> StopEvent ( eventId , true );
break ;
}
case SMART_ACTION_GAME_EVENT_START :
{
uint32 eventId = e . action . gameEventStart . id ;
if ( sGameEventMgr -> IsActiveEvent ( eventId ))
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_START, already activated event (id: %u)" , eventId );
2013-09-01 18:01:59 +01:00
break ;
2013-08-30 01:16:12 +02:00
}
sGameEventMgr -> StartEvent ( eventId , true );
break ;
}
2016-11-25 00:31:10 +01:00
case SMART_ACTION_START_CLOSEST_WAYPOINT :
{
2017-06-03 10:21:06 +02:00
std :: vector < uint32 > waypoints ;
2020-06-25 12:15:21 +02:00
std :: copy_if ( std :: begin ( e . action . closestWaypointFromList . wps ), std :: end ( e . action . closestWaypointFromList . wps ),
2017-06-03 10:21:06 +02:00
std :: back_inserter ( waypoints ), []( uint32 wp ) { return wp != 0 ; });
2016-11-25 00:31:10 +01:00
float distanceToClosest = std :: numeric_limits < float >:: max ();
2017-08-12 01:40:25 +02:00
std :: pair < uint32 , uint32 > closest = { 0 , 0 };
2016-11-25 00:31:10 +01:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * target : targets )
2016-11-25 00:31:10 +01:00
{
2017-06-03 10:21:06 +02:00
if ( Creature * creature = target -> ToCreature ())
2016-11-25 00:31:10 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsSmart ( creature ))
2016-11-25 00:31:10 +01:00
{
2017-08-12 01:40:25 +02:00
for ( uint32 pathId : waypoints )
2016-11-25 00:31:10 +01:00
{
2017-08-12 01:40:25 +02:00
WaypointPath const * path = sSmartWaypointMgr -> GetPath ( pathId );
if ( ! path || path -> nodes . empty ())
2017-06-03 10:21:06 +02:00
continue ;
2016-11-25 00:31:10 +01:00
2017-08-12 01:40:25 +02:00
for ( auto itr = path -> nodes . begin (); itr != path -> nodes . end (); ++ itr )
2017-06-03 10:21:06 +02:00
{
2017-08-12 01:40:25 +02:00
WaypointNode const waypoint = * itr ;
float distamceToThisNode = creature -> GetDistance ( waypoint . x , waypoint . y , waypoint . z );
if ( distamceToThisNode < distanceToClosest )
2016-11-25 00:31:10 +01:00
{
2017-08-12 01:40:25 +02:00
distanceToClosest = distamceToThisNode ;
closest . first = pathId ;
closest . second = waypoint . id ;
2016-11-25 00:31:10 +01:00
}
}
}
2017-06-03 10:21:06 +02:00
2017-08-12 01:40:25 +02:00
if ( closest . first != 0 )
CAST_AI ( SmartAI , creature -> AI ()) -> StartPath ( false , closest . first , true , nullptr , closest . second );
2016-11-25 00:31:10 +01:00
}
}
}
break ;
}
2016-01-26 03:26:41 +00:00
case SMART_ACTION_RANDOM_SOUND :
{
std :: vector < uint32 > sounds ;
2017-05-18 23:52:58 +02:00
std :: copy_if ( std :: begin ( e . action . randomSound . sounds ), std :: end ( e . action . randomSound . sounds ),
2016-01-26 03:37:07 +00:00
std :: back_inserter ( sounds ), []( uint32 sound ) { return sound != 0 ; });
2016-01-26 03:26:41 +00:00
bool onlySelf = e . action . randomSound . onlySelf != 0 ;
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
2016-01-26 03:26:41 +00:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2016-01-26 03:26:41 +00:00
{
2017-06-03 10:21:06 +02:00
uint32 sound = Trinity :: Containers :: SelectRandomContainerElement ( sounds );
target -> PlayDirectSound ( sound , onlySelf ? target -> ToPlayer () : nullptr );
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_SOUND: target: %s (%s), sound: %u, onlyself: %s" ,
target -> GetName (). c_str (), target -> GetGUID (). ToString (). c_str (), sound , onlySelf ? "true" : "false" );
2016-01-26 03:26:41 +00:00
}
}
2017-06-03 10:21:06 +02:00
break ;
2016-01-26 03:26:41 +00:00
}
2020-05-21 22:15:58 +02:00
/* fallthrough */
2016-03-03 23:16:59 +01:00
case SMART_ACTION_SET_CORPSE_DELAY :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
2016-03-03 23:16:59 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
target -> ToCreature () -> SetCorpseDelay ( e . action . corpseDelay . timer );
2016-03-03 23:16:59 +01:00
}
2017-05-07 21:48:41 +01:00
break ;
}
case SMART_ACTION_SPAWN_SPAWNGROUP :
{
if ( e . action . groupSpawn . minDelay == 0 && e . action . groupSpawn . maxDelay == 0 )
{
bool const ignoreRespawn = (( e . action . groupSpawn . spawnflags & SMARTAI_SPAWN_FLAGS :: SMARTAI_SPAWN_FLAG_IGNORE_RESPAWN ) != 0 );
bool const force = (( e . action . groupSpawn . spawnflags & SMARTAI_SPAWN_FLAGS :: SMARTAI_SPAWN_FLAG_FORCE_SPAWN ) != 0 );
// Instant spawn
2017-08-26 13:14:25 +02:00
GetBaseObject () -> GetMap () -> SpawnGroupSpawn ( e . action . groupSpawn . groupId , ignoreRespawn , force );
2017-05-07 21:48:41 +01:00
}
else
{
// Delayed spawn (use values from parameter to schedule event to call us back
SmartEvent ne = SmartEvent ();
ne . type = ( SMART_EVENT ) SMART_EVENT_UPDATE ;
ne . event_chance = 100 ;
ne . minMaxRepeat . min = e . action . groupSpawn . minDelay ;
ne . minMaxRepeat . max = e . action . groupSpawn . maxDelay ;
ne . minMaxRepeat . repeatMin = 0 ;
ne . minMaxRepeat . repeatMax = 0 ;
ne . event_flags = 0 ;
ne . event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE ;
SmartAction ac = SmartAction ();
ac . type = ( SMART_ACTION ) SMART_ACTION_SPAWN_SPAWNGROUP ;
ac . groupSpawn . groupId = e . action . groupSpawn . groupId ;
ac . groupSpawn . minDelay = 0 ;
ac . groupSpawn . maxDelay = 0 ;
ac . groupSpawn . spawnflags = e . action . groupSpawn . spawnflags ;
ac . timeEvent . id = e . action . timeEvent . id ;
SmartScriptHolder ev = SmartScriptHolder ();
ev . event = ne ;
ev . event_id = e . event_id ;
ev . target = e . target ;
ev . action = ac ;
InitTimer ( ev );
mStoredEvents . push_back ( ev );
}
break ;
}
case SMART_ACTION_DESPAWN_SPAWNGROUP :
{
if ( e . action . groupSpawn . minDelay == 0 && e . action . groupSpawn . maxDelay == 0 )
{
bool const deleteRespawnTimes = (( e . action . groupSpawn . spawnflags & SMARTAI_SPAWN_FLAGS :: SMARTAI_SPAWN_FLAG_NOSAVE_RESPAWN ) != 0 );
// Instant spawn
2017-08-26 13:14:25 +02:00
GetBaseObject () -> GetMap () -> SpawnGroupDespawn ( e . action . groupSpawn . groupId , deleteRespawnTimes );
2017-05-07 21:48:41 +01:00
}
else
{
// Delayed spawn (use values from parameter to schedule event to call us back
SmartEvent ne = SmartEvent ();
ne . type = ( SMART_EVENT ) SMART_EVENT_UPDATE ;
ne . event_chance = 100 ;
ne . minMaxRepeat . min = e . action . groupSpawn . minDelay ;
ne . minMaxRepeat . max = e . action . groupSpawn . maxDelay ;
ne . minMaxRepeat . repeatMin = 0 ;
ne . minMaxRepeat . repeatMax = 0 ;
ne . event_flags = 0 ;
ne . event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE ;
SmartAction ac = SmartAction ();
ac . type = ( SMART_ACTION ) SMART_ACTION_DESPAWN_SPAWNGROUP ;
ac . groupSpawn . groupId = e . action . groupSpawn . groupId ;
ac . groupSpawn . minDelay = 0 ;
ac . groupSpawn . maxDelay = 0 ;
ac . groupSpawn . spawnflags = e . action . groupSpawn . spawnflags ;
ac . timeEvent . id = e . action . timeEvent . id ;
SmartScriptHolder ev = SmartScriptHolder ();
ev . event = ne ;
ev . event_id = e . event_id ;
ev . target = e . target ;
ev . action = ac ;
InitTimer ( ev );
mStoredEvents . push_back ( ev );
}
2016-03-03 23:16:59 +01:00
break ;
}
2016-08-19 14:53:53 +02:00
case SMART_ACTION_DISABLE_EVADE :
{
if ( ! IsSmart ())
break ;
ENSURE_AI ( SmartAI , me -> AI ()) -> SetEvadeDisabled ( e . action . disableEvade . disable != 0 );
break ;
}
2017-02-17 21:33:18 +01:00
case SMART_ACTION_REMOVE_AURAS_BY_TYPE : // can be used to exit vehicle for example
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
if ( IsUnit ( target ))
target -> ToUnit () -> RemoveAurasByType (( AuraType ) e . action . auraType . type );
2017-02-17 21:33:18 +01:00
break ;
}
case SMART_ACTION_SET_SIGHT_DIST :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
if ( IsCreature ( target ))
target -> ToCreature () -> m_SightDistance = e . action . sightDistance . dist ;
2017-02-17 21:33:18 +01:00
break ;
}
case SMART_ACTION_FLEE :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
if ( IsCreature ( target ))
target -> ToCreature () -> GetMotionMaster () -> MoveFleeing ( me , e . action . flee . fleeTime );
2017-02-17 21:33:18 +01:00
break ;
}
case SMART_ACTION_ADD_THREAT :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
if ( IsUnit ( target ))
2017-07-01 20:18:02 +02:00
me -> GetThreatManager (). AddThreat ( target -> ToUnit (), float ( e . action . threatPCT . threatINC ) - float ( e . action . threatPCT . threatDEC ), nullptr , true , true );
2017-02-17 21:33:18 +01:00
break ;
}
case SMART_ACTION_LOAD_EQUIPMENT :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
if ( IsCreature ( target ))
target -> ToCreature () -> LoadEquipment ( e . action . loadEquipment . id , e . action . loadEquipment . force != 0 );
2017-02-17 21:33:18 +01:00
break ;
}
case SMART_ACTION_TRIGGER_RANDOM_TIMED_EVENT :
{
uint32 eventId = urand ( e . action . randomTimedEvent . minId , e . action . randomTimedEvent . maxId );
2020-08-14 17:06:03 +02:00
ProcessEventsFor (( SMART_EVENT ) SMART_EVENT_TIMED_EVENT_TRIGGERED , nullptr , eventId );
2017-02-17 21:33:18 +01:00
break ;
}
case SMART_ACTION_REMOVE_ALL_GAMEOBJECTS :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
if ( IsUnit ( target ))
target -> ToUnit () -> RemoveAllGameObjects ();
2017-02-17 21:33:18 +01:00
break ;
}
case SMART_ACTION_STOP_MOTION :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
{
if ( IsUnit ( target ))
2017-02-17 21:33:18 +01:00
{
if ( e . action . stopMotion . stopMovement )
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> StopMoving ();
2017-02-17 21:33:18 +01:00
if ( e . action . stopMotion . movementExpired )
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> GetMotionMaster () -> MovementExpired ();
2017-02-17 21:33:18 +01:00
}
2017-06-03 10:21:06 +02:00
}
2017-02-17 21:33:18 +01:00
break ;
}
2017-03-11 13:39:38 +01:00
case SMART_ACTION_PLAY_ANIMKIT :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
2017-03-11 13:39:38 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsCreature ( target ))
2017-03-11 13:39:38 +01:00
{
if ( e . action . animKit . type == 0 )
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> PlayOneShotAnimKitId ( e . action . animKit . animKit );
2017-03-11 13:39:38 +01:00
else if ( e . action . animKit . type == 1 )
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetAIAnimKitId ( e . action . animKit . animKit );
2017-03-11 13:39:38 +01:00
else if ( e . action . animKit . type == 2 )
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetMeleeAnimKitId ( e . action . animKit . animKit );
2017-03-11 13:39:38 +01:00
else if ( e . action . animKit . type == 3 )
2017-06-03 10:21:06 +02:00
target -> ToCreature () -> SetMovementAnimKitId ( e . action . animKit . animKit );
2017-03-11 13:39:38 +01:00
else
{
TC_LOG_ERROR ( "sql.sql" , "SmartScript: Invalid type for SMART_ACTION_PLAY_ANIMKIT, skipping" );
break ;
}
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_PLAY_ANIMKIT: target: %s (%s), AnimKit: %u, Type: %u" ,
2017-06-03 10:21:06 +02:00
target -> GetName (). c_str (), target -> GetGUID (). ToString (). c_str (), e . action . animKit . animKit , e . action . animKit . type );
2017-03-11 13:39:38 +01:00
}
}
break ;
}
2017-03-17 21:21:35 +01:00
case SMART_ACTION_SCENE_PLAY :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
2017-03-17 21:21:35 +01:00
if ( Player * playerTarget = target -> ToPlayer ())
playerTarget -> GetSceneMgr (). PlayScene ( e . action . scene . sceneId );
break ;
}
case SMART_ACTION_SCENE_CANCEL :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
2017-03-17 21:21:35 +01:00
if ( Player * playerTarget = target -> ToPlayer ())
playerTarget -> GetSceneMgr (). CancelSceneBySceneId ( e . action . scene . sceneId );
break ;
}
2018-01-30 11:31:52 +01:00
case SMART_ACTION_SET_MOVEMENT_SPEED :
{
uint32 speedInteger = e . action . movementSpeed . speedInteger ;
uint32 speedFraction = e . action . movementSpeed . speedFraction ;
float speed = float ( speedInteger ) + float ( speedFraction ) / std :: pow ( 10 , std :: floor ( std :: log10 ( float ( speedFraction ? speedFraction : 1 )) + 1 ));
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
2018-01-30 11:31:52 +01:00
if ( IsCreature ( target ))
me -> SetSpeed ( UnitMoveType ( e . action . movementSpeed . movementType ), speed );
break ;
}
2019-09-01 15:51:01 +02:00
case SMART_ACTION_PLAY_SPELL_VISUAL_KIT :
{
2017-06-03 10:21:06 +02:00
for ( WorldObject * const target : targets )
2019-09-01 15:51:01 +02:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ))
2019-09-01 15:51:01 +02:00
{
2017-06-03 10:21:06 +02:00
target -> ToUnit () -> SendPlaySpellVisualKit ( e . action . spellVisualKit . spellVisualKitId , e . action . spellVisualKit . kitType ,
2019-09-01 15:51:01 +02:00
e . action . spellVisualKit . duration );
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::ProcessAction:: SMART_ACTION_PLAY_SPELL_VISUAL_KIT: target: %s (%s), SpellVisualKit: %u" ,
2017-06-03 10:21:06 +02:00
target -> GetName (). c_str (), target -> GetGUID (). ToString (). c_str (), e . action . spellVisualKit . spellVisualKitId );
2019-09-01 15:51:01 +02:00
}
}
break ;
}
2010-10-27 21:01:47 +02:00
default :
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript::ProcessAction: Entry " SI64FMTD " SourceType %u, Event %u, Unhandled Action type %u" , e . entryOrGuid , e . GetScriptType (), e . event_id , e . GetActionType ());
2010-10-27 21:01:47 +02:00
break ;
}
2012-01-22 20:36:01 -05:00
if ( e . link && e . link != e . event_id )
{
2014-10-11 18:52:01 +02:00
SmartScriptHolder & linked = SmartAIMgr :: FindLinkedEvent ( mEvents , e . link );
if ( linked )
2017-03-17 21:21:35 +01:00
ProcessEvent ( linked , unit , var0 , var1 , bvar , spell , gob , varString );
2012-01-22 20:36:01 -05:00
else
2014-12-28 10:20:23 +01:00
TC_LOG_DEBUG ( "sql.sql" , "SmartScript::ProcessAction: Entry " SI64FMTD " SourceType %u, Event %u, Link Event %u not found or invalid, skipped." , e . entryOrGuid , e . GetScriptType (), e . event_id , e . link );
2012-01-22 20:36:01 -05:00
}
2010-10-27 21:01:47 +02:00
}
2020-09-04 13:38:24 +02:00
void SmartScript :: ProcessTimedAction ( SmartScriptHolder & e , uint32 const & min , uint32 const & max , Unit * unit , uint32 var0 , uint32 var1 , bool bvar , SpellInfo const * spell , GameObject * gob , std :: string const & varString )
2013-01-17 14:04:20 +01:00
{
2017-02-17 21:33:18 +01:00
// We may want to execute action rarely and because of this if condition is not fulfilled the action will be rechecked in a long time
2015-10-25 13:20:28 +01:00
if ( sConditionMgr -> IsObjectMeetingSmartEventConditions ( e . entryOrGuid , e . event_id , e . source_type , unit , GetBaseObject ()))
2017-02-17 21:33:18 +01:00
{
RecalcTimer ( e , min , max );
2017-06-06 22:24:10 +02:00
ProcessAction ( e , unit , var0 , var1 , bvar , spell , gob , varString );
2017-02-17 21:33:18 +01:00
}
else
RecalcTimer ( e , std :: min < uint32 > ( min , 5000 ), std :: min < uint32 > ( min , 5000 ));
2013-01-17 14:04:20 +01:00
}
2011-05-12 10:40:53 +02:00
void SmartScript :: InstallTemplate ( SmartScriptHolder const & e )
2010-10-27 21:01:47 +02:00
{
if ( ! GetBaseObject ())
return ;
2017-06-03 10:21:06 +02:00
if ( mTemplate != SMARTAI_TEMPLATE_BASIC )
2010-10-27 21:01:47 +02:00
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript::InstallTemplate: Entry " SI64FMTD " SourceType %u AI Template can not be set more then once, skipped." , e . entryOrGuid , e . GetScriptType ());
2010-10-27 21:01:47 +02:00
return ;
}
2017-06-03 10:21:06 +02:00
2010-10-27 21:01:47 +02:00
mTemplate = ( SMARTAI_TEMPLATE ) e . action . installTtemplate . id ;
switch (( SMARTAI_TEMPLATE ) e . action . installTtemplate . id )
{
case SMARTAI_TEMPLATE_CASTER :
{
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_UPDATE_IC , 0 , 0 , 0 , e . action . installTtemplate . param2 , e . action . installTtemplate . param3 , 0 , SMART_ACTION_CAST , e . action . installTtemplate . param1 , e . target . raw . param1 , 0 , 0 , 0 , 0 , SMART_TARGET_VICTIM , 0 , 0 , 0 , 1 );
AddEvent ( SMART_EVENT_RANGE , 0 , e . action . installTtemplate . param4 , 300 , 0 , 0 , 0 , SMART_ACTION_ALLOW_COMBAT_MOVEMENT , 1 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 1 );
AddEvent ( SMART_EVENT_RANGE , 0 , 0 , e . action . installTtemplate . param4 > 10 ? e . action . installTtemplate . param4 - 10 : 0 , 0 , 0 , 0 , SMART_ACTION_ALLOW_COMBAT_MOVEMENT , 0 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 1 );
AddEvent ( SMART_EVENT_MANA_PCT , 0 , e . action . installTtemplate . param5 - 15 > 100 ? 100 : e . action . installTtemplate . param5 + 15 , 100 , 1000 , 1000 , 0 , SMART_ACTION_SET_EVENT_PHASE , 1 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 0 );
AddEvent ( SMART_EVENT_MANA_PCT , 0 , 0 , e . action . installTtemplate . param5 , 1000 , 1000 , 0 , SMART_ACTION_SET_EVENT_PHASE , 0 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 0 );
AddEvent ( SMART_EVENT_MANA_PCT , 0 , 0 , e . action . installTtemplate . param5 , 1000 , 1000 , 0 , SMART_ACTION_ALLOW_COMBAT_MOVEMENT , 1 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 0 );
2010-10-27 21:01:47 +02:00
break ;
}
case SMARTAI_TEMPLATE_TURRET :
{
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_UPDATE_IC , 0 , 0 , 0 , e . action . installTtemplate . param2 , e . action . installTtemplate . param3 , 0 , SMART_ACTION_CAST , e . action . installTtemplate . param1 , e . target . raw . param1 , 0 , 0 , 0 , 0 , SMART_TARGET_VICTIM , 0 , 0 , 0 , 0 );
AddEvent ( SMART_EVENT_JUST_CREATED , 0 , 0 , 0 , 0 , 0 , 0 , SMART_ACTION_ALLOW_COMBAT_MOVEMENT , 0 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 0 );
2010-10-27 21:01:47 +02:00
break ;
}
case SMARTAI_TEMPLATE_CAGED_NPC_PART :
{
2012-03-28 20:00:29 +08:00
if ( ! me )
return ;
2010-10-27 21:01:47 +02:00
//store cage as id1
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_DATA_SET , 0 , 0 , 0 , 0 , 0 , 0 , SMART_ACTION_STORE_TARGET_LIST , 1 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_CLOSEST_GAMEOBJECT , e . action . installTtemplate . param1 , 10 , 0 , 0 );
2010-10-27 21:01:47 +02:00
//reset(close) cage on hostage(me) respawn
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_UPDATE , SMART_EVENT_FLAG_NOT_REPEATABLE , 0 , 0 , 0 , 0 , 0 , SMART_ACTION_RESET_GOBJECT , 0 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_GAMEOBJECT_DISTANCE , e . action . installTtemplate . param1 , 5 , 0 , 0 );
2010-12-13 22:37:56 +01:00
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_DATA_SET , 0 , 0 , 0 , 0 , 0 , 0 , SMART_ACTION_SET_RUN , e . action . installTtemplate . param3 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 0 );
AddEvent ( SMART_EVENT_DATA_SET , 0 , 0 , 0 , 0 , 0 , 0 , SMART_ACTION_SET_EVENT_PHASE , 1 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 0 );
2010-10-27 21:01:47 +02:00
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_UPDATE , SMART_EVENT_FLAG_NOT_REPEATABLE , 1000 , 1000 , 0 , 0 , 0 , SMART_ACTION_MOVE_OFFSET , 0 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_SELF , 0 , e . action . installTtemplate . param4 , 0 , 1 );
2010-10-27 21:01:47 +02:00
//phase 1: give quest credit on movepoint reached
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_MOVEMENTINFORM , 0 , POINT_MOTION_TYPE , SMART_RANDOM_POINT , 0 , 0 , 0 , SMART_ACTION_SET_DATA , 0 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_STORED , 1 , 0 , 0 , 1 );
2010-10-27 21:01:47 +02:00
//phase 1: despawn after time on movepoint reached
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_MOVEMENTINFORM , 0 , POINT_MOTION_TYPE , SMART_RANDOM_POINT , 0 , 0 , 0 , SMART_ACTION_FORCE_DESPAWN , e . action . installTtemplate . param2 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 1 );
2010-10-27 21:01:47 +02:00
2010-12-22 21:25:23 +01:00
if ( sCreatureTextMgr -> TextExist ( me -> GetEntry (), ( uint8 ) e . action . installTtemplate . param5 ))
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_MOVEMENTINFORM , 0 , POINT_MOTION_TYPE , SMART_RANDOM_POINT , 0 , 0 , 0 , SMART_ACTION_TALK , e . action . installTtemplate . param5 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 1 );
2010-10-27 21:01:47 +02:00
break ;
}
case SMARTAI_TEMPLATE_CAGED_GO_PART :
{
2012-03-28 20:00:29 +08:00
if ( ! go )
return ;
2010-10-27 21:01:47 +02:00
//store hostage as id1
2017-05-01 18:19:36 -03:00
AddEvent ( SMART_EVENT_GO_LOOT_STATE_CHANGED , 0 , GO_ACTIVATED , 0 , 0 , 0 , 0 , SMART_ACTION_STORE_TARGET_LIST , 1 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_CLOSEST_CREATURE , e . action . installTtemplate . param1 , 10 , 0 , 0 );
2010-10-27 21:01:47 +02:00
//store invoker as id2
2017-05-01 18:19:36 -03:00
AddEvent ( SMART_EVENT_GO_LOOT_STATE_CHANGED , 0 , GO_ACTIVATED , 0 , 0 , 0 , 0 , SMART_ACTION_STORE_TARGET_LIST , 2 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_NONE , 0 , 0 , 0 , 0 );
2010-10-27 21:01:47 +02:00
//signal hostage
2017-05-01 18:19:36 -03:00
AddEvent ( SMART_EVENT_GO_LOOT_STATE_CHANGED , 0 , GO_ACTIVATED , 0 , 0 , 0 , 0 , SMART_ACTION_SET_DATA , 0 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_STORED , 1 , 0 , 0 , 0 );
2010-10-27 21:01:47 +02:00
//when hostage raeched end point, give credit to invoker
if ( e . action . installTtemplate . param2 )
2019-04-30 13:03:49 +02:00
AddEvent ( SMART_EVENT_DATA_SET , 0 , 0 , 0 , 0 , 0 , 0 , SMART_ACTION_CALL_KILLEDMONSTER , e . action . installTtemplate . param1 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_STORED , 2 , 0 , 0 , 0 );
2010-10-27 21:01:47 +02:00
else
2017-05-01 18:19:36 -03:00
AddEvent ( SMART_EVENT_GO_LOOT_STATE_CHANGED , 0 , GO_ACTIVATED , 0 , 0 , 0 , 0 , SMART_ACTION_CALL_KILLEDMONSTER , e . action . installTtemplate . param1 , 0 , 0 , 0 , 0 , 0 , SMART_TARGET_STORED , 2 , 0 , 0 , 0 );
2010-10-27 21:01:47 +02:00
break ;
}
case SMARTAI_TEMPLATE_BASIC :
default :
return ;
}
}
2019-04-30 13:03:49 +02:00
void SmartScript :: AddEvent ( SMART_EVENT e , uint32 event_flags , uint32 event_param1 , uint32 event_param2 , uint32 event_param3 , uint32 event_param4 , uint32 event_param5 , SMART_ACTION action , uint32 action_param1 , uint32 action_param2 , uint32 action_param3 , uint32 action_param4 , uint32 action_param5 , uint32 action_param6 , SMARTAI_TARGETS t , uint32 target_param1 , uint32 target_param2 , uint32 target_param3 , uint32 phaseMask )
2010-10-27 21:01:47 +02:00
{
2019-04-30 13:03:49 +02:00
mInstallEvents . push_back ( CreateSmartEvent ( e , event_flags , event_param1 , event_param2 , event_param3 , event_param4 , event_param5 , action , action_param1 , action_param2 , action_param3 , action_param4 , action_param5 , action_param6 , t , target_param1 , target_param2 , target_param3 , phaseMask ));
2010-10-27 21:01:47 +02:00
}
2019-04-30 13:03:49 +02:00
SmartScriptHolder SmartScript :: CreateSmartEvent ( SMART_EVENT e , uint32 event_flags , uint32 event_param1 , uint32 event_param2 , uint32 event_param3 , uint32 event_param4 , uint32 event_param5 , SMART_ACTION action , uint32 action_param1 , uint32 action_param2 , uint32 action_param3 , uint32 action_param4 , uint32 action_param5 , uint32 action_param6 , SMARTAI_TARGETS t , uint32 target_param1 , uint32 target_param2 , uint32 target_param3 , uint32 phaseMask )
2010-10-27 21:01:47 +02:00
{
SmartScriptHolder script ;
script . event . type = e ;
script . event . raw . param1 = event_param1 ;
script . event . raw . param2 = event_param2 ;
script . event . raw . param3 = event_param3 ;
script . event . raw . param4 = event_param4 ;
2019-04-30 13:03:49 +02:00
script . event . raw . param5 = event_param5 ;
2010-10-27 21:01:47 +02:00
script . event . event_phase_mask = phaseMask ;
script . event . event_flags = event_flags ;
2013-08-26 16:12:51 +01:00
script . event . event_chance = 100 ;
2010-10-27 21:01:47 +02:00
script . action . type = action ;
script . action . raw . param1 = action_param1 ;
script . action . raw . param2 = action_param2 ;
script . action . raw . param3 = action_param3 ;
script . action . raw . param4 = action_param4 ;
script . action . raw . param5 = action_param5 ;
script . action . raw . param6 = action_param6 ;
script . target . type = t ;
script . target . raw . param1 = target_param1 ;
script . target . raw . param2 = target_param2 ;
script . target . raw . param3 = target_param3 ;
script . source_type = SMART_SCRIPT_TYPE_CREATURE ;
InitTimer ( script );
return script ;
}
2017-06-03 10:21:06 +02:00
void SmartScript :: GetTargets ( ObjectVector & targets , SmartScriptHolder const & e , Unit * invoker /*= nullptr*/ ) const
2010-10-27 21:01:47 +02:00
{
2016-08-05 12:41:56 +02:00
Unit * scriptTrigger = nullptr ;
2010-11-04 19:56:39 +01:00
if ( invoker )
2013-01-16 08:59:56 +01:00
scriptTrigger = invoker ;
2011-02-21 22:23:43 +01:00
else if ( Unit * tempLastInvoker = GetLastInvoker ())
2013-01-16 08:59:56 +01:00
scriptTrigger = tempLastInvoker ;
WorldObject * baseObject = GetBaseObject ();
2010-10-27 21:01:47 +02:00
switch ( e . GetTargetType ())
{
case SMART_TARGET_SELF :
2013-01-16 08:59:56 +01:00
if ( baseObject )
2017-06-03 10:21:06 +02:00
targets . push_back ( baseObject );
2010-10-27 21:01:47 +02:00
break ;
case SMART_TARGET_VICTIM :
2013-09-21 11:21:29 +02:00
if ( me )
if ( Unit * victim = me -> GetVictim ())
2017-06-03 10:21:06 +02:00
targets . push_back ( victim );
2010-10-27 21:01:47 +02:00
break ;
case SMART_TARGET_HOSTILE_SECOND_AGGRO :
2011-03-26 23:45:23 +01:00
if ( me )
2017-02-17 21:33:18 +01:00
{
if ( e . target . hostilRandom . powerType )
{
2017-07-01 20:18:02 +02:00
if ( Unit * u = me -> AI () -> SelectTarget ( SELECT_TARGET_MAXTHREAT , 1 , PowerUsersSelector ( me , Powers ( e . target . hostilRandom . powerType - 1 ), float ( e . target . hostilRandom . maxDist ), e . target . hostilRandom . playerOnly != 0 )))
2017-06-03 10:21:06 +02:00
targets . push_back ( u );
2017-02-17 21:33:18 +01:00
}
2017-07-01 20:18:02 +02:00
else if ( Unit * u = me -> AI () -> SelectTarget ( SELECT_TARGET_MAXTHREAT , 1 , float ( e . target . hostilRandom . maxDist ), e . target . hostilRandom . playerOnly != 0 ))
2017-06-03 10:21:06 +02:00
targets . push_back ( u );
2017-02-17 21:33:18 +01:00
}
2010-10-27 21:01:47 +02:00
break ;
case SMART_TARGET_HOSTILE_LAST_AGGRO :
2011-03-26 23:45:23 +01:00
if ( me )
2017-02-17 21:33:18 +01:00
{
if ( e . target . hostilRandom . powerType )
{
2017-07-01 20:18:02 +02:00
if ( Unit * u = me -> AI () -> SelectTarget ( SELECT_TARGET_MINTHREAT , 0 , PowerUsersSelector ( me , Powers ( e . target . hostilRandom . powerType - 1 ), float ( e . target . hostilRandom . maxDist ), e . target . hostilRandom . playerOnly != 0 )))
2017-06-03 10:21:06 +02:00
targets . push_back ( u );
2017-02-17 21:33:18 +01:00
}
2017-07-01 20:18:02 +02:00
else if ( Unit * u = me -> AI () -> SelectTarget ( SELECT_TARGET_MINTHREAT , 0 , float ( e . target . hostilRandom . maxDist ), e . target . hostilRandom . playerOnly != 0 ))
2017-06-03 10:21:06 +02:00
targets . push_back ( u );
2017-02-17 21:33:18 +01:00
}
2010-10-27 21:01:47 +02:00
break ;
case SMART_TARGET_HOSTILE_RANDOM :
2011-03-26 23:45:23 +01:00
if ( me )
2017-02-17 21:33:18 +01:00
{
if ( e . target . hostilRandom . powerType )
{
2017-06-03 10:21:06 +02:00
if ( Unit * u = me -> AI () -> SelectTarget ( SELECT_TARGET_RANDOM , 0 , PowerUsersSelector ( me , Powers ( e . target . hostilRandom . powerType - 1 ), float ( e . target . hostilRandom . maxDist ), e . target . hostilRandom . playerOnly != 0 )))
targets . push_back ( u );
2017-02-17 21:33:18 +01:00
}
2017-06-03 10:21:06 +02:00
else if ( Unit * u = me -> AI () -> SelectTarget ( SELECT_TARGET_RANDOM , 0 , float ( e . target . hostilRandom . maxDist ), e . target . hostilRandom . playerOnly != 0 ))
targets . push_back ( u );
2017-02-17 21:33:18 +01:00
}
2010-10-27 21:01:47 +02:00
break ;
case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP :
2011-03-26 23:45:23 +01:00
if ( me )
2017-02-17 21:33:18 +01:00
{
if ( e . target . hostilRandom . powerType )
{
2017-06-03 10:21:06 +02:00
if ( Unit * u = me -> AI () -> SelectTarget ( SELECT_TARGET_RANDOM , 1 , PowerUsersSelector ( me , Powers ( e . target . hostilRandom . powerType - 1 ), float ( e . target . hostilRandom . maxDist ), e . target . hostilRandom . playerOnly != 0 )))
targets . push_back ( u );
2017-02-17 21:33:18 +01:00
}
2017-06-03 10:21:06 +02:00
else if ( Unit * u = me -> AI () -> SelectTarget ( SELECT_TARGET_RANDOM , 1 , float ( e . target . hostilRandom . maxDist ), e . target . hostilRandom . playerOnly != 0 ))
targets . push_back ( u );
2017-02-17 21:33:18 +01:00
}
break ;
case SMART_TARGET_FARTHEST :
if ( me )
{
2017-07-01 20:18:02 +02:00
if ( Unit * u = me -> AI () -> SelectTarget ( SELECT_TARGET_MAXDISTANCE , 0 , FarthestTargetSelector ( me , float ( e . target . farthest . maxDist ), e . target . farthest . playerOnly != 0 , e . target . farthest . isInLos != 0 )))
2017-06-03 10:21:06 +02:00
targets . push_back ( u );
2017-02-17 21:33:18 +01:00
}
2010-10-27 21:01:47 +02:00
break ;
case SMART_TARGET_ACTION_INVOKER :
2013-01-16 08:59:56 +01:00
if ( scriptTrigger )
2017-06-03 10:21:06 +02:00
targets . push_back ( scriptTrigger );
2010-10-27 21:01:47 +02:00
break ;
2010-10-31 14:21:35 +01:00
case SMART_TARGET_ACTION_INVOKER_VEHICLE :
2013-01-16 08:59:56 +01:00
if ( scriptTrigger && scriptTrigger -> GetVehicle () && scriptTrigger -> GetVehicle () -> GetBase ())
2017-06-03 10:21:06 +02:00
targets . push_back ( scriptTrigger -> GetVehicle () -> GetBase ());
2010-10-31 14:21:35 +01:00
break ;
2010-10-27 21:01:47 +02:00
case SMART_TARGET_INVOKER_PARTY :
2013-01-16 08:59:56 +01:00
if ( scriptTrigger )
2010-10-27 21:01:47 +02:00
{
2013-01-16 08:59:56 +01:00
if ( Player * player = scriptTrigger -> ToPlayer ())
2012-06-04 17:20:40 +02:00
{
2011-08-20 20:31:31 -03:00
if ( Group * group = player -> GetGroup ())
2012-06-04 17:20:40 +02:00
{
2016-08-05 12:41:56 +02:00
for ( GroupReference * groupRef = group -> GetFirstMember (); groupRef != nullptr ; groupRef = groupRef -> next ())
2013-06-11 21:25:12 -02:30
if ( Player * member = groupRef -> GetSource ())
2017-02-04 22:37:16 +01:00
if ( member -> IsInMap ( player ))
2017-06-03 10:21:06 +02:00
targets . push_back ( member );
2012-06-04 17:20:40 +02:00
}
// We still add the player to the list if there is no group. If we do
// this even if there is a group (thus the else-check), it will add the
// same player to the list twice. We don't want that to happen.
else
2017-06-03 10:21:06 +02:00
targets . push_back ( scriptTrigger );
2012-06-04 17:20:40 +02:00
}
2010-10-27 21:01:47 +02:00
}
break ;
case SMART_TARGET_CREATURE_RANGE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
ObjectVector units ;
GetWorldObjectsInDist ( units , static_cast < float > ( e . target . unitRange . maxDist ));
for ( WorldObject * unit : units )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsCreature ( unit ))
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
if ( me && me -> GetGUID () == unit -> GetGUID ())
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
if (( ! e . target . unitRange . creature || unit -> ToCreature () -> GetEntry () == e . target . unitRange . creature ) && baseObject -> IsInRange ( unit , float ( e . target . unitRange . minDist ), float ( e . target . unitRange . maxDist )))
targets . push_back ( unit );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_CREATURE_DISTANCE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
ObjectVector units ;
GetWorldObjectsInDist ( units , static_cast < float > ( e . target . unitDistance . dist ));
for ( WorldObject * unit : units )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsCreature ( unit ))
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
if ( me && me -> GetGUID () == unit -> GetGUID ())
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
if ( ! e . target . unitDistance . creature || unit -> ToCreature () -> GetEntry () == e . target . unitDistance . creature )
targets . push_back ( unit );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_GAMEOBJECT_DISTANCE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
ObjectVector units ;
GetWorldObjectsInDist ( units , static_cast < float > ( e . target . goDistance . dist ));
for ( WorldObject * unit : units )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsGameObject ( unit ))
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
if ( go && go -> GetGUID () == unit -> GetGUID ())
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
if ( ! e . target . goDistance . entry || unit -> ToGameObject () -> GetEntry () == e . target . goDistance . entry )
targets . push_back ( unit );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_GAMEOBJECT_RANGE :
2011-03-26 23:45:23 +01:00
{
2017-06-03 10:21:06 +02:00
ObjectVector units ;
GetWorldObjectsInDist ( units , static_cast < float > ( e . target . goRange . maxDist ));
for ( WorldObject * unit : units )
2010-10-27 21:01:47 +02:00
{
2017-06-03 10:21:06 +02:00
if ( ! IsGameObject ( unit ))
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
if ( go && go -> GetGUID () == unit -> GetGUID ())
2011-03-26 23:45:23 +01:00
continue ;
2017-06-03 10:21:06 +02:00
if (( ! e . target . goRange . entry && unit -> ToGameObject () -> GetEntry () == e . target . goRange . entry ) && baseObject -> IsInRange ( unit , float ( e . target . goRange . minDist ), float ( e . target . goRange . maxDist )))
targets . push_back ( unit );
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_CREATURE_GUID :
2011-03-26 23:45:23 +01:00
{
2013-01-16 08:59:56 +01:00
if ( ! scriptTrigger && ! baseObject )
2010-10-27 21:01:47 +02:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SMART_TARGET_CREATURE_GUID can not be used without invoker" );
2013-01-03 19:22:12 +01:00
break ;
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
2014-10-11 18:52:01 +02:00
if ( Creature * target = FindCreatureNear ( scriptTrigger ? scriptTrigger : baseObject , e . target . unitGUID . dbGuid ))
if ( ! e . target . unitGUID . entry || target -> GetEntry () == e . target . unitGUID . entry )
2017-06-03 10:21:06 +02:00
targets . push_back ( target );
2011-03-26 23:45:23 +01:00
break ;
}
case SMART_TARGET_GAMEOBJECT_GUID :
{
2013-01-16 08:59:56 +01:00
if ( ! scriptTrigger && ! baseObject )
2010-10-27 21:01:47 +02:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SMART_TARGET_GAMEOBJECT_GUID can not be used without invoker" );
2013-01-03 19:22:12 +01:00
break ;
2010-10-27 21:01:47 +02:00
}
2011-03-26 23:45:23 +01:00
2014-10-11 18:52:01 +02:00
if ( GameObject * target = FindGameObjectNear ( scriptTrigger ? scriptTrigger : baseObject , e . target . goGUID . dbGuid ))
if ( ! e . target . goGUID . entry || target -> GetEntry () == e . target . goGUID . entry )
2017-06-03 10:21:06 +02:00
targets . push_back ( target );
2011-03-26 23:45:23 +01:00
break ;
}
case SMART_TARGET_PLAYER_RANGE :
{
2017-06-03 10:21:06 +02:00
ObjectVector units ;
GetWorldObjectsInDist ( units , static_cast < float > ( e . target . playerRange . maxDist ));
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
if ( ! units . empty () && baseObject )
for ( WorldObject * unit : units )
if ( IsPlayer ( unit ) && baseObject -> IsInRange ( unit , float ( e . target . playerRange . minDist ), float ( e . target . playerRange . maxDist )))
targets . push_back ( unit );
2011-03-26 23:45:23 +01:00
break ;
}
case SMART_TARGET_PLAYER_DISTANCE :
{
2017-06-03 10:21:06 +02:00
ObjectVector units ;
GetWorldObjectsInDist ( units , static_cast < float > ( e . target . playerDistance . dist ));
2011-03-26 23:45:23 +01:00
2017-06-03 10:21:06 +02:00
for ( WorldObject * unit : units )
if ( IsPlayer ( unit ))
targets . push_back ( unit );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_STORED :
2011-03-26 23:45:23 +01:00
{
2017-06-04 16:43:36 -03:00
WorldObject * ref = GetBaseObject ();
if ( ! ref )
ref = scriptTrigger ;
if ( ref )
if ( ObjectVector const * stored = GetStoredTargetVector ( e . target . stored . id , * ref ))
targets . assign ( stored -> begin (), stored -> end ());
2017-02-17 21:33:18 +01:00
break ;
2011-03-26 23:45:23 +01:00
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_CLOSEST_CREATURE :
2011-03-26 23:45:23 +01:00
{
2017-05-28 16:34:44 +02:00
if ( Creature * target = baseObject -> FindNearestCreature ( e . target . closest . entry , float ( e . target . closest . dist ? e . target . closest . dist : 100 ), ! e . target . closest . dead ))
2017-06-03 10:21:06 +02:00
targets . push_back ( target );
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_CLOSEST_GAMEOBJECT :
2011-03-26 23:45:23 +01:00
{
2017-05-28 16:34:44 +02:00
if ( GameObject * target = baseObject -> FindNearestGameObject ( e . target . closest . entry , float ( e . target . closest . dist ? e . target . closest . dist : 100 )))
2017-06-03 10:21:06 +02:00
targets . push_back ( target );
2011-03-26 23:45:23 +01:00
break ;
}
2011-10-25 21:43:24 +01:00
case SMART_TARGET_CLOSEST_PLAYER :
{
2017-06-03 10:21:06 +02:00
if ( WorldObject * obj = GetBaseObject ())
if ( Player * target = obj -> SelectNearestPlayer ( float ( e . target . playerDistance . dist )))
targets . push_back ( target );
2011-10-25 21:43:24 +01:00
break ;
}
2010-11-07 18:02:33 +01:00
case SMART_TARGET_OWNER_OR_SUMMONER :
2011-03-26 23:45:23 +01:00
{
if ( me )
2013-09-04 14:07:27 +02:00
{
2014-09-14 16:14:12 +02:00
ObjectGuid charmerOrOwnerGuid = me -> GetCharmerOrOwnerGUID ();
2013-09-04 09:35:21 +02:00
2016-08-24 00:13:26 +02:00
if ( ! charmerOrOwnerGuid )
if ( TempSummon * tempSummon = me -> ToTempSummon ())
if ( Unit * summoner = tempSummon -> GetSummoner ())
charmerOrOwnerGuid = summoner -> GetGUID ();
2013-09-04 14:07:27 +02:00
if ( ! charmerOrOwnerGuid )
charmerOrOwnerGuid = me -> GetCreatorGUID ();
2013-09-04 09:35:21 +02:00
if ( Unit * owner = ObjectAccessor :: GetUnit ( * me , charmerOrOwnerGuid ))
2017-06-03 10:21:06 +02:00
targets . push_back ( owner );
2013-09-04 14:07:27 +02:00
}
2017-02-17 21:33:18 +01:00
else if ( go )
{
2017-06-03 10:21:06 +02:00
if ( Unit * owner = ObjectAccessor :: GetUnit ( * go , go -> GetOwnerGUID ()))
targets . push_back ( owner );
2017-02-17 21:33:18 +01:00
}
// Get owner of owner
2017-06-03 10:21:06 +02:00
if ( e . target . owner . useCharmerOrOwner && ! targets . empty ())
2017-02-17 21:33:18 +01:00
{
2017-06-03 10:21:06 +02:00
Unit * owner = targets . front () -> ToUnit ();
targets . clear ();
2017-02-17 21:33:18 +01:00
2017-06-03 10:21:06 +02:00
if ( Unit * base = ObjectAccessor :: GetUnit ( * owner , owner -> GetCharmerOrOwnerGUID ()))
targets . push_back ( base );
2017-02-17 21:33:18 +01:00
}
2011-03-26 23:45:23 +01:00
break ;
}
2010-11-20 12:42:10 +01:00
case SMART_TARGET_THREAT_LIST :
2011-03-26 23:45:23 +01:00
{
2017-07-01 20:18:02 +02:00
if ( me && me -> CanHaveThreatList ())
for ( auto * ref : me -> GetThreatManager (). GetUnsortedThreatList ())
if ( ! e . target . hostilRandom . maxDist || me -> IsWithinCombatRange ( ref -> GetVictim (), float ( e . target . hostilRandom . maxDist )))
targets . push_back ( ref -> GetVictim ());
2011-03-26 23:45:23 +01:00
break ;
}
2013-08-07 19:59:06 +01:00
case SMART_TARGET_CLOSEST_ENEMY :
{
if ( me )
2014-07-17 15:42:57 +02:00
if ( Unit * target = me -> SelectNearestTarget ( e . target . closestAttackable . maxDist , e . target . closestAttackable . playerOnly != 0 ))
2017-06-03 10:21:06 +02:00
targets . push_back ( target );
2013-08-07 19:59:06 +01:00
break ;
}
2013-08-15 01:22:22 +01:00
case SMART_TARGET_CLOSEST_FRIENDLY :
{
if ( me )
2014-07-17 15:42:57 +02:00
if ( Unit * target = DoFindClosestFriendlyInRange ( e . target . closestFriendly . maxDist , e . target . closestFriendly . playerOnly != 0 ))
2017-06-03 10:21:06 +02:00
targets . push_back ( target );
2013-08-15 01:22:22 +01:00
break ;
}
2016-08-19 14:25:23 +02:00
case SMART_TARGET_LOOT_RECIPIENTS :
{
if ( me )
{
if ( Group * lootGroup = me -> GetLootRecipientGroup ())
{
for ( GroupReference * it = lootGroup -> GetFirstMember (); it != nullptr ; it = it -> next ())
if ( Player * recipient = it -> GetSource ())
2017-02-04 22:37:16 +01:00
if ( recipient -> IsInMap ( me ))
2017-06-03 10:21:06 +02:00
targets . push_back ( recipient );
2016-08-19 14:25:23 +02:00
}
else
{
if ( Player * recipient = me -> GetLootRecipient ())
2017-06-03 10:21:06 +02:00
targets . push_back ( recipient );
2016-08-19 14:25:23 +02:00
}
}
2017-03-26 01:07:09 +01:00
break ;
2016-08-19 14:25:23 +02:00
}
2017-03-23 03:58:03 +01:00
case SMART_TARGET_VEHICLE_ACCESSORY :
{
if ( me && me -> IsVehicle ())
{
if ( Unit * target = me -> GetVehicleKit () -> GetPassenger ( e . target . vehicle . seat ))
2017-06-03 10:21:06 +02:00
targets . push_back ( target );
2017-03-23 03:58:03 +01:00
}
2017-03-26 01:07:09 +01:00
break ;
2017-03-23 03:58:03 +01:00
}
2010-10-27 21:01:47 +02:00
case SMART_TARGET_POSITION :
2013-09-23 16:47:22 +02:00
case SMART_TARGET_NONE :
2010-10-27 21:01:47 +02:00
default :
2011-03-26 23:45:23 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
}
2017-06-03 10:21:06 +02:00
void SmartScript :: GetWorldObjectsInDist ( ObjectVector & targets , float dist ) const
2010-10-27 21:01:47 +02:00
{
WorldObject * obj = GetBaseObject ();
2017-06-03 10:21:06 +02:00
if ( ! obj )
return ;
Trinity :: AllWorldObjectsInRange u_check ( obj , dist );
Trinity :: WorldObjectListSearcher < Trinity :: AllWorldObjectsInRange > searcher ( obj , targets , u_check );
Cell :: VisitAllObjects ( obj , searcher , dist );
2010-10-27 21:01:47 +02:00
}
2020-09-04 13:38:24 +02:00
void SmartScript :: ProcessEvent ( SmartScriptHolder & e , Unit * unit , uint32 var0 , uint32 var1 , bool bvar , SpellInfo const * spell , GameObject * gob , std :: string const & varString )
2010-10-27 21:01:47 +02:00
{
if ( ! e . active && e . GetEventType () != SMART_EVENT_LINK )
return ;
if (( e . event . event_phase_mask && ! IsInPhase ( e . event . event_phase_mask )) || (( e . event . event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE ) && e . runOnce ))
return ;
2010-12-13 22:37:56 +01:00
2016-10-14 03:59:13 -03:00
if ( ! ( e . event . event_flags & SMART_EVENT_FLAG_WHILE_CHARMED ) && IsCharmedCreature ( me ))
2016-09-02 23:14:50 +02:00
return ;
2010-10-27 21:01:47 +02:00
switch ( e . GetEventType ())
{
case SMART_EVENT_LINK : //special handling
ProcessAction ( e , unit , var0 , var1 , bvar , spell , gob );
break ;
//called from Update tick
case SMART_EVENT_UPDATE :
2013-01-17 14:04:20 +01:00
ProcessTimedAction ( e , e . event . minMaxRepeat . repeatMin , e . event . minMaxRepeat . repeatMax );
2010-10-27 21:01:47 +02:00
break ;
case SMART_EVENT_UPDATE_OOC :
2017-07-01 20:18:02 +02:00
if ( me && me -> IsEngaged ())
2010-10-27 21:01:47 +02:00
return ;
2013-01-17 14:04:20 +01:00
ProcessTimedAction ( e , e . event . minMaxRepeat . repeatMin , e . event . minMaxRepeat . repeatMax );
2010-10-27 21:01:47 +02:00
break ;
case SMART_EVENT_UPDATE_IC :
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged ())
2010-10-27 21:01:47 +02:00
return ;
2013-01-17 14:04:20 +01:00
ProcessTimedAction ( e , e . event . minMaxRepeat . repeatMin , e . event . minMaxRepeat . repeatMax );
2010-10-27 21:01:47 +02:00
break ;
case SMART_EVENT_HEALT_PCT :
2011-03-27 12:54:42 +02:00
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged () || ! me -> GetMaxHealth ())
2011-03-27 12:54:42 +02:00
return ;
uint32 perc = ( uint32 ) me -> GetHealthPct ();
if ( perc > e . event . minMaxRepeat . max || perc < e . event . minMaxRepeat . min )
return ;
2013-01-17 14:04:20 +01:00
ProcessTimedAction ( e , e . event . minMaxRepeat . repeatMin , e . event . minMaxRepeat . repeatMax );
2011-03-27 12:54:42 +02:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_EVENT_TARGET_HEALTH_PCT :
2011-03-27 12:54:42 +02:00
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged () || ! me -> GetVictim () || ! me -> EnsureVictim () -> GetMaxHealth ())
2011-03-27 12:54:42 +02:00
return ;
2014-04-19 21:48:22 +02:00
uint32 perc = ( uint32 ) me -> EnsureVictim () -> GetHealthPct ();
2011-03-27 12:54:42 +02:00
if ( perc > e . event . minMaxRepeat . max || perc < e . event . minMaxRepeat . min )
return ;
2013-06-11 19:54:27 -02:30
ProcessTimedAction ( e , e . event . minMaxRepeat . repeatMin , e . event . minMaxRepeat . repeatMax , me -> GetVictim ());
2011-03-27 12:54:42 +02:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_EVENT_MANA_PCT :
2011-03-27 12:54:42 +02:00
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged () || ! me -> GetMaxPower ( POWER_MANA ))
2011-03-27 12:54:42 +02:00
return ;
2018-01-03 16:39:00 +01:00
uint32 perc = uint32 ( me -> GetPowerPct ( POWER_MANA ));
2011-03-27 12:54:42 +02:00
if ( perc > e . event . minMaxRepeat . max || perc < e . event . minMaxRepeat . min )
return ;
2013-01-17 14:04:20 +01:00
ProcessTimedAction ( e , e . event . minMaxRepeat . repeatMin , e . event . minMaxRepeat . repeatMax );
2011-03-27 12:54:42 +02:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_EVENT_TARGET_MANA_PCT :
2011-03-27 12:54:42 +02:00
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged () || ! me -> GetVictim () || ! me -> EnsureVictim () -> GetMaxPower ( POWER_MANA ))
2011-03-27 12:54:42 +02:00
return ;
2018-01-03 16:39:00 +01:00
uint32 perc = uint32 ( me -> EnsureVictim () -> GetPowerPct ( POWER_MANA ));
2011-03-27 12:54:42 +02:00
if ( perc > e . event . minMaxRepeat . max || perc < e . event . minMaxRepeat . min )
return ;
2013-06-11 19:54:27 -02:30
ProcessTimedAction ( e , e . event . minMaxRepeat . repeatMin , e . event . minMaxRepeat . repeatMax , me -> GetVictim ());
2011-03-27 12:54:42 +02:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_EVENT_RANGE :
2011-03-27 12:54:42 +02:00
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged () || ! me -> GetVictim ())
2011-03-27 12:54:42 +02:00
return ;
2010-11-03 17:25:46 +01:00
2013-06-11 19:54:27 -02:30
if ( me -> IsInRange ( me -> GetVictim (), ( float ) e . event . minMaxRepeat . min , ( float ) e . event . minMaxRepeat . max ))
ProcessTimedAction ( e , e . event . minMaxRepeat . repeatMin , e . event . minMaxRepeat . repeatMax , me -> GetVictim ());
2017-02-17 21:33:18 +01:00
else // make it predictable
RecalcTimer ( e , 500 , 500 );
2011-03-27 12:54:42 +02:00
break ;
}
2013-10-22 15:59:32 +02:00
case SMART_EVENT_VICTIM_CASTING :
2011-03-27 12:54:42 +02:00
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged ())
2011-03-27 12:54:42 +02:00
return ;
2013-01-17 14:04:20 +01:00
2013-09-01 10:49:29 +02:00
Unit * victim = me -> GetVictim ();
2013-12-25 14:16:55 -03:30
if ( ! victim || ! victim -> IsNonMeleeSpellCast ( false , false , true ))
2013-09-01 10:49:29 +02:00
return ;
if ( e . event . targetCasting . spellId > 0 )
if ( Spell * currSpell = victim -> GetCurrentSpell ( CURRENT_GENERIC_SPELL ))
if ( currSpell -> m_spellInfo -> Id != e . event . targetCasting . spellId )
return ;
ProcessTimedAction ( e , e . event . targetCasting . repeatMin , e . event . targetCasting . repeatMax , me -> GetVictim ());
2013-05-17 23:08:28 -05:00
break ;
2011-03-27 12:54:42 +02:00
}
2010-10-27 21:01:47 +02:00
case SMART_EVENT_FRIENDLY_HEALTH :
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged ())
2010-10-27 21:01:47 +02:00
return ;
2013-09-01 10:49:29 +02:00
Unit * target = DoSelectLowestHpFriendly (( float ) e . event . friendlyHealth . radius , e . event . friendlyHealth . hpDeficit );
2013-08-15 01:18:10 +01:00
if ( ! target || ! target -> IsInCombat ())
2017-02-17 21:33:18 +01:00
{
// if there are at least two same npcs, they will perform the same action immediately even if this is useless...
RecalcTimer ( e , 1000 , 3000 );
2010-10-27 21:01:47 +02:00
return ;
2017-02-17 21:33:18 +01:00
}
2013-09-01 10:49:29 +02:00
ProcessTimedAction ( e , e . event . friendlyHealth . repeatMin , e . event . friendlyHealth . repeatMax , target );
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_FRIENDLY_IS_CC :
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged ())
2010-10-27 21:01:47 +02:00
return ;
2017-06-03 10:21:06 +02:00
std :: vector < Creature *> creatures ;
DoFindFriendlyCC ( creatures , float ( e . event . friendlyCC . radius ));
if ( creatures . empty ())
2017-02-17 21:33:18 +01:00
{
// if there are at least two same npcs, they will perform the same action immediately even if this is useless...
RecalcTimer ( e , 1000 , 3000 );
2010-10-27 21:01:47 +02:00
return ;
2017-02-17 21:33:18 +01:00
}
2017-06-03 10:21:06 +02:00
ProcessTimedAction ( e , e . event . friendlyCC . repeatMin , e . event . friendlyCC . repeatMax , Trinity :: Containers :: SelectRandomContainerElement ( creatures ));
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_FRIENDLY_MISSING_BUFF :
{
2017-06-03 10:21:06 +02:00
std :: vector < Creature *> creatures ;
DoFindFriendlyMissingBuff ( creatures , float ( e . event . missingBuff . radius ), e . event . missingBuff . spell );
2010-10-27 21:01:47 +02:00
2017-06-03 10:21:06 +02:00
if ( creatures . empty ())
2010-10-27 21:01:47 +02:00
return ;
2013-01-17 14:04:20 +01:00
2017-06-03 10:21:06 +02:00
ProcessTimedAction ( e , e . event . missingBuff . repeatMin , e . event . missingBuff . repeatMax , Trinity :: Containers :: SelectRandomContainerElement ( creatures ));
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_HAS_AURA :
{
2011-03-27 12:54:42 +02:00
if ( ! me )
return ;
2010-10-27 21:01:47 +02:00
uint32 count = me -> GetAuraCount ( e . event . aura . spell );
2010-10-31 22:11:56 +01:00
if (( ! e . event . aura . count && ! count ) || ( e . event . aura . count && count >= e . event . aura . count ))
2013-01-17 14:04:20 +01:00
ProcessTimedAction ( e , e . event . aura . repeatMin , e . event . aura . repeatMax );
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_TARGET_BUFFED :
{
2013-06-11 19:54:27 -02:30
if ( ! me || ! me -> GetVictim ())
2011-03-27 12:54:42 +02:00
return ;
2014-04-19 21:48:22 +02:00
uint32 count = me -> EnsureVictim () -> GetAuraCount ( e . event . aura . spell );
2010-10-27 21:01:47 +02:00
if ( count < e . event . aura . count )
return ;
2013-01-17 14:04:20 +01:00
ProcessTimedAction ( e , e . event . aura . repeatMin , e . event . aura . repeatMax );
2010-10-27 21:01:47 +02:00
break ;
}
2016-09-02 23:14:50 +02:00
case SMART_EVENT_CHARMED :
{
if ( bvar == ( e . event . charm . onRemove != 1 ))
ProcessAction ( e , unit , var0 , var1 , bvar , spell , gob );
break ;
}
2010-10-27 21:01:47 +02:00
//no params
case SMART_EVENT_AGGRO :
case SMART_EVENT_DEATH :
case SMART_EVENT_EVADE :
case SMART_EVENT_REACHED_HOME :
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_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_RESET :
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-10-27 21:01:47 +02:00
ProcessAction ( e , unit , var0 , var1 , bvar , spell , gob );
break ;
2017-02-17 21:33:18 +01:00
case SMART_EVENT_GOSSIP_HELLO :
if ( e . event . gossipHello . noReportUse && var0 )
return ;
ProcessAction ( e , unit , var0 , var1 , bvar , spell , gob );
break ;
2011-04-14 00:30:32 -03:00
case SMART_EVENT_IS_BEHIND_TARGET :
{
if ( ! me )
return ;
2013-06-11 19:54:27 -02:30
if ( Unit * victim = me -> GetVictim ())
2011-04-14 00:30:32 -03:00
{
if ( ! victim -> HasInArc ( static_cast < float > ( M_PI ), me ))
2013-01-17 14:04:20 +01:00
ProcessTimedAction ( e , e . event . behindTarget . cooldownMin , e . event . behindTarget . cooldownMax , victim );
2011-04-14 00:30:32 -03:00
}
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_EVENT_RECEIVE_EMOTE :
if ( e . event . emote . emote == var0 )
{
RecalcTimer ( e , e . event . emote . cooldownMin , e . event . emote . cooldownMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit );
2010-10-27 21:01:47 +02:00
}
break ;
case SMART_EVENT_KILL :
{
2011-03-27 12:54:42 +02:00
if ( ! me || ! unit )
return ;
2010-10-27 21:01:47 +02:00
if ( e . event . kill . playerOnly && unit -> GetTypeId () != TYPEID_PLAYER )
return ;
if ( e . event . kill . creature && unit -> GetEntry () != e . event . kill . creature )
return ;
RecalcTimer ( e , e . event . kill . cooldownMin , e . event . kill . cooldownMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit );
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_SPELLHIT_TARGET :
case SMART_EVENT_SPELLHIT :
{
2011-03-27 12:54:42 +02:00
if ( ! spell )
return ;
if (( ! e . event . spellHit . spell || spell -> Id == e . event . spellHit . spell ) &&
( ! e . event . spellHit . school || ( spell -> SchoolMask & e . event . spellHit . school )))
2010-10-27 21:01:47 +02:00
{
RecalcTimer ( e , e . event . spellHit . cooldownMin , e . event . spellHit . cooldownMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit , 0 , 0 , bvar , spell );
2010-10-27 21:01:47 +02:00
}
break ;
}
case SMART_EVENT_OOC_LOS :
{
2017-07-01 20:18:02 +02:00
if ( ! me || me -> IsEngaged ())
2011-03-27 12:54:42 +02:00
return ;
2010-10-27 21:01:47 +02:00
//can trigger if closer than fMaxAllowedRange
float range = ( float ) e . event . los . maxDist ;
//if range is ok and we are actually in LOS
if ( me -> IsWithinDistInMap ( unit , range ) && me -> IsWithinLOSInMap ( unit ))
{
//if friendly event&&who is not hostile OR hostile event&&who is hostile
if (( e . event . los . noHostile && ! me -> IsHostileTo ( unit )) ||
( ! e . event . los . noHostile && me -> IsHostileTo ( unit )))
{
RecalcTimer ( e , e . event . los . cooldownMin , e . event . los . cooldownMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit );
2010-10-27 21:01:47 +02:00
}
}
break ;
}
case SMART_EVENT_IC_LOS :
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged ())
2011-03-27 12:54:42 +02:00
return ;
2010-10-27 21:01:47 +02:00
//can trigger if closer than fMaxAllowedRange
float range = ( float ) e . event . los . maxDist ;
//if range is ok and we are actually in LOS
if ( me -> IsWithinDistInMap ( unit , range ) && me -> IsWithinLOSInMap ( unit ))
{
//if friendly event&&who is not hostile OR hostile event&&who is hostile
if (( e . event . los . noHostile && ! me -> IsHostileTo ( unit )) ||
( ! e . event . los . noHostile && me -> IsHostileTo ( unit )))
{
RecalcTimer ( e , e . event . los . cooldownMin , e . event . los . cooldownMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit );
2010-10-27 21:01:47 +02:00
}
}
break ;
}
case SMART_EVENT_RESPAWN :
{
2011-03-27 12:54:42 +02:00
if ( ! GetBaseObject ())
return ;
2010-10-27 21:01:47 +02:00
if ( e . event . respawn . type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && GetBaseObject () -> GetMapId () != e . event . respawn . map )
return ;
if ( e . event . respawn . type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && GetBaseObject () -> GetZoneId () != e . event . respawn . area )
return ;
ProcessAction ( e );
break ;
}
case SMART_EVENT_SUMMONED_UNIT :
{
2011-03-27 12:54:42 +02:00
if ( ! IsCreature ( unit ))
return ;
2010-10-27 21:01:47 +02:00
if ( e . event . summoned . creature && unit -> GetEntry () != e . event . summoned . creature )
return ;
RecalcTimer ( e , e . event . summoned . cooldownMin , e . event . summoned . cooldownMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit );
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_RECEIVE_HEAL :
case SMART_EVENT_DAMAGED :
case SMART_EVENT_DAMAGED_TARGET :
{
if ( var0 > e . event . minMaxRepeat . max || var0 < e . event . minMaxRepeat . min )
return ;
2011-03-26 23:45:23 +01:00
RecalcTimer ( e , e . event . minMaxRepeat . repeatMin , e . event . minMaxRepeat . repeatMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit );
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_MOVEMENTINFORM :
{
if (( e . event . movementInform . type && var0 != e . event . movementInform . type ) || ( e . event . movementInform . id && var1 != e . event . movementInform . id ))
return ;
ProcessAction ( e , unit , var0 , var1 );
break ;
}
case SMART_EVENT_TRANSPORT_RELOCATE :
case SMART_EVENT_WAYPOINT_START :
{
if ( e . event . waypoint . pathID && var0 != e . event . waypoint . pathID )
return ;
ProcessAction ( e , unit , var0 );
break ;
}
case SMART_EVENT_WAYPOINT_REACHED :
case SMART_EVENT_WAYPOINT_RESUMED :
case SMART_EVENT_WAYPOINT_PAUSED :
case SMART_EVENT_WAYPOINT_STOPPED :
case SMART_EVENT_WAYPOINT_ENDED :
{
if ( ! me || ( e . event . waypoint . pointID && var0 != e . event . waypoint . pointID ) || ( e . event . waypoint . pathID && GetPathId () != e . event . waypoint . pathID ))
return ;
ProcessAction ( e , unit );
break ;
}
case SMART_EVENT_SUMMON_DESPAWNED :
2017-02-17 21:33:18 +01:00
{
if ( e . event . summoned . creature && e . event . summoned . creature != var0 )
return ;
RecalcTimer ( e , e . event . summoned . cooldownMin , e . event . summoned . cooldownMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit , var0 );
2017-02-17 21:33:18 +01:00
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_EVENT_INSTANCE_PLAYER_ENTER :
{
if ( e . event . instancePlayerEnter . team && var0 != e . event . instancePlayerEnter . team )
return ;
RecalcTimer ( e , e . event . instancePlayerEnter . cooldownMin , e . event . instancePlayerEnter . cooldownMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit , var0 );
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_ACCEPTED_QUEST :
case SMART_EVENT_REWARD_QUEST :
{
if ( e . event . quest . quest && var0 != e . event . quest . quest )
return ;
ProcessAction ( e , unit , var0 );
break ;
}
case SMART_EVENT_TRANSPORT_ADDCREATURE :
{
if ( e . event . transportAddCreature . creature && var0 != e . event . transportAddCreature . creature )
return ;
ProcessAction ( e , unit , var0 );
break ;
}
case SMART_EVENT_AREATRIGGER_ONTRIGGER :
{
if ( e . event . areatrigger . id && var0 != e . event . areatrigger . id )
return ;
ProcessAction ( e , unit , var0 );
break ;
}
case SMART_EVENT_TEXT_OVER :
{
2010-11-01 11:00:53 +01:00
if ( var0 != e . event . textOver . textGroupID || ( e . event . textOver . creatureEntry && e . event . textOver . creatureEntry != var1 ))
2010-10-27 21:01:47 +02:00
return ;
ProcessAction ( e , unit , var0 );
break ;
}
case SMART_EVENT_DATA_SET :
{
if ( e . event . dataSet . id != var0 || e . event . dataSet . value != var1 )
return ;
RecalcTimer ( e , e . event . dataSet . cooldownMin , e . event . dataSet . cooldownMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit , var0 , var1 );
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_PASSENGER_REMOVED :
case SMART_EVENT_PASSENGER_BOARDED :
{
2011-03-27 12:54:42 +02:00
if ( ! unit )
return ;
2010-10-27 21:01:47 +02:00
RecalcTimer ( e , e . event . minMax . repeatMin , e . event . minMax . repeatMax );
2017-06-06 22:16:14 +02:00
ProcessAction ( e , unit );
2010-10-27 21:01:47 +02:00
break ;
}
case SMART_EVENT_TIMED_EVENT_TRIGGERED :
2011-03-27 12:54:42 +02:00
{
if ( e . event . timedEvent . id == var0 )
ProcessAction ( e , unit );
break ;
}
2010-10-27 21:01:47 +02:00
case SMART_EVENT_GOSSIP_SELECT :
2011-03-27 12:54:42 +02:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript: Gossip Select: menu %u action %u" , var0 , var1 ); //little help for scripters
2011-03-27 12:54:42 +02:00
if ( e . event . gossip . sender != var0 || e . event . gossip . action != var1 )
return ;
ProcessAction ( e , unit , var0 , var1 );
break ;
}
2017-06-10 19:17:41 -03:00
case SMART_EVENT_EVENT_PHASE_CHANGE :
{
if ( ! IsInPhase ( e . event . eventPhaseChange . phasemask ))
return ;
ProcessAction ( e , GetLastInvoker ());
break ;
}
2011-12-11 16:22:18 +01:00
case SMART_EVENT_GAME_EVENT_START :
case SMART_EVENT_GAME_EVENT_END :
{
if ( e . event . gameEvent . gameEventId != var0 )
return ;
2016-08-05 12:41:56 +02:00
ProcessAction ( e , nullptr , var0 );
2011-12-11 16:22:18 +01:00
break ;
}
2017-05-01 18:19:36 -03:00
case SMART_EVENT_GO_LOOT_STATE_CHANGED :
2012-01-06 11:09:01 -05:00
{
2017-05-01 18:19:36 -03:00
if ( e . event . goLootStateChanged . lootState != var0 )
2012-01-06 11:09:01 -05:00
return ;
ProcessAction ( e , unit , var0 , var1 );
break ;
}
2012-06-11 11:10:46 +02:00
case SMART_EVENT_GO_EVENT_INFORM :
{
if ( e . event . eventInform . eventId != var0 )
return ;
2016-08-05 12:41:56 +02:00
ProcessAction ( e , nullptr , var0 );
2012-06-11 11:10:46 +02:00
break ;
}
2012-06-17 21:50:01 +01:00
case SMART_EVENT_ACTION_DONE :
{
if ( e . event . doAction . eventId != var0 )
return ;
ProcessAction ( e , unit , var0 );
2012-06-17 23:13:48 +01:00
break ;
2012-06-17 21:50:01 +01:00
}
2013-08-15 01:18:10 +01:00
case SMART_EVENT_FRIENDLY_HEALTH_PCT :
{
2017-07-01 20:18:02 +02:00
if ( ! me || ! me -> IsEngaged ())
2013-08-15 01:18:10 +01:00
return ;
2017-06-03 10:21:06 +02:00
ObjectVector targets ;
2013-08-15 01:18:10 +01:00
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 :
2017-06-03 10:21:06 +02:00
GetTargets ( targets , e );
2013-08-15 01:18:10 +01:00
break ;
default :
return ;
}
2017-06-03 10:21:06 +02:00
Unit * unitTarget = nullptr ;
for ( WorldObject * target : targets )
2013-08-15 01:18:10 +01:00
{
2017-06-03 10:21:06 +02:00
if ( IsUnit ( target ) && me -> IsFriendlyTo ( target -> ToUnit ()) && target -> ToUnit () -> IsAlive () && target -> ToUnit () -> IsInCombat ())
2013-08-15 01:18:10 +01:00
{
2017-06-03 10:21:06 +02:00
uint32 healthPct = uint32 ( target -> ToUnit () -> GetHealthPct ());
2013-09-01 10:49:29 +02:00
if ( healthPct > e . event . friendlyHealthPct . maxHpPct || healthPct < e . event . friendlyHealthPct . minHpPct )
2013-08-15 01:18:10 +01:00
continue ;
2017-06-03 10:21:06 +02:00
unitTarget = target -> ToUnit ();
2013-08-15 01:18:10 +01:00
break ;
}
}
2017-06-03 10:21:06 +02:00
if ( ! unitTarget )
2013-08-15 01:18:10 +01:00
return ;
2017-06-03 10:21:06 +02:00
ProcessTimedAction ( e , e . event . friendlyHealthPct . repeatMin , e . event . friendlyHealthPct . repeatMax , unitTarget );
2013-08-15 01:18:10 +01:00
break ;
}
2014-03-17 16:58:10 -04:00
case SMART_EVENT_DISTANCE_CREATURE :
{
if ( ! me )
return ;
2016-04-23 14:45:05 +02:00
Creature * creature = nullptr ;
2014-03-17 16:58:10 -04:00
if ( e . event . distance . guid != 0 )
{
creature = FindCreatureNear ( me , e . event . distance . guid );
if ( ! creature )
return ;
2016-04-23 14:45:05 +02:00
if ( ! me -> IsInRange ( creature , 0 , static_cast < float > ( e . event . distance . dist )))
2014-03-17 16:58:10 -04:00
return ;
}
else if ( e . event . distance . entry != 0 )
{
std :: list < Creature *> list ;
2016-04-23 14:45:05 +02:00
me -> GetCreatureListWithEntryInGrid ( list , e . event . distance . entry , static_cast < float > ( e . event . distance . dist ));
2014-03-17 16:58:10 -04:00
2015-03-11 08:53:13 +01:00
if ( ! list . empty ())
2014-03-17 16:58:10 -04:00
creature = list . front ();
}
if ( creature )
2016-04-23 14:45:05 +02:00
ProcessTimedAction ( e , e . event . distance . repeat , e . event . distance . repeat , creature );
2014-03-17 16:58:10 -04:00
break ;
}
case SMART_EVENT_DISTANCE_GAMEOBJECT :
{
if ( ! me )
return ;
2016-04-23 14:45:05 +02:00
GameObject * gameobject = nullptr ;
2014-03-17 16:58:10 -04:00
if ( e . event . distance . guid != 0 )
{
gameobject = FindGameObjectNear ( me , e . event . distance . guid );
if ( ! gameobject )
return ;
2016-04-23 14:45:05 +02:00
if ( ! me -> IsInRange ( gameobject , 0 , static_cast < float > ( e . event . distance . dist )))
2014-03-17 16:58:10 -04:00
return ;
}
else if ( e . event . distance . entry != 0 )
{
std :: list < GameObject *> list ;
2016-04-23 14:45:05 +02:00
me -> GetGameObjectListWithEntryInGrid ( list , e . event . distance . entry , static_cast < float > ( e . event . distance . dist ));
2014-03-17 16:58:10 -04:00
2015-03-11 08:53:13 +01:00
if ( ! list . empty ())
2014-03-17 16:58:10 -04:00
gameobject = list . front ();
}
if ( gameobject )
2016-04-23 14:45:05 +02:00
ProcessTimedAction ( e , e . event . distance . repeat , e . event . distance . repeat , nullptr , 0 , 0 , false , nullptr , gameobject );
2014-03-17 16:58:10 -04:00
break ;
}
2015-04-02 18:02:34 +02:00
case SMART_EVENT_COUNTER_SET :
2017-02-17 21:33:18 +01:00
if ( e . event . counter . id != var0 || GetCounterValue ( e . event . counter . id ) != e . event . counter . value )
return ;
ProcessTimedAction ( e , e . event . counter . cooldownMin , e . event . counter . cooldownMax );
2015-04-02 18:02:34 +02:00
break ;
2017-03-17 21:21:35 +01:00
case SMART_EVENT_SCENE_START :
case SMART_EVENT_SCENE_CANCEL :
case SMART_EVENT_SCENE_COMPLETE :
{
ProcessAction ( e , unit );
break ;
}
case SMART_EVENT_SCENE_TRIGGER :
{
if ( e . event . param_string != varString )
return ;
ProcessAction ( e , unit , var0 , 0 , false , nullptr , nullptr , varString );
break ;
}
2010-10-27 21:01:47 +02:00
default :
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "SmartScript::ProcessEvent: Unhandled Event type %u" , e . GetEventType ());
2010-10-27 21:01:47 +02:00
break ;
}
}
2011-03-27 12:54:42 +02:00
void SmartScript :: InitTimer ( SmartScriptHolder & e )
2010-10-27 21:01:47 +02:00
{
switch ( e . GetEventType ())
2011-03-27 12:54:42 +02:00
{
//set only events which have initial timers
2010-10-27 21:01:47 +02:00
case SMART_EVENT_UPDATE :
case SMART_EVENT_UPDATE_IC :
case SMART_EVENT_UPDATE_OOC :
RecalcTimer ( e , e . event . minMaxRepeat . min , e . event . minMaxRepeat . max );
2012-10-08 18:33:17 -05:00
break ;
2014-03-17 16:58:10 -04:00
case SMART_EVENT_DISTANCE_CREATURE :
case SMART_EVENT_DISTANCE_GAMEOBJECT :
RecalcTimer ( e , e . event . distance . repeat , e . event . distance . repeat );
break ;
2010-10-27 21:01:47 +02:00
default :
e . active = true ;
break ;
}
}
2014-12-28 10:34:33 +01:00
void SmartScript :: RecalcTimer ( SmartScriptHolder & e , uint32 min , uint32 max )
2010-10-27 21:01:47 +02:00
{
// min/max was checked at loading!
2014-08-14 16:36:04 +02:00
e . timer = urand ( min , max );
2010-10-27 21:01:47 +02:00
e . active = e . timer ? false : true ;
}
2011-03-27 12:54:42 +02:00
void SmartScript :: UpdateTimer ( SmartScriptHolder & e , uint32 const diff )
2010-10-27 21:01:47 +02:00
{
if ( e . GetEventType () == SMART_EVENT_LINK )
return ;
2011-03-27 12:54:42 +02:00
2010-10-27 21:01:47 +02:00
if ( e . event . event_phase_mask && ! IsInPhase ( e . event . event_phase_mask ))
return ;
2010-12-13 22:37:56 +01:00
2017-07-01 20:18:02 +02:00
if ( e . GetEventType () == SMART_EVENT_UPDATE_IC && ( ! me || ! me -> IsEngaged ()))
2010-11-03 14:10:16 +01:00
return ;
2011-03-27 12:54:42 +02:00
2017-07-01 20:18:02 +02:00
if ( e . GetEventType () == SMART_EVENT_UPDATE_OOC && ( me && me -> IsEngaged ())) //can be used with me=nullptr (go script)
2010-11-03 14:10:16 +01:00
return ;
2011-03-27 12:54:42 +02:00
2010-10-27 21:01:47 +02:00
if ( e . timer < diff )
{
2013-12-25 14:16:55 -03:30
// delay spell cast event if another spell is being cast
2011-10-23 21:34:50 +03:00
if ( e . GetActionType () == SMART_ACTION_CAST )
{
2016-08-19 15:23:19 +02:00
if ( ! ( e . action . cast . castFlags & SMARTCAST_INTERRUPT_PREVIOUS ))
2011-10-23 21:34:50 +03:00
{
2012-02-03 19:02:17 +02:00
if ( me && me -> HasUnitState ( UNIT_STATE_CASTING ))
2011-10-23 21:34:50 +03:00
{
e . timer = 1 ;
return ;
}
}
}
2016-06-04 21:17:15 +02:00
// Delay flee for assist event if stunned or rooted
if ( e . GetActionType () == SMART_ACTION_FLEE_FOR_ASSIST )
{
2017-02-17 21:33:18 +01:00
if ( me && me -> HasUnitState ( UNIT_STATE_ROOT | UNIT_STATE_LOST_CONTROL ))
2016-06-04 21:17:15 +02:00
{
e . timer = 1 ;
return ;
}
}
2010-10-27 21:01:47 +02:00
e . active = true ; //activate events with cooldown
switch ( e . GetEventType ()) //process ONLY timed events
{
case SMART_EVENT_UPDATE :
case SMART_EVENT_UPDATE_OOC :
case SMART_EVENT_UPDATE_IC :
case SMART_EVENT_HEALT_PCT :
case SMART_EVENT_TARGET_HEALTH_PCT :
case SMART_EVENT_MANA_PCT :
case SMART_EVENT_TARGET_MANA_PCT :
2010-12-13 22:37:56 +01:00
case SMART_EVENT_RANGE :
2013-10-22 15:59:32 +02:00
case SMART_EVENT_VICTIM_CASTING :
2010-10-27 21:01:47 +02:00
case SMART_EVENT_FRIENDLY_HEALTH :
case SMART_EVENT_FRIENDLY_IS_CC :
2010-12-13 22:37:56 +01:00
case SMART_EVENT_FRIENDLY_MISSING_BUFF :
2010-10-27 21:01:47 +02:00
case SMART_EVENT_HAS_AURA :
case SMART_EVENT_TARGET_BUFFED :
2011-04-14 00:30:32 -03:00
case SMART_EVENT_IS_BEHIND_TARGET :
2013-08-15 01:18:10 +01:00
case SMART_EVENT_FRIENDLY_HEALTH_PCT :
2014-03-17 16:58:10 -04:00
case SMART_EVENT_DISTANCE_CREATURE :
case SMART_EVENT_DISTANCE_GAMEOBJECT :
2010-11-03 14:10:16 +01:00
{
2010-10-27 21:01:47 +02:00
ProcessEvent ( e );
2010-11-03 14:10:16 +01:00
if ( e . GetScriptType () == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST )
{
e . enableTimed = false ; //disable event if it is in an ActionList and was processed once
for ( SmartAIEventList :: iterator i = mTimedActionList . begin (); i != mTimedActionList . end (); ++ i )
{
//find the first event which is not the current one and enable it
if ( i -> event_id > e . event_id )
{
i -> enableTimed = true ;
break ;
}
}
}
2010-10-27 21:01:47 +02:00
break ;
2010-11-03 14:10:16 +01:00
}
2010-10-27 21:01:47 +02:00
}
2011-03-27 12:54:42 +02:00
}
else
e . timer -= diff ;
2010-10-27 21:01:47 +02:00
}
2011-03-27 12:54:42 +02:00
bool SmartScript :: CheckTimer ( SmartScriptHolder const & e ) const
2010-10-27 21:01:47 +02:00
{
return e . active ;
}
void SmartScript :: InstallEvents ()
{
if ( ! mInstallEvents . empty ())
{
for ( SmartAIEventList :: iterator i = mInstallEvents . begin (); i != mInstallEvents . end (); ++ i )
2011-03-27 12:54:42 +02:00
mEvents . push_back ( * i ); //must be before UpdateTimers
2010-10-27 21:01:47 +02:00
mInstallEvents . clear ();
}
}
2017-05-18 23:52:58 +02:00
void SmartScript :: RemoveStoredEvent ( uint32 id )
{
if ( ! mStoredEvents . empty ())
{
2017-02-17 21:33:18 +01:00
for ( auto i = mStoredEvents . begin (); i != mStoredEvents . end (); ++ i )
2017-05-18 23:52:58 +02:00
{
if ( i -> event_id == id )
{
mStoredEvents . erase ( i );
return ;
}
}
}
}
2017-06-03 10:21:06 +02:00
WorldObject * SmartScript :: GetBaseObject () const
2017-05-18 23:52:58 +02:00
{
WorldObject * obj = nullptr ;
if ( me )
obj = me ;
else if ( go )
obj = go ;
return obj ;
}
WorldObject * SmartScript :: GetBaseObjectOrUnit ( Unit * unit )
{
WorldObject * summoner = GetBaseObject ();
if ( ! summoner && unit )
return unit ;
return summoner ;
}
bool SmartScript :: IsUnit ( WorldObject * obj )
{
return obj && ( obj -> GetTypeId () == TYPEID_UNIT || obj -> GetTypeId () == TYPEID_PLAYER );
}
bool SmartScript :: IsPlayer ( WorldObject * obj )
{
return obj && obj -> GetTypeId () == TYPEID_PLAYER ;
}
bool SmartScript :: IsCreature ( WorldObject * obj )
{
return obj && obj -> GetTypeId () == TYPEID_UNIT ;
}
2016-10-14 03:59:13 -03:00
bool SmartScript :: IsCharmedCreature ( WorldObject * obj )
2017-05-18 23:52:58 +02:00
{
2016-10-14 03:59:13 -03:00
if ( ! obj )
2017-05-18 23:52:58 +02:00
return false ;
2016-10-14 03:59:13 -03:00
if ( Creature * creatureObj = obj -> ToCreature ())
return creatureObj -> IsCharmed ();
return false ;
2017-05-18 23:52:58 +02:00
}
bool SmartScript :: IsGameObject ( WorldObject * obj )
{
return obj && obj -> GetTypeId () == TYPEID_GAMEOBJECT ;
}
2011-03-27 12:54:42 +02:00
void SmartScript :: OnUpdate ( uint32 const diff )
2010-10-27 21:01:47 +02:00
{
if (( mScriptType == SMART_SCRIPT_TYPE_CREATURE || mScriptType == SMART_SCRIPT_TYPE_GAMEOBJECT ) && ! GetBaseObject ())
return ;
2011-03-27 12:54:42 +02:00
2010-10-27 21:01:47 +02:00
InstallEvents (); //before UpdateTimers
for ( SmartAIEventList :: iterator i = mEvents . begin (); i != mEvents . end (); ++ i )
2011-03-27 12:54:42 +02:00
UpdateTimer ( * i , diff );
2010-10-27 21:01:47 +02:00
if ( ! mStoredEvents . empty ())
2017-02-17 21:33:18 +01:00
{
SmartAIEventStoredList :: iterator i , icurr ;
for ( i = mStoredEvents . begin (); i != mStoredEvents . end ();)
{
icurr = i ++ ;
UpdateTimer ( * icurr , diff );
}
}
2011-03-27 12:54:42 +02:00
2010-11-03 14:10:16 +01:00
bool needCleanup = true ;
if ( ! mTimedActionList . empty ())
{
2014-02-08 21:57:28 +01:00
isProcessingTimedActionList = true ;
2010-11-03 14:10:16 +01:00
for ( SmartAIEventList :: iterator i = mTimedActionList . begin (); i != mTimedActionList . end (); ++ i )
{
if (( * i ). enableTimed )
{
2011-03-27 12:54:42 +02:00
UpdateTimer ( * i , diff );
2010-11-03 14:10:16 +01:00
needCleanup = false ;
}
}
2014-02-08 21:57:28 +01:00
isProcessingTimedActionList = false ;
2010-11-03 14:10:16 +01:00
}
if ( needCleanup )
mTimedActionList . clear ();
2010-10-27 21:01:47 +02:00
if ( ! mRemIDs . empty ())
{
2017-02-17 21:33:18 +01:00
for ( auto i : mRemIDs )
RemoveStoredEvent ( i );
mRemIDs . clear ();
2010-10-27 21:01:47 +02:00
}
2017-02-17 21:33:18 +01:00
2010-10-27 21:01:47 +02:00
if ( mUseTextTimer && me )
{
if ( mTextTimer < diff )
{
2011-09-20 17:56:47 +02:00
uint32 textID = mLastTextID ;
2010-11-01 11:00:53 +01:00
mLastTextID = 0 ;
2011-09-20 17:56:47 +02:00
uint32 entry = mTalkerEntry ;
mTalkerEntry = 0 ;
2010-11-01 11:00:53 +01:00
mTextTimer = 0 ;
mUseTextTimer = false ;
2016-08-05 12:41:56 +02:00
ProcessEventsFor ( SMART_EVENT_TEXT_OVER , nullptr , textID , entry );
2010-10-27 21:01:47 +02:00
} else mTextTimer -= diff ;
}
}
2017-03-17 21:21:35 +01:00
void SmartScript :: FillScript ( SmartAIEventList e , WorldObject * obj , AreaTriggerEntry const * at , SceneTemplate const * scene )
2010-10-27 21:01:47 +02:00
{
if ( e . empty ())
{
if ( obj )
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript: EventMap for Entry %u is empty but is using SmartScript." , obj -> GetEntry ());
2010-10-27 21:01:47 +02:00
if ( at )
2014-11-06 01:13:06 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript: EventMap for AreaTrigger %u is empty but is using SmartScript." , at -> ID );
2017-03-17 21:21:35 +01:00
if ( scene )
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript: EventMap for SceneId %u is empty but is using SmartScript." , scene -> SceneId );
2010-10-27 21:01:47 +02:00
return ;
}
for ( SmartAIEventList :: iterator i = e . begin (); i != e . end (); ++ i )
{
#ifndef TRINITY_DEBUG
2010-10-27 20:03:42 -07:00
if (( * i ). event . event_flags & SMART_EVENT_FLAG_DEBUG_ONLY )
2010-10-27 21:01:47 +02:00
continue ;
#endif
if (( * i ). event . event_flags & SMART_EVENT_FLAG_DIFFICULTY_ALL ) //if has instance flag add only if in it
{
if ( obj && obj -> GetMap () -> IsDungeon ())
{
2018-09-15 17:55:26 +02:00
// TODO: fix it for new maps and difficulties
switch ( obj -> GetMap () -> GetDifficultyID ())
2010-10-27 21:01:47 +02:00
{
2018-09-15 17:55:26 +02:00
case DIFFICULTY_NORMAL :
case DIFFICULTY_10_N :
if ( i -> event . event_flags & SMART_EVENT_FLAG_DIFFICULTY_0 )
mEvents . emplace_back ( std :: move ( * i ));
break ;
case DIFFICULTY_HEROIC :
case DIFFICULTY_25_N :
if ( i -> event . event_flags & SMART_EVENT_FLAG_DIFFICULTY_1 )
mEvents . emplace_back ( std :: move ( * i ));
break ;
case DIFFICULTY_10_HC :
if ( i -> event . event_flags & SMART_EVENT_FLAG_DIFFICULTY_2 )
mEvents . emplace_back ( std :: move ( * i ));
break ;
case DIFFICULTY_25_HC :
if ( i -> event . event_flags & SMART_EVENT_FLAG_DIFFICULTY_3 )
mEvents . emplace_back ( std :: move ( * i ));
break ;
default :
break ;
2010-10-27 21:01:47 +02:00
}
}
continue ;
}
mEvents . push_back (( * i )); //NOTE: 'world(0)' events still get processed in ANY instance mode
}
}
void SmartScript :: GetScript ()
{
SmartAIEventList e ;
if ( me )
{
2015-02-25 00:13:14 +01:00
e = sSmartScriptMgr -> GetScript ( - (( int32 ) me -> GetSpawnId ()), mScriptType );
2010-10-27 21:01:47 +02:00
if ( e . empty ())
2010-12-22 21:25:23 +01:00
e = sSmartScriptMgr -> GetScript (( int32 ) me -> GetEntry (), mScriptType );
2018-09-15 17:55:26 +02:00
FillScript ( std :: move ( e ), me , nullptr , nullptr );
2010-10-27 21:01:47 +02:00
}
else if ( go )
{
2015-02-25 00:13:14 +01:00
e = sSmartScriptMgr -> GetScript ( - (( int32 ) go -> GetSpawnId ()), mScriptType );
2010-10-27 21:01:47 +02:00
if ( e . empty ())
2010-12-22 21:25:23 +01:00
e = sSmartScriptMgr -> GetScript (( int32 ) go -> GetEntry (), mScriptType );
2018-09-15 17:55:26 +02:00
FillScript ( std :: move ( e ), go , nullptr , nullptr );
2010-10-27 21:01:47 +02:00
}
else if ( trigger )
{
2014-11-06 01:13:06 +02:00
e = sSmartScriptMgr -> GetScript (( int32 ) trigger -> ID , mScriptType );
2018-09-15 17:55:26 +02:00
FillScript ( std :: move ( e ), nullptr , trigger , nullptr );
2017-03-17 21:21:35 +01:00
}
else if ( sceneTemplate )
{
e = sSmartScriptMgr -> GetScript ( sceneTemplate -> SceneId , mScriptType );
2018-09-15 17:55:26 +02:00
FillScript ( std :: move ( e ), nullptr , nullptr , sceneTemplate );
2010-10-27 21:01:47 +02:00
}
}
2017-03-17 21:21:35 +01:00
void SmartScript :: OnInitialize ( WorldObject * obj , AreaTriggerEntry const * at , SceneTemplate const * scene )
2010-10-27 21:01:47 +02:00
{
if ( obj ) //handle object based scripts
{
switch ( obj -> GetTypeId ())
{
case TYPEID_UNIT :
mScriptType = SMART_SCRIPT_TYPE_CREATURE ;
me = obj -> ToCreature ();
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::OnInitialize: source is Creature %u" , me -> GetEntry ());
2010-10-27 21:01:47 +02:00
break ;
case TYPEID_GAMEOBJECT :
mScriptType = SMART_SCRIPT_TYPE_GAMEOBJECT ;
go = obj -> ToGameObject ();
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::OnInitialize: source is GameObject %u" , go -> GetEntry ());
2010-10-27 21:01:47 +02:00
break ;
default :
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "SmartScript::OnInitialize: Unhandled TypeID !WARNING!" );
2010-10-27 21:01:47 +02:00
return ;
}
2017-03-17 21:21:35 +01:00
}
else if ( at )
2010-10-27 21:01:47 +02:00
{
mScriptType = SMART_SCRIPT_TYPE_AREATRIGGER ;
trigger = at ;
2014-11-06 01:13:06 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::OnInitialize: source is AreaTrigger %u" , trigger -> ID );
2010-10-27 21:01:47 +02:00
}
2017-03-17 21:21:35 +01:00
else if ( scene )
{
mScriptType = SMART_SCRIPT_TYPE_SCENE ;
sceneTemplate = scene ;
TC_LOG_DEBUG ( "scripts.ai" , "SmartScript::OnInitialize: source is Scene with id %u" , scene -> SceneId );
}
2010-10-27 21:01:47 +02:00
else
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "SmartScript::OnInitialize: !WARNING! Initialized objects are NULL." );
2010-10-27 21:01:47 +02:00
return ;
}
GetScript (); //load copy of script
for ( SmartAIEventList :: iterator i = mEvents . begin (); i != mEvents . end (); ++ i )
InitTimer (( * i )); //calculate timers for first time use
ProcessEventsFor ( SMART_EVENT_AI_INIT );
InstallEvents ();
ProcessEventsFor ( SMART_EVENT_JUST_CREATED );
}
void SmartScript :: OnMoveInLineOfSight ( Unit * who )
{
2012-03-28 20:00:29 +08:00
if ( ! me )
return ;
2017-07-01 20:18:02 +02:00
ProcessEventsFor ( me -> IsEngaged () ? SMART_EVENT_IC_LOS : SMART_EVENT_OOC_LOS , who );
2010-10-27 21:01:47 +02:00
}
// SmartScript end
2017-06-03 10:21:06 +02:00
Unit * SmartScript :: DoSelectLowestHpFriendly ( float range , uint32 MinHPDiff ) const
2010-10-27 21:01:47 +02:00
{
2011-10-19 17:40:44 +01:00
if ( ! me )
2016-08-05 12:41:56 +02:00
return nullptr ;
2011-10-19 17:40:44 +01:00
2016-08-05 12:41:56 +02:00
Unit * unit = nullptr ;
2017-02-17 21:33:18 +01:00
2010-10-27 21:01:47 +02:00
Trinity :: MostHPMissingInRange u_check ( me , range , MinHPDiff );
2011-08-20 20:31:31 -03:00
Trinity :: UnitLastSearcher < Trinity :: MostHPMissingInRange > searcher ( me , unit , u_check );
2017-05-13 19:37:33 +02:00
Cell :: VisitGridObjects ( me , searcher , range );
2011-08-20 20:31:31 -03:00
return unit ;
2010-10-27 21:01:47 +02:00
}
2017-06-03 10:21:06 +02:00
void SmartScript :: DoFindFriendlyCC ( std :: vector < Creature *>& creatures , float range ) const
2010-10-27 21:01:47 +02:00
{
2011-10-19 17:40:44 +01:00
if ( ! me )
return ;
2010-10-27 21:01:47 +02:00
Trinity :: FriendlyCCedInRange u_check ( me , range );
2017-06-03 10:21:06 +02:00
Trinity :: CreatureListSearcher < Trinity :: FriendlyCCedInRange > searcher ( me , creatures , u_check );
2017-05-13 19:37:33 +02:00
Cell :: VisitGridObjects ( me , searcher , range );
2010-10-27 21:01:47 +02:00
}
2017-06-03 10:21:06 +02:00
void SmartScript :: DoFindFriendlyMissingBuff ( std :: vector < Creature *>& creatures , float range , uint32 spellid ) const
2010-10-27 21:01:47 +02:00
{
2011-10-19 17:40:44 +01:00
if ( ! me )
return ;
2010-10-27 21:01:47 +02:00
Trinity :: FriendlyMissingBuffInRange u_check ( me , range , spellid );
2017-06-03 10:21:06 +02:00
Trinity :: CreatureListSearcher < Trinity :: FriendlyMissingBuffInRange > searcher ( me , creatures , u_check );
2017-05-13 19:37:33 +02:00
Cell :: VisitGridObjects ( me , searcher , range );
2010-11-07 22:10:11 +01:00
}
2017-06-03 10:21:06 +02:00
Unit * SmartScript :: DoFindClosestFriendlyInRange ( float range , bool playerOnly ) const
2013-08-15 01:22:22 +01:00
{
if ( ! me )
2016-08-05 12:41:56 +02:00
return nullptr ;
2013-08-15 01:22:22 +01:00
2016-08-05 12:41:56 +02:00
Unit * unit = nullptr ;
2013-09-30 10:11:02 +02:00
Trinity :: AnyFriendlyUnitInObjectRangeCheck u_check ( me , me , range , playerOnly );
2013-08-15 01:22:22 +01:00
Trinity :: UnitLastSearcher < Trinity :: AnyFriendlyUnitInObjectRangeCheck > searcher ( me , unit , u_check );
2017-05-13 19:37:33 +02:00
Cell :: VisitAllObjects ( me , searcher , range );
2013-08-15 01:22:22 +01:00
return unit ;
}
2011-03-27 12:54:42 +02:00
void SmartScript :: SetScript9 ( SmartScriptHolder & e , uint32 entry )
2010-11-07 22:10:11 +01:00
{
2014-02-08 21:57:28 +01:00
//do NOT clear mTimedActionList if it's being iterated because it will invalidate the iterator and delete
// any SmartScriptHolder contained like the "e" parameter passed to this function
if ( isProcessingTimedActionList )
{
2014-10-26 02:57:28 +02:00
TC_LOG_ERROR ( "scripts.ai" , "Entry " SI64FMTD " SourceType %u Event %u Action %u is trying to overwrite timed action list from a timed action, this is not allowed!." , e . entryOrGuid , e . GetScriptType (), e . GetEventType (), e . GetActionType ());
2014-02-08 21:57:28 +01:00
return ;
}
2010-11-07 22:10:11 +01:00
mTimedActionList . clear ();
2010-12-22 21:25:23 +01:00
mTimedActionList = sSmartScriptMgr -> GetScript ( entry , SMART_SCRIPT_TYPE_TIMED_ACTIONLIST );
2010-11-07 22:10:11 +01:00
if ( mTimedActionList . empty ())
return ;
for ( SmartAIEventList :: iterator i = mTimedActionList . begin (); i != mTimedActionList . end (); ++ i )
{
2013-10-01 10:08:05 +02:00
i -> enableTimed = i == mTimedActionList . begin (); //enable processing only for the first action
2010-12-13 22:37:56 +01:00
2013-10-01 10:08:05 +02:00
if ( e . action . timedActionList . timerType == 0 )
i -> event . type = SMART_EVENT_UPDATE_OOC ;
else if ( e . action . timedActionList . timerType == 1 )
2010-11-07 22:10:11 +01:00
i -> event . type = SMART_EVENT_UPDATE_IC ;
else if ( e . action . timedActionList . timerType > 1 )
i -> event . type = SMART_EVENT_UPDATE ;
2013-10-01 10:08:05 +02:00
2010-11-07 22:10:11 +01:00
InitTimer (( * i ));
}
2011-12-11 16:22:18 +01:00
}
2017-06-03 10:21:06 +02:00
Unit * SmartScript :: GetLastInvoker ( Unit * invoker ) const
2011-02-21 22:23:43 +01:00
{
2017-02-05 23:42:31 +01:00
// Look for invoker only on map of base object... Prevents multithreaded crashes
if ( WorldObject * baseObject = GetBaseObject ())
return ObjectAccessor :: GetUnit ( * baseObject , mLastInvoker );
// used for area triggers invoker cast
else if ( invoker )
return ObjectAccessor :: GetUnit ( * invoker , mLastInvoker );
return nullptr ;
2010-11-16 14:08:12 +01:00
}
2019-11-01 14:54:34 +01:00
void SmartScript :: IncPhase ( uint32 p )
{
// protect phase from overflowing
2017-06-10 19:17:41 -03:00
SetPhase ( std :: min < uint32 > ( SMART_EVENT_PHASE_12 , mEventPhase + p ));
}
void SmartScript :: DecPhase ( uint32 p )
{
if ( p >= mEventPhase )
SetPhase ( 0 );
else
SetPhase ( mEventPhase - p );
}
void SmartScript :: SetPhase ( uint32 p )
{
uint32 oldPhase = mEventPhase ;
mEventPhase = p ;
if ( oldPhase != mEventPhase )
ProcessEventsFor ( SMART_EVENT_EVENT_PHASE_CHANGE );
}
bool SmartScript :: IsInPhase ( uint32 p ) const
{
if ( mEventPhase == 0 )
return false ;
return (( 1 << ( mEventPhase - 1 )) & p ) != 0 ;
2019-11-01 14:54:34 +01:00
}