2012-01-13 16:58:48 +01:00
/* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
2008-10-14 11:57:03 -05:00
*
* Thanks to the original authors: ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
*
2008-10-11 14:16:25 -05:00
* This program is free software licensed under GPL version 2
* Please see the included DOCS/LICENSE.TXT for more information */
2009-10-17 15:51:44 -07:00
2010-06-07 16:21:52 -06:00
#include "ScriptPCH.h"
2008-10-11 14:16:25 -05:00
#include "Item.h"
#include "Spell.h"
2009-02-05 15:38:24 -06:00
#include "ObjectMgr.h"
2009-05-11 11:46:48 -05:00
#include "TemporarySummon.h"
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Spell summary for ScriptedAI::SelectSpell
2009-08-14 19:45:06 +02:00
struct TSpellSummary
{
2008-10-25 11:40:10 -05:00
uint8 Targets ; // set of enum SelectTarget
uint8 Effects ; // set of enum SelectEffect
2011-08-18 14:55:27 -03:00
} extern * SpellSummary ;
2009-10-17 15:51:44 -07:00
2009-05-13 10:54:11 -05:00
void SummonList :: DoZoneInCombat ( uint32 entry )
{
2009-11-20 19:11:28 -08:00
for ( iterator i = begin (); i != end ();)
2009-05-13 10:54:11 -05:00
{
2011-08-18 14:55:27 -03:00
Creature * summon = Unit :: GetCreature ( * me , * i );
2009-05-13 10:54:11 -05:00
++ i ;
2010-04-07 19:14:10 +02:00
if ( summon && summon -> IsAIEnabled
2009-05-13 10:54:11 -05:00
&& ( ! entry || summon -> GetEntry () == entry ))
summon -> AI () -> DoZoneInCombat ();
}
}
2009-10-17 15:51:44 -07:00
2011-03-08 17:17:41 +01:00
void SummonList :: DoAction ( uint32 entry , int32 info )
2008-11-03 10:16:06 -06:00
{
2009-11-20 19:11:28 -08:00
for ( iterator i = begin (); i != end ();)
2008-11-03 10:16:06 -06:00
{
2011-08-18 14:55:27 -03:00
Creature * summon = Unit :: GetCreature ( * me , * i );
2009-04-22 23:03:49 -05:00
++ i ;
2010-04-07 19:14:10 +02:00
if ( summon && summon -> IsAIEnabled
2009-05-13 10:54:11 -05:00
&& ( ! entry || summon -> GetEntry () == entry ))
2009-04-22 23:03:49 -05:00
summon -> AI () -> DoAction ( info );
2008-11-03 10:16:06 -06:00
}
}
2009-10-17 15:51:44 -07:00
2008-11-03 10:16:06 -06:00
void SummonList :: DespawnEntry ( uint32 entry )
{
2009-11-20 19:11:28 -08:00
for ( iterator i = begin (); i != end ();)
2008-11-03 10:16:06 -06:00
{
2011-08-18 14:55:27 -03:00
Creature * summon = Unit :: GetCreature ( * me , * i );
2010-04-07 19:14:10 +02:00
if ( ! summon )
2009-04-22 23:03:49 -05:00
erase ( i ++ );
2010-04-07 19:14:10 +02:00
else if ( summon -> GetEntry () == entry )
2008-11-03 10:16:06 -06:00
{
2009-04-22 23:03:49 -05:00
erase ( i ++ );
2011-10-05 20:48:34 +02:00
summon -> DespawnOrUnsummon ();
2008-11-03 10:16:06 -06:00
}
else
2009-04-22 23:03:49 -05:00
++ i ;
2008-11-03 10:16:06 -06:00
}
}
2009-10-17 15:51:44 -07:00
2008-11-03 10:16:06 -06:00
void SummonList :: DespawnAll ()
{
2010-04-07 19:13:19 +02:00
while ( ! empty ())
2008-11-03 10:16:06 -06:00
{
2011-08-18 14:55:27 -03:00
Creature * summon = Unit :: GetCreature ( * me , * begin ());
2010-04-07 19:14:10 +02:00
if ( ! summon )
2009-04-22 23:03:49 -05:00
erase ( begin ());
else
2008-11-03 10:16:06 -06:00
{
2009-04-22 23:03:49 -05:00
erase ( begin ());
2011-10-05 20:48:34 +02:00
summon -> DespawnOrUnsummon ();
2008-11-03 10:16:06 -06:00
}
}
}
2009-10-17 15:51:44 -07:00
2011-03-04 23:53:11 +01:00
void SummonList :: RemoveNotExisting ()
{
for ( iterator i = begin (); i != end ();)
{
if ( Unit :: GetCreature ( * me , * i ))
++ i ;
else
erase ( i ++ );
}
}
bool SummonList :: HasEntry ( uint32 entry )
{
for ( iterator i = begin (); i != end ();)
{
Creature * summon = Unit :: GetCreature ( * me , * i );
if ( ! summon )
erase ( i ++ );
else if ( summon -> GetEntry () == entry )
return true ;
else
++ i ;
}
return false ;
}
2011-08-18 14:55:27 -03:00
ScriptedAI :: ScriptedAI ( Creature * creature ) : CreatureAI ( creature ),
me ( creature ),
2009-08-16 21:46:31 +02:00
IsFleeing ( false ),
2011-05-09 03:37:31 +02:00
_evadeCheckCooldown ( 2500 ),
_isCombatMovementAllowed ( true )
2009-04-29 00:15:18 -05:00
{
2011-03-19 10:54:16 +01:00
_isHeroic = me -> GetMap () -> IsHeroic ();
_difficulty = Difficulty ( me -> GetMap () -> GetSpawnMode ());
2009-04-29 00:15:18 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: AttackStartNoMove ( Unit * who )
2008-10-25 11:40:10 -05:00
{
2011-08-18 14:55:27 -03:00
if ( ! who )
2008-10-25 11:40:10 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
if ( me -> Attack ( who , false ))
DoStartNoMovement ( who );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-03-19 19:41:42 +01:00
void ScriptedAI :: UpdateAI ( uint32 const /*diff*/ )
2008-10-11 14:16:25 -05:00
{
//Check if we have a current target
2009-08-14 19:45:06 +02:00
if ( ! UpdateVictim ())
return ;
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
if ( me -> isAttackReady ())
2008-10-11 14:16:25 -05:00
{
2009-08-14 19:45:06 +02:00
//If we are within range melee the target
2010-04-14 23:07:41 +02:00
if ( me -> IsWithinMeleeRange ( me -> getVictim ()))
2008-10-11 14:16:25 -05:00
{
2010-04-14 23:07:41 +02:00
me -> AttackerStateUpdate ( me -> getVictim ());
me -> resetAttackTimer ();
2008-10-11 14:16:25 -05:00
}
}
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: DoStartMovement ( Unit * victim , float distance , float angle )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
if ( victim )
me -> GetMotionMaster () -> MoveChase ( victim , distance , angle );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: DoStartNoMovement ( Unit * victim )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
if ( ! victim )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
me -> GetMotionMaster () -> MoveIdle ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void ScriptedAI :: DoStopAttack ()
{
2010-04-14 23:07:41 +02:00
if ( me -> getVictim ())
me -> AttackStop ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: DoCastSpell ( Unit * target , SpellInfo const * spellInfo , bool triggered )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
if ( ! target || me -> IsNonMeleeSpellCasted ( false ))
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
me -> StopMoving ();
2011-08-18 14:55:27 -03:00
me -> CastSpell ( target , spellInfo , triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: DoPlaySoundToSet ( WorldObject * source , uint32 soundId )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
if ( ! source )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
if ( ! GetSoundEntriesStore () -> LookupEntry ( soundId ))
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
sLog -> outError ( "TSCR: Invalid soundId %u used in DoPlaySoundToSet (Source: TypeId %u, GUID %u)" , soundId , source -> GetTypeId (), source -> GetGUIDLow ());
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
source -> PlayDirectSound ( soundId );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
Creature * ScriptedAI :: DoSpawnCreature ( uint32 entry , float offsetX , float offsetY , float offsetZ , float angle , uint32 type , uint32 despawntime )
2008-10-11 14:16:25 -05:00
{
2011-03-19 10:54:16 +01:00
return me -> SummonCreature ( entry , me -> GetPositionX () + offsetX , me -> GetPositionY () + offsetY , me -> GetPositionZ () + offsetZ , angle , TempSummonType ( type ), despawntime );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellInfo const * ScriptedAI :: SelectSpell ( Unit * target , uint32 school , uint32 mechanic , SelectTargetType targets , uint32 powerCostMin , uint32 powerCostMax , float rangeMin , float rangeMax , SelectEffect effects )
2008-10-11 14:16:25 -05:00
{
2009-10-27 21:39:53 -07:00
//No target so we can't cast
2011-03-19 10:54:16 +01:00
if ( ! target )
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Silenced so we can't cast
2010-04-14 23:07:41 +02:00
if ( me -> HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SILENCED ))
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Using the extended script system we first create a list of viable spells
2011-07-26 23:09:28 +02:00
SpellInfo const * apSpell [ CREATURE_MAX_SPELLS ];
memset ( apSpell , 0 , CREATURE_MAX_SPELLS * sizeof ( SpellInfo * ));
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
uint32 spellCount = 0 ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
SpellInfo const * tempSpell = NULL ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Check if each spell is viable(set it to null if not)
2009-02-11 22:59:02 +01:00
for ( uint32 i = 0 ; i < CREATURE_MAX_SPELLS ; i ++ )
2008-10-11 14:16:25 -05:00
{
2011-07-26 23:09:28 +02:00
tempSpell = sSpellMgr -> GetSpellInfo ( me -> m_spells [ i ]);
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//This spell doesn't exist
2011-03-19 10:54:16 +01:00
if ( ! tempSpell )
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Targets and Effects checked first as most used restrictions
//Check the spell targets if specified
2011-03-19 10:54:16 +01:00
if ( targets && ! ( SpellSummary [ me -> m_spells [ i ]]. Targets & ( 1 << ( targets - 1 ))))
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Check the type of spell if we are looking for a specific spell type
2011-03-19 10:54:16 +01:00
if ( effects && ! ( SpellSummary [ me -> m_spells [ i ]]. Effects & ( 1 << ( effects - 1 ))))
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Check for school if specified
2011-03-19 10:54:16 +01:00
if ( school && ( tempSpell -> SchoolMask & school ) == 0 )
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Check for spell mechanic if specified
2011-03-19 10:54:16 +01:00
if ( mechanic && tempSpell -> Mechanic != mechanic )
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Make sure that the spell uses the requested amount of power
2011-07-26 23:09:28 +02:00
if ( powerCostMin && tempSpell -> ManaCost < powerCostMin )
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( powerCostMax && tempSpell -> ManaCost > powerCostMax )
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Continue if we don't have the mana to actually cast this spell
2011-11-25 18:54:59 +01:00
if ( tempSpell -> ManaCost > ( uint32 ) me -> GetPower ( Powers ( tempSpell -> PowerType )))
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//Check if the spell meets our range requirements
2011-07-26 23:09:28 +02:00
if ( rangeMin && me -> GetSpellMinRangeForTarget ( target , tempSpell ) < rangeMin )
2008-10-11 14:16:25 -05:00
continue ;
2011-07-26 23:09:28 +02:00
if ( rangeMax && me -> GetSpellMaxRangeForTarget ( target , tempSpell ) > rangeMax )
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-10-27 21:39:53 -07:00
//Check if our target is in range
2011-07-26 23:09:28 +02:00
if ( me -> IsWithinDistInMap ( target , float ( me -> GetSpellMinRangeForTarget ( target , tempSpell ))) || ! me -> IsWithinDistInMap ( target , float ( me -> GetSpellMaxRangeForTarget ( target , tempSpell ))))
2008-10-11 14:16:25 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//All good so lets add it to the spell list
2011-03-19 10:54:16 +01:00
apSpell [ spellCount ] = tempSpell ;
++ spellCount ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//We got our usable spells so now lets randomly pick one
2011-03-19 10:54:16 +01:00
if ( ! spellCount )
2008-10-11 14:16:25 -05:00
return NULL ;
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
return apSpell [ urand ( 0 , spellCount - 1 )];
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void ScriptedAI :: DoResetThreat ()
{
2010-04-14 23:07:41 +02:00
if ( ! me -> CanHaveThreatList () || me -> getThreatManager (). isThreatListEmpty ())
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "TSCR: DoResetThreat called for creature that either cannot have threat list or has empty threat list (me entry = %d)" , me -> GetEntry ());
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
std :: list < HostileReference *>& threatlist = me -> getThreatManager (). getThreatList ();
2009-10-17 15:51:44 -07:00
2010-03-09 11:11:10 +01:00
for ( std :: list < HostileReference *>:: iterator itr = threatlist . begin (); itr != threatlist . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
Unit * unit = Unit :: GetUnit (( * me ), ( * itr ) -> getUnitGuid ());
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
if ( unit && DoGetThreat ( unit ))
DoModifyThreatPercent ( unit , - 100 );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
float ScriptedAI :: DoGetThreat ( Unit * unit )
2009-01-09 12:06:08 -06:00
{
2011-08-18 14:55:27 -03:00
if ( ! unit )
return 0.0f ;
return me -> getThreatManager (). getThreat ( unit );
2009-01-09 12:06:08 -06:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: DoModifyThreatPercent ( Unit * unit , int32 pct )
2009-01-09 12:06:08 -06:00
{
2011-08-18 14:55:27 -03:00
if ( ! unit )
return ;
me -> getThreatManager (). modifyThreatPercent ( unit , pct );
2009-01-09 12:06:08 -06:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: DoTeleportTo ( float x , float y , float z , uint32 time )
2009-02-23 13:14:04 -06:00
{
2011-08-18 14:55:27 -03:00
me -> Relocate ( x , y , z );
2012-01-14 15:34:41 +01:00
float speed = me -> GetDistance ( x , y , z ) / (( float ) time * 0.001f );
me -> MonsterMoveWithSpeed ( x , y , z , speed );
2009-02-23 13:14:04 -06:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: DoTeleportTo ( const float position [ 4 ])
2009-05-13 10:54:11 -05:00
{
2011-08-18 14:55:27 -03:00
me -> NearTeleportTo ( position [ 0 ], position [ 1 ], position [ 2 ], position [ 3 ]);
2009-05-13 10:54:11 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: DoTeleportPlayer ( Unit * unit , float x , float y , float z , float o )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
if ( ! unit || unit -> GetTypeId () != TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
if ( unit )
sLog -> outError ( "TSCR: Creature " UI64FMTD " (Entry: %u) Tried to teleport non-player unit (Type: %u GUID: " UI64FMTD ") to x: %f y:%f z: %f o: %f. Aborted." , me -> GetGUID (), me -> GetEntry (), unit -> GetTypeId (), unit -> GetGUID (), x , y , z , o );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
CAST_PLR ( unit ) -> TeleportTo ( unit -> GetMapId (), x , y , z , o , TELE_TO_NOT_LEAVE_COMBAT );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void ScriptedAI :: DoTeleportAll ( float x , float y , float z , float o )
2008-11-18 19:40:06 -06:00
{
2011-08-18 14:55:27 -03:00
Map * map = me -> GetMap ();
2008-11-18 19:40:06 -06:00
if ( ! map -> IsDungeon ())
return ;
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Map :: PlayerList const & PlayerList = map -> GetPlayers ();
for ( Map :: PlayerList :: const_iterator itr = PlayerList . begin (); itr != PlayerList . end (); ++ itr )
if ( Player * player = itr -> getSource ())
if ( player -> isAlive ())
player -> TeleportTo ( me -> GetMapId (), x , y , z , o , TELE_TO_NOT_LEAVE_COMBAT );
2008-11-18 19:40:06 -06:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Unit * ScriptedAI :: DoSelectLowestHpFriendly ( float range , uint32 minHPDiff )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
Unit * unit = NULL ;
Trinity :: MostHPMissingInRange u_check ( me , range , minHPDiff );
Trinity :: UnitLastSearcher < Trinity :: MostHPMissingInRange > searcher ( me , unit , u_check );
me -> VisitNearbyObject ( range , searcher );
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
return unit ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
std :: list < Creature *> ScriptedAI :: DoFindFriendlyCC ( float range )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
std :: list < Creature *> list ;
Trinity :: FriendlyCCedInRange u_check ( me , range );
Trinity :: CreatureListSearcher < Trinity :: FriendlyCCedInRange > searcher ( me , list , u_check );
me -> VisitNearbyObject ( range , searcher );
return list ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
std :: list < Creature *> ScriptedAI :: DoFindFriendlyMissingBuff ( float range , uint32 uiSpellid )
2008-10-11 14:16:25 -05:00
{
2011-08-18 14:55:27 -03:00
std :: list < Creature *> list ;
Trinity :: FriendlyMissingBuffInRange u_check ( me , range , uiSpellid );
Trinity :: CreatureListSearcher < Trinity :: FriendlyMissingBuffInRange > searcher ( me , list , u_check );
me -> VisitNearbyObject ( range , searcher );
return list ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Player * ScriptedAI :: GetPlayerAtMinimumRange ( float minimumRange )
2009-07-24 05:27:49 +02:00
{
2011-08-18 14:55:27 -03:00
Player * player = NULL ;
2009-10-17 15:51:44 -07:00
2011-10-18 10:53:34 -04:00
CellCoord pair ( Trinity :: ComputeCellCoord ( me -> GetPositionX (), me -> GetPositionY ()));
2009-07-24 05:27:49 +02:00
Cell cell ( pair );
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Trinity :: PlayerAtMinimumRangeAway check ( me , minimumRange );
Trinity :: PlayerSearcher < Trinity :: PlayerAtMinimumRangeAway > searcher ( me , player , check );
2009-07-24 05:27:49 +02:00
TypeContainerVisitor < Trinity :: PlayerSearcher < Trinity :: PlayerAtMinimumRangeAway > , GridTypeMapContainer > visitor ( searcher );
2009-10-17 15:51:44 -07:00
2011-10-19 17:40:44 +01:00
cell . Visit ( pair , visitor , * me -> GetMap (), * me , minimumRange );
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
return player ;
2009-07-24 05:27:49 +02:00
}
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
void ScriptedAI :: SetEquipmentSlots ( bool loadDefault , int32 mainHand /*= EQUIP_NO_CHANGE*/ , int32 offHand /*= EQUIP_NO_CHANGE*/ , int32 ranged /*= EQUIP_NO_CHANGE*/ )
2009-04-19 21:16:11 +02:00
{
2011-03-19 10:54:16 +01:00
if ( loadDefault )
2009-04-19 21:16:11 +02:00
{
2011-04-28 22:57:08 +02:00
if ( CreatureTemplate const * creatureInfo = sObjectMgr -> GetCreatureTemplate ( me -> GetEntry ()))
2011-03-19 10:54:16 +01:00
me -> LoadEquipment ( creatureInfo -> equipmentId , true );
2009-10-17 15:51:44 -07:00
2009-04-19 21:16:11 +02:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
if ( mainHand >= 0 )
me -> SetUInt32Value ( UNIT_VIRTUAL_ITEM_SLOT_ID + 0 , uint32 ( mainHand ));
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
if ( offHand >= 0 )
me -> SetUInt32Value ( UNIT_VIRTUAL_ITEM_SLOT_ID + 1 , uint32 ( offHand ));
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
if ( ranged >= 0 )
me -> SetUInt32Value ( UNIT_VIRTUAL_ITEM_SLOT_ID + 2 , uint32 ( ranged ));
2009-04-19 21:16:11 +02:00
}
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
void ScriptedAI :: SetCombatMovement ( bool allowMovement )
2009-05-19 21:03:43 +02:00
{
2011-03-19 10:54:16 +01:00
_isCombatMovementAllowed = allowMovement ;
2009-05-19 21:03:43 +02:00
}
2009-10-17 15:51:44 -07:00
2009-10-17 07:42:48 -07:00
enum eNPCs
2009-08-14 19:45:06 +02:00
{
NPC_BROODLORD = 12017 ,
NPC_VOID_REAVER = 19516 ,
NPC_JAN_ALAI = 23578 ,
NPC_SARTHARION = 28860
};
2009-10-17 15:51:44 -07:00
2009-08-08 21:29:12 +02:00
// Hacklike storage used for misc creatures that are expected to evade of outside of a certain area.
2010-02-05 00:31:28 +01:00
// It is assumed the information is found elswehere and can be handled by the core. So far no luck finding such information/way to extract it.
2011-03-19 10:54:16 +01:00
bool ScriptedAI :: EnterEvadeIfOutOfCombatArea ( uint32 const diff )
2009-08-08 21:29:12 +02:00
{
2011-03-19 10:54:16 +01:00
if ( _evadeCheckCooldown <= diff )
_evadeCheckCooldown = 2500 ;
2009-08-08 21:29:12 +02:00
else
{
2011-03-19 10:54:16 +01:00
_evadeCheckCooldown -= diff ;
2009-08-08 21:29:12 +02:00
return false ;
}
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
if ( me -> IsInEvadeMode () || ! me -> getVictim ())
2009-08-08 21:29:12 +02:00
return false ;
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
float x = me -> GetPositionX ();
float y = me -> GetPositionY ();
float z = me -> GetPositionZ ();
2009-10-17 15:51:44 -07:00
2011-09-29 12:43:05 +02:00
switch ( me -> GetEntry ())
2009-08-08 21:29:12 +02:00
{
2009-08-14 19:45:06 +02:00
case NPC_BROODLORD : // broodlord (not move down stairs)
2011-08-18 14:55:27 -03:00
if ( z > 448.60f )
2009-08-08 21:29:12 +02:00
return false ;
break ;
2009-08-14 19:45:06 +02:00
case NPC_VOID_REAVER : // void reaver (calculate from center of room)
2010-04-14 23:07:41 +02:00
if ( me -> GetDistance2d ( 432.59f , 371.93f ) < 105.0f )
2009-08-08 21:29:12 +02:00
return false ;
break ;
2009-08-14 19:45:06 +02:00
case NPC_JAN_ALAI : // jan'alai (calculate by Z)
2011-08-18 14:55:27 -03:00
if ( z > 12.0f )
2009-08-08 21:29:12 +02:00
return false ;
break ;
2009-08-14 19:45:06 +02:00
case NPC_SARTHARION : // sartharion (calculate box)
2011-08-18 14:55:27 -03:00
if ( x > 3218.86f && x < 3275.69f && y < 572.40f && y > 484.68f )
2009-08-08 21:29:12 +02:00
return false ;
break ;
2011-09-22 22:14:52 +02:00
default : // For most of creatures that certain area is their home area.
sLog -> outDetail ( "TSCR: EnterEvadeIfOutOfCombatArea used for creature entry %u, but does not have any definition. Using the default one." , me -> GetEntry ());
uint32 homeAreaId = me -> GetMap () -> GetAreaId ( me -> GetHomePosition (). GetPositionX (), me -> GetHomePosition (). GetPositionY (), me -> GetHomePosition (). GetPositionZ ());
2011-09-29 12:43:05 +02:00
if ( me -> GetAreaId () == homeAreaId )
2011-09-22 22:14:52 +02:00
return false ;
2009-08-08 21:29:12 +02:00
}
2009-10-17 15:51:44 -07:00
2009-08-08 21:29:12 +02:00
EnterEvadeMode ();
return true ;
}
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
void Scripted_NoMovementAI :: AttackStart ( Unit * target )
2008-10-11 14:16:25 -05:00
{
2011-03-19 10:54:16 +01:00
if ( ! target )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
if ( me -> Attack ( target , true ))
DoStartNoMovement ( target );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-05-28 00:28:04 +02:00
// BossAI - for instanced bosses
2011-05-09 03:37:31 +02:00
BossAI :: BossAI ( Creature * creature , uint32 bossId ) : ScriptedAI ( creature ),
instance ( creature -> GetInstanceScript ()),
summons ( creature ),
_boundary ( instance ? instance -> GetBossBoundary ( bossId ) : NULL ),
_bossId ( bossId )
2009-05-17 16:37:03 -05:00
{
}
2009-10-17 15:51:44 -07:00
2009-05-10 22:48:22 -05:00
void BossAI :: _Reset ()
{
2010-04-07 19:14:10 +02:00
if ( ! me -> isAlive ())
2009-06-13 11:23:50 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-03-13 22:28:37 +01:00
me -> ResetLootMode ();
2009-05-10 22:48:22 -05:00
events . Reset ();
summons . DespawnAll ();
2010-04-07 19:14:10 +02:00
if ( instance )
2011-03-19 10:54:16 +01:00
instance -> SetBossState ( _bossId , NOT_STARTED );
2009-05-10 22:48:22 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-10 22:48:22 -05:00
void BossAI :: _JustDied ()
{
events . Reset ();
summons . DespawnAll ();
2010-04-07 19:14:10 +02:00
if ( instance )
2009-10-29 20:45:19 +01:00
{
2011-03-19 10:54:16 +01:00
instance -> SetBossState ( _bossId , DONE );
2009-10-29 20:45:19 +01:00
instance -> SaveToDB ();
}
2009-05-10 22:48:22 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-10 22:48:22 -05:00
void BossAI :: _EnterCombat ()
{
2009-05-20 11:44:38 -05:00
me -> setActive ( true );
2009-05-10 22:48:22 -05:00
DoZoneInCombat ();
2010-04-07 19:14:10 +02:00
if ( instance )
2011-01-01 23:37:35 +01:00
{
// bosses do not respawn, check only on enter combat
2011-03-19 10:54:16 +01:00
if ( ! instance -> CheckRequiredBosses ( _bossId ))
2011-01-01 23:37:35 +01:00
{
EnterEvadeMode ();
return ;
}
2011-03-19 10:54:16 +01:00
instance -> SetBossState ( _bossId , IN_PROGRESS );
2011-01-01 23:37:35 +01:00
}
2009-05-10 22:48:22 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-26 19:55:41 -05:00
void BossAI :: TeleportCheaters ()
{
float x , y , z ;
me -> GetPosition ( x , y , z );
2011-03-19 10:54:16 +01:00
std :: list < HostileReference *>& threatList = me -> getThreatManager (). getThreatList ();
for ( std :: list < HostileReference *>:: iterator itr = threatList . begin (); itr != threatList . end (); ++ itr )
if ( Unit * target = ( * itr ) -> getTarget ())
if ( target -> GetTypeId () == TYPEID_PLAYER && ! CheckBoundary ( target ))
target -> NearTeleportTo ( x , y , z , 0 );
2009-05-26 19:55:41 -05:00
}
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
bool BossAI :: CheckBoundary ( Unit * who )
2009-05-17 16:37:03 -05:00
{
2011-03-19 10:54:16 +01:00
if ( ! GetBoundary () || ! who )
2009-05-17 16:37:03 -05:00
return true ;
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
for ( BossBoundaryMap :: const_iterator itr = GetBoundary () -> begin (); itr != GetBoundary () -> end (); ++ itr )
2009-05-17 16:37:03 -05:00
{
2009-11-22 00:46:38 -08:00
switch ( itr -> first )
2009-05-17 16:37:03 -05:00
{
case BOUNDARY_N :
2009-11-22 00:46:38 -08:00
if ( me -> GetPositionX () > itr -> second )
2009-05-17 16:37:03 -05:00
return false ;
break ;
case BOUNDARY_S :
2009-11-22 00:46:38 -08:00
if ( me -> GetPositionX () < itr -> second )
2009-05-17 16:37:03 -05:00
return false ;
break ;
case BOUNDARY_E :
2009-11-22 00:46:38 -08:00
if ( me -> GetPositionY () < itr -> second )
2009-05-17 16:37:03 -05:00
return false ;
break ;
case BOUNDARY_W :
2009-11-22 00:46:38 -08:00
if ( me -> GetPositionY () > itr -> second )
2009-05-17 16:37:03 -05:00
return false ;
break ;
case BOUNDARY_NW :
2009-11-22 00:46:38 -08:00
if ( me -> GetPositionX () + me -> GetPositionY () > itr -> second )
2009-05-17 16:37:03 -05:00
return false ;
break ;
case BOUNDARY_SE :
2009-11-22 00:46:38 -08:00
if ( me -> GetPositionX () + me -> GetPositionY () < itr -> second )
2009-05-17 16:37:03 -05:00
return false ;
break ;
case BOUNDARY_NE :
2009-11-22 00:46:38 -08:00
if ( me -> GetPositionX () - me -> GetPositionY () > itr -> second )
2009-05-17 16:37:03 -05:00
return false ;
break ;
case BOUNDARY_SW :
2009-11-22 00:46:38 -08:00
if ( me -> GetPositionX () - me -> GetPositionY () < itr -> second )
2009-05-17 16:37:03 -05:00
return false ;
break ;
2010-08-21 20:55:31 +02:00
default :
break ;
2009-05-17 16:37:03 -05:00
}
}
2009-10-17 15:51:44 -07:00
2009-05-17 16:37:03 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
void BossAI :: JustSummoned ( Creature * summon )
2009-05-10 22:48:22 -05:00
{
summons . Summon ( summon );
2010-04-07 19:14:10 +02:00
if ( me -> isInCombat ())
2009-05-13 10:54:11 -05:00
DoZoneInCombat ( summon );
2009-05-10 22:48:22 -05:00
}
2009-10-17 15:51:44 -07:00
2011-03-19 10:54:16 +01:00
void BossAI :: SummonedCreatureDespawn ( Creature * summon )
2009-05-10 22:48:22 -05:00
{
summons . Despawn ( summon );
}
2009-10-17 15:51:44 -07:00
2011-05-25 18:50:44 +02:00
void BossAI :: UpdateAI ( uint32 const diff )
2011-05-28 00:28:04 +02:00
{
if ( ! UpdateVictim ())
return ;
events . Update ( diff );
2012-02-03 19:12:41 +02:00
if ( me -> HasUnitState ( UNIT_STATE_CASTING ))
2011-05-28 00:28:04 +02:00
return ;
while ( uint32 eventId = events . ExecuteEvent ())
ExecuteEvent ( eventId );
DoMeleeAttackIfReady ();
}
// WorldBossAI - for non-instanced bosses
WorldBossAI :: WorldBossAI ( Creature * creature ) :
ScriptedAI ( creature ),
summons ( creature )
{
}
void WorldBossAI :: _Reset ()
{
if ( ! me -> isAlive ())
return ;
events . Reset ();
summons . DespawnAll ();
}
void WorldBossAI :: _JustDied ()
{
events . Reset ();
summons . DespawnAll ();
}
void WorldBossAI :: _EnterCombat ()
{
2011-05-28 02:14:47 +02:00
Unit * target = SelectTarget ( SELECT_TARGET_RANDOM , 0 , 0.0f , true );
if ( target )
2011-05-28 01:24:27 +02:00
AttackStart ( target );
2011-05-28 00:28:04 +02:00
}
void WorldBossAI :: JustSummoned ( Creature * summon )
{
summons . Summon ( summon );
2011-05-28 02:14:47 +02:00
Unit * target = SelectTarget ( SELECT_TARGET_RANDOM , 0 , 0.0f , true );
2011-06-12 02:30:32 +02:00
if ( target )
2011-05-28 01:24:27 +02:00
summon -> AI () -> AttackStart ( target );
2011-05-28 00:28:04 +02:00
}
void WorldBossAI :: SummonedCreatureDespawn ( Creature * summon )
{
summons . Despawn ( summon );
}
void WorldBossAI :: UpdateAI ( uint32 const diff )
2011-05-25 18:50:44 +02:00
{
if ( ! UpdateVictim ())
return ;
events . Update ( diff );
2012-02-03 19:12:41 +02:00
if ( me -> HasUnitState ( UNIT_STATE_CASTING ))
2011-05-25 18:50:44 +02:00
return ;
while ( uint32 eventId = events . ExecuteEvent ())
ExecuteEvent ( eventId );
DoMeleeAttackIfReady ();
}
2009-11-22 00:46:38 -08:00
// SD2 grid searchers.
2011-03-19 10:54:16 +01:00
Creature * GetClosestCreatureWithEntry ( WorldObject * source , uint32 entry , float maxSearchRange , bool alive /*= true*/ )
2009-11-21 05:01:03 -08:00
{
2011-03-19 10:54:16 +01:00
return source -> FindNearestCreature ( entry , maxSearchRange , alive );
2009-11-21 05:01:03 -08:00
}
2011-03-19 10:54:16 +01:00
GameObject * GetClosestGameObjectWithEntry ( WorldObject * source , uint32 entry , float maxSearchRange )
2009-07-12 01:17:04 +02:00
{
2011-03-19 10:54:16 +01:00
return source -> FindNearestGameObject ( entry , maxSearchRange );
2009-07-12 01:17:04 +02:00
}
2011-03-19 10:54:16 +01:00
void GetCreatureListWithEntryInGrid ( std :: list < Creature *>& list , WorldObject * source , uint32 entry , float maxSearchRange )
2009-11-21 05:01:03 -08:00
{
2011-03-19 10:54:16 +01:00
source -> GetCreatureListWithEntryInGrid ( list , entry , maxSearchRange );
2009-11-21 05:01:03 -08:00
}
2011-03-19 10:54:16 +01:00
void GetGameObjectListWithEntryInGrid ( std :: list < GameObject *>& list , WorldObject * source , uint32 entry , float maxSearchRange )
2009-11-21 05:01:03 -08:00
{
2011-03-19 10:54:16 +01:00
source -> GetGameObjectListWithEntryInGrid ( list , entry , maxSearchRange );
2009-11-21 05:01:03 -08:00
}