2008-10-14 11:57:03 -05:00
/* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
*
* 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 */
#include "precompiled.h"
#include "Item.h"
#include "Spell.h"
// Spell summary for ScriptedAI::SelectSpell
struct TSpellSummary {
2008-10-25 11:40:10 -05:00
uint8 Targets ; // set of enum SelectTarget
uint8 Effects ; // set of enum SelectEffect
2008-10-11 14:16:25 -05:00
} * SpellSummary ;
2008-11-03 10:16:06 -06:00
void SummonList :: Despawn ( Creature * summon )
{
uint64 guid = summon -> GetGUID ();
for ( iterator i = begin (); i != end (); ++ i )
{
if ( * i == guid )
{
erase ( i );
return ;
}
}
}
void SummonList :: DespawnEntry ( uint32 entry )
{
for ( iterator i = begin (); i != end (); ++ i )
{
if ( Creature * summon = ( Creature * ) Unit :: GetUnit ( * m_creature , * i ))
{
if ( summon -> GetEntry () == entry )
{
summon -> setDeathState ( JUST_DIED );
summon -> RemoveCorpse ();
i = erase ( i );
-- i ;
}
}
else
{
i = erase ( i );
-- i ;
}
}
}
void SummonList :: DespawnAll ()
{
for ( iterator i = begin (); i != end (); ++ i )
{
if ( Creature * summon = ( Creature * ) Unit :: GetUnit ( * m_creature , * i ))
{
summon -> setDeathState ( JUST_DIED );
summon -> RemoveCorpse ();
}
}
clear ();
}
2008-10-11 14:16:25 -05:00
bool ScriptedAI :: IsVisible ( Unit * who ) const
{
if ( ! who )
return false ;
return ( m_creature -> GetDistance ( who ) < VISIBLE_RANGE ) && who -> isVisibleForOrDetect ( m_creature , true );
}
void ScriptedAI :: MoveInLineOfSight ( Unit * who )
{
2008-11-21 10:07:11 -06:00
if ( ! m_creature -> getVictim () && m_creature -> canStartAttack ( who ))
2008-11-07 09:36:46 -06:00
AttackStart ( who );
2008-10-25 11:40:10 -05:00
}
2008-10-11 14:16:25 -05:00
2008-10-25 11:40:10 -05:00
void ScriptedAI :: AttackStart ( Unit * who , bool melee )
{
if ( ! who )
return ;
if ( m_creature -> Attack ( who , melee ))
{
m_creature -> AddThreat ( who , 0.0f );
m_creature -> SetInCombatWith ( who );
who -> SetInCombatWith ( m_creature );
if ( ! InCombat )
{
InCombat = true ;
Aggro ( who );
2008-10-11 14:16:25 -05:00
}
2008-10-25 11:40:10 -05:00
if ( melee )
DoStartMovement ( who );
else
DoStartNoMovement ( who );
2008-10-11 14:16:25 -05:00
}
}
void ScriptedAI :: AttackStart ( Unit * who )
{
if ( ! who )
return ;
2008-10-25 11:40:10 -05:00
if ( m_creature -> Attack ( who , true ))
2008-10-11 14:16:25 -05:00
{
2008-10-25 11:40:10 -05:00
m_creature -> AddThreat ( who , 0.0f );
m_creature -> SetInCombatWith ( who );
who -> SetInCombatWith ( m_creature );
2008-10-11 14:16:25 -05:00
if ( ! InCombat )
{
InCombat = true ;
Aggro ( who );
}
2008-10-25 11:40:10 -05:00
DoStartMovement ( who );
2008-10-11 14:16:25 -05:00
}
}
void ScriptedAI :: UpdateAI ( const uint32 diff )
{
//Check if we have a current target
2008-10-25 11:40:10 -05:00
if ( m_creature -> isAlive () && m_creature -> SelectHostilTarget () && m_creature -> getVictim ())
2008-10-11 14:16:25 -05:00
{
2008-10-25 11:40:10 -05:00
if ( m_creature -> isAttackReady () )
2008-10-11 14:16:25 -05:00
{
//If we are within range melee the target
2008-12-05 18:39:31 -06:00
if ( m_creature -> IsWithinMeleeRange ( m_creature -> getVictim ()))
2008-10-11 14:16:25 -05:00
{
m_creature -> AttackerStateUpdate ( m_creature -> getVictim ());
m_creature -> resetAttackTimer ();
}
}
}
}
void ScriptedAI :: EnterEvadeMode ()
{
2008-11-24 17:15:41 -06:00
//m_creature->InterruptNonMeleeSpells(true);
2008-10-11 14:16:25 -05:00
m_creature -> RemoveAllAuras ();
m_creature -> DeleteThreatList ();
m_creature -> CombatStop ();
m_creature -> LoadCreaturesAddon ();
m_creature -> SetLootRecipient ( NULL );
2008-11-24 17:15:41 -06:00
if ( m_creature -> isAlive ())
{
if ( Unit * owner = m_creature -> GetOwner ())
{
if ( owner -> isAlive ())
m_creature -> GetMotionMaster () -> MoveFollow ( owner , PET_FOLLOW_DIST , PET_FOLLOW_ANGLE );
}
else
m_creature -> GetMotionMaster () -> MoveTargetedHome ();
}
2008-10-11 14:16:25 -05:00
InCombat = false ;
Reset ();
}
void ScriptedAI :: JustRespawned ()
{
InCombat = false ;
Reset ();
}
2008-10-25 11:40:10 -05:00
void ScriptedAI :: DoStartMovement ( Unit * victim , float distance , float angle )
2008-10-11 14:16:25 -05:00
{
if ( ! victim )
return ;
2008-10-25 11:40:10 -05:00
m_creature -> GetMotionMaster () -> MoveChase ( victim , distance , angle );
2008-10-11 14:16:25 -05:00
}
2008-10-25 11:40:10 -05:00
void ScriptedAI :: DoStartNoMovement ( Unit * victim )
2008-10-11 14:16:25 -05:00
{
if ( ! victim )
return ;
2008-10-25 11:40:10 -05:00
m_creature -> GetMotionMaster () -> MoveIdle ();
m_creature -> StopMoving ();
2008-10-11 14:16:25 -05:00
}
void ScriptedAI :: DoMeleeAttackIfReady ()
{
//Make sure our attack is ready and we aren't currently casting before checking distance
2008-11-25 17:58:06 -06:00
if ( m_creature -> isAttackReady () && ! m_creature -> hasUnitState ( UNIT_STAT_CASTING ))
2008-10-11 14:16:25 -05:00
{
//If we are within range melee the target
2008-12-05 18:39:31 -06:00
if ( m_creature -> IsWithinMeleeRange ( m_creature -> getVictim ()))
2008-10-11 14:16:25 -05:00
{
m_creature -> AttackerStateUpdate ( m_creature -> getVictim ());
m_creature -> resetAttackTimer ();
}
}
2008-11-25 17:58:06 -06:00
if ( m_creature -> haveOffhandWeapon () && m_creature -> isAttackReady ( OFF_ATTACK ) && ! m_creature -> hasUnitState ( UNIT_STAT_CASTING ))
2008-11-09 14:54:13 -06:00
{
//If we are within range melee the target
2008-12-05 18:39:31 -06:00
if ( m_creature -> IsWithinMeleeRange ( m_creature -> getVictim ()))
2008-11-09 14:54:13 -06:00
{
m_creature -> AttackerStateUpdate ( m_creature -> getVictim (), OFF_ATTACK );
m_creature -> resetAttackTimer ( OFF_ATTACK );
}
}
2008-10-11 14:16:25 -05:00
}
void ScriptedAI :: DoStopAttack ()
{
2008-10-25 11:40:10 -05:00
if ( m_creature -> getVictim () != NULL )
2008-10-11 14:16:25 -05:00
{
m_creature -> AttackStop ();
}
}
void ScriptedAI :: DoCast ( Unit * victim , uint32 spellId , bool triggered )
{
2008-12-10 20:25:47 -06:00
if ( ! victim || m_creature -> hasUnitState ( UNIT_STAT_CASTING ))
2008-10-11 14:16:25 -05:00
return ;
2008-12-10 20:25:47 -06:00
//m_creature->StopMoving();
2008-10-11 14:16:25 -05:00
m_creature -> CastSpell ( victim , spellId , triggered );
}
void ScriptedAI :: DoCastSpell ( Unit * who , SpellEntry const * spellInfo , bool triggered )
{
if ( ! who || m_creature -> IsNonMeleeSpellCasted ( false ))
return ;
m_creature -> StopMoving ();
m_creature -> CastSpell ( who , spellInfo , triggered );
}
2008-12-27 21:27:41 +01:00
void ScriptedAI :: DoSay ( const char * text , uint32 language , Unit * target , bool SayEmote )
2008-10-11 14:16:25 -05:00
{
2008-12-27 21:27:41 +01:00
if ( target )
{
m_creature -> Say ( text , language , target -> GetGUID ());
if ( SayEmote )
m_creature -> HandleEmoteCommand ( EMOTE_ONESHOT_TALK );
}
2008-10-11 14:16:25 -05:00
else m_creature -> Say ( text , language , 0 );
}
void ScriptedAI :: DoYell ( const char * text , uint32 language , Unit * target )
{
2008-10-25 11:40:10 -05:00
if ( target ) m_creature -> Yell ( text , language , target -> GetGUID ());
2008-10-11 14:16:25 -05:00
else m_creature -> Yell ( text , language , 0 );
}
void ScriptedAI :: DoTextEmote ( const char * text , Unit * target , bool IsBossEmote )
{
2008-10-25 11:40:10 -05:00
if ( target ) m_creature -> TextEmote ( text , target -> GetGUID (), IsBossEmote );
2008-10-11 14:16:25 -05:00
else m_creature -> TextEmote ( text , 0 , IsBossEmote );
}
void ScriptedAI :: DoWhisper ( const char * text , Unit * reciever , bool IsBossWhisper )
{
if ( ! reciever || reciever -> GetTypeId () != TYPEID_PLAYER )
return ;
m_creature -> Whisper ( text , reciever -> GetGUID (), IsBossWhisper );
}
void ScriptedAI :: DoPlaySoundToSet ( Unit * unit , uint32 sound )
{
if ( ! unit )
return ;
if ( ! GetSoundEntriesStore () -> LookupEntry ( sound ))
{
error_log ( "SD2: Invalid soundId %u used in DoPlaySoundToSet (by unit TypeId %u, guid %u)" , sound , unit -> GetTypeId (), unit -> GetGUID ());
return ;
}
2008-10-25 11:40:10 -05:00
WorldPacket data ( 4 );
data . SetOpcode ( SMSG_PLAY_SOUND );
data << uint32 ( sound );
unit -> SendMessageToSet ( & data , false );
2008-10-11 14:16:25 -05:00
}
Creature * ScriptedAI :: DoSpawnCreature ( uint32 id , float x , float y , float z , float angle , uint32 type , uint32 despawntime )
{
return m_creature -> SummonCreature ( id , m_creature -> GetPositionX () + x , m_creature -> GetPositionY () + y , m_creature -> GetPositionZ () + z , angle , ( TempSummonType ) type , despawntime );
}
Unit * ScriptedAI :: SelectUnit ( SelectAggroTarget target , uint32 position )
{
//ThreatList m_threatlist;
std :: list < HostilReference *>& m_threatlist = m_creature -> getThreatManager (). getThreatList ();
std :: list < HostilReference *>:: iterator i = m_threatlist . begin ();
std :: list < HostilReference *>:: reverse_iterator r = m_threatlist . rbegin ();
if ( position >= m_threatlist . size () || ! m_threatlist . size ())
return NULL ;
switch ( target )
{
case SELECT_TARGET_RANDOM :
advance ( i , position + ( rand () % ( m_threatlist . size () - position ) ));
return Unit :: GetUnit (( * m_creature ),( * i ) -> getUnitGuid ());
break ;
case SELECT_TARGET_TOPAGGRO :
advance ( i , position );
return Unit :: GetUnit (( * m_creature ),( * i ) -> getUnitGuid ());
break ;
case SELECT_TARGET_BOTTOMAGGRO :
advance ( r , position );
return Unit :: GetUnit (( * m_creature ),( * r ) -> getUnitGuid ());
break ;
}
return NULL ;
}
2008-10-28 16:28:42 -05:00
struct TargetDistanceOrder : public std :: binary_function < const Unit , const Unit , bool >
{
const Unit * me ;
TargetDistanceOrder ( const Unit * Target ) : me ( Target ) {};
// functor for operator ">"
bool operator ()( const Unit * _Left , const Unit * _Right ) const
{
return ( me -> GetDistance ( _Left ) < me -> GetDistance ( _Right ));
}
};
Unit * ScriptedAI :: SelectUnit ( SelectAggroTarget targetType , uint32 position , float dist , bool playerOnly )
{
if ( targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST )
{
std :: list < HostilReference *> & m_threatlist = m_creature -> getThreatManager (). getThreatList ();
if ( m_threatlist . empty ()) return NULL ;
std :: list < Unit *> targetList ;
std :: list < HostilReference *>:: iterator itr = m_threatlist . begin ();
for (; itr != m_threatlist . end (); ++ itr )
{
Unit * target = Unit :: GetUnit ( * m_creature , ( * itr ) -> getUnitGuid ());
if ( ! target
|| playerOnly && target -> GetTypeId () != TYPEID_PLAYER
|| dist && ! m_creature -> IsWithinDistInMap ( target , dist ))
{
continue ;
}
targetList . push_back ( target );
}
if ( position >= targetList . size ())
return NULL ;
targetList . sort ( TargetDistanceOrder ( m_creature ));
if ( targetType == SELECT_TARGET_NEAREST )
{
std :: list < Unit *>:: iterator i = targetList . begin ();
advance ( i , position );
return * i ;
}
else
{
std :: list < Unit *>:: reverse_iterator i = targetList . rbegin ();
advance ( i , position );
return * i ;
}
}
else
{
std :: list < HostilReference *> m_threatlist = m_creature -> getThreatManager (). getThreatList ();
std :: list < HostilReference *>:: iterator i ;
Unit * target ;
while ( position < m_threatlist . size ())
{
if ( targetType == SELECT_TARGET_BOTTOMAGGRO )
{
i = m_threatlist . end ();
advance ( i , - ( int32 ) position - 1 );
}
else
{
i = m_threatlist . begin ();
if ( targetType == SELECT_TARGET_TOPAGGRO )
advance ( i , position );
else // random
advance ( i , position + rand () % ( m_threatlist . size () - position ));
}
target = Unit :: GetUnit ( * m_creature ,( * i ) -> getUnitGuid ());
if ( ! target
|| playerOnly && target -> GetTypeId () != TYPEID_PLAYER
|| dist && ! m_creature -> IsWithinDistInMap ( target , dist ))
{
m_threatlist . erase ( i );
}
else
{
return target ;
}
}
}
return NULL ;
}
void ScriptedAI :: SelectUnitList ( std :: list < Unit *> & targetList , uint32 num , SelectAggroTarget targetType , float dist , bool playerOnly )
{
if ( targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST )
{
std :: list < HostilReference *> & m_threatlist = m_creature -> getThreatManager (). getThreatList ();
if ( m_threatlist . empty ()) return ;
std :: list < HostilReference *>:: iterator itr = m_threatlist . begin ();
for (; itr != m_threatlist . end (); ++ itr )
{
Unit * target = Unit :: GetUnit ( * m_creature , ( * itr ) -> getUnitGuid ());
if ( ! target
|| playerOnly && target -> GetTypeId () != TYPEID_PLAYER
|| dist && ! m_creature -> IsWithinDistInMap ( target , dist ))
{
continue ;
}
targetList . push_back ( target );
}
targetList . sort ( TargetDistanceOrder ( m_creature ));
targetList . resize ( num );
if ( targetType == SELECT_TARGET_FARTHEST )
targetList . reverse ();
}
else
{
std :: list < HostilReference *> m_threatlist = m_creature -> getThreatManager (). getThreatList ();
std :: list < HostilReference *>:: iterator i ;
Unit * target ;
while ( m_threatlist . size ())
{
if ( targetType == SELECT_TARGET_BOTTOMAGGRO )
{
i = m_threatlist . end ();
-- i ;
}
else
{
i = m_threatlist . begin ();
if ( targetType == SELECT_TARGET_RANDOM )
advance ( i , rand () % m_threatlist . size ());
}
target = Unit :: GetUnit ( * m_creature ,( * i ) -> getUnitGuid ());
m_threatlist . erase ( i );
if ( ! target
|| playerOnly && target -> GetTypeId () != TYPEID_PLAYER
|| dist && ! m_creature -> IsWithinDistInMap ( target , dist ))
{
continue ;
}
targetList . push_back ( target );
}
}
}
2008-10-11 14:16:25 -05:00
SpellEntry const * ScriptedAI :: SelectSpell ( Unit * Target , int32 School , int32 Mechanic , SelectTarget Targets , uint32 PowerCostMin , uint32 PowerCostMax , float RangeMin , float RangeMax , SelectEffect Effects )
{
//No target so we can't cast
if ( ! Target )
return false ;
//Silenced so we can't cast
if ( m_creature -> HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SILENCED ))
return false ;
//Using the extended script system we first create a list of viable spells
SpellEntry const * Spell [ 4 ];
Spell [ 0 ] = 0 ;
Spell [ 1 ] = 0 ;
Spell [ 2 ] = 0 ;
Spell [ 3 ] = 0 ;
uint32 SpellCount = 0 ;
SpellEntry const * TempSpell ;
SpellRangeEntry const * TempRange ;
//Check if each spell is viable(set it to null if not)
for ( uint32 i = 0 ; i < 4 ; i ++ )
{
TempSpell = GetSpellStore () -> LookupEntry ( m_creature -> m_spells [ i ]);
//This spell doesn't exist
if ( ! TempSpell )
continue ;
// Targets and Effects checked first as most used restrictions
//Check the spell targets if specified
if ( Targets && ! ( SpellSummary [ m_creature -> m_spells [ i ]]. Targets & ( 1 << ( Targets - 1 ))) )
continue ;
//Check the type of spell if we are looking for a specific spell type
if ( Effects && ! ( SpellSummary [ m_creature -> m_spells [ i ]]. Effects & ( 1 << ( Effects - 1 ))) )
continue ;
//Check for school if specified
if ( School >= 0 && TempSpell -> SchoolMask & School )
continue ;
//Check for spell mechanic if specified
if ( Mechanic >= 0 && TempSpell -> Mechanic != Mechanic )
continue ;
//Make sure that the spell uses the requested amount of power
if ( PowerCostMin && TempSpell -> manaCost < PowerCostMin )
continue ;
if ( PowerCostMax && TempSpell -> manaCost > PowerCostMax )
continue ;
//Continue if we don't have the mana to actually cast this spell
if ( TempSpell -> manaCost > m_creature -> GetPower (( Powers ) TempSpell -> powerType ))
continue ;
//Get the Range
TempRange = GetSpellRangeStore () -> LookupEntry ( TempSpell -> rangeIndex );
//Spell has invalid range store so we can't use it
if ( ! TempRange )
continue ;
//Check if the spell meets our range requirements
if ( RangeMin && TempRange -> maxRange < RangeMin )
continue ;
if ( RangeMax && TempRange -> maxRange > RangeMax )
continue ;
//Check if our target is in range
if ( m_creature -> IsWithinDistInMap ( Target , TempRange -> minRange ) || ! m_creature -> IsWithinDistInMap ( Target , TempRange -> maxRange ))
continue ;
//All good so lets add it to the spell list
Spell [ SpellCount ] = TempSpell ;
SpellCount ++ ;
}
//We got our usable spells so now lets randomly pick one
if ( ! SpellCount )
return NULL ;
return Spell [ rand () % SpellCount ];
}
bool ScriptedAI :: CanCast ( Unit * Target , SpellEntry const * Spell , bool Triggered )
{
//No target so we can't cast
if ( ! Target || ! Spell )
return false ;
//Silenced so we can't cast
if ( ! Triggered && m_creature -> HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SILENCED ))
return false ;
//Check for power
if ( ! Triggered && m_creature -> GetPower (( Powers ) Spell -> powerType ) < Spell -> manaCost )
return false ;
SpellRangeEntry const * TempRange = NULL ;
TempRange = GetSpellRangeStore () -> LookupEntry ( Spell -> rangeIndex );
//Spell has invalid range store so we can't use it
if ( ! TempRange )
return false ;
//Unit is out of range of this spell
if ( m_creature -> GetDistance ( Target ) > TempRange -> maxRange || m_creature -> GetDistance ( Target ) < TempRange -> minRange )
return false ;
return true ;
}
void FillSpellSummary ()
{
SpellSummary = new TSpellSummary [ GetSpellStore () -> GetNumRows ()];
SpellEntry const * TempSpell ;
for ( int i = 0 ; i < GetSpellStore () -> GetNumRows (); i ++ )
{
SpellSummary [ i ]. Effects = 0 ;
SpellSummary [ i ]. Targets = 0 ;
TempSpell = GetSpellStore () -> LookupEntry ( i );
//This spell doesn't exist
if ( ! TempSpell )
continue ;
for ( int j = 0 ; j < 3 ; j ++ )
{
//Spell targets self
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SELF )
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_SELF - 1 );
//Spell targets a single enemy
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_CHAIN_DAMAGE ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_CURRENT_ENEMY_COORDINATES )
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_SINGLE_ENEMY - 1 );
//Spell targets AoE at enemy
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_ENEMY_IN_AREA ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_ENEMY_IN_AREA_INSTANT ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_AROUND_CASTER ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED )
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_AOE_ENEMY - 1 );
//Spell targets an enemy
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_CHAIN_DAMAGE ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_CURRENT_ENEMY_COORDINATES ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_ENEMY_IN_AREA ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_ENEMY_IN_AREA_INSTANT ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_AROUND_CASTER ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED )
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_ANY_ENEMY - 1 );
//Spell targets a single friend(or self)
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SELF ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SINGLE_FRIEND ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SINGLE_PARTY )
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_SINGLE_FRIEND - 1 );
//Spell targets aoe friends
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_PARTY_AROUND_CASTER ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_AREAEFFECT_PARTY ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_AROUND_CASTER )
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_AOE_FRIEND - 1 );
//Spell targets any friend(or self)
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SELF ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SINGLE_FRIEND ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SINGLE_PARTY ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_PARTY_AROUND_CASTER ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_AREAEFFECT_PARTY ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_ALL_AROUND_CASTER )
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_ANY_FRIEND - 1 );
//Make sure that this spell includes a damage effect
if ( TempSpell -> Effect [ j ] == SPELL_EFFECT_SCHOOL_DAMAGE ||
TempSpell -> Effect [ j ] == SPELL_EFFECT_INSTAKILL ||
TempSpell -> Effect [ j ] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE ||
TempSpell -> Effect [ j ] == SPELL_EFFECT_HEALTH_LEECH )
SpellSummary [ i ]. Effects |= 1 << ( SELECT_EFFECT_DAMAGE - 1 );
//Make sure that this spell includes a healing effect (or an apply aura with a periodic heal)
if ( TempSpell -> Effect [ j ] == SPELL_EFFECT_HEAL ||
TempSpell -> Effect [ j ] == SPELL_EFFECT_HEAL_MAX_HEALTH ||
TempSpell -> Effect [ j ] == SPELL_EFFECT_HEAL_MECHANICAL ||
( TempSpell -> Effect [ j ] == SPELL_EFFECT_APPLY_AURA && TempSpell -> EffectApplyAuraName [ j ] == 8 ))
SpellSummary [ i ]. Effects |= 1 << ( SELECT_EFFECT_HEALING - 1 );
//Make sure that this spell applies an aura
if ( TempSpell -> Effect [ j ] == SPELL_EFFECT_APPLY_AURA )
SpellSummary [ i ]. Effects |= 1 << ( SELECT_EFFECT_AURA - 1 );
}
}
}
void ScriptedAI :: DoZoneInCombat ( Unit * pUnit )
{
if ( ! pUnit )
pUnit = m_creature ;
Map * map = pUnit -> GetMap ();
if ( ! map -> IsDungeon ()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
{
error_log ( "SD2: DoZoneInCombat call for map that isn't an instance (pUnit entry = %d)" , pUnit -> GetTypeId () == TYPEID_UNIT ? (( Creature * ) pUnit ) -> GetEntry () : 0 );
return ;
}
2008-10-26 13:58:39 -05:00
if ( ! pUnit -> CanHaveThreatList () || pUnit -> getThreatManager (). isThreatListEmpty ())
2008-10-11 14:16:25 -05:00
{
error_log ( "SD2: DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (pUnit entry = %d)" , pUnit -> GetTypeId () == TYPEID_UNIT ? (( Creature * ) pUnit ) -> GetEntry () : 0 );
2008-10-25 11:40:10 -05:00
2008-10-11 14:16:25 -05:00
return ;
2008-10-26 13:58:39 -05:00
}
2008-10-11 14:16:25 -05:00
2008-11-21 10:07:11 -06:00
Map :: PlayerList const & PlayerList = map -> GetPlayers ();
for ( Map :: PlayerList :: const_iterator i = PlayerList . begin (); i != PlayerList . end (); ++ i )
2008-11-24 15:15:09 -06:00
{
2008-11-21 10:07:11 -06:00
if ( Player * i_pl = i -> getSource ())
if ( ! i_pl -> isAlive ())
2008-11-24 15:15:09 -06:00
{
pUnit -> SetInCombatWith ( i_pl );
i_pl -> SetInCombatWith ( pUnit );
2008-11-18 19:40:06 -06:00
pUnit -> AddThreat ( i_pl , 0.0f );
2008-11-24 15:15:09 -06:00
}
}
2008-10-11 14:16:25 -05:00
}
void ScriptedAI :: DoResetThreat ()
{
if ( ! m_creature -> CanHaveThreatList () || m_creature -> getThreatManager (). isThreatListEmpty ())
{
error_log ( "SD2: DoResetThreat called for creature that either cannot have threat list or has empty threat list (m_creature entry = %d)" , m_creature -> GetEntry ());
return ;
}
std :: list < HostilReference *>& m_threatlist = m_creature -> getThreatManager (). getThreatList ();
std :: list < HostilReference *>:: iterator itr ;
for ( itr = m_threatlist . begin (); itr != m_threatlist . end (); ++ itr )
{
Unit * pUnit = NULL ;
pUnit = Unit :: GetUnit (( * m_creature ), ( * itr ) -> getUnitGuid ());
if ( pUnit && m_creature -> getThreatManager (). getThreat ( pUnit ))
m_creature -> getThreatManager (). modifyThreatPercent ( pUnit , - 100 );
}
}
void ScriptedAI :: DoTeleportPlayer ( Unit * pUnit , float x , float y , float z , float o )
{
if ( ! pUnit || pUnit -> GetTypeId () != TYPEID_PLAYER )
{
if ( pUnit )
error_log ( "SD2: Creature %u (Entry: %u) Tried to teleport non-player unit (Type: %u GUID: %u) to x: %f y:%f z: %f o: %f. Aborted." , m_creature -> GetGUID (), m_creature -> GetEntry (), pUnit -> GetTypeId (), pUnit -> GetGUID (), x , y , z , o );
return ;
}
(( Player * ) pUnit ) -> TeleportTo ( pUnit -> GetMapId (), x , y , z , o , TELE_TO_NOT_LEAVE_COMBAT );
}
2008-11-18 19:40:06 -06:00
void ScriptedAI :: DoTeleportAll ( float x , float y , float z , float o )
{
Map * map = m_creature -> GetMap ();
if ( ! map -> IsDungeon ())
return ;
2008-11-21 10:07:11 -06:00
Map :: PlayerList const & PlayerList = map -> GetPlayers ();
for ( Map :: PlayerList :: const_iterator i = PlayerList . begin (); i != PlayerList . end (); ++ i )
if ( Player * i_pl = i -> getSource ())
if ( ! i_pl -> isAlive ())
2008-11-18 19:40:06 -06:00
i_pl -> TeleportTo ( m_creature -> GetMapId (), x , y , z , o , TELE_TO_NOT_LEAVE_COMBAT );
}
2008-12-26 13:30:46 +01:00
Unit * ScriptedAI :: FindCreature ( uint32 entry , uint32 range )
{
CellPair pair ( Trinity :: ComputeCellPair ( m_creature -> GetPositionX (), m_creature -> GetPositionY ()));
Cell cell ( pair );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
std :: list < Creature *> NPCList ;
Trinity :: AllCreaturesOfEntryInRange check ( m_creature , entry , range );
Trinity :: CreatureListSearcher < Trinity :: AllCreaturesOfEntryInRange > searcher ( NPCList , check );
TypeContainerVisitor < Trinity :: CreatureListSearcher < Trinity :: AllCreaturesOfEntryInRange > , GridTypeMapContainer > visitor ( searcher );
CellLock < GridReadGuard > cell_lock ( cell , pair );
cell_lock -> Visit ( cell_lock , visitor , * ( m_creature -> GetMap ()));
if ( ! NPCList . empty ())
{
for ( std :: list < Creature *>:: iterator itr = NPCList . begin (); itr != NPCList . end (); ++ itr )
{
return Creature :: GetUnit (( * m_creature ), ( * itr ) -> GetGUID ());
}
} else error_log ( "SD2 ERROR: Entry: %u not found!" , entry ); return NULL ;
}
GameObject * ScriptedAI :: FindGameObject ( uint32 entry )
{
CellPair pair ( Trinity :: ComputeCellPair ( m_creature -> GetPositionX (), m_creature -> GetPositionY ()));
Cell cell ( pair );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
std :: list < GameObject *> GOList ;
Trinity :: AllGameObjectsWithEntryInGrid go_check ( entry );
Trinity :: GameObjectListSearcher < Trinity :: AllGameObjectsWithEntryInGrid > go_search ( GOList , go_check );
TypeContainerVisitor
< Trinity :: GameObjectListSearcher < Trinity :: AllGameObjectsWithEntryInGrid > , GridTypeMapContainer > go_visit ( go_search );
CellLock < GridReadGuard > cell_lock ( cell , pair );
cell_lock -> Visit ( cell_lock , go_visit , * ( m_creature -> GetMap ()));
if ( ! GOList . empty ())
{
for ( std :: list < GameObject *>:: iterator itr = GOList . begin (); itr != GOList . end (); ++ itr )
{
return ( * itr );
}
}
else error_log ( "SD2 ERROR: GameObject Entry: %u not found!" , entry ); return NULL ;
}
2008-11-18 19:40:06 -06:00
2008-10-11 14:16:25 -05:00
Unit * ScriptedAI :: DoSelectLowestHpFriendly ( float range , uint32 MinHPDiff )
{
2008-10-14 11:57:03 -05:00
CellPair p ( Trinity :: ComputeCellPair ( m_creature -> GetPositionX (), m_creature -> GetPositionY ()));
2008-10-11 14:16:25 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
Unit * pUnit = NULL ;
2008-10-14 11:57:03 -05:00
Trinity :: MostHPMissingInRange u_check ( m_creature , range , MinHPDiff );
Trinity :: UnitLastSearcher < Trinity :: MostHPMissingInRange > searcher ( pUnit , u_check );
2008-10-11 14:16:25 -05:00
/*
typedef TYPELIST_4(GameObject, Creature*except pets*, DynamicObject, Corpse*Bones*) AllGridObjectTypes;
This means that if we only search grid then we cannot possibly return pets or players so this is safe
*/
2008-10-14 11:57:03 -05:00
TypeContainerVisitor < Trinity :: UnitLastSearcher < Trinity :: MostHPMissingInRange > , GridTypeMapContainer > grid_unit_searcher ( searcher );
2008-10-11 14:16:25 -05:00
CellLock < GridReadGuard > cell_lock ( cell , p );
cell_lock -> Visit ( cell_lock , grid_unit_searcher , * ( m_creature -> GetMap ()));
return pUnit ;
}
std :: list < Creature *> ScriptedAI :: DoFindFriendlyCC ( float range )
{
2008-10-14 11:57:03 -05:00
CellPair p ( Trinity :: ComputeCellPair ( m_creature -> GetPositionX (), m_creature -> GetPositionY ()));
2008-10-11 14:16:25 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
std :: list < Creature *> pList ;
2008-10-14 11:57:03 -05:00
Trinity :: FriendlyCCedInRange u_check ( m_creature , range );
Trinity :: CreatureListSearcher < Trinity :: FriendlyCCedInRange > searcher ( pList , u_check );
2008-10-11 14:16:25 -05:00
2008-10-14 11:57:03 -05:00
TypeContainerVisitor < Trinity :: CreatureListSearcher < Trinity :: FriendlyCCedInRange > , GridTypeMapContainer > grid_creature_searcher ( searcher );
2008-10-11 14:16:25 -05:00
CellLock < GridReadGuard > cell_lock ( cell , p );
cell_lock -> Visit ( cell_lock , grid_creature_searcher , * ( m_creature -> GetMap ()));
return pList ;
}
std :: list < Creature *> ScriptedAI :: DoFindFriendlyMissingBuff ( float range , uint32 spellid )
{
2008-10-14 11:57:03 -05:00
CellPair p ( Trinity :: ComputeCellPair ( m_creature -> GetPositionX (), m_creature -> GetPositionY ()));
2008-10-11 14:16:25 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
std :: list < Creature *> pList ;
2008-10-14 11:57:03 -05:00
Trinity :: FriendlyMissingBuffInRange u_check ( m_creature , range , spellid );
Trinity :: CreatureListSearcher < Trinity :: FriendlyMissingBuffInRange > searcher ( pList , u_check );
2008-10-11 14:16:25 -05:00
2008-10-14 11:57:03 -05:00
TypeContainerVisitor < Trinity :: CreatureListSearcher < Trinity :: FriendlyMissingBuffInRange > , GridTypeMapContainer > grid_creature_searcher ( searcher );
2008-10-11 14:16:25 -05:00
CellLock < GridReadGuard > cell_lock ( cell , p );
cell_lock -> Visit ( cell_lock , grid_creature_searcher , * ( m_creature -> GetMap ()));
return pList ;
}
2008-11-27 15:19:06 -06:00
/*void Scripted_NoMovementAI::MoveInLineOfSight(Unit *who)
2008-10-11 14:16:25 -05:00
{
2008-11-14 16:28:45 -06:00
if( !m_creature->getVictim() && m_creature->canAttack(who) && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature) )
2008-10-11 14:16:25 -05:00
{
if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
return;
float attackRadius = m_creature->GetAttackDistance(who);
if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
{
who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
2008-10-25 11:40:10 -05:00
AttackStart(who);
2008-10-11 14:16:25 -05:00
}
}
2008-11-27 15:19:06 -06:00
}*/
2008-10-11 14:16:25 -05:00
void Scripted_NoMovementAI :: AttackStart ( Unit * who )
{
if ( ! who )
return ;
2008-10-25 11:40:10 -05:00
if ( m_creature -> Attack ( who , true ))
2008-10-11 14:16:25 -05:00
{
2008-10-25 11:40:10 -05:00
m_creature -> AddThreat ( who , 0.0f );
m_creature -> SetInCombatWith ( who );
who -> SetInCombatWith ( m_creature );
2008-10-11 14:16:25 -05:00
if ( ! InCombat )
{
InCombat = true ;
Aggro ( who );
}
2008-10-25 11:40:10 -05:00
DoStartNoMovement ( who );
2008-10-11 14:16:25 -05:00
}
}