2009-02-04 12:04:12 +01:00
/* Copyright (C) 2008-2009 Trinity <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 */
#include "precompiled.h"
#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"
2008-10-11 14:16:25 -05:00
// 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 ;
2009-05-13 10:54:11 -05:00
void SummonList :: DoZoneInCombat ( uint32 entry )
{
for ( iterator i = begin (); i != end ();)
{
Creature * summon = Unit :: GetCreature ( * m_creature , * i );
++ i ;
if ( summon && summon -> IsAIEnabled
&& ( ! entry || summon -> GetEntry () == entry ))
summon -> AI () -> DoZoneInCombat ();
}
}
2009-04-22 23:03:49 -05:00
void SummonList :: DoAction ( uint32 entry , uint32 info )
2008-11-03 10:16:06 -06:00
{
2009-04-22 23:03:49 -05:00
for ( iterator i = begin (); i != end ();)
2008-11-03 10:16:06 -06:00
{
2009-04-22 23:03:49 -05:00
Creature * summon = Unit :: GetCreature ( * m_creature , * i );
++ i ;
2009-05-13 10:54:11 -05:00
if ( summon && summon -> IsAIEnabled
&& ( ! entry || summon -> GetEntry () == entry ))
2009-04-22 23:03:49 -05:00
summon -> AI () -> DoAction ( info );
2008-11-03 10:16:06 -06:00
}
}
void SummonList :: DespawnEntry ( uint32 entry )
{
2009-04-22 23:03:49 -05:00
for ( iterator i = begin (); i != end ();)
2008-11-03 10:16:06 -06:00
{
2009-04-22 23:03:49 -05:00
Creature * summon = Unit :: GetCreature ( * m_creature , * i );
if ( ! summon )
erase ( i ++ );
else if ( summon -> GetEntry () == entry )
2008-11-03 10:16:06 -06:00
{
2009-04-22 23:03:49 -05:00
erase ( i ++ );
summon -> setDeathState ( JUST_DIED );
summon -> RemoveCorpse ();
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
}
}
void SummonList :: DespawnAll ()
{
2009-04-22 23:03:49 -05:00
while ( ! empty ())
2008-11-03 10:16:06 -06:00
{
2009-04-22 23:03:49 -05:00
Creature * summon = Unit :: GetCreature ( * m_creature , * begin ());
if ( ! summon )
erase ( begin ());
else
2008-11-03 10:16:06 -06:00
{
2009-04-22 23:03:49 -05:00
erase ( begin ());
2009-05-10 22:48:22 -05:00
summon -> SetVisibility ( VISIBILITY_OFF );
2009-05-11 11:46:48 -05:00
if ( summon -> HasSummonMask ( SUMMON_MASK_SUMMON ) && ! summon -> isPet ())
(( TempSummon * ) summon ) -> UnSummon ();
else
summon -> setDeathState ( JUST_DIED );
2008-11-03 10:16:06 -06:00
summon -> RemoveCorpse ();
}
}
}
2009-04-29 00:15:18 -05:00
ScriptedAI :: ScriptedAI ( Creature * creature ) : CreatureAI ( creature ), m_creature ( creature ), IsFleeing ( false )
{
HeroicMode = m_creature -> GetMap () -> IsHeroic ();
}
2009-05-17 16:37:03 -05:00
void ScriptedAI :: AttackStartNoMove ( Unit * who )
2008-10-25 11:40:10 -05:00
{
if ( ! who )
return ;
2009-05-17 16:37:03 -05:00
if ( m_creature -> Attack ( who , false ))
DoStartNoMovement ( who );
2008-10-11 14:16:25 -05:00
}
void ScriptedAI :: UpdateAI ( const uint32 diff )
{
//Check if we have a current target
2009-02-20 14:14:16 +01:00
if ( UpdateVictim ())
2008-10-11 14:16:25 -05:00
{
2009-02-20 14:14:16 +01: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 ();
}
}
}
}
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 ();
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 )
{
2009-02-15 13:19:18 -06:00
if ( ! victim || m_creature -> hasUnitState ( UNIT_STAT_CASTING ) && ! triggered )
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 );
}
2009-02-15 13:19:18 -06:00
void ScriptedAI :: DoCastAOE ( uint32 spellId , bool triggered )
{
if ( ! triggered && m_creature -> hasUnitState ( UNIT_STAT_CASTING ))
return ;
m_creature -> CastSpell (( Unit * ) NULL , spellId , triggered );
}
2008-10-11 14:16:25 -05:00
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
{
2009-02-09 08:16:34 -05:00
if ( target )
{
2009-02-19 22:30:30 -06:00
m_creature -> MonsterSay ( text , language , target -> GetGUID ());
2009-02-09 08:16:34 -05:00
if ( SayEmote )
m_creature -> HandleEmoteCommand ( EMOTE_ONESHOT_TALK );
}
2009-02-19 22:30:30 -06:00
else m_creature -> MonsterSay ( text , language , 0 );
2008-10-11 14:16:25 -05:00
}
void ScriptedAI :: DoYell ( const char * text , uint32 language , Unit * target )
{
2009-02-19 22:30:30 -06:00
if ( target ) m_creature -> MonsterYell ( text , language , target -> GetGUID ());
else m_creature -> MonsterYell ( text , language , 0 );
2008-10-11 14:16:25 -05:00
}
void ScriptedAI :: DoTextEmote ( const char * text , Unit * target , bool IsBossEmote )
{
2009-02-19 22:30:30 -06:00
if ( target ) m_creature -> MonsterTextEmote ( text , target -> GetGUID (), IsBossEmote );
else m_creature -> MonsterTextEmote ( text , 0 , IsBossEmote );
2008-10-11 14:16:25 -05:00
}
void ScriptedAI :: DoWhisper ( const char * text , Unit * reciever , bool IsBossWhisper )
{
if ( ! reciever || reciever -> GetTypeId () != TYPEID_PLAYER )
return ;
2009-02-19 22:30:30 -06:00
m_creature -> MonsterWhisper ( text , reciever -> GetGUID (), IsBossWhisper );
2008-10-11 14:16:25 -05:00
}
2009-04-09 23:07:32 +02:00
void ScriptedAI :: DoPlaySoundToSet ( Unit * pSource , uint32 uiSoundId )
2008-10-11 14:16:25 -05:00
{
2009-04-09 23:07:32 +02:00
if ( ! pSource )
2008-10-11 14:16:25 -05:00
return ;
2009-04-09 23:07:32 +02:00
if ( ! GetSoundEntriesStore () -> LookupEntry ( uiSoundId ))
2008-10-11 14:16:25 -05:00
{
2009-04-24 00:51:09 -04:00
error_log ( "TSCR: Invalid soundId %u used in DoPlaySoundToSet (by unit TypeId %u, guid %u)" , uiSoundId , pSource -> GetTypeId (), pSource -> GetGUID ());
2008-10-11 14:16:25 -05:00
return ;
}
2009-04-09 23:07:32 +02:00
pSource -> PlayDirectSound ( uiSoundId );
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 );
}
2009-05-13 10:54:11 -05:00
Creature * ScriptedAI :: DoSummon ( uint32 entry , const float pos [ 4 ], uint32 despawntime , TempSummonType type )
{
return me -> SummonCreature ( entry , pos [ 0 ], pos [ 1 ], pos [ 2 ], pos [ 3 ], type , despawntime );
}
Creature * ScriptedAI :: DoSummon ( uint32 entry , WorldObject * obj , float radius , uint32 despawntime , TempSummonType type )
{
float x , y , z ;
obj -> GetGroundPointAroundUnit ( x , y , z , radius * rand_norm (), rand_norm () * 2 * M_PI );
return me -> SummonCreature ( entry , x , y , z , me -> GetOrientation (), type , despawntime );
}
2008-10-11 14:16:25 -05:00
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 ;
}
2009-05-10 14:29:28 -05:00
SpellEntry const * ScriptedAI :: SelectSpell ( Unit * Target , int32 School , int32 Mechanic , SelectTargetType Targets , uint32 PowerCostMin , uint32 PowerCostMax , float RangeMin , float RangeMax , SelectEffect Effects )
2008-10-11 14:16:25 -05:00
{
//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
2009-02-11 21:40:07 +01:00
SpellEntry const * Spell [ CREATURE_MAX_SPELLS ];
for ( uint8 i = 0 ; i < CREATURE_MAX_SPELLS ; i ++ )
Spell [ i ] = 0 ;
2008-10-11 14:16:25 -05:00
uint32 SpellCount = 0 ;
SpellEntry const * TempSpell ;
SpellRangeEntry const * TempRange ;
//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
{
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
2009-02-14 15:56:04 +01:00
if ( RangeMin && m_creature -> GetSpellMinRangeForTarget ( Target , TempRange ) < RangeMin )
2008-10-11 14:16:25 -05:00
continue ;
2009-02-14 15:56:04 +01:00
if ( RangeMax && m_creature -> GetSpellMaxRangeForTarget ( Target , TempRange ) > RangeMax )
2008-10-11 14:16:25 -05:00
continue ;
//Check if our target is in range
2009-02-14 15:56:04 +01:00
if ( m_creature -> IsWithinDistInMap ( Target , m_creature -> GetSpellMinRangeForTarget ( Target , TempRange )) || ! m_creature -> IsWithinDistInMap ( Target , m_creature -> GetSpellMaxRangeForTarget ( Target , TempRange )))
2008-10-11 14:16:25 -05:00
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
2009-04-07 19:38:09 -05:00
if ( ! Triggered && me -> HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SILENCED ))
2008-10-11 14:16:25 -05:00
return false ;
//Check for power
2009-04-07 19:38:09 -05:00
if ( ! Triggered && me -> GetPower (( Powers ) Spell -> powerType ) < Spell -> manaCost )
2008-10-11 14:16:25 -05:00
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
2009-04-07 19:38:09 -05:00
if ( me -> GetDistance ( Target ) > me -> GetSpellMaxRangeForTarget ( Target , TempRange )
|| me -> GetDistance ( Target ) < me -> GetSpellMinRangeForTarget ( Target , TempRange ))
2008-10-11 14:16:25 -05:00
return false ;
return true ;
}
2009-02-14 15:56:04 +01:00
float GetSpellMaxRangeForHostile ( uint32 id )
2009-01-17 17:46:28 -06:00
{
SpellEntry const * spellInfo = GetSpellStore () -> LookupEntry ( id );
if ( ! spellInfo ) return 0 ;
SpellRangeEntry const * range = GetSpellRangeStore () -> LookupEntry ( spellInfo -> rangeIndex );
if ( ! range ) return 0 ;
2009-02-14 15:56:04 +01:00
return range -> maxRangeHostile ;
2009-01-17 17:46:28 -06:00
}
2008-10-11 14:16:25 -05:00
void FillSpellSummary ()
{
SpellSummary = new TSpellSummary [ GetSpellStore () -> GetNumRows ()];
SpellEntry const * TempSpell ;
2009-05-10 14:29:28 -05:00
for ( uint32 i = 0 ; i < GetSpellStore () -> GetNumRows (); ++ i )
2008-10-11 14:16:25 -05:00
{
SpellSummary [ i ]. Effects = 0 ;
SpellSummary [ i ]. Targets = 0 ;
TempSpell = GetSpellStore () -> LookupEntry ( i );
//This spell doesn't exist
if ( ! TempSpell )
continue ;
2009-05-10 14:29:28 -05:00
for ( uint32 j = 0 ; j < 3 ; ++ j )
2008-10-11 14:16:25 -05:00
{
//Spell targets self
2009-05-02 11:28:11 -05:00
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_CASTER )
2008-10-11 14:16:25 -05:00
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_SELF - 1 );
//Spell targets a single enemy
2009-05-02 11:28:11 -05:00
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_TARGET_ENEMY ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_DST_TARGET_ENEMY )
2008-10-11 14:16:25 -05:00
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_SINGLE_ENEMY - 1 );
//Spell targets AoE at enemy
2009-05-02 11:28:11 -05:00
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_AREA_ENEMY_SRC ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_AREA_ENEMY_DST ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SRC_CASTER ||
2009-04-30 23:38:21 -05:00
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_DEST_DYNOBJ_ENEMY )
2008-10-11 14:16:25 -05:00
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_AOE_ENEMY - 1 );
//Spell targets an enemy
2009-05-02 11:28:11 -05:00
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_TARGET_ENEMY ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_DST_TARGET_ENEMY ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_AREA_ENEMY_SRC ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_AREA_ENEMY_DST ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SRC_CASTER ||
2009-04-30 23:38:21 -05:00
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_DEST_DYNOBJ_ENEMY )
2008-10-11 14:16:25 -05:00
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_ANY_ENEMY - 1 );
//Spell targets a single friend(or self)
2009-05-02 11:28:11 -05:00
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_CASTER ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_TARGET_ALLY ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_TARGET_PARTY )
2008-10-11 14:16:25 -05:00
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_SINGLE_FRIEND - 1 );
//Spell targets aoe friends
2009-05-02 11:28:11 -05:00
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_PARTY_CASTER ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_PARTY_TARGET ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SRC_CASTER )
2008-10-11 14:16:25 -05:00
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_AOE_FRIEND - 1 );
//Spell targets any friend(or self)
2009-05-02 11:28:11 -05:00
if ( TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_CASTER ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_TARGET_ALLY ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_TARGET_PARTY ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_PARTY_CASTER ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_UNIT_PARTY_TARGET ||
TempSpell -> EffectImplicitTargetA [ j ] == TARGET_SRC_CASTER )
2008-10-11 14:16:25 -05:00
SpellSummary [ i ]. Targets |= 1 << ( SELECT_TARGET_ANY_FRIEND - 1 );
//Make sure that this spell includes a damage effect
2009-02-04 10:33:18 -06:00
if ( TempSpell -> Effect [ j ] == SPELL_EFFECT_SCHOOL_DAMAGE ||
TempSpell -> Effect [ j ] == SPELL_EFFECT_INSTAKILL ||
TempSpell -> Effect [ j ] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE ||
2008-10-11 14:16:25 -05:00
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)
2009-02-04 10:33:18 -06:00
if ( TempSpell -> Effect [ j ] == SPELL_EFFECT_HEAL ||
TempSpell -> Effect [ j ] == SPELL_EFFECT_HEAL_MAX_HEALTH ||
2008-10-11 14:16:25 -05:00
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 :: DoResetThreat ()
{
if ( ! m_creature -> CanHaveThreatList () || m_creature -> getThreatManager (). isThreatListEmpty ())
{
2009-04-24 00:51:09 -04:00
error_log ( "TSCR: DoResetThreat called for creature that either cannot have threat list or has empty threat list (m_creature entry = %d)" , m_creature -> GetEntry ());
2008-10-11 14:16:25 -05:00
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 ());
2009-01-09 12:06:08 -06:00
if ( pUnit && DoGetThreat ( pUnit ))
DoModifyThreatPercent ( pUnit , - 100 );
2008-10-11 14:16:25 -05:00
}
}
2009-01-09 12:06:08 -06:00
float ScriptedAI :: DoGetThreat ( Unit * pUnit )
{
if ( ! pUnit ) return 0.0f ;
return m_creature -> getThreatManager (). getThreat ( pUnit );
}
void ScriptedAI :: DoModifyThreatPercent ( Unit * pUnit , int32 pct )
{
if ( ! pUnit ) return ;
m_creature -> getThreatManager (). modifyThreatPercent ( pUnit , pct );
}
2009-02-23 13:14:04 -06:00
void ScriptedAI :: DoTeleportTo ( float x , float y , float z , uint32 time )
{
m_creature -> Relocate ( x , y , z );
m_creature -> SendMonsterMove ( x , y , z , time );
}
2009-05-13 10:54:11 -05:00
void ScriptedAI :: DoTeleportTo ( const float pos [ 4 ])
{
me -> NearTeleportTo ( pos [ 0 ], pos [ 1 ], pos [ 2 ], pos [ 3 ]);
}
2008-10-11 14:16:25 -05:00
void ScriptedAI :: DoTeleportPlayer ( Unit * pUnit , float x , float y , float z , float o )
{
if ( ! pUnit || pUnit -> GetTypeId () != TYPEID_PLAYER )
{
if ( pUnit )
2009-04-24 00:51:09 -04:00
error_log ( "TSCR: 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 );
2008-10-11 14:16:25 -05:00
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 ())
2009-01-03 12:42:23 +01:00
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 );
}
2009-01-25 09:57:40 +01:00
Unit * FindCreature ( uint32 entry , float range , Unit * Finder )
2009-02-04 10:33:18 -06:00
{
2009-01-25 09:57:40 +01:00
if ( ! Finder )
return NULL ;
2009-01-01 23:42:11 -06:00
Creature * target = NULL ;
2009-02-09 08:16:34 -05:00
Trinity :: AllCreaturesOfEntryInRange check ( Finder , entry , range );
2009-01-31 16:38:50 -06:00
Trinity :: CreatureSearcher < Trinity :: AllCreaturesOfEntryInRange > searcher ( Finder , target , check );
2009-01-25 09:57:40 +01:00
Finder -> VisitNearbyObject ( range , searcher );
2009-01-01 23:42:11 -06:00
return target ;
2008-12-26 13:30:46 +01:00
}
2009-01-25 09:57:40 +01:00
GameObject * FindGameObject ( uint32 entry , float range , Unit * Finder )
2008-12-26 13:30:46 +01:00
{
2009-01-25 09:57:40 +01:00
if ( ! Finder )
return NULL ;
2009-01-01 23:42:11 -06:00
GameObject * target = NULL ;
2009-02-09 08:16:34 -05:00
Trinity :: AllGameObjectsWithEntryInGrid go_check ( entry );
2009-01-31 16:38:50 -06:00
Trinity :: GameObjectSearcher < Trinity :: AllGameObjectsWithEntryInGrid > searcher ( Finder , target , go_check );
2009-01-25 09:57:40 +01:00
Finder -> VisitNearbyGridObject ( range , searcher );
2009-01-01 23:42:11 -06:00
return target ;
2008-12-26 13:30:46 +01:00
}
2008-11-18 19:40:06 -06:00
2008-10-11 14:16:25 -05:00
Unit * ScriptedAI :: DoSelectLowestHpFriendly ( float range , uint32 MinHPDiff )
{
Unit * pUnit = NULL ;
2008-10-14 11:57:03 -05:00
Trinity :: MostHPMissingInRange u_check ( m_creature , range , MinHPDiff );
2009-01-31 16:38:50 -06:00
Trinity :: UnitLastSearcher < Trinity :: MostHPMissingInRange > searcher ( m_creature , pUnit , u_check );
2009-01-05 15:25:35 -06:00
m_creature -> VisitNearbyObject ( range , searcher );
2008-10-11 14:16:25 -05:00
return pUnit ;
}
std :: list < Creature *> ScriptedAI :: DoFindFriendlyCC ( float range )
{
std :: list < Creature *> pList ;
2008-10-14 11:57:03 -05:00
Trinity :: FriendlyCCedInRange u_check ( m_creature , range );
2009-01-31 16:38:50 -06:00
Trinity :: CreatureListSearcher < Trinity :: FriendlyCCedInRange > searcher ( m_creature , pList , u_check );
2009-01-05 15:25:35 -06:00
m_creature -> VisitNearbyObject ( range , searcher );
2008-10-11 14:16:25 -05:00
return pList ;
}
std :: list < Creature *> ScriptedAI :: DoFindFriendlyMissingBuff ( float range , uint32 spellid )
{
std :: list < Creature *> pList ;
2008-10-14 11:57:03 -05:00
Trinity :: FriendlyMissingBuffInRange u_check ( m_creature , range , spellid );
2009-01-31 16:38:50 -06:00
Trinity :: CreatureListSearcher < Trinity :: FriendlyMissingBuffInRange > searcher ( m_creature , pList , u_check );
2009-01-05 15:25:35 -06:00
m_creature -> VisitNearbyObject ( range , searcher );
2008-10-11 14:16:25 -05:00
return pList ;
}
2009-04-19 21:16:11 +02:00
void ScriptedAI :: SetEquipmentSlots ( bool bLoadDefault , int32 uiMainHand , int32 uiOffHand , int32 uiRanged )
{
if ( bLoadDefault )
{
if ( CreatureInfo const * pInfo = GetCreatureTemplateStore ( m_creature -> GetEntry ()))
m_creature -> LoadEquipment ( pInfo -> equipmentId , true );
return ;
}
if ( uiMainHand >= 0 )
m_creature -> SetUInt32Value ( UNIT_VIRTUAL_ITEM_SLOT_ID + 0 , uint32 ( uiMainHand ));
if ( uiOffHand >= 0 )
m_creature -> SetUInt32Value ( UNIT_VIRTUAL_ITEM_SLOT_ID + 1 , uint32 ( uiOffHand ));
if ( uiRanged >= 0 )
m_creature -> SetUInt32Value ( UNIT_VIRTUAL_ITEM_SLOT_ID + 2 , uint32 ( uiRanged ));
}
void ScriptedAI :: SetSheathState ( SheathState newState )
{
m_creature -> SetByteValue ( UNIT_FIELD_BYTES_2 , 0 , newState );
}
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
DoStartNoMovement ( who );
2008-10-11 14:16:25 -05:00
}
}
2009-02-05 15:38:24 -06:00
2009-05-17 16:37:03 -05:00
BossAI :: BossAI ( Creature * c , uint32 id ) : ScriptedAI ( c )
, bossId ( id ), summons ( me ), instance ( c -> GetInstanceData ())
, boundary ( instance ? instance -> GetBossBoundary ( id ) : NULL )
{
}
2009-05-10 22:48:22 -05:00
void BossAI :: _Reset ()
{
events . Reset ();
summons . DespawnAll ();
2009-05-16 22:45:13 -05:00
if ( instance )
instance -> SetBossState ( bossId , NOT_STARTED );
2009-05-10 22:48:22 -05:00
}
void BossAI :: _JustDied ()
{
events . Reset ();
summons . DespawnAll ();
2009-05-16 22:45:13 -05:00
if ( instance )
instance -> SetBossState ( bossId , DONE );
2009-05-10 22:48:22 -05:00
}
void BossAI :: _EnterCombat ()
{
DoZoneInCombat ();
2009-05-16 22:45:13 -05:00
if ( instance )
instance -> SetBossState ( bossId , IN_PROGRESS );
2009-05-10 22:48:22 -05:00
}
2009-05-17 16:37:03 -05:00
bool BossAI :: CheckBoundary ( Unit * who )
{
if ( ! boundary || ! who )
return true ;
for ( BossBoundaryMap :: const_iterator itr = boundary -> begin (); itr != boundary -> end (); ++ itr )
{
switch ( itr -> first )
{
case BOUNDARY_N :
if ( me -> GetPositionX () > itr -> second )
return false ;
break ;
case BOUNDARY_S :
if ( me -> GetPositionX () < itr -> second )
return false ;
break ;
case BOUNDARY_E :
if ( me -> GetPositionY () < itr -> second )
return false ;
break ;
case BOUNDARY_W :
if ( me -> GetPositionY () > itr -> second )
return false ;
break ;
case BOUNDARY_NW :
if ( me -> GetPositionX () + me -> GetPositionY () > itr -> second )
return false ;
break ;
case BOUNDARY_SE :
if ( me -> GetPositionX () + me -> GetPositionY () < itr -> second )
return false ;
break ;
case BOUNDARY_NE :
if ( me -> GetPositionX () - me -> GetPositionY () > itr -> second )
return false ;
break ;
case BOUNDARY_SW :
if ( me -> GetPositionX () - me -> GetPositionY () < itr -> second )
return false ;
break ;
}
}
return true ;
}
2009-05-10 22:48:22 -05:00
void BossAI :: JustSummoned ( Creature * summon )
{
summons . Summon ( summon );
2009-05-13 10:54:11 -05:00
if ( me -> isInCombat ())
DoZoneInCombat ( summon );
2009-05-10 22:48:22 -05:00
}
void BossAI :: SummonedCreatureDespawn ( Creature * summon )
{
summons . Despawn ( summon );
}
2009-05-10 01:22:51 -05:00
#define GOBJECT(x) (const_cast<GameObjectInfo*>(GetGameObjectInfo(x)))
2009-02-05 15:38:24 -06:00
void LoadOverridenSQLData ()
{
GameObjectInfo * goInfo ;
// Sunwell Plateau : Kalecgos : Spectral Rift
2009-05-10 01:22:51 -05:00
if ( goInfo = GOBJECT ( 187055 ))
if ( goInfo -> type == GAMEOBJECT_TYPE_GOOBER )
goInfo -> goober . lockId = 57 ; // need LOCKTYPE_QUICK_OPEN
// Naxxramas : Sapphiron Birth
if ( goInfo = GOBJECT ( 181356 ))
if ( goInfo -> type == GAMEOBJECT_TYPE_TRAP )
goInfo -> trap . radius = 50 ;
2009-02-05 15:38:24 -06:00
}
void LoadOverridenDBCData ()
{
SpellEntry * spellInfo ;
2009-05-13 10:54:11 -05:00
for ( uint32 i = 0 ; i < GetSpellStore () -> GetNumRows (); ++ i )
2009-05-09 10:50:41 -05:00
{
2009-05-13 10:54:11 -05:00
spellInfo = ( SpellEntry * ) GetSpellStore () -> LookupEntry ( i );
if ( ! spellInfo )
continue ;
switch ( i )
{
// Black Temple : Illidan : Parasitic Shadowfiend Passive
case 41013 :
spellInfo -> EffectApplyAuraName [ 0 ] = 4 ; // proc debuff, and summon infinite fiends
break ;
//temp, not needed in 310
case 28531 :
case 55799 :
spellInfo -> DurationIndex = 21 ;
spellInfo -> Effect [ 0 ] = SPELL_EFFECT_APPLY_AREA_AURA_ENEMY ;
break ;
// Naxxramas: Gothik : Inform Inf range
case 27892 :
case 27928 :
case 27935 :
case 27915 :
case 27931 :
case 27937 :
spellInfo -> rangeIndex = 13 ;
break ;
}
2009-05-09 10:50:41 -05:00
}
}