2010-10-07 15:35:36 +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-07 15:35:36 +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/>.
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "CreatureAI.h"
2017-05-28 16:34:44 +02:00
#include "AreaBoundary.h"
2020-06-12 01:29:18 +02:00
#include "Containers.h"
2009-01-08 21:48:38 -06:00
#include "Creature.h"
2017-05-28 16:34:44 +02:00
#include "CreatureAIImpl.h"
#include "CreatureTextMgr.h"
2019-06-24 12:49:15 +02:00
#include "DB2Structure.h"
2021-10-22 12:51:45 +02:00
#include "Errors.h"
2017-05-28 16:34:44 +02:00
#include "Language.h"
2011-08-03 08:18:24 +02:00
#include "Log.h"
2017-06-04 01:00:45 +02:00
#include "Map.h"
2011-08-03 08:18:24 +02:00
#include "MapReference.h"
2017-06-04 01:00:45 +02:00
#include "MotionMaster.h"
2018-08-23 14:33:28 +02:00
#include "ObjectAccessor.h"
2011-08-03 08:18:24 +02:00
#include "Player.h"
2017-05-28 16:34:44 +02:00
#include "SpellMgr.h"
2019-12-29 14:05:03 +01:00
#include "SpellHistory.h"
2017-05-28 16:34:44 +02:00
#include "TemporarySummon.h"
#include "Vehicle.h"
#include "World.h"
2009-10-17 15:51:44 -07:00
2020-06-12 01:29:18 +02:00
std :: unordered_map < std :: pair < uint32 , Difficulty > , AISpellInfoType > UnitAI :: AISpellInfo ;
AISpellInfoType * GetAISpellInfo ( uint32 spellId , Difficulty difficulty )
{
return Trinity :: Containers :: MapGetValuePtr ( UnitAI :: AISpellInfo , { spellId , difficulty });
}
2009-10-17 15:51:44 -07:00
2021-10-22 12:51:45 +02:00
CreatureAI :: CreatureAI ( Creature * creature , uint32 scriptId )
: UnitAI ( creature ), me ( creature ), _boundary ( nullptr ),
2019-07-21 01:49:58 +02:00
_negateBoundary ( false ), _scriptId ( scriptId ? scriptId : creature -> GetScriptId ()), _isEngaged ( false ), _moveInLOSLocked ( false )
2017-05-18 23:52:58 +02:00
{
2021-10-22 12:51:45 +02:00
ASSERT ( _scriptId , "A CreatureAI was initialized with an invalid scriptId!" );
2017-05-18 23:52:58 +02:00
}
CreatureAI ::~ CreatureAI ()
{
}
2014-09-18 23:33:59 +02:00
void CreatureAI :: Talk ( uint8 id , WorldObject const * whisperTarget /*= nullptr*/ )
2010-11-16 19:21:48 +01:00
{
2013-12-23 14:23:49 +01:00
sCreatureTextMgr -> SendChat ( me , id , whisperTarget );
2010-11-16 19:21:48 +01:00
}
2019-05-15 19:23:28 +02:00
// Disable CreatureAI when charmed
void CreatureAI :: OnCharmed ( bool isNew )
{
if ( isNew && ! me -> IsCharmed () && ! me -> LastCharmerGUID . IsEmpty ())
{
if ( ! me -> HasReactState ( REACT_PASSIVE ))
{
if ( Unit * lastCharmer = ObjectAccessor :: GetUnit ( * me , me -> LastCharmerGUID ))
me -> EngageWithTarget ( lastCharmer );
}
me -> LastCharmerGUID . Clear ();
2020-03-02 20:43:52 +01:00
if ( ! me -> IsInCombat ())
EnterEvadeMode ( EVADE_REASON_NO_HOSTILES );
2019-05-15 19:23:28 +02:00
}
UnitAI :: OnCharmed ( isNew );
}
2018-08-22 21:51:16 +02:00
void CreatureAI :: DoZoneInCombat ( Creature * creature /*= nullptr*/ )
2009-04-07 19:38:09 -05:00
{
2009-04-30 22:26:51 -05:00
if ( ! creature )
creature = me ;
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Map * map = creature -> GetMap ();
2019-05-15 19:23:28 +02:00
if ( ! map -> IsDungeon ()) // use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
2009-04-07 19:38:09 -05:00
{
2019-05-15 19:23:28 +02:00
TC_LOG_ERROR ( "scripts.ai" , "CreatureAI::DoZoneInCombat: call for map that isn't an instance (%s)" , creature -> GetGUID (). ToString (). c_str ());
2018-08-20 19:04:21 +02:00
return ;
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2020-01-02 01:06:38 +01:00
if ( ! map -> HavePlayers ())
2009-05-27 21:30:03 +02:00
return ;
2009-10-17 15:51:44 -07:00
2020-01-02 01:06:38 +01:00
for ( MapReference const & ref : map -> GetPlayers ())
2019-05-15 19:23:28 +02:00
{
2018-08-20 19:04:21 +02:00
if ( Player * player = ref . GetSource ())
{
if ( ! player -> IsAlive () || ! CombatManager :: CanBeginCombat ( creature , player ))
continue ;
creature -> EngageWithTarget ( player );
2019-05-15 19:23:28 +02:00
2018-08-20 19:04:21 +02:00
for ( Unit * pet : player -> m_Controlled )
creature -> EngageWithTarget ( pet );
2019-05-15 19:23:28 +02:00
2018-08-20 19:04:21 +02:00
if ( Unit * vehicle = player -> GetVehicleBase ())
creature -> EngageWithTarget ( vehicle );
}
2019-05-15 19:23:28 +02:00
}
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2010-03-06 18:18:32 +02:00
// scripts does not take care about MoveInLineOfSight loops
// MoveInLineOfSight can be called inside another MoveInLineOfSight and cause stack overflow
2011-08-18 14:55:27 -03:00
void CreatureAI :: MoveInLineOfSight_Safe ( Unit * who )
2010-04-07 18:09:10 +02:00
{
2019-05-15 01:33:55 +02:00
if ( _moveInLOSLocked == true )
2010-03-06 18:18:32 +02:00
return ;
2019-05-15 01:33:55 +02:00
_moveInLOSLocked = true ;
2010-03-06 18:18:32 +02:00
MoveInLineOfSight ( who );
2019-05-15 01:33:55 +02:00
_moveInLOSLocked = false ;
2010-03-06 18:18:32 +02:00
}
2011-08-18 14:55:27 -03:00
void CreatureAI :: MoveInLineOfSight ( Unit * who )
2009-01-08 21:48:38 -06:00
{
2017-07-01 20:18:02 +02:00
if ( me -> IsEngaged ())
2009-04-13 18:03:28 -05:00
return ;
2009-10-17 16:20:24 -07:00
2016-02-11 18:33:00 +01:00
if ( me -> HasReactState ( REACT_AGGRESSIVE ) && me -> CanStartAttack ( who , false ))
2017-07-01 20:18:02 +02:00
me -> EngageWithTarget ( who );
2017-06-07 02:33:47 +02:00
}
2019-05-15 01:33:55 +02:00
void CreatureAI :: OnOwnerCombatInteraction ( Unit * target )
2017-06-07 02:33:47 +02:00
{
if ( ! target || ! me -> IsAlive ())
return ;
if ( ! me -> HasReactState ( REACT_PASSIVE ) && me -> CanStartAttack ( target , true ))
2017-07-01 20:18:02 +02:00
me -> EngageWithTarget ( target );
2009-01-30 18:10:05 -06:00
}
2009-10-17 15:51:44 -07:00
2015-07-15 18:43:19 +02:00
// Distract creature, if player gets too close while stealthed/prowling
void CreatureAI :: TriggerAlert ( Unit const * who ) const
{
// If there's no target, or target isn't a player do nothing
if ( ! who || who -> GetTypeId () != TYPEID_PLAYER )
return ;
2017-07-01 20:18:02 +02:00
// If this unit isn't an NPC, is already distracted, is fighting, is confused, stunned or fleeing, do nothing
if ( me -> GetTypeId () != TYPEID_UNIT || me -> IsEngaged () || me -> HasUnitState ( UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING | UNIT_STATE_DISTRACTED ))
2015-07-15 18:43:19 +02:00
return ;
// Only alert for hostiles!
if ( me -> IsCivilian () || me -> HasReactState ( REACT_PASSIVE ) || ! me -> IsHostileTo ( who ) || ! me -> _IsTargetAcceptable ( who ))
return ;
// Send alert sound (if any) for this creature
me -> SendAIReaction ( AI_REACTION_ALERT );
// Face the unit (stealthed player) and set distracted state for 5 seconds
2018-06-03 10:06:57 -07:00
me -> GetMotionMaster () -> MoveDistract ( 5 * IN_MILLISECONDS , me -> GetAbsoluteAngle ( who ));
2015-07-15 18:43:19 +02:00
}
2019-07-02 09:52:58 +02:00
// adapted from logic in Spell:EffectSummonType before commit 8499434
2019-06-26 01:04:27 +02:00
static bool ShouldFollowOnSpawn ( SummonPropertiesEntry const * properties )
2019-06-23 17:18:42 +02:00
{
2019-06-24 18:47:04 +02:00
// Summons without SummonProperties are generally scripted summons that don't belong to any owner
2019-06-26 01:04:27 +02:00
if ( ! properties )
return false ;
2019-06-24 12:49:15 +02:00
2019-06-26 01:04:27 +02:00
switch ( properties -> Control )
2019-06-23 17:18:42 +02:00
{
2019-06-26 01:04:27 +02:00
case SUMMON_CATEGORY_PET :
return true ;
case SUMMON_CATEGORY_WILD :
case SUMMON_CATEGORY_ALLY :
case SUMMON_CATEGORY_UNK :
if ( properties -> GetFlags (). HasFlag ( SummonPropertiesFlags :: JoinSummonerSpawnGroup ))
return true ;
switch ( SummonTitle ( properties -> Title ))
{
case SummonTitle :: Pet :
case SummonTitle :: Guardian :
case SummonTitle :: Runeblade :
case SummonTitle :: Minion :
case SummonTitle :: Companion :
return true ;
default :
return false ;
}
default :
return false ;
}
}
2019-06-29 16:01:58 +02:00
2019-06-26 01:04:27 +02:00
void CreatureAI :: JustAppeared ()
{
2019-07-21 03:59:17 +02:00
if ( ! IsEngaged ())
2019-06-26 01:04:27 +02:00
{
2019-07-21 03:59:17 +02:00
if ( TempSummon * summon = me -> ToTempSummon ())
2019-06-26 01:04:27 +02:00
{
2019-07-21 03:59:17 +02:00
// Only apply this to specific types of summons
2019-09-05 02:37:44 -04:00
if ( ! summon -> GetVehicle () && ShouldFollowOnSpawn ( summon -> m_Properties ) && summon -> CanFollowOwner ())
2019-06-26 01:04:27 +02:00
{
2019-07-21 03:59:17 +02:00
if ( Unit * owner = summon -> GetCharmerOrOwner ())
{
summon -> GetMotionMaster () -> Clear ();
summon -> GetMotionMaster () -> MoveFollow ( owner , PET_FOLLOW_DIST , summon -> GetFollowAngle ());
}
2019-06-26 01:04:27 +02:00
}
}
2019-06-23 17:18:42 +02:00
}
}
2019-07-21 01:49:58 +02:00
void CreatureAI :: JustEnteredCombat ( Unit * who )
{
if ( ! IsEngaged () && ! me -> CanHaveThreatList ())
EngagementStart ( who );
}
2016-01-13 15:33:17 +01:00
void CreatureAI :: EnterEvadeMode ( EvadeReason why )
2009-05-13 10:54:11 -05:00
{
2016-01-13 15:33:17 +01:00
if ( ! _EnterEvadeMode ( why ))
2009-05-13 10:54:11 -05:00
return ;
2009-10-17 15:51:44 -07:00
2019-05-15 19:23:28 +02:00
TC_LOG_DEBUG ( "scripts.ai" , "CreatureAI::EnterEvadeMode: entering evade mode (why: %u) (%s)" , why , me -> GetGUID (). ToString (). c_str ());
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! me -> GetVehicle ()) // otherwise me will be in evade mode forever
2009-07-22 17:10:30 +02:00
{
2011-08-18 14:55:27 -03:00
if ( Unit * owner = me -> GetCharmerOrOwner ())
2009-08-08 11:57:51 -05:00
{
2018-06-03 10:06:57 -07:00
me -> GetMotionMaster () -> Clear ();
me -> GetMotionMaster () -> MoveFollow ( owner , PET_FOLLOW_DIST , me -> GetFollowAngle ());
2009-08-08 11:57:51 -05:00
}
else
2012-09-22 02:11:31 +01:00
{
// Required to prevent attacking creatures that are evading and cause them to reenter combat
// Does not apply to MoveFollow
me -> AddUnitState ( UNIT_STATE_EVADE );
2009-08-08 11:57:51 -05:00
me -> GetMotionMaster () -> MoveTargetedHome ();
2012-09-22 02:11:31 +01:00
}
2009-07-22 17:10:30 +02:00
}
2009-10-17 15:51:44 -07:00
2009-05-11 11:46:48 -05:00
Reset ();
2009-01-08 21:48:38 -06:00
}
2009-10-17 15:51:44 -07:00
2013-01-02 14:20:20 +01:00
bool CreatureAI :: UpdateVictim ()
{
2019-07-21 01:49:58 +02:00
if ( ! IsEngaged ())
2013-01-02 14:20:20 +01:00
return false ;
2019-07-31 13:17:32 +02:00
if ( ! me -> IsAlive ())
{
EngagementOver ();
return false ;
}
2013-01-02 14:20:20 +01:00
if ( ! me -> HasReactState ( REACT_PASSIVE ))
{
if ( Unit * victim = me -> SelectVictim ())
2019-08-04 01:26:20 +02:00
if ( ! me -> HasSpellFocus () && victim != me -> GetVictim ())
2016-01-13 18:38:54 +01:00
AttackStart ( victim );
2014-07-17 15:42:57 +02:00
return me -> GetVictim () != nullptr ;
2013-01-02 14:20:20 +01:00
}
2018-01-04 04:46:22 +01:00
else if ( ! me -> IsInCombat ())
2013-01-02 14:20:20 +01:00
{
2016-01-13 15:33:17 +01:00
EnterEvadeMode ( EVADE_REASON_NO_HOSTILES );
2013-01-02 14:20:20 +01:00
return false ;
}
2018-01-04 04:46:22 +01:00
else if ( me -> GetVictim ())
2018-01-03 20:04:19 +01:00
me -> AttackStop ();
2013-01-02 14:20:20 +01:00
return true ;
}
2019-07-21 01:49:58 +02:00
void CreatureAI :: EngagementStart ( Unit * who )
{
if ( _isEngaged )
{
TC_LOG_ERROR ( "scripts.ai" , "CreatureAI::EngagementStart called even though creature is already engaged. Creature debug info: \n %s" , me -> GetDebugInfo (). c_str ());
return ;
}
_isEngaged = true ;
me -> AtEngage ( who );
}
void CreatureAI :: EngagementOver ()
{
if ( ! _isEngaged )
{
2020-03-02 20:17:47 +01:00
TC_LOG_DEBUG ( "scripts.ai" , "CreatureAI::EngagementOver called even though creature is not currently engaged. Creature debug info: \n %s" , me -> GetDebugInfo (). c_str ());
2019-07-21 01:49:58 +02:00
return ;
}
_isEngaged = false ;
me -> AtDisengage ();
}
2016-01-13 15:33:17 +01:00
bool CreatureAI :: _EnterEvadeMode ( EvadeReason /*why*/ )
2013-01-02 14:20:20 +01:00
{
2020-03-02 20:17:47 +01:00
if ( me -> IsInEvadeMode ())
2019-07-21 01:49:58 +02:00
return false ;
2013-06-11 19:54:27 -02:30
if ( ! me -> IsAlive ())
2019-07-21 01:49:58 +02:00
{
EngagementOver ();
2013-01-02 14:20:20 +01:00
return false ;
2019-07-21 01:49:58 +02:00
}
2013-01-02 14:20:20 +01:00
2016-04-25 11:46:00 +02:00
me -> RemoveAurasOnEvade ();
2013-01-02 14:20:20 +01:00
me -> CombatStop ( true );
2016-05-11 23:24:26 +02:00
me -> SetLootRecipient ( nullptr );
2013-01-02 14:20:20 +01:00
me -> ResetPlayerDamageReq ();
2013-08-02 19:56:48 +02:00
me -> SetLastDamagedTime ( 0 );
2016-03-24 16:12:53 +01:00
me -> SetCannotReachTarget ( false );
2019-08-04 01:26:20 +02:00
me -> DoNotReacquireSpellFocusTarget ();
2020-01-01 17:19:37 +01:00
me -> SetTarget ( ObjectGuid :: Empty );
2019-12-29 14:05:03 +01:00
me -> GetSpellHistory () -> ResetAllCooldowns ();
2019-07-21 01:49:58 +02:00
EngagementOver ();
2013-01-02 14:20:20 +01:00
2019-07-21 01:49:58 +02:00
return true ;
2013-01-02 14:20:20 +01:00
}
2018-01-01 17:07:39 +01:00
Optional < QuestGiverStatus > CreatureAI :: GetDialogStatus ( Player * /*player*/ )
{
return {};
}
2016-03-24 16:12:53 +01:00
const uint32 BOUNDARY_VISUALIZE_CREATURE = 15425 ;
const float BOUNDARY_VISUALIZE_CREATURE_SCALE = 0.25f ;
const int8 BOUNDARY_VISUALIZE_STEP_SIZE = 1 ;
const int32 BOUNDARY_VISUALIZE_FAILSAFE_LIMIT = 750 ;
const float BOUNDARY_VISUALIZE_SPAWN_HEIGHT = 5.0f ;
2020-07-26 20:44:07 +02:00
int32 CreatureAI :: VisualizeBoundary ( Seconds duration , Unit * owner , bool fill ) const
2016-01-13 15:33:17 +01:00
{
typedef std :: pair < int32 , int32 > coordinate ;
2016-03-16 21:38:01 +01:00
2016-01-13 15:33:17 +01:00
if ( ! owner )
return - 1 ;
if ( ! _boundary || _boundary -> empty ())
return LANG_CREATURE_MOVEMENT_NOT_BOUNDED ;
std :: queue < coordinate > Q ;
std :: unordered_set < coordinate > alreadyChecked ;
std :: unordered_set < coordinate > outOfBounds ;
2016-03-16 21:38:01 +01:00
2016-01-13 15:33:17 +01:00
Position startPosition = owner -> GetPosition ();
2019-05-15 19:23:28 +02:00
if ( ! IsInBoundary ( & startPosition )) // fall back to creature position
{
2016-01-13 15:33:17 +01:00
startPosition = me -> GetPosition ();
2019-05-15 19:23:28 +02:00
if ( ! IsInBoundary ( & startPosition )) // fall back to creature home position
{
2016-01-13 15:33:17 +01:00
startPosition = me -> GetHomePosition ();
2018-03-08 18:41:46 +01:00
if ( ! IsInBoundary ( & startPosition ))
2016-01-13 15:33:17 +01:00
return LANG_CREATURE_NO_INTERIOR_POINT_FOUND ;
}
}
float spawnZ = startPosition . GetPositionZ () + BOUNDARY_VISUALIZE_SPAWN_HEIGHT ;
bool boundsWarning = false ;
Q . push ({ 0 , 0 });
while ( ! Q . empty ())
{
coordinate front = Q . front ();
bool hasOutOfBoundsNeighbor = false ;
2019-05-15 19:23:28 +02:00
for ( coordinate const & off : std :: list < coordinate > { { 1 , 0 }, { 0 , 1 }, { - 1 , 0 }, { 0 , - 1 } })
2016-01-13 15:33:17 +01:00
{
coordinate next ( front . first + off . first , front . second + off . second );
if ( next . first > BOUNDARY_VISUALIZE_FAILSAFE_LIMIT || next . first < - BOUNDARY_VISUALIZE_FAILSAFE_LIMIT || next . second > BOUNDARY_VISUALIZE_FAILSAFE_LIMIT || next . second < - BOUNDARY_VISUALIZE_FAILSAFE_LIMIT )
{
boundsWarning = true ;
continue ;
}
if ( alreadyChecked . find ( next ) == alreadyChecked . end ()) // never check a coordinate twice
{
Position nextPos ( startPosition . GetPositionX () + next . first * BOUNDARY_VISUALIZE_STEP_SIZE , startPosition . GetPositionY () + next . second * BOUNDARY_VISUALIZE_STEP_SIZE , startPosition . GetPositionZ ());
2018-03-08 18:41:46 +01:00
if ( IsInBoundary ( & nextPos ))
2016-01-13 15:33:17 +01:00
Q . push ( next );
else
{
outOfBounds . insert ( next );
hasOutOfBoundsNeighbor = true ;
}
alreadyChecked . insert ( next );
}
2019-05-15 19:23:28 +02:00
else if ( outOfBounds . find ( next ) != outOfBounds . end ())
hasOutOfBoundsNeighbor = true ;
2016-01-13 15:33:17 +01:00
}
if ( fill || hasOutOfBoundsNeighbor )
2019-05-15 19:23:28 +02:00
{
2020-07-26 20:44:07 +02:00
if ( TempSummon * point = owner -> SummonCreature ( BOUNDARY_VISUALIZE_CREATURE , Position ( startPosition . GetPositionX () + front . first * BOUNDARY_VISUALIZE_STEP_SIZE , startPosition . GetPositionY () + front . second * BOUNDARY_VISUALIZE_STEP_SIZE , spawnZ ), TEMPSUMMON_TIMED_DESPAWN , duration ))
2016-01-13 15:33:17 +01:00
{
point -> SetObjectScale ( BOUNDARY_VISUALIZE_CREATURE_SCALE );
2017-07-09 02:07:29 +02:00
point -> AddUnitFlag ( UNIT_FLAG_STUNNED );
point -> SetImmuneToAll ( true );
2016-01-13 15:33:17 +01:00
if ( ! hasOutOfBoundsNeighbor )
2019-06-03 20:40:34 +02:00
point -> AddUnitFlag ( UNIT_FLAG_NOT_SELECTABLE );
2016-01-13 15:33:17 +01:00
}
2019-05-15 19:23:28 +02:00
}
2016-01-13 15:33:17 +01:00
Q . pop ();
}
return boundsWarning ? LANG_CREATURE_MOVEMENT_MAYBE_UNBOUNDED : 0 ;
}
2018-03-08 18:41:46 +01:00
bool CreatureAI :: IsInBoundary ( Position const * who ) const
2016-01-13 15:33:17 +01:00
{
2017-04-26 04:19:01 -03:00
if ( ! _boundary )
return true ;
2016-01-13 15:33:17 +01:00
if ( ! who )
who = me ;
2019-05-15 19:23:28 +02:00
return CreatureAI :: IsInBounds ( * _boundary , who ) != _negateBoundary ;
2016-01-13 15:33:17 +01:00
}
2017-04-26 04:19:01 -03:00
bool CreatureAI :: IsInBounds ( CreatureBoundary const & boundary , Position const * pos )
2017-03-28 01:52:49 -03:00
{
2017-04-26 04:19:01 -03:00
for ( AreaBoundary const * areaBoundary : boundary )
2017-03-28 01:52:49 -03:00
if ( ! areaBoundary -> IsWithinBoundary ( pos ))
return false ;
return true ;
}
2017-04-26 04:19:01 -03:00
void CreatureAI :: SetBoundary ( CreatureBoundary const * boundary , bool negateBoundaries /*= false*/ )
2017-05-18 23:52:58 +02:00
{
_boundary = boundary ;
2017-04-26 04:19:01 -03:00
_negateBoundary = negateBoundaries ;
2017-05-18 23:52:58 +02:00
me -> DoImmediateBoundaryCheck ();
}
2016-01-13 15:33:17 +01:00
bool CreatureAI :: CheckInRoom ()
{
2018-03-08 18:41:46 +01:00
if ( IsInBoundary ())
2016-01-13 15:33:17 +01:00
return true ;
else
{
EnterEvadeMode ( EVADE_REASON_BOUNDARY );
return false ;
}
}
2020-07-28 00:09:50 +02:00
Creature * CreatureAI :: DoSummon ( uint32 entry , Position const & pos , Milliseconds despawnTime , TempSummonType summonType )
2013-01-02 14:20:20 +01:00
{
2020-07-28 00:09:50 +02:00
return me -> SummonCreature ( entry , pos , summonType , despawnTime );
2013-01-02 14:20:20 +01:00
}
2020-07-28 00:09:50 +02:00
Creature * CreatureAI :: DoSummon ( uint32 entry , WorldObject * obj , float radius , Milliseconds despawnTime , TempSummonType summonType )
2013-01-02 14:20:20 +01:00
{
2014-04-25 21:19:30 +02:00
Position pos = obj -> GetRandomNearPosition ( radius );
2020-07-28 00:09:50 +02:00
return me -> SummonCreature ( entry , pos , summonType , despawnTime );
2013-01-02 14:20:20 +01:00
}
2020-07-28 00:09:50 +02:00
Creature * CreatureAI :: DoSummonFlyer ( uint32 entry , WorldObject * obj , float flightZ , float radius , Milliseconds despawnTime , TempSummonType summonType )
2013-01-02 14:20:20 +01:00
{
2014-04-25 21:19:30 +02:00
Position pos = obj -> GetRandomNearPosition ( radius );
2013-01-02 14:20:20 +01:00
pos . m_positionZ += flightZ ;
2020-07-28 00:09:50 +02:00
return me -> SummonCreature ( entry , pos , summonType , despawnTime );
2013-01-02 14:20:20 +01:00
}