2009-04-07 19:38:09 -05:00
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2009-04-07 19:38:09 -05: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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
#include "Common.h"
#include "CreatureEventAI.h"
#include "CreatureEventAIMgr.h"
#include "ObjectMgr.h"
#include "Spell.h"
#include "World.h"
#include "Cell.h"
#include "CellImpl.h"
#include "GameEventMgr.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "InstanceData.h"
2009-07-23 18:32:32 +02:00
#include "SpellMgr.h"
2009-08-28 16:38:43 -05:00
#include "CreatureAIImpl.h"
2009-10-17 15:51:44 -07:00
2009-11-11 15:11:51 -08:00
bool CreatureEventAIHolder :: UpdateRepeatTimer ( Creature * creature , uint32 repeatMin , uint32 repeatMax )
2009-05-19 15:38:36 -05:00
{
if ( repeatMin == repeatMax )
Time = repeatMin ;
else if ( repeatMax > repeatMin )
Time = urand ( repeatMin , repeatMax );
else
{
sLog . outErrorDb ( "CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled." , creature -> GetEntry (), Event . event_id , Event . event_type );
Enabled = false ;
return false ;
}
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
int CreatureEventAI :: Permissible ( const Creature * creature )
{
2009-11-11 15:11:51 -08:00
if ( creature -> GetAIName () == "EventAI" )
2009-04-07 19:38:09 -05:00
return PERMIT_BASE_SPECIAL ;
return PERMIT_BASE_NO ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
CreatureEventAI :: CreatureEventAI ( Creature * c ) : CreatureAI ( c )
2009-04-07 19:38:09 -05:00
{
2009-05-18 15:09:34 -05:00
// Need make copy for filter unneeded steps and safe in case table reload
2009-04-27 18:43:39 -05:00
CreatureEventAI_Event_Map :: const_iterator CreatureEvents = CreatureEAI_Mgr . GetCreatureEventAIMap (). find ( m_creature -> GetEntry ());
2009-04-07 19:38:09 -05:00
if ( CreatureEvents != CreatureEAI_Mgr . GetCreatureEventAIMap (). end ())
{
2009-04-27 18:43:39 -05:00
std :: vector < CreatureEventAI_Event >:: const_iterator i ;
2009-04-07 19:38:09 -05:00
for ( i = ( * CreatureEvents ). second . begin (); i != ( * CreatureEvents ). second . end (); ++ i )
{
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Debug check
2009-05-04 13:13:07 -05:00
#ifndef TRINITY_DEBUG
2009-04-07 19:38:09 -05:00
if (( * i ). event_flags & EFLAG_DEBUG_ONLY )
continue ;
#endif
2010-04-07 19:14:10 +02:00
if ( m_creature -> GetMap () -> IsDungeon ())
2009-04-07 19:38:09 -05:00
{
2009-12-17 11:06:50 +01:00
if (( 1 << ( m_creature -> GetMap () -> GetSpawnMode () + 1 )) & ( * i ). event_flags )
2009-04-07 19:38:09 -05:00
{
//event flagged for instance mode
CreatureEventAIList . push_back ( CreatureEventAIHolder ( * i ));
}
continue ;
}
CreatureEventAIList . push_back ( CreatureEventAIHolder ( * i ));
}
//EventMap had events but they were not added because they must be for instance
if ( CreatureEventAIList . empty ())
2009-04-29 00:31:03 -05:00
sLog . outError ( "CreatureEventAI: Creature %u has events but no events added to list because of instance flags." , m_creature -> GetEntry ());
2009-04-07 19:38:09 -05:00
}
else
2009-04-14 19:54:49 -05:00
sLog . outError ( "CreatureEventAI: EventMap for Creature %u is empty but creature is using CreatureEventAI." , m_creature -> GetEntry ());
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
bEmptyList = CreatureEventAIList . empty ();
Phase = 0 ;
CombatMovementEnabled = true ;
MeleeEnabled = true ;
2009-06-19 17:34:24 -05:00
AttackDistance = 0.0f ;
2009-04-07 19:38:09 -05:00
AttackAngle = 0.0f ;
2009-10-17 15:51:44 -07:00
2009-07-30 10:53:16 +08:00
InvinceabilityHpLevel = 0 ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Handle Spawned Events
if ( ! bEmptyList )
{
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
2009-05-21 10:52:05 -05:00
if ( SpawnedEventConditionsCheck (( * i ). Event ))
2009-04-07 19:38:09 -05:00
ProcessEvent ( * i );
}
}
2009-10-17 15:51:44 -07:00
2009-11-11 15:11:51 -08:00
bool CreatureEventAI :: ProcessEvent ( CreatureEventAIHolder & pHolder , Unit * pActionInvoker /*=NULL*/ )
2009-04-07 19:38:09 -05:00
{
if ( ! pHolder . Enabled || pHolder . Time )
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Check the inverse phase mask (event doesn't trigger if current phase bit is set in mask)
if ( pHolder . Event . event_inverse_phase_mask & ( 1 << Phase ))
return false ;
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
CreatureEventAI_Event const & event = pHolder . Event ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Check event conditions based on the event type, also reset events
2009-05-19 15:38:36 -05:00
switch ( event . event_type )
2009-04-07 19:38:09 -05:00
{
case EVENT_T_TIMER :
2009-04-24 11:57:36 -05:00
if ( ! m_creature -> isInCombat ())
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . timer . repeatMin , event . timer . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_TIMER_OOC :
2009-04-24 11:57:36 -05:00
if ( m_creature -> isInCombat ())
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . timer . repeatMin , event . timer . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_HP :
{
2009-04-24 11:57:36 -05:00
if ( ! m_creature -> isInCombat () || ! m_creature -> GetMaxHealth ())
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-14 19:54:49 -05:00
uint32 perc = ( m_creature -> GetHealth () * 100 ) / m_creature -> GetMaxHealth ();
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
if ( perc > event . percent_range . percentMax || perc < event . percent_range . percentMin )
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . percent_range . repeatMin , event . percent_range . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_MANA :
{
2009-04-24 11:57:36 -05:00
if ( ! m_creature -> isInCombat () || ! m_creature -> GetMaxPower ( POWER_MANA ))
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-14 19:54:49 -05:00
uint32 perc = ( m_creature -> GetPower ( POWER_MANA ) * 100 ) / m_creature -> GetMaxPower ( POWER_MANA );
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
if ( perc > event . percent_range . percentMax || perc < event . percent_range . percentMin )
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . percent_range . repeatMin , event . percent_range . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_AGGRO :
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_KILL :
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . kill . repeatMin , event . kill . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_DEATH :
case EVENT_T_EVADE :
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_SPELLHIT :
//Spell hit is special case, param1 and param2 handled within CreatureEventAI::SpellHit
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . spell_hit . repeatMin , event . spell_hit . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_RANGE :
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . range . repeatMin , event . range . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_OOC_LOS :
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . ooc_los . repeatMin , event . ooc_los . repeatMax );
break ;
2010-01-08 14:40:55 -03:00
case EVENT_T_RESET :
2009-04-07 19:38:09 -05:00
case EVENT_T_SPAWNED :
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_TARGET_HP :
{
2009-04-24 11:57:36 -05:00
if ( ! m_creature -> isInCombat () || ! m_creature -> getVictim () || ! m_creature -> getVictim () -> GetMaxHealth ())
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-14 19:54:49 -05:00
uint32 perc = ( m_creature -> getVictim () -> GetHealth () * 100 ) / m_creature -> getVictim () -> GetMaxHealth ();
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
if ( perc > event . percent_range . percentMax || perc < event . percent_range . percentMin )
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . percent_range . repeatMin , event . percent_range . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_TARGET_CASTING :
2009-04-24 11:57:36 -05:00
if ( ! m_creature -> isInCombat () || ! m_creature -> getVictim () || ! m_creature -> getVictim () -> IsNonMeleeSpellCasted ( false , false , true ))
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . target_casting . repeatMin , event . target_casting . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_FRIENDLY_HP :
{
2009-04-24 11:57:36 -05:00
if ( ! m_creature -> isInCombat ())
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
Unit * pUnit = DoSelectLowestHpFriendly ( event . friendly_hp . radius , event . friendly_hp . hpDeficit );
2009-04-07 19:38:09 -05:00
if ( ! pUnit )
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
pActionInvoker = pUnit ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . friendly_hp . repeatMin , event . friendly_hp . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_FRIENDLY_IS_CC :
{
2009-04-24 11:57:36 -05:00
if ( ! m_creature -> isInCombat ())
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
std :: list < Creature *> pList ;
2009-05-19 15:38:36 -05:00
DoFindFriendlyCC ( pList , event . friendly_is_cc . radius );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//List is empty
if ( pList . empty ())
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//We don't really care about the whole list, just return first available
pActionInvoker = * ( pList . begin ());
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . friendly_is_cc . repeatMin , event . friendly_is_cc . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_FRIENDLY_MISSING_BUFF :
{
std :: list < Creature *> pList ;
2009-05-19 15:38:36 -05:00
DoFindFriendlyMissingBuff ( pList , event . friendly_buff . radius , event . friendly_buff . spellId );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//List is empty
if ( pList . empty ())
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//We don't really care about the whole list, just return first available
pActionInvoker = * ( pList . begin ());
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . friendly_buff . repeatMin , event . friendly_buff . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_SUMMONED_UNIT :
{
//Prevent event from occuring on no unit or non creatures
2010-04-08 08:20:08 +02:00
if ( ! pActionInvoker || pActionInvoker -> GetTypeId () != TYPEID_UNIT )
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Creature id doesn't match up
2010-03-07 18:30:53 +01:00
if ( pActionInvoker -> ToCreature () -> GetEntry () != event . summon_unit . creatureId )
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2009-05-19 15:38:36 -05:00
pHolder . UpdateRepeatTimer ( m_creature , event . summon_unit . repeatMin , event . summon_unit . repeatMax );
2009-06-15 23:10:06 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
2009-05-19 15:38:36 -05:00
case EVENT_T_TARGET_MANA :
2009-04-07 19:38:09 -05:00
{
2009-05-19 15:38:36 -05:00
if ( ! m_creature -> isInCombat () || ! m_creature -> getVictim () || ! m_creature -> getVictim () -> GetMaxPower ( POWER_MANA ))
return false ;
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
uint32 perc = ( m_creature -> getVictim () -> GetPower ( POWER_MANA ) * 100 ) / m_creature -> getVictim () -> GetMaxPower ( POWER_MANA );
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
if ( perc > event . percent_range . percentMax || perc < event . percent_range . percentMin )
return false ;
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
//Repeat Timers
pHolder . UpdateRepeatTimer ( m_creature , event . percent_range . repeatMin , event . percent_range . repeatMax );
break ;
2009-04-07 19:38:09 -05:00
}
2009-05-19 15:38:36 -05:00
case EVENT_T_REACHED_HOME :
2009-04-07 19:38:09 -05:00
case EVENT_T_RECEIVE_EMOTE :
2009-05-19 15:38:36 -05:00
break ;
2009-06-15 23:10:06 -05:00
case EVENT_T_BUFFED :
{
//Note: checked only aura for effect 0, if need check aura for effect 1/2 then
// possible way: pack in event.buffed.amount 2 uint16 (ammount+effectIdx)
2010-01-10 01:23:15 +01:00
Aura const * aura = m_creature -> GetAura ( event . buffed . spellId );
2010-04-07 19:14:10 +02:00
if ( ! aura || aura -> GetStackAmount () < event . buffed . amount )
2009-06-15 23:10:06 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-06-15 23:10:06 -05:00
//Repeat Timers
pHolder . UpdateRepeatTimer ( m_creature , event . buffed . repeatMin , event . buffed . repeatMax );
break ;
}
case EVENT_T_TARGET_BUFFED :
{
//Prevent event from occuring on no unit
if ( ! pActionInvoker )
return false ;
2009-10-17 15:51:44 -07:00
2009-06-15 23:10:06 -05:00
//Note: checked only aura for effect 0, if need check aura for effect 1/2 then
// possible way: pack in event.buffed.amount 2 uint16 (ammount+effectIdx)
2010-01-10 02:12:02 +01:00
Aura const * aura = pActionInvoker -> GetAura ( event . buffed . spellId );
2010-04-07 19:14:10 +02:00
if ( ! aura || aura -> GetStackAmount () < event . buffed . amount )
2009-06-15 23:10:06 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-06-15 23:10:06 -05:00
//Repeat Timers
pHolder . UpdateRepeatTimer ( m_creature , event . buffed . repeatMin , event . buffed . repeatMax );
break ;
}
2009-04-07 19:38:09 -05:00
default :
2009-04-14 19:54:49 -05:00
sLog . outErrorDb ( "CreatureEventAI: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch." , m_creature -> GetEntry (), pHolder . Event . event_id , pHolder . Event . event_type );
2009-04-07 19:38:09 -05:00
break ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Disable non-repeatable events
if ( ! ( pHolder . Event . event_flags & EFLAG_REPEATABLE ))
pHolder . Enabled = false ;
2009-10-17 15:51:44 -07:00
2009-07-12 17:43:22 +08:00
//Store random here so that all random actions match up
uint32 rnd = rand ();
2009-10-17 15:51:44 -07:00
2009-07-12 17:43:22 +08:00
//Return if chance for event is not met
if ( pHolder . Event . event_chance <= rnd % 100 )
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Process actions
2009-11-11 15:11:51 -08:00
for ( uint8 j = 0 ; j < MAX_ACTIONS ; ++ j )
2009-05-18 15:14:27 -05:00
ProcessAction ( pHolder . Event . action [ j ], rnd , pHolder . Event . event_id , pActionInvoker );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
void CreatureEventAI :: ProcessAction ( CreatureEventAI_Action const & action , uint32 rnd , uint32 EventId , Unit * pActionInvoker )
2009-04-07 19:38:09 -05:00
{
2009-05-18 15:14:27 -05:00
switch ( action . type )
2009-04-07 19:38:09 -05:00
{
case ACTION_T_TEXT :
{
2009-05-18 15:14:27 -05:00
if ( ! action . text . TextId1 )
2009-04-07 19:38:09 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
int32 temp = 0 ;
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
if ( action . text . TextId2 && action . text . TextId3 )
2009-09-26 02:09:26 -07:00
temp = RAND ( action . text . TextId1 , action . text . TextId2 , action . text . TextId3 );
2009-05-18 15:14:27 -05:00
else if ( action . text . TextId2 && urand ( 0 , 1 ))
temp = action . text . TextId2 ;
else
temp = action . text . TextId1 ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( temp )
{
Unit * target = NULL ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( pActionInvoker )
{
if ( pActionInvoker -> GetTypeId () == TYPEID_PLAYER )
target = pActionInvoker ;
2009-04-29 00:31:03 -05:00
else if ( Unit * owner = pActionInvoker -> GetOwner ())
2009-04-07 19:38:09 -05:00
{
if ( owner -> GetTypeId () == TYPEID_PLAYER )
target = owner ;
}
}
2009-09-18 14:10:37 -07:00
else if (( target = m_creature -> getVictim ()))
2009-04-07 19:38:09 -05:00
{
if ( target -> GetTypeId () != TYPEID_PLAYER )
2009-04-29 00:31:03 -05:00
if ( Unit * owner = target -> GetOwner ())
2009-04-07 19:38:09 -05:00
if ( owner -> GetTypeId () == TYPEID_PLAYER )
target = owner ;
}
2009-10-17 15:51:44 -07:00
2009-04-14 19:54:49 -05:00
DoScriptText ( temp , m_creature , target );
2009-04-07 19:38:09 -05:00
}
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_SET_FACTION :
{
2009-05-18 15:14:27 -05:00
if ( action . set_faction . factionId )
m_creature -> setFaction ( action . set_faction . factionId );
2009-04-07 19:38:09 -05:00
else
{
2009-04-14 19:54:49 -05:00
if ( CreatureInfo const * ci = GetCreatureTemplateStore ( m_creature -> GetEntry ()))
2009-04-07 19:38:09 -05:00
{
//if no id provided, assume reset and then use default
2009-04-14 19:54:49 -05:00
if ( m_creature -> getFaction () != ci -> faction_A )
m_creature -> setFaction ( ci -> faction_A );
2009-04-07 19:38:09 -05:00
}
}
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_MORPH_TO_ENTRY_OR_MODEL :
{
2009-05-31 15:58:16 -05:00
if ( action . morph . creatureId || action . morph . modelId )
2009-04-07 19:38:09 -05:00
{
//set model based on entry from creature_template
2009-05-31 15:58:16 -05:00
if ( action . morph . creatureId )
2009-04-07 19:38:09 -05:00
{
2009-05-31 15:58:16 -05:00
if ( CreatureInfo const * ci = GetCreatureTemplateStore ( action . morph . creatureId ))
2009-04-07 19:38:09 -05:00
{
2009-06-15 18:02:12 -05:00
uint32 display_id = objmgr . ChooseDisplayId ( 0 , ci );
m_creature -> SetDisplayId ( display_id );
2009-04-07 19:38:09 -05:00
}
}
//if no param1, then use value from param2 (modelId)
else
2009-05-18 15:14:27 -05:00
m_creature -> SetDisplayId ( action . morph . modelId );
2009-04-07 19:38:09 -05:00
}
else
2009-04-14 19:54:49 -05:00
m_creature -> DeMorph ();
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_SOUND :
2009-05-18 15:14:27 -05:00
m_creature -> PlayDirectSound ( action . sound . soundId );
2009-04-07 19:38:09 -05:00
break ;
case ACTION_T_EMOTE :
2009-05-18 15:14:27 -05:00
m_creature -> HandleEmoteCommand ( action . emote . emoteId );
2009-04-07 19:38:09 -05:00
break ;
case ACTION_T_RANDOM_SOUND :
{
2009-05-18 15:14:27 -05:00
int32 temp = GetRandActionParam ( rnd , action . random_sound . soundId1 , action . random_sound . soundId2 , action . random_sound . soundId3 );
if ( temp >= 0 )
m_creature -> PlayDirectSound ( temp );
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_RANDOM_EMOTE :
{
2009-05-18 15:14:27 -05:00
int32 temp = GetRandActionParam ( rnd , action . random_emote . emoteId1 , action . random_emote . emoteId2 , action . random_emote . emoteId3 );
if ( temp >= 0 )
2009-04-14 19:54:49 -05:00
m_creature -> HandleEmoteCommand ( temp );
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_CAST :
{
2009-05-18 15:14:27 -05:00
Unit * target = GetTargetByType ( action . cast . target , pActionInvoker );
2009-04-14 19:54:49 -05:00
Unit * caster = m_creature ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( ! target )
return ;
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
if ( action . cast . castFlags & CAST_FORCE_TARGET_SELF )
2009-04-07 19:38:09 -05:00
caster = target ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered
2009-05-18 15:14:27 -05:00
bool canCast = ! caster -> IsNonMeleeSpellCasted ( false ) || ( action . cast . castFlags & ( CAST_TRIGGERED | CAST_INTURRUPT_PREVIOUS ));
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
// If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them
2010-04-07 19:14:10 +02:00
if ( action . cast . castFlags & CAST_AURA_NOT_PRESENT )
2009-04-07 19:38:09 -05:00
{
2010-04-07 19:14:10 +02:00
if ( target -> HasAura ( action . cast . spellId ))
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( canCast )
{
2009-05-18 15:14:27 -05:00
const SpellEntry * tSpell = GetSpellStore () -> LookupEntry ( action . cast . spellId );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Verify that spell exists
if ( tSpell )
{
//Check if cannot cast spell
2009-05-18 15:14:27 -05:00
if ( ! ( action . cast . castFlags & ( CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST )) &&
! CanCast ( target , tSpell , ( action . cast . castFlags & CAST_TRIGGERED )))
2009-04-07 19:38:09 -05:00
{
//Melee current victim if flag not set
2009-05-18 15:14:27 -05:00
if ( ! ( action . cast . castFlags & CAST_NO_MELEE_IF_OOM ))
2009-04-07 19:38:09 -05:00
{
2009-04-14 19:54:49 -05:00
if ( m_creature -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == TARGETED_MOTION_TYPE )
2009-04-07 19:38:09 -05:00
{
2009-06-19 17:34:24 -05:00
AttackDistance = 0.0f ;
AttackAngle = 0.0f ;
2009-10-17 15:51:44 -07:00
2009-04-14 19:54:49 -05:00
m_creature -> GetMotionMaster () -> MoveChase ( m_creature -> getVictim (), AttackDistance , AttackAngle );
2009-04-07 19:38:09 -05:00
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
}
else
{
//Interrupt any previous spell
2009-05-18 15:14:27 -05:00
if ( caster -> IsNonMeleeSpellCasted ( false ) && action . cast . castFlags & CAST_INTURRUPT_PREVIOUS )
2009-04-07 19:38:09 -05:00
caster -> InterruptNonMeleeSpells ( false );
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
caster -> CastSpell ( target , action . cast . spellId , ( action . cast . castFlags & CAST_TRIGGERED ));
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
}
else
sLog . outErrorDb ( "CreatureEventAI: event %d creature %d attempt to cast spell that doesn't exist %d" , EventId , m_creature -> GetEntry (), action . cast . spellId );
2009-04-07 19:38:09 -05:00
}
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_SUMMON :
{
2009-05-18 15:14:27 -05:00
Unit * target = GetTargetByType ( action . summon . target , pActionInvoker );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
Creature * pCreature = NULL ;
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
if ( action . summon . duration )
2009-08-29 14:58:45 -05:00
pCreature = m_creature -> SummonCreature ( action . summon . creatureId , 0.0f , 0.0f , 0.0f , 0.0f , TEMPSUMMON_TIMED_OR_DEAD_DESPAWN , action . summon . duration );
2009-04-07 19:38:09 -05:00
else
2009-08-29 14:58:45 -05:00
pCreature = m_creature -> SummonCreature ( action . summon . creatureId , 0.0f , 0.0f , 0.0f , 0.0f , TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT , 0 );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( ! pCreature )
2010-04-07 22:59:46 +02:00
sLog . outErrorDb ( "CreatureEventAI: failed to spawn creature %u. Spawn event %d is on creature %d" , action . summon . creatureId , EventId , m_creature -> GetEntry ());
2009-05-18 15:14:27 -05:00
else if ( action . summon . target != TARGET_T_SELF && target )
2009-04-07 19:38:09 -05:00
pCreature -> AI () -> AttackStart ( target );
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_THREAT_SINGLE_PCT :
2009-05-18 15:14:27 -05:00
if ( Unit * target = GetTargetByType ( action . threat_single_pct . target , pActionInvoker ))
m_creature -> getThreatManager (). modifyThreatPercent ( target , action . threat_single_pct . percent );
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_THREAT_ALL_PCT :
{
2010-03-09 11:11:10 +01:00
std :: list < HostileReference *>& threatList = m_creature -> getThreatManager (). getThreatList ();
for ( std :: list < HostileReference *>:: iterator i = threatList . begin (); i != threatList . end (); ++ i )
2010-04-07 19:14:10 +02:00
if ( Unit * Temp = Unit :: GetUnit ( * m_creature ,( * i ) -> getUnitGuid ()))
2009-05-18 15:14:27 -05:00
m_creature -> getThreatManager (). modifyThreatPercent ( Temp , action . threat_all_pct . percent );
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_QUEST_EVENT :
2009-05-18 15:14:27 -05:00
if ( Unit * target = GetTargetByType ( action . quest_event . target , pActionInvoker ))
if ( target -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
target -> ToPlayer () -> AreaExploredOrEventHappens ( action . quest_event . questId );
2009-05-18 15:14:27 -05:00
break ;
case ACTION_T_CAST_EVENT :
if ( Unit * target = GetTargetByType ( action . cast_event . target , pActionInvoker ))
if ( target -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
target -> ToPlayer () -> CastedCreatureOrGO ( action . cast_event . creatureId , m_creature -> GetGUID (), action . cast_event . spellId );
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_SET_UNIT_FIELD :
{
2009-05-18 15:14:27 -05:00
Unit * target = GetTargetByType ( action . set_unit_field . target , pActionInvoker );
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
// not allow modify important for integrity object fields
if ( action . set_unit_field . field < OBJECT_END || action . set_unit_field . field >= UNIT_END )
2009-04-07 19:38:09 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( target )
2009-05-18 15:14:27 -05:00
target -> SetUInt32Value ( action . set_unit_field . field , action . set_unit_field . value );
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
2009-05-18 15:14:27 -05:00
case ACTION_T_SET_UNIT_FLAG :
if ( Unit * target = GetTargetByType ( action . unit_flag . target , pActionInvoker ))
target -> SetFlag ( UNIT_FIELD_FLAGS , action . unit_flag . value );
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_REMOVE_UNIT_FLAG :
2009-05-18 15:14:27 -05:00
if ( Unit * target = GetTargetByType ( action . unit_flag . target , pActionInvoker ))
target -> RemoveFlag ( UNIT_FIELD_FLAGS , action . unit_flag . value );
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_AUTO_ATTACK :
2009-05-18 15:14:27 -05:00
MeleeEnabled = action . auto_attack . state != 0 ;
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_COMBAT_MOVEMENT :
2009-05-31 16:24:19 -05:00
// ignore no affect case
2010-04-08 08:20:08 +02:00
if ( CombatMovementEnabled == ( action . combat_movement . state != 0 ))
2009-05-31 16:24:19 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
CombatMovementEnabled = action . combat_movement . state != 0 ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Allow movement (create new targeted movement gen only if idle)
if ( CombatMovementEnabled )
{
2010-03-11 01:56:47 +01:00
Unit * victim = m_creature -> getVictim ();
if ( m_creature -> isInCombat () && victim )
{
if ( action . combat_movement . melee )
{
m_creature -> addUnitState ( UNIT_STAT_MELEE_ATTACKING );
2009-05-31 16:24:19 -05:00
m_creature -> SendMeleeAttackStart ( victim );
2010-04-07 18:09:10 +02:00
}
2010-03-11 01:56:47 +01:00
if ( m_creature -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == IDLE_MOTION_TYPE )
m_creature -> GetMotionMaster () -> MoveChase ( victim , AttackDistance , AttackAngle ); // Targeted movement generator will start melee automatically, no need to send it explicitly
}
2009-04-07 19:38:09 -05:00
}
else
2010-04-07 18:09:10 +02:00
{
2010-03-11 01:56:47 +01:00
if ( m_creature -> isInCombat ())
{
Unit * victim = m_creature -> getVictim ();
if ( action . combat_movement . melee && victim )
{
m_creature -> clearUnitState ( UNIT_STAT_MELEE_ATTACKING );
2009-05-31 16:24:19 -05:00
m_creature -> SendMeleeAttackStop ( victim );
2010-04-07 18:09:10 +02:00
}
2010-03-11 01:56:47 +01:00
if ( m_creature -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == TARGETED_MOTION_TYPE )
m_creature -> GetMotionMaster () -> MoveIdle ();
}
2009-04-07 19:38:09 -05:00
}
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_SET_PHASE :
2009-05-18 15:14:27 -05:00
Phase = action . set_phase . phase ;
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_INC_PHASE :
{
2009-05-18 15:14:27 -05:00
int32 new_phase = int32 ( Phase ) + action . set_inc_phase . step ;
if ( new_phase < 0 )
{
2010-04-07 22:59:46 +02:00
sLog . outErrorDb ( "CreatureEventAI: Event %d decrease Phase under 0. CreatureEntry = %d" , EventId , m_creature -> GetEntry ());
2009-05-18 15:14:27 -05:00
Phase = 0 ;
}
else if ( new_phase >= MAX_PHASE )
{
2010-04-07 22:59:46 +02:00
sLog . outErrorDb ( "CreatureEventAI: Event %d incremented Phase above %u. Phase mask cannot be used with phases past %u. CreatureEntry = %d" , EventId , MAX_PHASE - 1 , MAX_PHASE - 1 , m_creature -> GetEntry ());
2009-05-18 15:14:27 -05:00
Phase = MAX_PHASE - 1 ;
}
2009-05-31 15:56:51 -05:00
else
2009-05-18 15:14:27 -05:00
Phase = new_phase ;
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_EVADE :
EnterEvadeMode ();
2009-05-18 15:14:27 -05:00
break ;
2009-05-21 10:48:00 -05:00
case ACTION_T_FLEE_FOR_ASSIST :
m_creature -> DoFleeToGetAssistance ();
2009-04-07 19:38:09 -05:00
break ;
case ACTION_T_QUEST_EVENT_ALL :
2009-05-18 15:14:27 -05:00
if ( pActionInvoker && pActionInvoker -> GetTypeId () == TYPEID_PLAYER )
2009-04-07 19:38:09 -05:00
{
2009-05-18 15:14:27 -05:00
if ( Unit * Temp = Unit :: GetUnit ( * m_creature , pActionInvoker -> GetGUID ()))
if ( Temp -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
Temp -> ToPlayer () -> GroupEventHappens ( action . quest_event_all . questId , m_creature );
2009-04-07 19:38:09 -05:00
}
2009-05-18 15:14:27 -05:00
break ;
case ACTION_T_CAST_EVENT_ALL :
2009-04-07 19:38:09 -05:00
{
2010-03-09 11:11:10 +01:00
std :: list < HostileReference *>& threatList = m_creature -> getThreatManager (). getThreatList ();
for ( std :: list < HostileReference *>:: iterator i = threatList . begin (); i != threatList . end (); ++ i )
2009-05-18 15:14:27 -05:00
if ( Unit * Temp = Unit :: GetUnit ( * m_creature ,( * i ) -> getUnitGuid ()))
if ( Temp -> GetTypeId () == TYPEID_PLAYER )
2010-03-07 15:20:19 +01:00
Temp -> ToPlayer () -> CastedCreatureOrGO ( action . cast_event_all . creatureId , m_creature -> GetGUID (), action . cast_event_all . spellId );
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_REMOVEAURASFROMSPELL :
2009-05-18 15:14:27 -05:00
if ( Unit * target = GetTargetByType ( action . remove_aura . target , pActionInvoker ))
target -> RemoveAurasDueToSpell ( action . remove_aura . spellId );
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_RANGED_MOVEMENT :
2009-06-19 17:34:24 -05:00
AttackDistance = ( float ) action . ranged_movement . distance ;
AttackAngle = action . ranged_movement . angle / 180.0f * M_PI ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( CombatMovementEnabled )
{
2009-04-14 19:54:49 -05:00
m_creature -> GetMotionMaster () -> MoveChase ( m_creature -> getVictim (), AttackDistance , AttackAngle );
2009-04-07 19:38:09 -05:00
}
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_RANDOM_PHASE :
2009-05-18 15:14:27 -05:00
Phase = GetRandActionParam ( rnd , action . random_phase . phase1 , action . random_phase . phase2 , action . random_phase . phase3 );
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_RANDOM_PHASE_RANGE :
2010-01-12 21:16:12 +01:00
if ( action . random_phase_range . phaseMin <= action . random_phase_range . phaseMax )
Phase = urand ( action . random_phase_range . phaseMin , action . random_phase_range . phaseMax );
2009-04-07 19:38:09 -05:00
else
2010-04-07 22:59:46 +02:00
sLog . outErrorDb ( "CreatureEventAI: ACTION_T_RANDOM_PHASE_RANGE cannot have Param2 < Param1. Event = %d. CreatureEntry = %d" , EventId , m_creature -> GetEntry ());
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_SUMMON_ID :
{
2009-05-18 15:14:27 -05:00
Unit * target = GetTargetByType ( action . summon_id . target , pActionInvoker );
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
CreatureEventAI_Summon_Map :: const_iterator i = CreatureEAI_Mgr . GetCreatureEventAISummonMap (). find ( action . summon_id . spawnId );
2009-04-07 19:38:09 -05:00
if ( i == CreatureEAI_Mgr . GetCreatureEventAISummonMap (). end ())
{
2010-04-07 22:59:46 +02:00
sLog . outErrorDb ( "CreatureEventAI: failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d" , action . summon_id . creatureId , action . summon_id . spawnId , EventId , m_creature -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
Creature * pCreature = NULL ;
2009-04-07 19:38:09 -05:00
if (( * i ). second . SpawnTimeSecs )
2009-05-18 15:14:27 -05:00
pCreature = m_creature -> SummonCreature ( action . summon_id . creatureId , ( * i ). second . position_x , ( * i ). second . position_y , ( * i ). second . position_z , ( * i ). second . orientation , TEMPSUMMON_TIMED_OR_DEAD_DESPAWN , ( * i ). second . SpawnTimeSecs );
else
pCreature = m_creature -> SummonCreature ( action . summon_id . creatureId , ( * i ). second . position_x , ( * i ). second . position_y , ( * i ). second . position_z , ( * i ). second . orientation , TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT , 0 );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( ! pCreature )
2010-04-07 22:59:46 +02:00
sLog . outErrorDb ( "CreatureEventAI: failed to spawn creature %u. EventId %d.Creature %d" , action . summon_id . creatureId , EventId , m_creature -> GetEntry ());
2009-05-18 15:14:27 -05:00
else if ( action . summon_id . target != TARGET_T_SELF && target )
2009-04-07 19:38:09 -05:00
pCreature -> AI () -> AttackStart ( target );
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_KILLED_MONSTER :
//first attempt player who tapped creature
2009-04-14 19:54:49 -05:00
if ( Player * pPlayer = m_creature -> GetLootRecipient ())
2009-05-18 15:14:27 -05:00
pPlayer -> RewardPlayerAndGroupAtEvent ( action . killed_monster . creatureId , m_creature );
2009-04-07 19:38:09 -05:00
else
{
//if not available, use pActionInvoker
2009-05-18 15:14:27 -05:00
if ( Unit * pTarget = GetTargetByType ( action . killed_monster . target , pActionInvoker ))
2009-04-27 18:42:35 -05:00
if ( Player * pPlayer2 = pTarget -> GetCharmerOrOwnerPlayerOrPlayerItself ())
2009-05-18 15:14:27 -05:00
pPlayer2 -> RewardPlayerAndGroupAtEvent ( action . killed_monster . creatureId , m_creature );
2009-04-07 19:38:09 -05:00
}
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_SET_INST_DATA :
{
2009-04-14 19:54:49 -05:00
InstanceData * pInst = ( InstanceData * ) m_creature -> GetInstanceData ();
2009-04-07 19:38:09 -05:00
if ( ! pInst )
{
2009-04-14 19:54:49 -05:00
sLog . outErrorDb ( "CreatureEventAI: Event %d attempt to set instance data without instance script. Creature %d" , EventId , m_creature -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
pInst -> SetData ( action . set_inst_data . field , action . set_inst_data . value );
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_SET_INST_DATA64 :
{
2009-05-18 15:14:27 -05:00
Unit * target = GetTargetByType ( action . set_inst_data64 . target , pActionInvoker );
2009-04-07 19:38:09 -05:00
if ( ! target )
{
2009-04-14 19:54:49 -05:00
sLog . outErrorDb ( "CreatureEventAI: Event %d attempt to set instance data64 but Target == NULL. Creature %d" , EventId , m_creature -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-04-14 19:54:49 -05:00
InstanceData * pInst = ( InstanceData * ) m_creature -> GetInstanceData ();
2009-04-07 19:38:09 -05:00
if ( ! pInst )
{
2009-04-14 19:54:49 -05:00
sLog . outErrorDb ( "CreatureEventAI: Event %d attempt to set instance data64 without instance script. Creature %d" , EventId , m_creature -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
pInst -> SetData64 ( action . set_inst_data64 . field , target -> GetGUID ());
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_UPDATE_TEMPLATE :
2009-05-18 15:14:27 -05:00
if ( m_creature -> GetEntry () == action . update_template . creatureId )
2009-04-07 19:38:09 -05:00
{
2009-10-17 15:51:44 -07:00
2009-04-14 19:54:49 -05:00
sLog . outErrorDb ( "CreatureEventAI: Event %d ACTION_T_UPDATE_TEMPLATE call with param1 == current entry. Creature %d" , EventId , m_creature -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
m_creature -> UpdateEntry ( action . update_template . creatureId , action . update_template . team ? HORDE : ALLIANCE );
2009-05-21 10:15:09 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_DIE :
2009-04-14 19:54:49 -05:00
if ( m_creature -> isDead ())
2009-04-07 19:38:09 -05:00
{
2009-10-17 15:51:44 -07:00
2009-04-14 19:54:49 -05:00
sLog . outErrorDb ( "CreatureEventAI: Event %d ACTION_T_DIE on dead creature. Creature %d" , EventId , m_creature -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-15 14:03:55 -07:00
m_creature -> Kill ( m_creature );
2009-05-21 10:15:09 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_ZONE_COMBAT_PULSE :
2009-06-27 15:37:33 -05:00
{
m_creature -> SetInCombatWithZone ();
2009-05-21 10:15:09 -05:00
break ;
2009-06-27 15:37:33 -05:00
}
2009-05-21 10:15:09 -05:00
case ACTION_T_CALL_FOR_HELP :
{
2009-06-04 16:10:26 -05:00
m_creature -> CallForHelp ( action . call_for_help . radius );
2009-05-21 10:15:09 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
break ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
// TRINITY ONLY
2009-11-13 16:26:01 +01:00
case ACTION_T_MOVE_RANDOM_POINT : //dosen't work in combat
{
float x , y , z ;
me -> GetClosePoint ( x , y , z , me -> GetObjectSize () / 3 , action . raw . param1 );
me -> GetMotionMaster () -> MovePoint ( 0 , x , y , z );
break ;
}
case ACTION_T_SET_STAND_STATE :
me -> SetStandState ( UnitStandStateType ( action . raw . param1 ));
break ;
case ACTION_T_SET_PHASE_MASK :
me -> SetPhaseMask ( action . raw . param1 , true );
break ;
case ACTION_T_SET_VISIBILITY :
me -> SetVisibility ( UnitVisibility ( action . raw . param1 ));
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_SET_ACTIVE :
2009-05-18 15:14:27 -05:00
me -> setActive ( action . raw . param1 ? true : false );
2009-04-07 19:38:09 -05:00
break ;
case ACTION_T_SET_AGGRESSIVE :
2009-05-18 15:14:27 -05:00
me -> SetReactState ( ReactStates ( action . raw . param1 ));
2009-04-07 19:38:09 -05:00
break ;
case ACTION_T_ATTACK_START_PULSE :
2009-05-18 15:14:27 -05:00
AttackStart ( me -> SelectNearestTarget (( float ) action . raw . param1 ));
2009-04-07 19:38:09 -05:00
break ;
2009-04-17 15:36:10 -05:00
case ACTION_T_SUMMON_GO :
{
GameObject * pObject = NULL ;
2009-10-17 15:51:44 -07:00
2009-04-17 15:36:10 -05:00
float x , y , z ;
m_creature -> GetPosition ( x , y , z );
2009-05-18 15:14:27 -05:00
pObject = m_creature -> SummonGameObject ( action . raw . param1 , x , y , z , 0 , 0 , 0 , 0 , 0 , action . raw . param2 );
2009-04-17 15:36:10 -05:00
if ( ! pObject )
{
2009-05-18 15:14:27 -05:00
sLog . outErrorDb ( "TSCR: EventAI failed to spawn object %u. Spawn event %d is on creature %d" , action . raw . param1 , EventId , m_creature -> GetEntry ());
2009-04-17 15:36:10 -05:00
}
2009-04-25 09:15:40 -05:00
break ;
2009-04-17 15:36:10 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-28 18:43:57 -05:00
case ACTION_T_SET_SHEATH :
{
m_creature -> SetSheath ( SheathState ( action . set_sheath . sheath ));
break ;
}
2009-06-18 17:05:01 -05:00
case ACTION_T_FORCE_DESPAWN :
{
2010-01-16 19:51:59 +03:00
m_creature -> ForcedDespawn ( action . forced_despawn . msDelay );
2009-06-18 17:05:01 -05:00
break ;
}
2009-07-30 10:56:15 +08:00
case ACTION_T_SET_INVINCIBILITY_HP_LEVEL :
2009-07-30 10:53:16 +08:00
{
2010-04-07 19:14:10 +02:00
if ( action . invincibility_hp_level . is_percent )
2009-07-30 10:56:15 +08:00
InvinceabilityHpLevel = m_creature -> GetMaxHealth () * action . invincibility_hp_level . hp_level / 100 ;
2009-07-30 10:53:16 +08:00
else
2009-07-30 10:56:15 +08:00
InvinceabilityHpLevel = action . invincibility_hp_level . hp_level ;
2009-07-30 10:53:16 +08:00
break ;
}
2009-04-07 19:38:09 -05:00
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: JustRespawned ()
{
Reset ();
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( bEmptyList )
return ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Handle Spawned Events
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
2009-05-21 10:52:05 -05:00
if ( SpawnedEventConditionsCheck (( * i ). Event ))
2009-04-07 19:38:09 -05:00
ProcessEvent ( * i );
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: Reset ()
{
EventUpdateTime = EVENT_UPDATE_TIME ;
EventDiff = 0 ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( bEmptyList )
return ;
2009-10-17 15:51:44 -07:00
2010-01-08 14:40:55 -03:00
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
{
if (( * i ). Event . event_type == EVENT_T_RESET )
ProcessEvent ( * i );
}
2009-04-07 19:38:09 -05:00
//Reset all events to enabled
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
{
2009-05-19 15:38:36 -05:00
CreatureEventAI_Event const & event = ( * i ). Event ;
switch ( event . event_type )
2009-04-07 19:38:09 -05:00
{
//Reset all out of combat timers
case EVENT_T_TIMER_OOC :
{
2009-05-19 15:38:36 -05:00
if (( * i ). UpdateRepeatTimer ( m_creature , event . timer . initialMin , event . timer . initialMax ))
2009-04-07 19:38:09 -05:00
( * i ). Enabled = true ;
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
//default:
2009-04-27 21:23:42 -05:00
//TODO: enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void EnterCombat()
2009-04-07 19:38:09 -05:00
//(*i).Enabled = true;
//(*i).Time = 0;
//break;
}
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: JustReachedHome ()
{
2009-04-14 19:54:49 -05:00
m_creature -> LoadCreaturesAddon ();
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( ! bEmptyList )
{
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
{
if (( * i ). Event . event_type == EVENT_T_REACHED_HOME )
ProcessEvent ( * i );
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
Reset ();
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: EnterEvadeMode ()
{
2009-05-12 10:11:54 -05:00
CreatureAI :: EnterEvadeMode ();
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( bEmptyList )
return ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Handle Evade events
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
{
if (( * i ). Event . event_type == EVENT_T_EVADE )
ProcessEvent ( * i );
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: JustDied ( Unit * killer )
{
Reset ();
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( bEmptyList )
return ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Handle Evade events
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
{
if (( * i ). Event . event_type == EVENT_T_DEATH )
ProcessEvent ( * i , killer );
}
2009-10-17 15:51:44 -07:00
2009-06-15 23:10:06 -05:00
// reset phase after any death state events
Phase = 0 ;
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: KilledUnit ( Unit * victim )
{
if ( bEmptyList || victim -> GetTypeId () != TYPEID_PLAYER )
return ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
{
if (( * i ). Event . event_type == EVENT_T_KILL )
ProcessEvent ( * i , victim );
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: JustSummoned ( Creature * pUnit )
{
if ( bEmptyList || ! pUnit )
return ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
{
if (( * i ). Event . event_type == EVENT_T_SUMMONED_UNIT )
ProcessEvent ( * i , pUnit );
}
}
2009-10-17 15:51:44 -07:00
2009-04-27 19:14:37 -05:00
void CreatureEventAI :: EnterCombat ( Unit * enemy )
2009-04-07 19:38:09 -05:00
{
//Check for on combat start events
if ( ! bEmptyList )
{
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
{
2009-05-19 15:38:36 -05:00
CreatureEventAI_Event const & event = ( * i ). Event ;
switch ( event . event_type )
2009-04-07 19:38:09 -05:00
{
case EVENT_T_AGGRO :
( * i ). Enabled = true ;
2009-04-27 19:14:37 -05:00
ProcessEvent ( * i , enemy );
2009-04-07 19:38:09 -05:00
break ;
//Reset all in combat timers
case EVENT_T_TIMER :
2009-05-19 15:38:36 -05:00
if (( * i ). UpdateRepeatTimer ( m_creature , event . timer . initialMin , event . timer . initialMax ))
2009-04-07 19:38:09 -05:00
( * i ). Enabled = true ;
break ;
//All normal events need to be re-enabled and their time set to 0
default :
( * i ). Enabled = true ;
( * i ). Time = 0 ;
break ;
}
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
EventUpdateTime = EVENT_UPDATE_TIME ;
EventDiff = 0 ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: AttackStart ( Unit * who )
{
if ( ! who )
return ;
2009-10-17 15:51:44 -07:00
2009-04-14 19:54:49 -05:00
if ( m_creature -> Attack ( who , MeleeEnabled ))
2009-04-07 19:38:09 -05:00
{
if ( CombatMovementEnabled )
{
2009-04-14 19:54:49 -05:00
m_creature -> GetMotionMaster () -> MoveChase ( who , AttackDistance , AttackAngle );
2009-04-07 19:38:09 -05:00
}
else
{
2009-04-14 19:54:49 -05:00
m_creature -> GetMotionMaster () -> MoveIdle ();
2009-04-07 19:38:09 -05:00
}
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: MoveInLineOfSight ( Unit * who )
{
2010-04-07 19:14:10 +02:00
if ( me -> getVictim ())
2009-04-07 19:38:09 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Check for OOC LOS Event
2009-05-03 16:58:44 -05:00
if ( ! bEmptyList )
2009-04-07 19:38:09 -05:00
{
for ( std :: list < CreatureEventAIHolder >:: iterator itr = CreatureEventAIList . begin (); itr != CreatureEventAIList . end (); ++ itr )
{
if (( * itr ). Event . event_type == EVENT_T_OOC_LOS )
{
//can trigger if closer than fMaxAllowedRange
2009-05-19 15:38:36 -05:00
float fMaxAllowedRange = ( * itr ). Event . ooc_los . maxRange ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//if range is ok and we are actually in LOS
2009-04-14 19:54:49 -05:00
if ( m_creature -> IsWithinDistInMap ( who , fMaxAllowedRange ) && m_creature -> IsWithinLOSInMap ( who ))
2009-04-07 19:38:09 -05:00
{
//if friendly event&&who is not hostile OR hostile event&&who is hostile
2009-05-19 15:38:36 -05:00
if ((( * itr ). Event . ooc_los . noHostile && ! m_creature -> IsHostileTo ( who )) ||
(( ! ( * itr ). Event . ooc_los . noHostile ) && m_creature -> IsHostileTo ( who )))
2009-04-07 19:38:09 -05:00
ProcessEvent ( * itr , who );
}
}
}
}
2009-10-17 15:51:44 -07:00
2009-08-20 16:12:23 -05:00
CreatureAI :: MoveInLineOfSight ( who );
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: SpellHit ( Unit * pUnit , const SpellEntry * pSpell )
{
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( bEmptyList )
return ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
if (( * i ). Event . event_type == EVENT_T_SPELLHIT )
//If spell id matches (or no spell id) & if spell school matches (or no spell school)
2009-05-19 15:38:36 -05:00
if ( ! ( * i ). Event . spell_hit . spellId || pSpell -> Id == ( * i ). Event . spell_hit . spellId )
if ( pSpell -> SchoolMask & ( * i ). Event . spell_hit . schoolMask )
2009-04-07 19:38:09 -05:00
ProcessEvent ( * i , pUnit );
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: UpdateAI ( const uint32 diff )
{
//Check if we are in combat (also updates calls threat update code)
2009-04-24 11:57:36 -05:00
bool Combat = UpdateVictim ();
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( ! bEmptyList )
{
//Events are only updated once every EVENT_UPDATE_TIME ms to prevent lag with large amount of events
2009-11-11 15:11:51 -08:00
if ( EventUpdateTime <= diff )
2009-04-07 19:38:09 -05:00
{
EventDiff += diff ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Check for time based events
for ( std :: list < CreatureEventAIHolder >:: iterator i = CreatureEventAIList . begin (); i != CreatureEventAIList . end (); ++ i )
{
//Decrement Timers
if (( * i ). Time )
{
2009-11-11 15:11:51 -08:00
if ( EventDiff <= ( * i ). Time )
2009-04-07 19:38:09 -05:00
{
//Do not decrement timers if event cannot trigger in this phase
if ( ! (( * i ). Event . event_inverse_phase_mask & ( 1 << Phase )))
( * i ). Time -= EventDiff ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Skip processing of events that have time remaining
continue ;
}
else ( * i ). Time = 0 ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Events that are updated every EVENT_UPDATE_TIME
switch (( * i ). Event . event_type )
{
case EVENT_T_TIMER_OOC :
ProcessEvent ( * i );
break ;
case EVENT_T_TIMER :
case EVENT_T_MANA :
case EVENT_T_HP :
case EVENT_T_TARGET_HP :
case EVENT_T_TARGET_CASTING :
case EVENT_T_FRIENDLY_HP :
2009-05-15 14:23:05 -05:00
if ( me -> getVictim ())
2009-04-07 19:38:09 -05:00
ProcessEvent ( * i );
break ;
case EVENT_T_RANGE :
2009-05-15 14:23:05 -05:00
if ( me -> getVictim ())
2009-05-14 16:50:47 -05:00
if ( m_creature -> IsInMap ( m_creature -> getVictim ()))
2009-05-19 15:38:36 -05:00
if ( m_creature -> IsInRange ( m_creature -> getVictim (),( float )( * i ). Event . range . minDist ,( float )( * i ). Event . range . maxDist ))
2009-04-07 19:38:09 -05:00
ProcessEvent ( * i );
break ;
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
EventDiff = 0 ;
EventUpdateTime = EVENT_UPDATE_TIME ;
}
else
{
EventDiff += diff ;
EventUpdateTime -= diff ;
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Melee Auto-Attack
if ( Combat && MeleeEnabled )
DoMeleeAttackIfReady ();
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
inline uint32 CreatureEventAI :: GetRandActionParam ( uint32 rnd , uint32 param1 , uint32 param2 , uint32 param3 )
{
switch ( rnd % 3 )
{
2009-05-18 15:14:27 -05:00
case 0 : return param1 ;
case 1 : return param2 ;
case 2 : return param3 ;
}
return 0 ;
}
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
inline int32 CreatureEventAI :: GetRandActionParam ( uint32 rnd , int32 param1 , int32 param2 , int32 param3 )
{
switch ( rnd % 3 )
{
case 0 : return param1 ;
case 1 : return param2 ;
case 2 : return param3 ;
2009-04-07 19:38:09 -05:00
}
return 0 ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
inline Unit * CreatureEventAI :: GetTargetByType ( uint32 Target , Unit * pActionInvoker )
{
switch ( Target )
{
case TARGET_T_SELF :
2009-04-14 19:54:49 -05:00
return m_creature ;
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE :
2009-04-14 19:54:49 -05:00
return m_creature -> getVictim ();
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE_SECOND_AGGRO :
2010-03-13 12:15:32 +01:00
return SelectTarget ( SELECT_TARGET_TOPAGGRO , 1 );
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE_LAST_AGGRO :
2010-03-13 12:15:32 +01:00
return SelectTarget ( SELECT_TARGET_BOTTOMAGGRO , 0 );
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE_RANDOM :
2010-03-13 12:15:32 +01:00
return SelectTarget ( SELECT_TARGET_RANDOM , 0 );
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE_RANDOM_NOT_TOP :
2010-03-13 12:15:32 +01:00
return SelectTarget ( SELECT_TARGET_RANDOM , 1 );
2009-04-07 19:38:09 -05:00
case TARGET_T_ACTION_INVOKER :
return pActionInvoker ;
default :
return NULL ;
};
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
Unit * CreatureEventAI :: DoSelectLowestHpFriendly ( float range , uint32 MinHPDiff )
{
2009-12-20 15:20:04 +01:00
CellPair p ( Trinity :: ComputeCellPair ( m_creature -> GetPositionX (), m_creature -> GetPositionY ()));
2009-04-07 19:38:09 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
Unit * pUnit = NULL ;
2009-10-17 15:51:44 -07:00
2009-12-20 15:20:04 +01:00
Trinity :: MostHPMissingInRange u_check ( m_creature , range , MinHPDiff );
Trinity :: UnitLastSearcher < Trinity :: MostHPMissingInRange > searcher ( m_creature , pUnit , u_check );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -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
*/
2009-12-20 15:20:04 +01:00
TypeContainerVisitor < Trinity :: UnitLastSearcher < Trinity :: MostHPMissingInRange > , GridTypeMapContainer > grid_unit_searcher ( searcher );
2009-10-17 15:51:44 -07:00
2010-01-23 22:24:41 +01:00
cell . Visit ( p , grid_unit_searcher , * m_creature -> GetMap (), * m_creature , range );
2009-04-07 19:38:09 -05:00
return pUnit ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: DoFindFriendlyCC ( std :: list < Creature *>& _list , float range )
{
2009-12-20 15:20:04 +01:00
CellPair p ( Trinity :: ComputeCellPair ( m_creature -> GetPositionX (), m_creature -> GetPositionY ()));
2009-04-07 19:38:09 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2009-12-20 15:20:04 +01:00
Trinity :: FriendlyCCedInRange u_check ( m_creature , range );
Trinity :: CreatureListSearcher < Trinity :: FriendlyCCedInRange > searcher ( m_creature , _list , u_check );
2009-10-17 15:51:44 -07:00
2009-12-20 15:20:04 +01:00
TypeContainerVisitor < Trinity :: CreatureListSearcher < Trinity :: FriendlyCCedInRange > , GridTypeMapContainer > grid_creature_searcher ( searcher );
2009-10-17 15:51:44 -07:00
2010-01-23 22:24:41 +01:00
cell . Visit ( p , grid_creature_searcher , * m_creature -> GetMap ());
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: DoFindFriendlyMissingBuff ( std :: list < Creature *>& _list , float range , uint32 spellid )
{
2009-12-20 15:20:04 +01:00
CellPair p ( Trinity :: ComputeCellPair ( m_creature -> GetPositionX (), m_creature -> GetPositionY ()));
2009-04-07 19:38:09 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2009-12-20 15:20:04 +01:00
Trinity :: FriendlyMissingBuffInRange u_check ( m_creature , range , spellid );
Trinity :: CreatureListSearcher < Trinity :: FriendlyMissingBuffInRange > searcher ( m_creature , _list , u_check );
2009-10-17 15:51:44 -07:00
2009-12-20 15:20:04 +01:00
TypeContainerVisitor < Trinity :: CreatureListSearcher < Trinity :: FriendlyMissingBuffInRange > , GridTypeMapContainer > grid_creature_searcher ( searcher );
2009-10-17 15:51:44 -07:00
2010-01-23 22:24:41 +01:00
cell . Visit ( p , grid_creature_searcher , * m_creature -> GetMap ());
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//*********************************
//*** Functions used globally ***
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
void CreatureEventAI :: DoScriptText ( int32 textEntry , WorldObject * pSource , Unit * target )
{
if ( ! pSource )
{
sLog . outErrorDb ( "CreatureEventAI: DoScriptText entry %i, invalid Source pointer." , textEntry );
return ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( textEntry >= 0 )
{
sLog . outErrorDb ( "CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative." , pSource -> GetEntry (), pSource -> GetTypeId (), pSource -> GetGUIDLow (), textEntry );
return ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
CreatureEventAI_TextMap :: const_iterator i = CreatureEAI_Mgr . GetCreatureEventAITextMap (). find ( textEntry );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
if ( i == CreatureEAI_Mgr . GetCreatureEventAITextMap (). end ())
{
sLog . outErrorDb ( "CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i." , pSource -> GetEntry (), pSource -> GetTypeId (), pSource -> GetGUIDLow (), textEntry );
return ;
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
sLog . outDebug ( "CreatureEventAI: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u" , textEntry ,( * i ). second . SoundId ,( * i ). second . Type ,( * i ). second . Language ,( * i ). second . Emote );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if (( * i ). second . SoundId )
2009-04-07 19:38:09 -05:00
{
if ( GetSoundEntriesStore () -> LookupEntry (( * i ). second . SoundId ))
pSource -> PlayDirectSound (( * i ). second . SoundId );
else
sLog . outErrorDb ( "CreatureEventAI: DoScriptText entry %i tried to process invalid sound id %u." , textEntry ,( * i ). second . SoundId );
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if (( * i ). second . Emote )
2009-04-07 19:38:09 -05:00
{
if ( pSource -> GetTypeId () == TYPEID_UNIT || pSource -> GetTypeId () == TYPEID_PLAYER )
{
(( Unit * ) pSource ) -> HandleEmoteCommand (( * i ). second . Emote );
}
else
sLog . outErrorDb ( "CreatureEventAI: DoScriptText entry %i tried to process emote for invalid TypeId (%u)." , textEntry , pSource -> GetTypeId ());
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
switch (( * i ). second . Type )
{
case CHAT_TYPE_SAY :
pSource -> MonsterSay ( textEntry , ( * i ). second . Language , target ? target -> GetGUID () : 0 );
break ;
case CHAT_TYPE_YELL :
pSource -> MonsterYell ( textEntry , ( * i ). second . Language , target ? target -> GetGUID () : 0 );
break ;
case CHAT_TYPE_TEXT_EMOTE :
pSource -> MonsterTextEmote ( textEntry , target ? target -> GetGUID () : 0 );
break ;
case CHAT_TYPE_BOSS_EMOTE :
pSource -> MonsterTextEmote ( textEntry , target ? target -> GetGUID () : 0 , true );
break ;
case CHAT_TYPE_WHISPER :
{
if ( target && target -> GetTypeId () == TYPEID_PLAYER )
pSource -> MonsterWhisper ( textEntry , target -> GetGUID ());
else sLog . outErrorDb ( "CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER)." , textEntry );
} break ;
case CHAT_TYPE_BOSS_WHISPER :
{
if ( target && target -> GetTypeId () == TYPEID_PLAYER )
pSource -> MonsterWhisper ( textEntry , target -> GetGUID (), true );
else sLog . outErrorDb ( "CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER)." , textEntry );
} break ;
case CHAT_TYPE_ZONE_YELL :
pSource -> MonsterYellToZone ( textEntry , ( * i ). second . Language , target ? target -> GetGUID () : 0 );
break ;
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
bool CreatureEventAI :: CanCast ( Unit * Target , SpellEntry const * Spell , bool Triggered )
{
//No target so we can't cast
if ( ! Target || ! Spell )
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Silenced so we can't cast
if ( ! Triggered && me -> HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SILENCED ))
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Check for power
2009-07-23 18:32:32 +02:00
if ( ! Triggered && me -> GetPower (( Powers ) Spell -> powerType ) < CalculatePowerCost ( Spell , me , GetSpellSchoolMask ( Spell )))
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
SpellRangeEntry const * TempRange = NULL ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
TempRange = GetSpellRangeStore () -> LookupEntry ( Spell -> rangeIndex );
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Spell has invalid range store so we can't use it
if ( ! TempRange )
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Unit is out of range of this spell
2009-05-14 16:50:47 -05:00
if ( ! m_creature -> IsInRange ( Target , TempRange -> minRangeHostile , TempRange -> maxRangeHostile ))
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-04-15 17:29:33 -05:00
void CreatureEventAI :: ReceiveEmote ( Player * pPlayer , uint32 text_emote )
2009-04-07 19:38:09 -05:00
{
2009-04-15 17:29:33 -05:00
if ( bEmptyList )
return ;
2009-10-17 15:51:44 -07:00
2009-04-15 17:29:33 -05:00
for ( std :: list < CreatureEventAIHolder >:: iterator itr = CreatureEventAIList . begin (); itr != CreatureEventAIList . end (); ++ itr )
2009-04-07 19:38:09 -05:00
{
if (( * itr ). Event . event_type == EVENT_T_RECEIVE_EMOTE )
{
2009-05-19 15:38:36 -05:00
if (( * itr ). Event . receive_emote . emoteId != text_emote )
2009-04-15 17:29:33 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-05-19 15:38:36 -05:00
PlayerCondition pcon (( * itr ). Event . receive_emote . condition ,( * itr ). Event . receive_emote . conditionValue1 ,( * itr ). Event . receive_emote . conditionValue2 );
if ( pcon . Meets ( pPlayer ))
2009-04-07 19:38:09 -05:00
{
sLog . outDebug ( "CreatureEventAI: ReceiveEmote CreatureEventAI: Condition ok, processing" );
2009-04-15 17:29:33 -05:00
ProcessEvent ( * itr , pPlayer );
2009-04-07 19:38:09 -05:00
}
}
}
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void CreatureEventAI :: DamageTaken ( Unit * done_by , uint32 & damage )
2009-07-30 10:53:16 +08:00
{
2010-04-07 19:14:10 +02:00
if ( InvinceabilityHpLevel > 0 && m_creature -> GetHealth () < InvinceabilityHpLevel + damage )
2009-07-30 10:53:16 +08:00
{
2010-04-07 19:14:10 +02:00
if ( m_creature -> GetHealth () <= InvinceabilityHpLevel )
2009-07-30 10:53:16 +08:00
damage = 0 ;
else
damage = m_creature -> GetHealth () - InvinceabilityHpLevel ;
}
}
2009-10-17 15:51:44 -07:00
2009-05-21 10:52:05 -05:00
bool CreatureEventAI :: SpawnedEventConditionsCheck ( CreatureEventAI_Event const & event )
{
2010-04-07 19:14:10 +02:00
if ( event . event_type != EVENT_T_SPAWNED )
2009-05-21 10:52:05 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-05-21 10:52:05 -05:00
switch ( event . spawned . condition )
{
case SPAWNED_EVENT_ALWAY :
// always
return true ;
case SPAWNED_EVENT_MAP :
// map ID check
return m_creature -> GetMapId () == event . spawned . conditionValue1 ;
case SPAWNED_EVENT_ZONE :
{
// zone ID check
uint32 zone , area ;
m_creature -> GetZoneAndAreaId ( zone , area );
return zone == event . spawned . conditionValue1 || area == event . spawned . conditionValue1 ;
}
default :
break ;
}
2009-10-17 15:51:44 -07:00
2009-05-21 10:52:05 -05:00
return false ;
}