2010-10-27 21:01:47 +02:00
/*
2012-01-01 00:32:13 +01:00
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
2010-10-27 21:01:47 +02:00
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DatabaseEnv.h"
#include "ObjectMgr.h"
#include "ObjectDefines.h"
#include "GridDefines.h"
#include "GridNotifiers.h"
#include "SpellMgr.h"
#include "GridNotifiersImpl.h"
#include "Cell.h"
#include "CellImpl.h"
#include "InstanceScript.h"
#include "ScriptedCreature.h"
2010-11-29 07:50:31 +01:00
#include "Group.h"
2010-10-27 21:01:47 +02:00
#include "SmartAI.h"
2012-07-29 21:40:10 +02:00
#include "ScriptMgr.h"
2010-10-27 21:01:47 +02:00
2011-03-27 12:54:42 +02:00
SmartAI :: SmartAI ( Creature * c ) : CreatureAI ( c )
2010-10-27 21:01:47 +02:00
{
2010-11-16 14:08:12 +01:00
// copy script to local (protection for table reload)
2010-10-27 21:01:47 +02:00
mWayPoints = NULL ;
mEscortState = SMART_ESCORT_NONE ;
mCurrentWPID = 0 ; //first wp id is 1 !!
mWPReached = false ;
mWPPauseTimer = 0 ;
mLastWP = NULL ;
mCanRepeatPath = false ;
// spawn in run mode
2012-02-23 11:50:58 +01:00
me -> SetWalk ( false );
2012-01-21 18:54:05 -05:00
mRun = false ;
2010-10-27 21:01:47 +02:00
me -> GetPosition ( & mLastOOCPos );
2010-12-13 22:37:56 +01:00
2010-10-27 21:01:47 +02:00
mCanAutoAttack = true ;
mCanCombatMove = true ;
mForcedPaused = false ;
mLastWPIDReached = 0 ;
mEscortQuestID = 0 ;
mDespawnTime = 0 ;
mDespawnState = 0 ;
mEscortInvokerCheckTimer = 1000 ;
mFollowGuid = 0 ;
mFollowDist = 0 ;
mFollowAngle = 0 ;
mFollowCredit = 0 ;
mFollowArrivedEntry = 0 ;
mFollowCreditType = 0 ;
2012-03-29 00:47:56 +02:00
mInvincibilityHpLevel = 0 ;
2010-10-27 21:01:47 +02:00
}
void SmartAI :: UpdateDespawn ( const uint32 diff )
{
2012-03-28 20:00:29 +08:00
if ( mDespawnState <= 1 || mDespawnState > 3 )
return ;
2010-10-27 21:01:47 +02:00
if ( mDespawnTime < diff )
{
if ( mDespawnState == 2 )
{
2010-11-16 01:13:04 +01:00
me -> SetVisible ( false );
2010-10-27 21:01:47 +02:00
mDespawnTime = 5000 ;
mDespawnState ++ ;
}
else
2011-01-02 21:33:37 +01:00
me -> DespawnOrUnsummon ();
2010-10-27 21:01:47 +02:00
} else mDespawnTime -= diff ;
}
void SmartAI :: Reset ()
{
2010-11-16 00:13:47 +01:00
if ( ! HasEscortState ( SMART_ESCORT_ESCORTING )) //dont mess up escort movement after combat
2012-01-27 08:34:36 -05:00
SetRun ( mRun );
2010-10-27 21:01:47 +02:00
GetScript () -> OnReset ();
}
WayPoint * SmartAI :: GetNextWayPoint ()
{
if ( ! mWayPoints || mWayPoints -> empty ())
return NULL ;
mCurrentWPID ++ ;
WPPath :: const_iterator itr = mWayPoints -> find ( mCurrentWPID );
if ( itr != mWayPoints -> end ())
{
mLastWP = ( * itr ). second ;
if ( mLastWP -> id != mCurrentWPID )
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "SmartAI::GetNextWayPoint: Got not expected waypoint id %u, expected %u" , mLastWP -> id , mCurrentWPID );
2010-10-27 21:01:47 +02:00
}
return ( * itr ). second ;
}
return NULL ;
}
2010-11-16 14:08:12 +01:00
void SmartAI :: StartPath ( bool run , uint32 path , bool repeat , Unit * /*invoker*/ )
2010-10-27 21:01:47 +02:00
{
if ( me -> isInCombat ()) // no wp movement in combat
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "SmartAI::StartPath: Creature entry %u wanted to start waypoint movement while in combat, ignoring." , me -> GetEntry ());
2010-10-27 21:01:47 +02:00
return ;
}
if ( HasEscortState ( SMART_ESCORT_ESCORTING ))
StopPath ();
if ( path )
if ( ! LoadPath ( path ))
return ;
if ( ! mWayPoints || mWayPoints -> empty ())
return ;
AddEscortState ( SMART_ESCORT_ESCORTING );
mCanRepeatPath = repeat ;
SetRun ( run );
2012-08-03 14:20:18 +02:00
if ( WayPoint * wp = GetNextWayPoint ())
2010-10-27 21:01:47 +02:00
{
me -> GetPosition ( & mLastOOCPos );
me -> GetMotionMaster () -> MovePoint ( wp -> id , wp -> x , wp -> y , wp -> z );
GetScript () -> ProcessEventsFor ( SMART_EVENT_WAYPOINT_START , NULL , wp -> id , GetScript () -> GetPathId ());
}
}
bool SmartAI :: LoadPath ( uint32 entry )
{
if ( HasEscortState ( SMART_ESCORT_ESCORTING ))
return false ;
2010-12-22 21:25:23 +01:00
mWayPoints = sSmartWaypointMgr -> GetPath ( entry );
2010-10-27 21:01:47 +02:00
if ( ! mWayPoints )
{
GetScript () -> SetPathId ( 0 );
return false ;
}
GetScript () -> SetPathId ( entry );
return true ;
}
void SmartAI :: PausePath ( uint32 delay , bool forced )
{
if ( ! HasEscortState ( SMART_ESCORT_ESCORTING ))
return ;
if ( HasEscortState ( SMART_ESCORT_PAUSED ))
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "SmartAI::StartPath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring." , me -> GetEntry ());
2010-10-27 21:01:47 +02:00
return ;
}
mForcedPaused = forced ;
me -> GetPosition ( & mLastOOCPos );
AddEscortState ( SMART_ESCORT_PAUSED );
mWPPauseTimer = delay ;
if ( forced )
{
SetRun ( mRun );
me -> StopMoving (); //force stop
me -> GetMotionMaster () -> MoveIdle (); //force stop
}
GetScript () -> ProcessEventsFor ( SMART_EVENT_WAYPOINT_PAUSED , NULL , mLastWP -> id , GetScript () -> GetPathId ());
}
void SmartAI :: StopPath ( uint32 DespawnTime , uint32 quest , bool fail )
{
if ( ! HasEscortState ( SMART_ESCORT_ESCORTING ))
return ;
if ( quest )
mEscortQuestID = quest ;
SetDespawnTime ( DespawnTime );
//mDespawnTime = DespawnTime;
me -> GetPosition ( & mLastOOCPos );
me -> StopMoving (); //force stop
me -> GetMotionMaster () -> MoveIdle ();
GetScript () -> ProcessEventsFor ( SMART_EVENT_WAYPOINT_STOPPED , NULL , mLastWP -> id , GetScript () -> GetPathId ());
EndPath ( fail );
}
void SmartAI :: EndPath ( bool fail )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_WAYPOINT_ENDED , NULL , mLastWP -> id , GetScript () -> GetPathId ());
RemoveEscortState ( SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING );
mWayPoints = NULL ;
mCurrentWPID = 0 ;
mWPPauseTimer = 0 ;
mLastWP = NULL ;
2010-12-13 22:37:56 +01:00
2010-10-27 21:01:47 +02:00
if ( mCanRepeatPath )
StartPath ( mRun , GetScript () -> GetPathId (), mCanRepeatPath );
else
GetScript () -> SetPathId ( 0 );
ObjectList * targets = GetScript () -> GetTargetList ( SMART_ESCORT_TARGETS );
if ( targets && mEscortQuestID )
{
if ( targets -> size () == 1 && GetScript () -> IsPlayer (( * targets -> begin ())))
{
2011-08-20 20:31:31 -03:00
Player * player = ( * targets -> begin ()) -> ToPlayer ();
if ( ! fail && player -> IsAtGroupRewardDistance ( me ) && ! player -> GetCorpse ())
player -> GroupEventHappens ( mEscortQuestID , me );
2010-10-27 21:01:47 +02:00
2011-08-20 20:31:31 -03:00
if ( fail && player -> GetQuestStatus ( mEscortQuestID ) == QUEST_STATUS_INCOMPLETE )
player -> FailQuest ( mEscortQuestID );
2010-10-27 21:01:47 +02:00
2011-08-20 20:31:31 -03:00
if ( Group * group = player -> GetGroup ())
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
for ( GroupReference * groupRef = group -> GetFirstMember (); groupRef != NULL ; groupRef = groupRef -> next ())
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
Player * groupGuy = groupRef -> getSource ();
2010-10-27 21:01:47 +02:00
2011-08-20 20:31:31 -03:00
if ( ! fail && groupGuy -> IsAtGroupRewardDistance ( me ) && ! groupGuy -> GetCorpse ())
groupGuy -> AreaExploredOrEventHappens ( mEscortQuestID );
if ( fail && groupGuy -> GetQuestStatus ( mEscortQuestID ) == QUEST_STATUS_INCOMPLETE )
groupGuy -> FailQuest ( mEscortQuestID );
2010-10-27 21:01:47 +02:00
}
}
} else
{
2011-08-23 18:05:01 +03:00
for ( ObjectList :: iterator iter = targets -> begin (); iter != targets -> end (); ++ iter )
2010-10-27 21:01:47 +02:00
{
if ( GetScript () -> IsPlayer (( * iter )))
{
2011-08-20 20:31:31 -03:00
Player * player = ( * iter ) -> ToPlayer ();
if ( ! fail && player -> IsAtGroupRewardDistance ( me ) && ! player -> GetCorpse ())
player -> AreaExploredOrEventHappens ( mEscortQuestID );
if ( fail && player -> GetQuestStatus ( mEscortQuestID ) == QUEST_STATUS_INCOMPLETE )
player -> FailQuest ( mEscortQuestID );
2010-10-27 21:01:47 +02:00
}
}
}
}
if ( mDespawnState == 1 )
StartDespawn ();
}
void SmartAI :: ResumePath ()
{
//mWPReached = false;
SetRun ( mRun );
if ( mLastWP )
me -> GetMotionMaster () -> MovePoint ( mLastWP -> id , mLastWP -> x , mLastWP -> y , mLastWP -> z );
}
void SmartAI :: ReturnToLastOOCPos ()
{
SetRun ( mRun );
me -> GetMotionMaster () -> MovePoint ( SMART_ESCORT_LAST_OOC_POINT , mLastOOCPos );
}
void SmartAI :: UpdatePath ( const uint32 diff )
{
if ( ! HasEscortState ( SMART_ESCORT_ESCORTING ))
return ;
if ( mEscortInvokerCheckTimer < diff )
{
if ( ! IsEscortInvokerInRange ())
{
StopPath ( mDespawnTime , mEscortQuestID , true );
}
mEscortInvokerCheckTimer = 1000 ;
} else mEscortInvokerCheckTimer -= diff ;
// handle pause
if ( HasEscortState ( SMART_ESCORT_PAUSED ))
{
if ( mWPPauseTimer < diff )
{
if ( ! me -> isInCombat () && ! HasEscortState ( SMART_ESCORT_RETURNING ) && ( mWPReached || mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT || mForcedPaused ))
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_WAYPOINT_RESUMED , NULL , mLastWP -> id , GetScript () -> GetPathId ());
RemoveEscortState ( SMART_ESCORT_PAUSED );
if ( mForcedPaused ) // if paused between 2 wps resend movement
{
ResumePath ();
mWPReached = false ;
mForcedPaused = false ;
}
if ( mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT )
mWPReached = true ;
}
mWPPauseTimer = 0 ;
} else {
mWPPauseTimer -= diff ;
}
}
if ( HasEscortState ( SMART_ESCORT_RETURNING ))
{
if ( mWPReached ) //reached OOC WP
{
RemoveEscortState ( SMART_ESCORT_RETURNING );
if ( ! HasEscortState ( SMART_ESCORT_PAUSED ))
ResumePath ();
mWPReached = false ;
}
}
if ( me -> isInCombat () || HasEscortState ( SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING ))
return ;
// handle next wp
if ( mWPReached ) //reached WP
{
mWPReached = false ;
if ( mCurrentWPID == GetWPCount ())
{
EndPath ();
}
2012-08-03 14:20:18 +02:00
else if ( WayPoint * wp = GetNextWayPoint ())
{
SetRun ( mRun );
me -> GetMotionMaster () -> MovePoint ( wp -> id , wp -> x , wp -> y , wp -> z );
}
2010-10-27 21:01:47 +02:00
}
}
void SmartAI :: UpdateAI ( const uint32 diff )
{
GetScript () -> OnUpdate ( diff );
UpdatePath ( diff );
UpdateDespawn ( diff );
//TODO move to void
if ( mFollowGuid )
{
if ( mFollowArrivedTimer < diff )
{
2011-04-29 20:47:02 +02:00
if ( me -> FindNearestCreature ( mFollowArrivedEntry , INTERACTION_DISTANCE , true ))
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
if ( Player * player = me -> GetPlayer ( * me , mFollowGuid ))
2010-10-27 21:01:47 +02:00
{
if ( ! mFollowCreditType )
2011-08-20 20:31:31 -03:00
player -> RewardPlayerAndGroupAtEvent ( mFollowCredit , me );
2010-10-27 21:01:47 +02:00
else
2011-08-20 20:31:31 -03:00
player -> GroupEventHappens ( mFollowCredit , me );
2010-10-27 21:01:47 +02:00
}
mFollowGuid = 0 ;
mFollowDist = 0 ;
mFollowAngle = 0 ;
mFollowCredit = 0 ;
mFollowArrivedTimer = 1000 ;
mFollowArrivedEntry = 0 ;
mFollowCreditType = 0 ;
SetDespawnTime ( 5000 );
me -> StopMoving ();
me -> GetMotionMaster () -> MoveIdle ();
StartDespawn ();
2010-11-17 23:24:21 +01:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_FOLLOW_COMPLETED );
2010-10-27 21:01:47 +02:00
return ;
}
mFollowArrivedTimer = 1000 ;
} else mFollowArrivedTimer -= diff ;
}
if ( ! UpdateVictim ())
return ;
2011-06-12 02:30:32 +02:00
if ( mCanAutoAttack )
2010-10-27 21:01:47 +02:00
DoMeleeAttackIfReady ();
}
bool SmartAI :: IsEscortInvokerInRange ()
{
ObjectList * targets = GetScript () -> GetTargetList ( SMART_ESCORT_TARGETS );
if ( targets )
{
if ( targets -> size () == 1 && GetScript () -> IsPlayer (( * targets -> begin ())))
{
2011-08-20 20:31:31 -03:00
Player * player = ( * targets -> begin ()) -> ToPlayer ();
if ( me -> GetDistance ( player ) <= SMART_ESCORT_MAX_PLAYER_DIST )
2010-10-27 21:01:47 +02:00
return true ;
2011-08-20 20:31:31 -03:00
if ( Group * group = player -> GetGroup ())
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
for ( GroupReference * groupRef = group -> GetFirstMember (); groupRef != NULL ; groupRef = groupRef -> next ())
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
Player * groupGuy = groupRef -> getSource ();
2010-10-27 21:01:47 +02:00
2011-08-20 20:31:31 -03:00
if ( me -> GetDistance ( groupGuy ) <= SMART_ESCORT_MAX_PLAYER_DIST )
2010-10-27 21:01:47 +02:00
return true ;
}
}
} else
{
2011-08-23 18:05:01 +03:00
for ( ObjectList :: iterator iter = targets -> begin (); iter != targets -> end (); ++ iter )
2010-10-27 21:01:47 +02:00
{
if ( GetScript () -> IsPlayer (( * iter )))
{
if ( me -> GetDistance (( * iter ) -> ToPlayer ()) <= SMART_ESCORT_MAX_PLAYER_DIST )
return true ;
}
}
}
}
2010-11-16 00:13:47 +01:00
return true ; //escort targets were not set, ignore range check
2010-10-27 21:01:47 +02:00
}
void SmartAI :: MovepointReached ( uint32 id )
{
2011-02-15 02:53:03 +01:00
if ( id != SMART_ESCORT_LAST_OOC_POINT && mLastWPIDReached != id )
2010-10-27 21:01:47 +02:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_WAYPOINT_REACHED , NULL , id );
mLastWPIDReached = id ;
mWPReached = true ;
}
void SmartAI :: MovementInform ( uint32 MovementType , uint32 Data )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_MOVEMENTINFORM , NULL , MovementType , Data );
if ( MovementType != POINT_MOTION_TYPE || ! HasEscortState ( SMART_ESCORT_ESCORTING ))
return ;
MovepointReached ( Data );
}
2012-01-05 15:09:55 -05:00
void SmartAI :: RemoveAuras ()
{
2012-01-06 20:50:05 -05:00
// Only loop throught the applied auras, because here is where all auras on the current unit are stored
2012-01-05 15:09:55 -05:00
Unit :: AuraApplicationMap appliedAuras = me -> GetAppliedAuras ();
2012-01-06 20:50:05 -05:00
for ( Unit :: AuraApplicationMap :: iterator iter = appliedAuras . begin (); iter != appliedAuras . end (); ++ iter )
2012-01-05 15:09:55 -05:00
{
Aura const * aura = iter -> second -> GetBase ();
2012-01-06 20:50:05 -05:00
if ( ! aura -> GetSpellInfo () -> IsPassive () && ! aura -> GetSpellInfo () -> HasAura ( SPELL_AURA_CONTROL_VEHICLE ) && aura -> GetCaster () != me )
me -> RemoveAurasDueToSpell ( aura -> GetId ());
2012-01-05 15:09:55 -05:00
}
}
2010-10-27 21:01:47 +02:00
void SmartAI :: EnterEvadeMode ()
{
if ( ! me -> isAlive ())
return ;
2012-01-05 15:09:55 -05:00
RemoveAuras ();
2012-02-18 16:52:08 +01:00
2010-10-27 21:01:47 +02:00
me -> DeleteThreatList ();
me -> CombatStop ( true );
me -> LoadCreaturesAddon ();
me -> SetLootRecipient ( NULL );
me -> ResetPlayerDamageReq ();
GetScript () -> ProcessEventsFor ( SMART_EVENT_EVADE ); //must be after aura clear so we can cast spells from db
SetRun ( mRun );
if ( HasEscortState ( SMART_ESCORT_ESCORTING ))
{
AddEscortState ( SMART_ESCORT_RETURNING );
ReturnToLastOOCPos ();
2011-10-24 23:21:34 +01:00
}
else if ( mFollowGuid )
{
2010-10-27 21:01:47 +02:00
if ( Unit * target = me -> GetUnit ( * me , mFollowGuid ))
me -> GetMotionMaster () -> MoveFollow ( target , mFollowDist , mFollowAngle );
}
2011-10-24 23:21:34 +01:00
else
me -> GetMotionMaster () -> MoveTargetedHome ();
2010-10-27 21:01:47 +02:00
2010-12-13 22:37:56 +01:00
Reset ();
2010-10-27 21:01:47 +02:00
}
void SmartAI :: MoveInLineOfSight ( Unit * who )
{
2011-10-01 16:57:10 +01:00
if ( ! who )
return ;
2012-02-18 16:52:08 +01:00
2010-10-27 21:01:47 +02:00
GetScript () -> OnMoveInLineOfSight ( who );
2012-02-18 16:52:08 +01:00
2010-10-27 21:01:47 +02:00
if ( me -> HasReactState ( REACT_PASSIVE ) || AssistPlayerInCombat ( who ))
return ;
if ( ! CanAIAttack ( who ))
return ;
2012-02-18 16:52:08 +01:00
2011-10-01 16:29:23 +01:00
if ( ! me -> canStartAttack ( who , false ))
return ;
2010-10-27 21:01:47 +02:00
if ( me -> IsHostileTo ( who ))
{
float fAttackRadius = me -> GetAttackDistance ( who );
if ( me -> IsWithinDistInMap ( who , fAttackRadius ) && me -> IsWithinLOSInMap ( who ))
{
if ( ! me -> getVictim ())
{
who -> RemoveAurasByType ( SPELL_AURA_MOD_STEALTH );
AttackStart ( who );
}
else /* if (me->GetMap()->IsDungeon())*/
{
who -> SetInCombatWith ( me );
me -> AddThreat ( who , 0.0f );
}
}
}
}
2010-11-16 14:08:12 +01:00
bool SmartAI :: CanAIAttack ( const Unit * /*who*/ ) const
2010-10-27 21:01:47 +02:00
{
if ( me -> GetReactState () == REACT_PASSIVE )
return false ;
return true ;
}
2011-08-20 20:31:31 -03:00
bool SmartAI :: AssistPlayerInCombat ( Unit * who )
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
if ( ! who || ! who -> getVictim ())
2010-10-27 21:01:47 +02:00
return false ;
//experimental (unknown) flag not present
2012-02-27 14:58:47 +01:00
if ( ! ( me -> GetCreatureTemplate () -> type_flags & CREATURE_TYPEFLAGS_AID_PLAYERS ))
2010-10-27 21:01:47 +02:00
return false ;
//not a player
2011-08-20 20:31:31 -03:00
if ( ! who -> getVictim () -> GetCharmerOrOwnerPlayerOrPlayerItself ())
2010-10-27 21:01:47 +02:00
return false ;
//never attack friendly
2011-08-20 20:31:31 -03:00
if ( me -> IsFriendlyTo ( who ))
2010-10-27 21:01:47 +02:00
return false ;
//too far away and no free sight?
2011-08-20 20:31:31 -03:00
if ( me -> IsWithinDistInMap ( who , SMART_MAX_AID_DIST ) && me -> IsWithinLOSInMap ( who ))
2010-10-27 21:01:47 +02:00
{
//already fighting someone?
if ( ! me -> getVictim ())
{
2011-08-20 20:31:31 -03:00
AttackStart ( who );
2010-10-27 21:01:47 +02:00
return true ;
}
else
{
2011-08-20 20:31:31 -03:00
who -> SetInCombatWith ( me );
me -> AddThreat ( who , 0.0f );
2010-10-27 21:01:47 +02:00
return true ;
}
}
return false ;
}
void SmartAI :: JustRespawned ()
{
mDespawnTime = 0 ;
mDespawnState = 0 ;
mEscortState = SMART_ESCORT_NONE ;
2010-11-16 01:13:04 +01:00
me -> SetVisible ( true );
2012-02-27 14:58:47 +01:00
if ( me -> getFaction () != me -> GetCreatureTemplate () -> faction_A )
2010-10-27 21:01:47 +02:00
me -> RestoreFaction ();
GetScript () -> ProcessEventsFor ( SMART_EVENT_RESPAWN );
Reset ();
mFollowGuid = 0 ; //do not reset follower on Reset(), we need it after combat evade
mFollowDist = 0 ;
mFollowAngle = 0 ;
mFollowCredit = 0 ;
mFollowArrivedTimer = 1000 ;
mFollowArrivedEntry = 0 ;
mFollowCreditType = 0 ;
}
int SmartAI :: Permissible ( const Creature * creature )
{
if ( creature -> GetAIName () == "SmartAI" )
return PERMIT_BASE_SPECIAL ;
return PERMIT_BASE_NO ;
}
void SmartAI :: JustReachedHome ()
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_REACHED_HOME );
}
void SmartAI :: EnterCombat ( Unit * enemy )
{
2011-09-06 18:12:09 +01:00
me -> InterruptNonMeleeSpells ( false ); // must be before ProcessEvents
2010-10-27 21:01:47 +02:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_AGGRO , enemy );
me -> GetPosition ( & mLastOOCPos );
}
void SmartAI :: JustDied ( Unit * killer )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_DEATH , killer );
if ( HasEscortState ( SMART_ESCORT_ESCORTING ))
EndPath ( true );
}
void SmartAI :: KilledUnit ( Unit * victim )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_KILL , victim );
}
2011-06-15 17:32:31 +02:00
void SmartAI :: JustSummoned ( Creature * creature )
2010-10-27 21:01:47 +02:00
{
2011-06-15 17:32:31 +02:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_SUMMONED_UNIT , creature );
2010-10-27 21:01:47 +02:00
}
void SmartAI :: AttackStart ( Unit * who )
{
if ( who && me -> Attack ( who , true ))
{
SetRun ( mRun );
2011-06-15 17:32:31 +02:00
if ( me -> GetMotionMaster () -> GetMotionSlotType ( MOTION_SLOT_ACTIVE ) == POINT_MOTION_TYPE )
2010-10-27 21:01:47 +02:00
me -> GetMotionMaster () -> MovementExpired ();
if ( mCanCombatMove )
me -> GetMotionMaster () -> MoveChase ( who );
me -> GetPosition ( & mLastOOCPos );
}
}
2011-08-20 20:31:31 -03:00
void SmartAI :: SpellHit ( Unit * unit , const SpellInfo * spellInfo )
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_SPELLHIT , unit , 0 , 0 , false , spellInfo );
2010-10-27 21:01:47 +02:00
}
2011-08-20 20:31:31 -03:00
void SmartAI :: SpellHitTarget ( Unit * target , const SpellInfo * spellInfo )
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_SPELLHIT_TARGET , target , 0 , 0 , false , spellInfo );
2010-10-27 21:01:47 +02:00
}
2011-08-20 20:31:31 -03:00
void SmartAI :: DamageTaken ( Unit * doneBy , uint32 & damage )
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_DAMAGED , doneBy , damage );
2012-09-05 14:04:09 +03:00
if (( damage >= me -> GetHealth () - mInvincibilityHpLevel ) && ( mInvincibilityHpLevel > 0 ))
2012-09-05 04:40:03 +03:00
{
damage = 0 ;
me -> SetHealth ( mInvincibilityHpLevel );
}
2010-10-27 21:01:47 +02:00
}
2011-08-20 20:31:31 -03:00
void SmartAI :: HealReceived ( Unit * doneBy , uint32 & addhealth )
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_RECEIVE_HEAL , doneBy , addhealth );
2010-10-27 21:01:47 +02:00
}
2011-08-20 20:31:31 -03:00
void SmartAI :: ReceiveEmote ( Player * player , uint32 textEmote )
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_RECEIVE_EMOTE , player , textEmote );
2010-10-27 21:01:47 +02:00
}
void SmartAI :: IsSummonedBy ( Unit * summoner )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_JUST_SUMMONED , summoner );
}
2011-08-20 20:31:31 -03:00
void SmartAI :: DamageDealt ( Unit * doneTo , uint32 & damage , DamageEffectType /*damagetype*/ )
2010-10-27 21:01:47 +02:00
{
2011-08-20 20:31:31 -03:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_DAMAGED_TARGET , doneTo , damage );
2010-10-27 21:01:47 +02:00
}
void SmartAI :: SummonedCreatureDespawn ( Creature * unit )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_SUMMON_DESPAWNED , unit );
}
2010-11-16 14:08:12 +01:00
void SmartAI :: UpdateAIWhileCharmed ( const uint32 /*diff*/ )
2010-10-27 21:01:47 +02:00
{
}
void SmartAI :: CorpseRemoved ( uint32 & respawnDelay )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_CORPSE_REMOVED , NULL , respawnDelay );
}
void SmartAI :: PassengerBoarded ( Unit * who , int8 seatId , bool apply )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_PASSENGER_BOARDED , who , ( uint32 ) seatId , 0 , apply );
}
void SmartAI :: InitializeAI ()
{
GetScript () -> OnInitialize ( me );
2010-12-13 22:37:56 +01:00
if ( ! me -> isDead ())
2010-10-27 21:01:47 +02:00
Reset ();
GetScript () -> ProcessEventsFor ( SMART_EVENT_RESPAWN );
}
void SmartAI :: OnCharmed ( bool apply )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_CHARMED , NULL , 0 , 0 , apply );
}
2012-06-17 21:50:01 +01:00
void SmartAI :: DoAction ( const int32 param )
2010-10-27 21:01:47 +02:00
{
2012-06-17 21:50:01 +01:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_ACTION_DONE , NULL , param );
2010-10-27 21:01:47 +02:00
}
2010-11-16 14:08:12 +01:00
uint32 SmartAI :: GetData ( uint32 /*id*/ )
2010-10-27 21:01:47 +02:00
{
return 0 ;
}
void SmartAI :: SetData ( uint32 id , uint32 value )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_DATA_SET , NULL , id , value );
}
2011-08-30 13:46:36 +02:00
void SmartAI :: SetGUID ( uint64 /*guid*/ , int32 /*id*/ )
2010-10-27 21:01:47 +02:00
{
}
2010-11-16 14:08:12 +01:00
uint64 SmartAI :: GetGUID ( int32 /*id*/ )
2010-10-27 21:01:47 +02:00
{
return 0 ;
}
void SmartAI :: SetRun ( bool run )
{
if ( run )
2012-02-23 11:50:58 +01:00
me -> SetWalk ( false );
2010-10-27 21:01:47 +02:00
else
2012-02-23 11:50:58 +01:00
me -> SetWalk ( true );
2011-12-10 13:44:06 +01:00
2010-10-27 21:01:47 +02:00
mRun = run ;
}
2011-08-20 20:31:31 -03:00
void SmartAI :: SetFly ( bool fly )
2010-10-27 21:01:47 +02:00
{
2012-03-12 00:45:58 +01:00
me -> SetDisableGravity ( fly );
2011-10-24 23:21:34 +01:00
me -> SendMovementFlagUpdate ();
2010-10-27 21:01:47 +02:00
}
2011-08-21 00:07:38 -03:00
void SmartAI :: SetSwim ( bool swim )
2010-10-27 21:01:47 +02:00
{
2011-08-21 00:07:38 -03:00
if ( swim )
2010-10-27 21:01:47 +02:00
me -> AddUnitMovementFlag ( MOVEMENTFLAG_SWIMMING );
else
me -> RemoveUnitMovementFlag ( MOVEMENTFLAG_SWIMMING );
2011-10-24 23:21:34 +01:00
me -> SendMovementFlagUpdate ();
2010-10-27 21:01:47 +02:00
}
void SmartAI :: sGossipHello ( Player * player )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_GOSSIP_HELLO , player );
}
void SmartAI :: sGossipSelect ( Player * player , uint32 sender , uint32 action )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_GOSSIP_SELECT , player , sender , action );
}
2010-11-16 14:08:12 +01:00
void SmartAI :: sGossipSelectCode ( Player * /*player*/ , uint32 /*sender*/ , uint32 /*action*/ , const char * /*code*/ )
2010-10-27 21:01:47 +02:00
{
}
void SmartAI :: sQuestAccept ( Player * player , Quest const * quest )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_ACCEPTED_QUEST , player , quest -> GetQuestId ());
}
void SmartAI :: sQuestReward ( Player * player , Quest const * quest , uint32 opt )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_REWARD_QUEST , player , quest -> GetQuestId (), opt );
}
2010-11-17 23:24:21 +01:00
2010-12-18 22:04:19 +01:00
bool SmartAI :: sOnDummyEffect ( Unit * caster , uint32 spellId , SpellEffIndex effIndex )
2010-11-17 23:24:21 +01:00
{
2011-04-29 20:47:02 +02:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_DUMMY_EFFECT , caster , spellId , ( uint32 ) effIndex );
2010-12-18 22:04:19 +01:00
return true ;
2010-11-17 23:24:21 +01:00
}
2010-10-27 21:01:47 +02:00
void SmartAI :: SetCombatMove ( bool on )
{
if ( mCanCombatMove == on )
return ;
mCanCombatMove = on ;
if ( ! HasEscortState ( SMART_ESCORT_ESCORTING ))
{
if ( on && me -> getVictim ())
{
if ( me -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == IDLE_MOTION_TYPE )
{
SetRun ( mRun );
me -> GetMotionMaster () -> MoveChase ( me -> getVictim ());
me -> CastStop ();
}
}
else
{
me -> StopMoving ();
me -> GetMotionMaster () -> MoveIdle ();
}
}
}
void SmartAI :: SetFollow ( Unit * target , float dist , float angle , uint32 credit , uint32 end , uint32 creditType )
{
if ( ! target )
return ;
SetRun ( mRun );
mFollowGuid = target -> GetGUID ();
2012-05-19 13:04:58 +02:00
mFollowDist = dist >= 0.0f ? dist : PET_FOLLOW_DIST ;
mFollowAngle = angle >= 0.0f ? angle : me -> GetFollowAngle ();
2010-10-27 21:01:47 +02:00
mFollowArrivedTimer = 1000 ;
mFollowCredit = credit ;
mFollowArrivedEntry = end ;
2012-05-19 13:04:58 +02:00
me -> GetMotionMaster () -> MoveFollow ( target , mFollowDist , mFollowAngle );
2010-10-27 21:01:47 +02:00
mFollowCreditType = creditType ;
}
2010-12-07 18:31:34 +01:00
2011-08-18 14:55:27 -03:00
void SmartAI :: SetScript9 ( SmartScriptHolder & e , uint32 entry , Unit * invoker )
2010-12-07 18:31:34 +01:00
{
2010-12-07 20:25:45 +01:00
if ( invoker )
2011-02-21 22:23:43 +01:00
GetScript () -> mLastInvoker = invoker -> GetGUID ();
2010-12-07 18:31:34 +01:00
GetScript () -> SetScript9 ( e , entry );
}
2012-02-18 16:52:08 +01:00
2011-12-11 16:22:18 +01:00
void SmartAI :: sOnGameEvent ( bool start , uint16 eventId )
{
GetScript () -> ProcessEventsFor ( start ? SMART_EVENT_GAME_EVENT_START : SMART_EVENT_GAME_EVENT_END , NULL , eventId );
}
2012-06-19 00:07:20 +02:00
void SmartAI :: OnSpellClick ( Unit * clicker )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_ON_SPELLCLICK , clicker );
}
2010-10-27 21:01:47 +02:00
int SmartGameObjectAI :: Permissible ( const GameObject * g )
{
if ( g -> GetAIName () == "SmartGameObjectAI" )
return PERMIT_BASE_SPECIAL ;
return PERMIT_BASE_NO ;
}
2012-04-14 18:26:16 +02:00
void SmartGameObjectAI :: UpdateAI ( uint32 diff )
2010-10-27 21:01:47 +02:00
{
GetScript () -> OnUpdate ( diff );
}
void SmartGameObjectAI :: InitializeAI ()
{
GetScript () -> OnInitialize ( go );
GetScript () -> ProcessEventsFor ( SMART_EVENT_RESPAWN );
//Reset();
}
void SmartGameObjectAI :: Reset ()
{
GetScript () -> OnReset ();
}
// Called when a player opens a gossip dialog with the gameobject.
2010-12-13 22:37:56 +01:00
bool SmartGameObjectAI :: GossipHello ( Player * player )
2010-10-27 21:01:47 +02:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_DATABASE_AI , "SmartGameObjectAI::GossipHello" );
2011-09-29 12:43:05 +02:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_GOSSIP_HELLO , player , 0 , 0 , false , NULL , go );
2010-10-27 21:01:47 +02:00
return false ;
}
// Called when a player selects a gossip item in the gameobject's gossip menu.
bool SmartGameObjectAI :: GossipSelect ( Player * player , uint32 sender , uint32 action )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_GOSSIP_SELECT , player , sender , action , false , NULL , go );
return false ;
}
// Called when a player selects a gossip with a code in the gameobject's gossip menu.
bool SmartGameObjectAI :: GossipSelectCode ( Player * /*player*/ , uint32 /*sender*/ , uint32 /*action*/ , const char * /*code*/ )
{
return false ;
}
// Called when a player accepts a quest from the gameobject.
bool SmartGameObjectAI :: QuestAccept ( Player * player , Quest const * quest )
{
2011-09-29 12:43:05 +02:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_ACCEPTED_QUEST , player , quest -> GetQuestId (), 0 , false , NULL , go );
2010-10-27 21:01:47 +02:00
return false ;
}
// Called when a player selects a quest reward.
bool SmartGameObjectAI :: QuestReward ( Player * player , Quest const * quest , uint32 opt )
{
2011-09-29 12:43:05 +02:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_REWARD_QUEST , player , quest -> GetQuestId (), opt , false , NULL , go );
2010-10-27 21:01:47 +02:00
return false ;
}
// Called when the dialog status between a player and the gameobject is requested.
uint32 SmartGameObjectAI :: GetDialogStatus ( Player * /*player*/ ) { return 100 ; }
// Called when the gameobject is destroyed (destructible buildings only).
void SmartGameObjectAI :: Destroyed ( Player * player , uint32 eventId )
{
2011-09-29 12:43:05 +02:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_DEATH , player , eventId , 0 , false , NULL , go );
2010-10-27 21:01:47 +02:00
}
void SmartGameObjectAI :: SetData ( uint32 id , uint32 value )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_DATA_SET , NULL , id , value );
}
2011-08-18 14:55:27 -03:00
void SmartGameObjectAI :: SetScript9 ( SmartScriptHolder & e , uint32 entry , Unit * invoker )
2010-12-07 20:25:45 +01:00
{
if ( invoker )
2011-02-21 22:23:43 +01:00
GetScript () -> mLastInvoker = invoker -> GetGUID ();
2010-12-07 20:25:45 +01:00
GetScript () -> SetScript9 ( e , entry );
}
2011-12-11 16:22:18 +01:00
void SmartGameObjectAI :: OnGameEvent ( bool start , uint16 eventId )
{
GetScript () -> ProcessEventsFor ( start ? SMART_EVENT_GAME_EVENT_START : SMART_EVENT_GAME_EVENT_END , NULL , eventId );
}
2012-01-22 20:36:01 -05:00
void SmartGameObjectAI :: OnStateChanged ( uint32 state , Unit * unit )
2012-01-06 11:09:01 -05:00
{
2012-01-22 20:36:01 -05:00
GetScript () -> ProcessEventsFor ( SMART_EVENT_GO_STATE_CHANGED , unit , state );
2012-01-06 11:09:01 -05:00
}
2012-06-11 11:10:46 +02:00
void SmartGameObjectAI :: EventInform ( uint32 eventId )
{
GetScript () -> ProcessEventsFor ( SMART_EVENT_GO_EVENT_INFORM , NULL , eventId );
}
2010-10-27 21:01:47 +02:00
class SmartTrigger : public AreaTriggerScript
{
public :
2011-10-31 02:01:17 +01:00
SmartTrigger () : AreaTriggerScript ( "SmartTrigger" ) {}
2010-10-27 21:01:47 +02:00
bool OnTrigger ( Player * player , AreaTriggerEntry const * trigger )
{
2011-10-31 02:01:17 +01:00
if ( ! player -> isAlive ())
return false ;
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_DATABASE_AI , "AreaTrigger %u is using SmartTrigger script" , trigger -> id );
2010-10-27 21:01:47 +02:00
SmartScript script ;
script . OnInitialize ( NULL , trigger );
script . ProcessEventsFor ( SMART_EVENT_AREATRIGGER_ONTRIGGER , player , trigger -> id );
return true ;
}
};
void AddSC_SmartSCripts ()
{
new SmartTrigger ();
2010-11-16 14:08:12 +01:00
}