2010-10-07 15:35:36 +02:00
/*
2011-01-01 15:01:13 +01:00
* Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2009-04-07 19:38:09 -05:00
*/
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"
2010-06-08 13:05:47 -06:00
#include "Cell.h"
#include "CellImpl.h"
2009-04-07 19:38:09 -05:00
#include "GameEventMgr.h"
2010-06-08 13:05:47 -06:00
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
2010-08-08 22:54:58 +06:00
#include "InstanceScript.h"
2009-07-23 18:32:32 +02:00
#include "SpellMgr.h"
2009-08-28 16:38:43 -05:00
#include "CreatureAIImpl.h"
2010-06-04 23:24:48 +02:00
#include "ConditionMgr.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
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled." , creature -> GetEntry (), Event . event_id , Event . event_type );
2009-05-19 15:38:36 -05:00
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
2011-08-18 14:55:27 -03:00
int CreatureEventAI :: Permissible ( const Creature * creature )
2009-04-07 19:38:09 -05:00
{
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
2011-08-18 14:55:27 -03: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
2010-12-22 21:25:23 +01:00
CreatureEventAI_Event_Map :: const_iterator CreatureEvents = sEventAIMgr -> GetCreatureEventAIMap (). find ( me -> GetEntry ());
if ( CreatureEvents != sEventAIMgr -> GetCreatureEventAIMap (). end ())
2009-04-07 19:38:09 -05:00
{
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-14 23:07:41 +02:00
if ( me -> GetMap () -> IsDungeon ())
2009-04-07 19:38:09 -05:00
{
2010-04-14 23:07:41 +02:00
if (( 1 << ( me -> GetMap () -> GetSpawnMode () + 1 )) & ( * i ). event_flags )
2009-04-07 19:38:09 -05:00
{
//event flagged for instance mode
2010-08-16 17:07:02 +06:00
m_CreatureEventAIList . push_back ( CreatureEventAIHolder ( * i ));
2009-04-07 19:38:09 -05:00
}
continue ;
}
2010-08-16 17:07:02 +06:00
m_CreatureEventAIList . push_back ( CreatureEventAIHolder ( * i ));
2009-04-07 19:38:09 -05:00
}
//EventMap had events but they were not added because they must be for instance
2010-08-16 17:07:02 +06:00
if ( m_CreatureEventAIList . empty ())
2010-12-23 23:25:44 +01:00
sLog -> outError ( "CreatureEventAI: Creature %u has events but no events added to list because of instance flags." , me -> GetEntry ());
2009-04-07 19:38:09 -05:00
}
else
2010-12-23 23:25:44 +01:00
sLog -> outError ( "CreatureEventAI: EventMap for Creature %u is empty but creature is using CreatureEventAI." , me -> GetEntry ());
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
m_bEmptyList = m_CreatureEventAIList . empty ();
m_Phase = 0 ;
m_CombatMovementEnabled = true ;
m_MeleeEnabled = true ;
m_AttackDistance = 0.0f ;
m_AttackAngle = 0.0f ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
m_InvinceabilityHpLevel = 0 ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Handle Spawned Events
2010-08-16 17:07:02 +06:00
if ( ! m_bEmptyList )
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_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
2011-08-18 14:55:27 -03:00
bool CreatureEventAI :: ProcessEvent ( CreatureEventAIHolder & holder , Unit * actionInvoker /*=NULL*/ )
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
if ( ! holder . Enabled || holder . Time )
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
//Check the inverse phase mask (event doesn't trigger if current phase bit is set in mask)
2011-08-18 14:55:27 -03:00
if ( holder . Event . event_inverse_phase_mask & ( 1 << m_Phase ))
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
CreatureEventAI_Event const & event = holder . 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 :
2010-04-14 23:07:41 +02:00
if ( ! me -> 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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . timer . repeatMin , event . timer . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_TIMER_OOC :
2010-04-14 23:07:41 +02:00
if ( me -> 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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . timer . repeatMin , event . timer . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_HP :
{
2010-04-14 23:07:41 +02:00
if ( ! me -> isInCombat () || ! me -> GetMaxHealth ())
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-08-26 01:20:57 +06:00
uint32 perc = uint32 ( me -> GetHealthPct ());
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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . percent_range . repeatMin , event . percent_range . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_MANA :
{
2010-04-14 23:07:41 +02:00
if ( ! me -> isInCombat () || ! me -> GetMaxPower ( POWER_MANA ))
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
uint32 perc = ( me -> GetPower ( POWER_MANA ) * 100 ) / me -> 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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . percent_range . repeatMin , event . percent_range . repeatMax );
2009-05-19 15:38:36 -05:00
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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . kill . repeatMin , event . kill . repeatMax );
2009-05-19 15:38:36 -05:00
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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . spell_hit . repeatMin , event . spell_hit . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_RANGE :
//Repeat Timers
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . range . repeatMin , event . range . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_OOC_LOS :
//Repeat Timers
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . ooc_los . repeatMin , event . ooc_los . repeatMax );
2009-05-19 15:38:36 -05:00
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 :
{
2010-04-14 23:07:41 +02:00
if ( ! me -> isInCombat () || ! me -> getVictim () || ! me -> getVictim () -> GetMaxHealth ())
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-08-26 01:20:57 +06:00
uint32 perc = uint32 ( me -> getVictim () -> GetHealthPct ());
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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . percent_range . repeatMin , event . percent_range . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_TARGET_CASTING :
2010-04-14 23:07:41 +02:00
if ( ! me -> isInCombat () || ! me -> getVictim () || ! me -> 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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . target_casting . repeatMin , event . target_casting . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
case EVENT_T_FRIENDLY_HP :
{
2010-04-14 23:07:41 +02:00
if ( ! me -> isInCombat ())
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Unit * unit = DoSelectLowestHpFriendly (( float ) event . friendly_hp . radius , event . friendly_hp . hpDeficit );
if ( ! unit )
2009-04-07 19:38:09 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
actionInvoker = unit ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . friendly_hp . repeatMin , event . friendly_hp . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_FRIENDLY_IS_CC :
{
2010-04-14 23:07:41 +02:00
if ( ! me -> 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 ;
2010-08-22 12:39:39 -07:00
DoFindFriendlyCC ( pList , ( float ) 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
2011-08-18 14:55:27 -03:00
actionInvoker = * ( pList . begin ());
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . friendly_is_cc . repeatMin , event . friendly_is_cc . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_FRIENDLY_MISSING_BUFF :
{
std :: list < Creature *> pList ;
2010-08-22 12:39:39 -07:00
DoFindFriendlyMissingBuff ( pList , ( float ) 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
2011-08-18 14:55:27 -03:00
actionInvoker = * ( pList . begin ());
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Repeat Timers
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . friendly_buff . repeatMin , event . friendly_buff . repeatMax );
2009-05-19 15:38:36 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case EVENT_T_SUMMONED_UNIT :
{
//Prevent event from occuring on no unit or non creatures
2011-08-18 14:55:27 -03:00
if ( ! actionInvoker || actionInvoker -> 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
2011-08-18 14:55:27 -03:00
if ( actionInvoker -> 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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , 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
{
2010-04-14 23:07:41 +02:00
if ( ! me -> isInCombat () || ! me -> getVictim () || ! me -> getVictim () -> GetMaxPower ( POWER_MANA ))
2009-05-19 15:38:36 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
uint32 perc = ( me -> getVictim () -> GetPower ( POWER_MANA ) * 100 ) / me -> 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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . percent_range . repeatMin , event . percent_range . repeatMax );
2009-05-19 15:38:36 -05:00
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)
2011-06-11 22:35:29 +02:00
Aura const * aura = me -> 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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . buffed . repeatMin , event . buffed . repeatMax );
2009-06-15 23:10:06 -05:00
break ;
}
case EVENT_T_TARGET_BUFFED :
{
//Prevent event from occuring on no unit
2011-08-18 14:55:27 -03:00
if ( ! actionInvoker )
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
//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)
2011-08-18 14:55:27 -03:00
Aura const * aura = actionInvoker -> 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
2011-08-18 14:55:27 -03:00
holder . UpdateRepeatTimer ( me , event . buffed . repeatMin , event . buffed . repeatMax );
2009-06-15 23:10:06 -05:00
break ;
}
2009-04-07 19:38:09 -05:00
default :
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch." , me -> GetEntry (), holder . Event . event_id , holder . 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
2011-08-18 14:55:27 -03:00
if ( ! ( holder . Event . event_flags & EFLAG_REPEATABLE ))
holder . 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
2011-08-18 14:55:27 -03:00
if ( holder . Event . event_chance <= rnd % 100 )
2009-07-12 17:43:22 +08:00
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 )
2011-08-18 14:55:27 -03:00
ProcessAction ( holder . Event . action [ j ], rnd , holder . Event . event_id , actionInvoker );
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
2011-08-18 14:55:27 -03:00
void CreatureEventAI :: ProcessAction ( CreatureEventAI_Action const & action , uint32 rnd , uint32 eventId , Unit * actionInvoker )
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
2011-05-12 10:40:53 +02:00
int32 temp = action . text . TextId1 ;
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
if ( action . text . TextId2 && action . text . TextId3 )
2011-04-29 20:47:02 +02:00
temp = RAND ( action . text . TextId1 , action . text . TextId2 , action . text . TextId3 );
else if ( action . text . TextId2 && urand ( 0 , 1 ))
2009-05-18 15:14:27 -05:00
temp = action . text . TextId2 ;
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
2011-08-18 14:55:27 -03:00
if ( actionInvoker )
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
if ( actionInvoker -> GetTypeId () == TYPEID_PLAYER )
target = actionInvoker ;
else if ( Unit * owner = actionInvoker -> GetOwner ())
2009-04-07 19:38:09 -05:00
{
if ( owner -> GetTypeId () == TYPEID_PLAYER )
target = owner ;
}
}
2010-04-19 17:13:20 +02:00
else
2009-04-07 19:38:09 -05:00
{
2010-04-19 17:03:10 +02:00
target = me -> getVictim ();
if ( target && 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
2010-04-14 23:07:41 +02:00
DoScriptText ( temp , me , 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 )
2010-04-14 23:07:41 +02:00
me -> setFaction ( action . set_faction . factionId );
2009-04-07 19:38:09 -05:00
else
{
2011-04-28 22:57:08 +02:00
if ( CreatureTemplate const * ci = sObjectMgr -> GetCreatureTemplate ( me -> GetEntry ()))
2009-04-07 19:38:09 -05:00
{
//if no id provided, assume reset and then use default
2010-04-14 23:07:41 +02:00
if ( me -> getFaction () != ci -> faction_A )
me -> 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
{
2011-04-28 22:57:08 +02:00
if ( CreatureTemplate const * ci = sObjectMgr -> GetCreatureTemplate ( action . morph . creatureId ))
2009-04-07 19:38:09 -05:00
{
2011-04-29 20:47:02 +02:00
uint32 display_id = sObjectMgr -> ChooseDisplayId ( 0 , ci );
2010-04-14 23:07:41 +02:00
me -> SetDisplayId ( display_id );
2009-04-07 19:38:09 -05:00
}
}
//if no param1, then use value from param2 (modelId)
else
2010-04-14 23:07:41 +02:00
me -> SetDisplayId ( action . morph . modelId );
2009-04-07 19:38:09 -05:00
}
else
2010-04-14 23:07:41 +02:00
me -> DeMorph ();
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_SOUND :
2010-04-14 23:07:41 +02:00
me -> PlayDirectSound ( action . sound . soundId );
2009-04-07 19:38:09 -05:00
break ;
case ACTION_T_EMOTE :
2010-04-14 23:07:41 +02:00
me -> 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 )
2010-04-14 23:07:41 +02:00
me -> PlayDirectSound ( temp );
2009-05-18 15:14:27 -05:00
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 )
2010-04-14 23:07:41 +02:00
me -> HandleEmoteCommand ( temp );
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_CAST :
{
2011-08-18 14:55:27 -03:00
Unit * target = GetTargetByType ( action . cast . target , actionInvoker );
2010-04-14 23:07:41 +02:00
Unit * caster = me ;
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
2010-07-19 14:17:30 +02:00
bool canCast = ! caster -> IsNonMeleeSpellCasted ( false ) || ( action . cast . castFlags & ( CAST_TRIGGERED | CAST_INTERRUPT_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 )
{
2011-07-26 23:09:28 +02:00
const SpellInfo * tSpell = sSpellMgr -> GetSpellInfo ( 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
{
2010-04-14 23:07:41 +02:00
if ( me -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == TARGETED_MOTION_TYPE )
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
m_AttackDistance = 0.0f ;
m_AttackAngle = 0.0f ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
me -> GetMotionMaster () -> MoveChase ( me -> getVictim (), m_AttackDistance , m_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
2010-07-19 14:17:30 +02:00
if ( caster -> IsNonMeleeSpellCasted ( false ) && action . cast . castFlags & CAST_INTERRUPT_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
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: event %d creature %d attempt to cast spell that doesn't exist %d" , eventId , me -> 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 :
{
2011-08-18 14:55:27 -03:00
Unit * target = GetTargetByType ( action . summon . target , actionInvoker );
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Creature * creature = NULL ;
2009-10-17 15:51:44 -07:00
2009-05-18 15:14:27 -05:00
if ( action . summon . duration )
2011-08-18 14:55:27 -03:00
creature = me -> 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
2011-08-18 14:55:27 -03:00
creature = me -> 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
2011-08-18 14:55:27 -03:00
if ( ! creature )
sLog -> outErrorDb ( "CreatureEventAI: failed to spawn creature %u. Spawn event %d is on creature %d" , action . summon . creatureId , eventId , me -> GetEntry ());
2009-05-18 15:14:27 -05:00
else if ( action . summon . target != TARGET_T_SELF && target )
2011-08-18 14:55:27 -03:00
creature -> 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 :
2011-08-18 14:55:27 -03:00
if ( Unit * target = GetTargetByType ( action . threat_single_pct . target , actionInvoker ))
2010-04-14 23:07:41 +02:00
me -> getThreatManager (). modifyThreatPercent ( target , action . threat_single_pct . percent );
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_THREAT_ALL_PCT :
{
2010-04-14 23:07:41 +02:00
std :: list < HostileReference *>& threatList = me -> getThreatManager (). getThreatList ();
2010-03-09 11:11:10 +01:00
for ( std :: list < HostileReference *>:: iterator i = threatList . begin (); i != threatList . end (); ++ i )
2011-04-29 20:47:02 +02:00
if ( Unit * Temp = Unit :: GetUnit ( * me , ( * i ) -> getUnitGuid ()))
2010-04-14 23:07:41 +02:00
me -> getThreatManager (). modifyThreatPercent ( Temp , action . threat_all_pct . percent );
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_QUEST_EVENT :
2011-08-18 14:55:27 -03:00
if ( Unit * target = GetTargetByType ( action . quest_event . target , actionInvoker ))
2009-05-18 15:14:27 -05:00
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 :
2011-08-18 14:55:27 -03:00
if ( Unit * target = GetTargetByType ( action . cast_event . target , actionInvoker ))
2009-05-18 15:14:27 -05:00
if ( target -> GetTypeId () == TYPEID_PLAYER )
2010-04-14 23:07:41 +02:00
target -> ToPlayer () -> CastedCreatureOrGO ( action . cast_event . creatureId , me -> 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 :
{
2011-08-18 14:55:27 -03:00
Unit * target = GetTargetByType ( action . set_unit_field . target , actionInvoker );
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 :
2011-08-18 14:55:27 -03:00
if ( Unit * target = GetTargetByType ( action . unit_flag . target , actionInvoker ))
2009-05-18 15:14:27 -05:00
target -> SetFlag ( UNIT_FIELD_FLAGS , action . unit_flag . value );
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_REMOVE_UNIT_FLAG :
2011-08-18 14:55:27 -03:00
if ( Unit * target = GetTargetByType ( action . unit_flag . target , actionInvoker ))
2009-05-18 15:14:27 -05:00
target -> RemoveFlag ( UNIT_FIELD_FLAGS , action . unit_flag . value );
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_AUTO_ATTACK :
2010-08-16 17:07:02 +06:00
m_MeleeEnabled = action . auto_attack . state != 0 ;
2009-05-18 15:14:27 -05:00
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-08-16 17:07:02 +06:00
if ( m_CombatMovementEnabled == ( action . combat_movement . state != 0 ))
2009-05-31 16:24:19 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
m_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)
2010-08-16 17:07:02 +06:00
if ( m_CombatMovementEnabled )
2009-04-07 19:38:09 -05:00
{
2010-04-14 23:07:41 +02:00
Unit * victim = me -> getVictim ();
if ( me -> isInCombat () && victim )
2010-03-11 01:56:47 +01:00
{
if ( action . combat_movement . melee )
{
2010-12-17 13:43:24 +01:00
me -> AddUnitState ( UNIT_STAT_MELEE_ATTACKING );
2010-04-14 23:07:41 +02:00
me -> SendMeleeAttackStart ( victim );
2010-04-07 18:09:10 +02:00
}
2010-04-14 23:07:41 +02:00
if ( me -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == IDLE_MOTION_TYPE )
2010-08-16 17:07:02 +06:00
me -> GetMotionMaster () -> MoveChase ( victim , m_AttackDistance , m_AttackAngle ); // Targeted movement generator will start melee automatically, no need to send it explicitly
2010-03-11 01:56:47 +01:00
}
2009-04-07 19:38:09 -05:00
}
else
2010-04-07 18:09:10 +02:00
{
2010-04-14 23:07:41 +02:00
if ( me -> isInCombat ())
2010-03-11 01:56:47 +01:00
{
2010-04-14 23:07:41 +02:00
Unit * victim = me -> getVictim ();
2010-03-11 01:56:47 +01:00
if ( action . combat_movement . melee && victim )
{
2010-12-17 13:43:24 +01:00
me -> ClearUnitState ( UNIT_STAT_MELEE_ATTACKING );
2010-04-14 23:07:41 +02:00
me -> SendMeleeAttackStop ( victim );
2010-04-07 18:09:10 +02:00
}
2010-04-14 23:07:41 +02:00
if ( me -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == TARGETED_MOTION_TYPE )
me -> GetMotionMaster () -> MoveIdle ();
2010-03-11 01:56:47 +01:00
}
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 :
2010-08-16 17:07:02 +06:00
m_Phase = action . set_phase . phase ;
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_INC_PHASE :
{
2010-08-16 17:07:02 +06:00
int32 new_phase = int32 ( m_Phase ) + action . set_inc_phase . step ;
2009-05-18 15:14:27 -05:00
if ( new_phase < 0 )
{
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: Event %d decrease m_Phase under 0. CreatureEntry = %d" , eventId , me -> GetEntry ());
2010-08-16 17:07:02 +06:00
m_Phase = 0 ;
2009-05-18 15:14:27 -05:00
}
else if ( new_phase >= MAX_PHASE )
{
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: Event %d incremented m_Phase above %u. m_Phase mask cannot be used with phases past %u. CreatureEntry = %d" , eventId , MAX_PHASE - 1 , MAX_PHASE - 1 , me -> GetEntry ());
2010-08-16 17:07:02 +06:00
m_Phase = MAX_PHASE - 1 ;
2009-05-18 15:14:27 -05:00
}
2009-05-31 15:56:51 -05:00
else
2010-08-16 17:07:02 +06:00
m_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 :
2010-04-14 23:07:41 +02:00
me -> DoFleeToGetAssistance ();
2009-04-07 19:38:09 -05:00
break ;
case ACTION_T_QUEST_EVENT_ALL :
2011-08-18 14:55:27 -03:00
if ( actionInvoker && actionInvoker -> GetTypeId () == TYPEID_PLAYER )
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
if ( Unit * Temp = Unit :: GetUnit ( * me , actionInvoker -> GetGUID ()))
2009-05-18 15:14:27 -05:00
if ( Temp -> GetTypeId () == TYPEID_PLAYER )
2011-04-29 20:47:02 +02:00
Temp -> ToPlayer () -> GroupEventHappens ( action . quest_event_all . questId , me );
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-04-14 23:07:41 +02:00
std :: list < HostileReference *>& threatList = me -> getThreatManager (). getThreatList ();
2010-03-09 11:11:10 +01:00
for ( std :: list < HostileReference *>:: iterator i = threatList . begin (); i != threatList . end (); ++ i )
2011-04-29 20:47:02 +02:00
if ( Unit * Temp = Unit :: GetUnit ( * me , ( * i ) -> getUnitGuid ()))
2009-05-18 15:14:27 -05:00
if ( Temp -> GetTypeId () == TYPEID_PLAYER )
2010-04-14 23:07:41 +02:00
Temp -> ToPlayer () -> CastedCreatureOrGO ( action . cast_event_all . creatureId , me -> 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 :
2011-08-18 14:55:27 -03:00
if ( Unit * target = GetTargetByType ( action . remove_aura . target , actionInvoker ))
2009-05-18 15:14:27 -05:00
target -> RemoveAurasDueToSpell ( action . remove_aura . spellId );
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_RANGED_MOVEMENT :
2010-08-16 17:07:02 +06:00
m_AttackDistance = ( float ) action . ranged_movement . distance ;
m_AttackAngle = action . ranged_movement . angle / 180.0f * M_PI ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
if ( m_CombatMovementEnabled )
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
me -> GetMotionMaster () -> MoveChase ( me -> getVictim (), m_AttackDistance , m_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 :
2010-08-16 17:07:02 +06:00
m_Phase = GetRandActionParam ( rnd , action . random_phase . phase1 , action . random_phase . phase2 , action . random_phase . phase3 );
2009-05-18 15:14:27 -05:00
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 )
2010-08-16 17:07:02 +06:00
m_Phase = urand ( action . random_phase_range . phaseMin , action . random_phase_range . phaseMax );
2009-04-07 19:38:09 -05:00
else
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: ACTION_T_RANDOM_PHASE_RANGE cannot have Param2 < Param1. Event = %d. CreatureEntry = %d" , eventId , me -> GetEntry ());
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
case ACTION_T_SUMMON_ID :
{
2011-08-18 14:55:27 -03:00
Unit * target = GetTargetByType ( action . summon_id . target , actionInvoker );
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
CreatureEventAI_Summon_Map :: const_iterator i = sEventAIMgr -> GetCreatureEventAISummonMap (). find ( action . summon_id . spawnId );
if ( i == sEventAIMgr -> GetCreatureEventAISummonMap (). end ())
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03: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 , me -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Creature * creature = NULL ;
2009-04-07 19:38:09 -05:00
if (( * i ). second . SpawnTimeSecs )
2011-08-18 14:55:27 -03:00
creature = me -> 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 );
2009-05-18 15:14:27 -05:00
else
2011-08-18 14:55:27 -03:00
creature = me -> 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
2011-08-18 14:55:27 -03:00
if ( ! creature )
sLog -> outErrorDb ( "CreatureEventAI: failed to spawn creature %u. EventId %d.Creature %d" , action . summon_id . creatureId , eventId , me -> GetEntry ());
2009-05-18 15:14:27 -05:00
else if ( action . summon_id . target != TARGET_T_SELF && target )
2011-08-18 14:55:27 -03:00
creature -> 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
2011-08-18 14:55:27 -03:00
if ( Player * player = me -> GetLootRecipient ())
player -> RewardPlayerAndGroupAtEvent ( action . killed_monster . creatureId , player ); // player as param is a hacky solution not to use GUID
2009-04-07 19:38:09 -05:00
else
{
2011-08-18 14:55:27 -03:00
//if not available, use actionInvoker
if ( Unit * target = GetTargetByType ( action . killed_monster . target , actionInvoker ))
if ( Player * player2 = target -> GetCharmerOrOwnerPlayerOrPlayerItself ())
player2 -> RewardPlayerAndGroupAtEvent ( action . killed_monster . creatureId , player2 );
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 :
{
2011-08-18 14:55:27 -03:00
InstanceScript * instance = ( InstanceScript * ) me -> GetInstanceScript ();
if ( ! instance )
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: Event %d attempt to set instance data without instance script. Creature %d" , eventId , me -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
instance -> SetData ( action . set_inst_data . field , action . set_inst_data . value );
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_SET_INST_DATA64 :
{
2011-08-18 14:55:27 -03:00
Unit * target = GetTargetByType ( action . set_inst_data64 . target , actionInvoker );
2009-04-07 19:38:09 -05:00
if ( ! target )
{
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: Event %d attempt to set instance data64 but Target == NULL. Creature %d" , eventId , me -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
InstanceScript * instance = ( InstanceScript * ) me -> GetInstanceScript ();
if ( ! instance )
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: Event %d attempt to set instance data64 without instance script. Creature %d" , eventId , me -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
instance -> SetData64 ( action . set_inst_data64 . field , target -> GetGUID ());
2009-05-18 15:14:27 -05:00
break ;
2009-04-07 19:38:09 -05:00
}
case ACTION_T_UPDATE_TEMPLATE :
2010-04-14 23:07:41 +02:00
if ( me -> GetEntry () == action . update_template . creatureId )
2009-04-07 19:38:09 -05:00
{
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: Event %d ACTION_T_UPDATE_TEMPLATE call with param1 == current entry. Creature %d" , eventId , me -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
me -> 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 :
2010-04-14 23:07:41 +02:00
if ( me -> isDead ())
2009-04-07 19:38:09 -05:00
{
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: Event %d ACTION_T_DIE on dead creature. Creature %d" , eventId , me -> GetEntry ());
2009-04-07 19:38:09 -05:00
return ;
}
2010-04-14 23:07:41 +02:00
me -> Kill ( me );
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
{
2010-04-14 23:07:41 +02:00
me -> 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 :
{
2010-08-22 12:39:39 -07:00
me -> CallForHelp (( float ) 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
{
2011-04-29 20:47:02 +02:00
float x , y , z ;
2010-08-22 12:39:39 -07:00
me -> GetClosePoint ( x , y , z , me -> GetObjectSize () / 3 , ( float ) action . raw . param1 );
2011-04-29 20:47:02 +02:00
me -> GetMotionMaster () -> MovePoint ( 0 , x , y , z );
2009-11-13 16:26:01 +01:00
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 :
2010-11-16 01:13:04 +01:00
me -> SetVisible ( bool ( action . raw . param1 ));
2009-11-13 16:26:01 +01:00
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 :
{
2011-08-18 14:55:27 -03:00
GameObject * object = NULL ;
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
float x , y , z ;
me -> GetPosition ( x , y , z );
2011-08-18 14:55:27 -03:00
object = me -> SummonGameObject ( action . raw . param1 , x , y , z , 0 , 0 , 0 , 0 , 0 , action . raw . param2 );
if ( ! object )
2009-04-17 15:36:10 -05:00
{
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "TSCR: EventAI failed to spawn object %u. Spawn event %d is on creature %d" , action . raw . param1 , eventId , me -> 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 :
{
2010-04-14 23:07:41 +02:00
me -> SetSheath ( SheathState ( action . set_sheath . sheath ));
2009-05-28 18:43:57 -05:00
break ;
}
2009-06-18 17:05:01 -05:00
case ACTION_T_FORCE_DESPAWN :
{
2011-01-02 21:33:37 +01:00
me -> DespawnOrUnsummon ( 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 )
2010-08-26 01:20:57 +06:00
m_InvinceabilityHpLevel = me -> CountPctFromMaxHealth ( action . invincibility_hp_level . hp_level );
2009-07-30 10:53:16 +08:00
else
2010-08-16 17:07:02 +06:00
m_InvinceabilityHpLevel = action . invincibility_hp_level . hp_level ;
2009-07-30 10:53:16 +08:00
break ;
}
2010-08-24 10:34:35 -07:00
case ACTION_T_MOUNT_TO_ENTRY_OR_MODEL :
{
if ( action . mount . creatureId || action . mount . modelId )
{
// set model based on entry from creature_template
if ( action . mount . creatureId )
{
2011-04-28 22:57:08 +02:00
if ( CreatureTemplate const * cInfo = sObjectMgr -> GetCreatureTemplate ( action . mount . creatureId ))
2010-08-24 10:34:35 -07:00
{
2010-12-22 21:25:23 +01:00
uint32 display_id = sObjectMgr -> ChooseDisplayId ( 0 , cInfo );
2010-08-24 10:34:35 -07:00
me -> Mount ( display_id );
}
}
//if no param1, then use value from param2 (modelId)
else
me -> Mount ( action . mount . modelId );
}
else
me -> Unmount ();
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
2010-08-16 17:07:02 +06:00
if ( m_bEmptyList )
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
//Handle Spawned Events
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_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 ()
{
2010-08-16 17:07:02 +06:00
m_EventUpdateTime = EVENT_UPDATE_TIME ;
m_EventDiff = 0 ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
if ( m_bEmptyList )
2009-04-07 19:38:09 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2010-01-08 14:40:55 -03:00
{
if (( * i ). Event . event_type == EVENT_T_RESET )
ProcessEvent ( * i );
}
2009-04-07 19:38:09 -05:00
//Reset all events to enabled
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2009-04-07 19:38:09 -05:00
{
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 :
{
2011-04-29 20:47:02 +02:00
if (( * i ). UpdateRepeatTimer ( me , 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 ()
{
2010-08-16 17:07:02 +06:00
if ( ! m_bEmptyList )
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2009-04-07 19:38:09 -05:00
{
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
2010-08-16 17:07:02 +06:00
if ( m_bEmptyList )
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
//Handle Evade events
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2009-04-07 19:38:09 -05:00
{
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
2010-08-16 17:07:02 +06:00
if ( m_bEmptyList )
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
//Handle Evade events
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2009-04-07 19:38:09 -05:00
{
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
2010-08-16 17:07:02 +06:00
m_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 )
{
2010-08-16 17:07:02 +06:00
if ( m_bEmptyList || victim -> GetTypeId () != TYPEID_PLAYER )
2009-04-07 19:38:09 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2009-04-07 19:38:09 -05:00
{
if (( * i ). Event . event_type == EVENT_T_KILL )
ProcessEvent ( * i , victim );
}
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void CreatureEventAI :: JustSummoned ( Creature * unit )
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
if ( m_bEmptyList || ! unit )
2009-04-07 19:38:09 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2009-04-07 19:38:09 -05:00
{
if (( * i ). Event . event_type == EVENT_T_SUMMONED_UNIT )
2011-08-18 14:55:27 -03:00
ProcessEvent ( * i , unit );
2009-04-07 19:38:09 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void CreatureEventAI :: EnterCombat ( Unit * enemy )
2009-04-07 19:38:09 -05:00
{
//Check for on combat start events
2010-08-16 17:07:02 +06:00
if ( ! m_bEmptyList )
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2009-04-07 19:38:09 -05:00
{
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 :
2011-04-29 20:47:02 +02:00
if (( * i ). UpdateRepeatTimer ( me , 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
2010-08-16 17:07:02 +06:00
m_EventUpdateTime = EVENT_UPDATE_TIME ;
m_EventDiff = 0 ;
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void CreatureEventAI :: AttackStart ( Unit * who )
2009-04-07 19:38:09 -05:00
{
if ( ! who )
return ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
if ( me -> Attack ( who , m_MeleeEnabled ))
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
if ( m_CombatMovementEnabled )
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
me -> GetMotionMaster () -> MoveChase ( who , m_AttackDistance , m_AttackAngle );
2009-04-07 19:38:09 -05:00
}
else
{
2010-04-14 23:07:41 +02:00
me -> GetMotionMaster () -> MoveIdle ();
2009-04-07 19:38:09 -05:00
}
}
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
void CreatureEventAI :: MoveInLineOfSight ( Unit * who )
2009-04-07 19:38:09 -05:00
{
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
2010-08-16 17:07:02 +06:00
if ( ! m_bEmptyList )
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator itr = m_CreatureEventAIList . begin (); itr != m_CreatureEventAIList . end (); ++ itr )
2009-04-07 19:38:09 -05:00
{
if (( * itr ). Event . event_type == EVENT_T_OOC_LOS )
{
//can trigger if closer than fMaxAllowedRange
2010-08-22 12:39:39 -07:00
float fMaxAllowedRange = ( float )(( * 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
2010-04-14 23:07:41 +02:00
if ( me -> IsWithinDistInMap ( who , fMaxAllowedRange ) && me -> IsWithinLOSInMap ( who ))
2009-04-07 19:38:09 -05:00
{
//if friendly event&&who is not hostile OR hostile event&&who is hostile
2010-04-14 23:07:41 +02:00
if ((( * itr ). Event . ooc_los . noHostile && ! me -> IsHostileTo ( who )) ||
(( ! ( * itr ). Event . ooc_los . noHostile ) && me -> 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
2011-08-18 14:55:27 -03:00
void CreatureEventAI :: SpellHit ( Unit * unit , const SpellInfo * spell )
2009-04-07 19:38:09 -05:00
{
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
if ( m_bEmptyList )
2009-04-07 19:38:09 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2009-04-07 19:38:09 -05:00
if (( * i ). Event . event_type == EVENT_T_SPELLHIT )
//If spell id matches (or no spell id) & if spell school matches (or no spell school)
2011-08-18 14:55:27 -03:00
if ( ! ( * i ). Event . spell_hit . spellId || spell -> Id == ( * i ). Event . spell_hit . spellId )
if ( spell -> SchoolMask & ( * i ). Event . spell_hit . schoolMask )
ProcessEvent ( * i , unit );
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 :: 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
2010-08-16 17:07:02 +06:00
if ( ! m_bEmptyList )
2009-04-07 19:38:09 -05:00
{
//Events are only updated once every EVENT_UPDATE_TIME ms to prevent lag with large amount of events
2010-08-16 17:07:02 +06:00
if ( m_EventUpdateTime <= diff )
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
m_EventDiff += diff ;
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Check for time based events
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator i = m_CreatureEventAIList . begin (); i != m_CreatureEventAIList . end (); ++ i )
2009-04-07 19:38:09 -05:00
{
//Decrement Timers
if (( * i ). Time )
{
2010-08-16 17:07:02 +06:00
if ( m_EventDiff <= ( * i ). Time )
2009-04-07 19:38:09 -05:00
{
//Do not decrement timers if event cannot trigger in this phase
2010-08-16 17:07:02 +06:00
if ( ! (( * i ). Event . event_inverse_phase_mask & ( 1 << m_Phase )))
( * i ). Time -= m_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 ())
2010-04-14 23:07:41 +02:00
if ( me -> IsInMap ( me -> getVictim ()))
2011-04-29 20:47:02 +02:00
if ( me -> IsInRange ( me -> 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
2010-08-16 17:07:02 +06:00
m_EventDiff = 0 ;
m_EventUpdateTime = EVENT_UPDATE_TIME ;
2009-04-07 19:38:09 -05:00
}
else
{
2010-08-16 17:07:02 +06:00
m_EventDiff += diff ;
m_EventUpdateTime -= diff ;
2009-04-07 19:38:09 -05:00
}
}
2009-10-17 15:51:44 -07:00
2009-04-07 19:38:09 -05:00
//Melee Auto-Attack
2010-08-16 17:07:02 +06:00
if ( Combat && m_MeleeEnabled )
2009-04-07 19:38:09 -05:00
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
2011-08-18 14:55:27 -03:00
inline Unit * CreatureEventAI :: GetTargetByType ( uint32 target , Unit * actionInvoker )
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
switch ( target )
2009-04-07 19:38:09 -05:00
{
case TARGET_T_SELF :
2010-04-14 23:07:41 +02:00
return me ;
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE :
2010-04-14 23:07:41 +02:00
return me -> getVictim ();
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE_SECOND_AGGRO :
2011-04-29 20:47:02 +02:00
return SelectTarget ( SELECT_TARGET_TOPAGGRO , 1 );
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE_LAST_AGGRO :
2011-04-29 20:47:02 +02:00
return SelectTarget ( SELECT_TARGET_BOTTOMAGGRO , 0 );
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE_RANDOM :
2011-04-29 20:47:02 +02:00
return SelectTarget ( SELECT_TARGET_RANDOM , 0 );
2009-04-07 19:38:09 -05:00
case TARGET_T_HOSTILE_RANDOM_NOT_TOP :
2011-04-29 20:47:02 +02:00
return SelectTarget ( SELECT_TARGET_RANDOM , 1 );
2009-04-07 19:38:09 -05:00
case TARGET_T_ACTION_INVOKER :
2011-08-18 14:55:27 -03:00
return actionInvoker ;
2009-04-07 19:38:09 -05:00
default :
return NULL ;
};
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Unit * CreatureEventAI :: DoSelectLowestHpFriendly ( float range , uint32 minHPDiff )
2009-04-07 19:38:09 -05:00
{
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( me -> GetPositionX (), me -> GetPositionY ()));
2009-04-07 19:38:09 -05:00
Cell cell ( p );
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Unit * unit = NULL ;
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
Trinity :: MostHPMissingInRange u_check ( me , range , minHPDiff );
Trinity :: UnitLastSearcher < Trinity :: MostHPMissingInRange > searcher ( me , unit , 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-04-14 23:07:41 +02:00
cell . Visit ( p , grid_unit_searcher , * me -> GetMap (), * me , range );
2011-08-18 14:55:27 -03:00
return unit ;
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 :: DoFindFriendlyCC ( std :: list < Creature *>& _list , float range )
{
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( me -> GetPositionX (), me -> GetPositionY ()));
2009-04-07 19:38:09 -05:00
Cell cell ( p );
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
Trinity :: FriendlyCCedInRange u_check ( me , range );
Trinity :: CreatureListSearcher < Trinity :: FriendlyCCedInRange > searcher ( me , _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
2011-10-19 17:40:44 +01:00
cell . Visit ( p , grid_creature_searcher , * me -> GetMap (), * me , range );
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 )
{
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( me -> GetPositionX (), me -> GetPositionY ()));
2009-04-07 19:38:09 -05:00
Cell cell ( p );
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2010-04-14 23:07:41 +02:00
Trinity :: FriendlyMissingBuffInRange u_check ( me , range , spellid );
Trinity :: CreatureListSearcher < Trinity :: FriendlyMissingBuffInRange > searcher ( me , _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
2011-10-19 17:40:44 +01:00
cell . Visit ( p , grid_creature_searcher , * me -> GetMap (), * me , range );
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2011-01-16 12:23:17 +01:00
// *********************************
// *** Functions used globally ***
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
void CreatureEventAI :: DoScriptText ( int32 textEntry , WorldObject * source , Unit * target )
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
if ( ! source )
2009-04-07 19:38:09 -05:00
{
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "CreatureEventAI: DoScriptText entry %i, invalid Source pointer." , textEntry );
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 ( textEntry >= 0 )
{
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative." , source -> GetEntry (), source -> GetTypeId (), source -> GetGUIDLow (), textEntry );
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
CreatureEventAI_TextMap :: const_iterator i = sEventAIMgr -> GetCreatureEventAITextMap (). find ( textEntry );
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
if ( i == sEventAIMgr -> GetCreatureEventAITextMap (). end ())
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i." , source -> GetEntry (), source -> GetTypeId (), source -> GetGUIDLow (), textEntry );
2009-04-07 19:38:09 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
sLog -> outDebug ( LOG_FILTER_DATABASE_AI , "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 ))
2011-08-18 14:55:27 -03:00
source -> PlayDirectSound (( * i ). second . SoundId );
2009-04-07 19:38:09 -05:00
else
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "CreatureEventAI: DoScriptText entry %i tried to process invalid sound id %u." , textEntry , ( * i ). second . SoundId );
2009-04-07 19:38:09 -05:00
}
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
{
2011-08-18 14:55:27 -03:00
if ( source -> GetTypeId () == TYPEID_UNIT || source -> GetTypeId () == TYPEID_PLAYER )
2009-04-07 19:38:09 -05:00
{
2011-08-18 14:55:27 -03:00
(( Unit * ) source ) -> HandleEmoteCommand (( * i ). second . Emote );
2009-04-07 19:38:09 -05:00
}
else
2011-08-18 14:55:27 -03:00
sLog -> outErrorDb ( "CreatureEventAI: DoScriptText entry %i tried to process emote for invalid TypeId (%u)." , textEntry , source -> GetTypeId ());
2009-04-07 19:38:09 -05:00
}
2009-10-17 15:51:44 -07:00
2011-09-29 12:43:05 +02:00
switch (( * i ). second . Type )
2009-04-07 19:38:09 -05:00
{
case CHAT_TYPE_SAY :
2011-08-18 14:55:27 -03:00
source -> MonsterSay ( textEntry , ( * i ). second . Language , target ? target -> GetGUID () : 0 );
2009-04-07 19:38:09 -05:00
break ;
case CHAT_TYPE_YELL :
2011-08-18 14:55:27 -03:00
source -> MonsterYell ( textEntry , ( * i ). second . Language , target ? target -> GetGUID () : 0 );
2009-04-07 19:38:09 -05:00
break ;
case CHAT_TYPE_TEXT_EMOTE :
2011-08-18 14:55:27 -03:00
source -> MonsterTextEmote ( textEntry , target ? target -> GetGUID () : 0 );
2009-04-07 19:38:09 -05:00
break ;
case CHAT_TYPE_BOSS_EMOTE :
2011-08-18 14:55:27 -03:00
source -> MonsterTextEmote ( textEntry , target ? target -> GetGUID () : 0 , true );
2009-04-07 19:38:09 -05:00
break ;
case CHAT_TYPE_WHISPER :
{
if ( target && target -> GetTypeId () == TYPEID_PLAYER )
2011-08-18 14:55:27 -03:00
source -> MonsterWhisper ( textEntry , target -> GetGUID ());
2010-12-23 23:25:44 +01:00
else sLog -> outErrorDb ( "CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER)." , textEntry );
2009-04-07 19:38:09 -05:00
} break ;
case CHAT_TYPE_BOSS_WHISPER :
{
if ( target && target -> GetTypeId () == TYPEID_PLAYER )
2011-08-18 14:55:27 -03:00
source -> MonsterWhisper ( textEntry , target -> GetGUID (), true );
2010-12-23 23:25:44 +01:00
else sLog -> outErrorDb ( "CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER)." , textEntry );
2009-04-07 19:38:09 -05:00
} break ;
case CHAT_TYPE_ZONE_YELL :
2011-08-18 14:55:27 -03:00
source -> MonsterYellToZone ( textEntry , ( * i ). second . Language , target ? target -> GetGUID () : 0 );
2009-04-07 19:38:09 -05:00
break ;
}
}
2009-10-17 15:51:44 -07:00
2011-08-18 14:55:27 -03:00
bool CreatureEventAI :: CanCast ( Unit * target , SpellInfo const * spell , bool triggered )
2009-04-07 19:38:09 -05:00
{
//No target so we can't cast
2011-08-18 14:55:27 -03:00
if ( ! target || ! 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
//Silenced so we can't cast
2011-08-18 14:55:27 -03:00
if ( ! triggered && me -> HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SILENCED ))
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
//Check for power
2011-11-25 18:54:59 +01:00
if ( ! triggered && ( uint32 ) me -> GetPower (( Powers ) spell -> PowerType ) < spell -> CalcPowerCost ( me , spell -> GetSchoolMask ()))
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
//Unit is out of range of this spell
2011-08-18 14:55:27 -03:00
if ( ! me -> IsInRange ( target , spell -> GetMinRange ( false ), spell -> GetMaxRange ( false )))
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
2011-08-18 14:55:27 -03:00
void CreatureEventAI :: ReceiveEmote ( Player * player , uint32 textEmote )
2009-04-07 19:38:09 -05:00
{
2010-08-16 17:07:02 +06:00
if ( m_bEmptyList )
2009-04-15 17:29:33 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-08-16 17:07:02 +06:00
for ( CreatureEventAIList :: iterator itr = m_CreatureEventAIList . begin (); itr != m_CreatureEventAIList . end (); ++ itr )
2009-04-07 19:38:09 -05:00
{
if (( * itr ). Event . event_type == EVENT_T_RECEIVE_EMOTE )
{
2011-08-18 14:55:27 -03:00
if (( * itr ). Event . receive_emote . emoteId != textEmote )
2009-04-15 17:29:33 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-06-11 05:00:46 +03:00
Condition cond ;
2010-08-08 19:45:53 +02:00
cond . mConditionType = ConditionType (( * itr ). Event . receive_emote . condition );
2010-06-11 05:00:46 +03:00
cond . mConditionValue1 = ( * itr ). Event . receive_emote . conditionValue1 ;
cond . mConditionValue2 = ( * itr ). Event . receive_emote . conditionValue2 ;
2010-08-08 19:45:53 +02:00
2011-08-18 14:55:27 -03:00
if ( cond . Meets ( player ))
2009-04-07 19:38:09 -05:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_DATABASE_AI , "CreatureEventAI: ReceiveEmote CreatureEventAI: Condition ok, processing" );
2011-08-18 14:55:27 -03:00
ProcessEvent ( * itr , player );
2009-04-07 19:38:09 -05:00
}
}
}
}
2009-10-17 15:51:44 -07:00
2010-04-19 09:26:37 +02:00
void CreatureEventAI :: DamageTaken ( Unit * /*done_by*/ , uint32 & damage )
2009-07-30 10:53:16 +08:00
{
2010-08-16 17:07:02 +06:00
if ( m_InvinceabilityHpLevel > 0 && me -> GetHealth () < m_InvinceabilityHpLevel + damage )
2009-07-30 10:53:16 +08:00
{
2010-08-16 17:07:02 +06:00
if ( me -> GetHealth () <= m_InvinceabilityHpLevel )
2009-07-30 10:53:16 +08:00
damage = 0 ;
else
2010-08-16 17:07:02 +06:00
damage = me -> GetHealth () - m_InvinceabilityHpLevel ;
2009-07-30 10:53:16 +08:00
}
}
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
2010-04-14 23:07:41 +02:00
return me -> GetMapId () == event . spawned . conditionValue1 ;
2009-05-21 10:52:05 -05:00
case SPAWNED_EVENT_ZONE :
{
// zone ID check
uint32 zone , area ;
2011-04-29 20:47:02 +02:00
me -> GetZoneAndAreaId ( zone , area );
2009-05-21 10:52:05 -05:00
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 ;
}