2010-10-07 15:35:36 +02:00
/*
2012-12-31 23:15:50 +01:00
* Copyright (C) 2008-2013 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/>.
2008-10-11 14:16:25 -05:00
*/
2009-10-17 15:51:44 -07:00
2012-11-20 12:30:30 +01:00
#include "BattlegroundMgr.h"
#include "CellImpl.h"
2008-10-11 14:16:25 -05:00
#include "Common.h"
#include "CreatureAI.h"
#include "CreatureAISelector.h"
2012-11-20 12:30:30 +01:00
#include "CreatureGroups.h"
#include "Creature.h"
#include "DatabaseEnv.h"
2010-06-08 15:50:23 -06:00
#include "Formulas.h"
2012-11-20 12:30:30 +01:00
#include "GameEventMgr.h"
#include "GossipDef.h"
2010-06-08 15:50:23 -06:00
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
2010-11-29 07:50:31 +01:00
#include "Group.h"
2012-11-20 12:30:30 +01:00
#include "GroupMgr.h"
#include "InstanceScript.h"
#include "Log.h"
#include "LootMgr.h"
#include "MapManager.h"
2012-01-14 15:34:41 +01:00
#include "MoveSpline.h"
2012-11-20 12:30:30 +01:00
#include "MoveSplineInit.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "OutdoorPvPMgr.h"
#include "Player.h"
#include "PoolMgr.h"
#include "QuestDef.h"
#include "SpellAuraEffects.h"
#include "SpellMgr.h"
#include "TemporarySummon.h"
#include "Util.h"
#include "Vehicle.h"
#include "WaypointMovementGenerator.h"
#include "World.h"
#include "WorldPacket.h"
2008-10-11 14:16:25 -05:00
// apply implementation of the singletons
2010-06-25 00:18:01 +02:00
2008-10-11 14:16:25 -05:00
TrainerSpell const * TrainerSpellData :: Find ( uint32 spell_id ) const
{
2009-02-16 20:10:04 -06:00
TrainerSpellMap :: const_iterator itr = spellList . find ( spell_id );
if ( itr != spellList . end ())
return & itr -> second ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return NULL ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
bool VendorItemData :: RemoveItem ( uint32 item_id )
2008-10-11 14:16:25 -05:00
{
2010-04-30 22:35:37 +02:00
bool found = false ;
2010-05-05 14:30:53 +02:00
for ( VendorItemList :: iterator i = m_items . begin (); i != m_items . end ();)
2008-10-11 14:16:25 -05:00
{
2010-04-07 23:25:02 +02:00
if (( * i ) -> item == item_id )
2009-12-24 10:20:15 +01:00
{
2010-05-05 14:30:53 +02:00
i = m_items . erase ( i ++ );
2010-04-30 22:35:37 +02:00
found = true ;
2009-12-24 10:20:15 +01:00
}
2010-05-05 14:30:53 +02:00
else
++ i ;
2008-10-11 14:16:25 -05:00
}
2010-04-30 22:35:37 +02:00
return found ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-07-15 10:12:51 +02:00
VendorItem const * VendorItemData :: FindItemCostPair ( uint32 item_id , uint32 extendedCost ) const
2008-10-11 14:16:25 -05:00
{
2010-04-07 22:59:46 +02:00
for ( VendorItemList :: const_iterator i = m_items . begin (); i != m_items . end (); ++ i )
2011-06-12 02:30:32 +02:00
if (( * i ) -> item == item_id && ( * i ) -> ExtendedCost == extendedCost )
2009-12-24 10:20:15 +01:00
return * i ;
2008-10-11 14:16:25 -05:00
return NULL ;
}
2009-10-17 15:51:44 -07:00
2011-04-28 22:57:08 +02:00
uint32 CreatureTemplate :: GetRandomValidModelId () const
2008-10-27 11:48:45 -05:00
{
2009-09-24 11:26:27 -07:00
uint8 c = 0 ;
2008-10-27 11:48:45 -05:00
uint32 modelIDs [ 4 ];
2009-10-17 15:51:44 -07:00
2009-09-21 07:52:16 +02:00
if ( Modelid1 ) modelIDs [ c ++ ] = Modelid1 ;
if ( Modelid2 ) modelIDs [ c ++ ] = Modelid2 ;
if ( Modelid3 ) modelIDs [ c ++ ] = Modelid3 ;
if ( Modelid4 ) modelIDs [ c ++ ] = Modelid4 ;
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
return (( c > 0 ) ? modelIDs [ urand ( 0 , c - 1 )] : 0 );
2008-10-27 11:48:45 -05:00
}
2009-10-17 15:51:44 -07:00
2011-04-28 22:57:08 +02:00
uint32 CreatureTemplate :: GetFirstValidModelId () const
2008-10-27 11:48:45 -05:00
{
2010-04-07 19:14:10 +02:00
if ( Modelid1 ) return Modelid1 ;
if ( Modelid2 ) return Modelid2 ;
if ( Modelid3 ) return Modelid3 ;
if ( Modelid4 ) return Modelid4 ;
2008-10-27 11:48:45 -05:00
return 0 ;
}
2009-10-17 15:51:44 -07:00
2008-11-25 16:36:50 -06:00
bool AssistDelayEvent :: Execute ( uint64 /*e_time*/ , uint32 /*p_time*/ )
{
2010-04-07 19:14:10 +02:00
if ( Unit * victim = Unit :: GetUnit ( m_owner , m_victim ))
2008-11-25 16:36:50 -06:00
{
while ( ! m_assistants . empty ())
{
2009-04-11 13:42:34 -05:00
Creature * assistant = Unit :: GetCreature ( m_owner , * m_assistants . begin ());
2008-11-25 16:36:50 -06:00
m_assistants . pop_front ();
2009-10-17 15:51:44 -07:00
2008-11-25 16:36:50 -06:00
if ( assistant && assistant -> CanAssistTo ( & m_owner , victim ))
{
2008-12-01 12:59:39 -06:00
assistant -> SetNoCallAssistance ( true );
2008-11-25 16:36:50 -06:00
assistant -> CombatStart ( victim );
2010-04-07 19:14:10 +02:00
if ( assistant -> IsAIEnabled )
2008-11-25 16:36:50 -06:00
assistant -> AI () -> AttackStart ( victim );
}
}
}
return true ;
}
2009-10-17 15:51:44 -07:00
2010-03-03 02:48:31 +02:00
CreatureBaseStats const * CreatureBaseStats :: GetBaseStats ( uint8 level , uint8 unitClass )
2010-01-10 22:02:03 +01:00
{
2010-12-22 21:25:23 +01:00
return sObjectMgr -> GetCreatureBaseStats ( level , unitClass );
2010-01-10 22:02:03 +01:00
}
2010-01-16 19:51:59 +03:00
bool ForcedDespawnDelayEvent :: Execute ( uint64 /*e_time*/ , uint32 /*p_time*/ )
{
2012-04-24 16:53:37 +02:00
m_owner . DespawnOrUnsummon (); // since we are here, we are not TempSummon as object type cannot change during runtime
2010-01-16 19:51:59 +03:00
return true ;
}
2011-12-20 17:05:08 -05:00
Creature :: Creature ( bool isWorldObject ) : Unit ( isWorldObject ), MapCreature (),
2010-08-02 17:28:47 +02:00
lootForPickPocketed ( false ), lootForBody ( false ), m_groupLootTimer ( 0 ), lootingGroupLowGUID ( 0 ),
2012-02-16 21:46:37 +01:00
m_PlayerDamageReq ( 0 ), m_lootRecipient ( 0 ), m_lootRecipientGroup ( 0 ), m_corpseRemoveTime ( 0 ), m_respawnTime ( 0 ),
2010-08-21 20:08:47 +02:00
m_respawnDelay ( 300 ), m_corpseDelay ( 60 ), m_respawnradius ( 0.0f ), m_reactState ( REACT_AGGRESSIVE ),
2009-02-24 11:14:28 -06:00
m_defaultMovementType ( IDLE_MOTION_TYPE ), m_DBTableGuid ( 0 ), m_equipmentId ( 0 ), m_AlreadyCallAssistance ( false ),
2011-06-27 20:22:53 +02:00
m_AlreadySearchedAssistance ( false ), m_regenHealth ( true ), m_AI_locked ( false ), m_meleeDamageSchoolMask ( SPELL_SCHOOL_MASK_NORMAL ),
2012-02-16 13:56:08 +01:00
m_creatureInfo ( NULL ), m_creatureData ( NULL ), m_path_id ( 0 ), m_formation ( NULL )
2008-10-11 14:16:25 -05:00
{
2010-01-10 01:23:15 +01:00
m_regenTimer = CREATURE_REGEN_INTERVAL ;
2008-10-11 14:16:25 -05:00
m_valuesCount = UNIT_END ;
2009-10-17 15:51:44 -07:00
2009-11-17 23:56:54 -08:00
for ( uint8 i = 0 ; i < CREATURE_MAX_SPELLS ; ++ i )
2008-10-11 14:16:25 -05:00
m_spells [ i ] = 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_CreatureSpellCooldowns . clear ();
m_CreatureCategoryCooldowns . clear ();
2009-04-10 18:11:09 +02:00
DisableReputationGain = false ;
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
m_SightDistance = sWorld -> getFloatConfig ( CONFIG_SIGHT_MONSTER );
2009-08-23 16:27:00 -05:00
m_CombatDistance = 0 ; //MELEE_RANGE;
2009-10-28 16:31:19 -07:00
ResetLootMode (); // restore default loot mode
2010-11-03 18:33:47 +01:00
TriggerJustRespawned = false ;
2011-12-20 17:05:08 -05:00
m_isTempWorldObject = false ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
Creature ::~ Creature ()
{
m_vendorItemCounts . clear ();
2009-10-17 15:51:44 -07:00
2010-06-21 23:20:58 +02:00
delete i_AI ;
i_AI = NULL ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
//if (m_uint32Values)
2012-08-03 14:20:18 +02:00
// sLog->outError(LOG_FILTER_UNITS, "Deconstruct Creature Entry = %u", GetEntry());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: AddToWorld ()
{
///- Register the creature for guid lookup
2010-04-07 19:14:10 +02:00
if ( ! IsInWorld ())
2009-03-23 20:13:37 -06:00
{
2010-04-07 19:14:10 +02:00
if ( m_zoneScript )
2010-12-05 18:04:10 +01:00
m_zoneScript -> OnCreatureCreate ( this );
2010-12-23 23:25:44 +01:00
sObjectAccessor -> AddObject ( this );
2009-03-23 20:13:37 -06:00
Unit :: AddToWorld ();
2009-09-19 12:13:08 -07:00
SearchFormation ();
2009-04-06 20:33:52 -05:00
AIM_Initialize ();
2010-04-07 19:14:10 +02:00
if ( IsVehicle ())
2009-08-28 11:26:20 -05:00
GetVehicleKit () -> Install ();
2009-03-23 20:13:37 -06:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: RemoveFromWorld ()
{
2010-04-07 19:14:10 +02:00
if ( IsInWorld ())
2009-03-23 20:13:37 -06:00
{
2010-04-07 19:14:10 +02:00
if ( m_zoneScript )
2010-12-05 18:04:10 +01:00
m_zoneScript -> OnCreatureRemove ( this );
2010-04-07 19:14:10 +02:00
if ( m_formation )
2012-03-25 09:25:28 -05:00
sFormationMgr -> RemoveCreatureFromGroup ( m_formation , this );
2009-03-23 20:13:37 -06:00
Unit :: RemoveFromWorld ();
2010-12-23 23:25:44 +01:00
sObjectAccessor -> RemoveObject ( this );
2009-03-23 20:13:37 -06:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-08-14 22:26:07 -05:00
void Creature :: DisappearAndDie ()
{
2009-08-28 11:26:20 -05:00
DestroyForNearbyPlayers ();
//SetVisibility(VISIBILITY_OFF);
//ObjectAccessor::UpdateObjectVisibility(this);
2010-04-07 19:14:10 +02:00
if ( isAlive ())
2009-08-26 19:28:21 -05:00
setDeathState ( JUST_DIED );
2010-09-15 06:22:54 +02:00
RemoveCorpse ( false );
2009-08-14 22:26:07 -05:00
}
2009-10-17 15:51:44 -07:00
2009-09-19 12:13:08 -07:00
void Creature :: SearchFormation ()
2008-12-15 00:07:21 +02:00
{
2010-04-07 19:14:10 +02:00
if ( isSummon ())
2009-04-04 15:04:24 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-02-09 08:16:34 -05:00
uint32 lowguid = GetDBTableGUIDLow ();
2010-04-07 19:14:10 +02:00
if ( ! lowguid )
2009-04-06 13:27:42 -05:00
return ;
2009-10-17 15:51:44 -07:00
2012-03-25 09:25:28 -05:00
CreatureGroupInfoType :: iterator frmdata = sFormationMgr -> CreatureGroupMap . find ( lowguid );
if ( frmdata != sFormationMgr -> CreatureGroupMap . end ())
sFormationMgr -> AddCreatureToGroup ( frmdata -> second -> leaderGUID , this );
2008-12-15 00:07:21 +02:00
}
2009-10-17 15:51:44 -07:00
2010-09-15 06:22:54 +02:00
void Creature :: RemoveCorpse ( bool setSpawnTime )
2008-10-11 14:16:25 -05:00
{
2011-06-27 20:22:53 +02:00
if ( getDeathState () != CORPSE )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-09-15 06:22:54 +02:00
m_corpseRemoveTime = time ( NULL );
2008-10-11 14:16:25 -05:00
setDeathState ( DEAD );
2011-07-12 00:19:50 +02:00
RemoveAllAuras ();
2010-02-03 16:53:40 +02:00
UpdateObjectVisibility ();
2008-10-11 14:16:25 -05:00
loot . clear ();
2009-10-09 20:48:55 -07:00
uint32 respawnDelay = m_respawnDelay ;
2009-12-06 16:41:05 +01:00
if ( IsAIEnabled )
2009-10-09 20:48:55 -07:00
AI () -> CorpseRemoved ( respawnDelay );
2009-10-17 15:51:44 -07:00
2010-09-15 06:22:54 +02:00
// Should get removed later, just keep "compatibility" with scripts
2011-06-12 02:30:32 +02:00
if ( setSpawnTime )
2010-09-15 06:22:54 +02:00
m_respawnTime = time ( NULL ) + respawnDelay ;
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
float x , y , z , o ;
2011-10-18 10:53:34 -04:00
GetRespawnPosition ( x , y , z , & o );
2011-04-29 20:47:02 +02:00
SetHomePosition ( x , y , z , o );
GetMap () -> CreatureRelocation ( this , x , y , z , o );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/**
* change the entry of creature until respawn
*/
2011-09-15 14:08:17 +02:00
bool Creature :: InitEntry ( uint32 Entry , uint32 /*team*/ , const CreatureData * data )
2008-10-11 14:16:25 -05:00
{
2011-09-15 14:08:17 +02:00
CreatureTemplate const * normalInfo = sObjectMgr -> GetCreatureTemplate ( Entry );
2010-04-07 19:14:10 +02:00
if ( ! normalInfo )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SQL , "Creature::InitEntry creature entry %u does not exist." , Entry );
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2009-12-17 11:06:50 +01:00
// get difficulty 1 mode entry
2011-09-15 14:08:17 +02:00
CreatureTemplate const * cinfo = normalInfo ;
2011-02-04 15:45:59 +01:00
for ( uint8 diff = uint8 ( GetMap () -> GetSpawnMode ()); diff > 0 ;)
2008-10-11 14:16:25 -05:00
{
2011-02-04 15:45:59 +01:00
// we already have valid Map pointer for current creature!
if ( normalInfo -> DifficultyEntry [ diff - 1 ])
2008-10-11 14:16:25 -05:00
{
2011-04-28 22:57:08 +02:00
cinfo = sObjectMgr -> GetCreatureTemplate ( normalInfo -> DifficultyEntry [ diff - 1 ]);
2011-02-04 15:45:59 +01:00
if ( cinfo )
break ; // template found
// check and reported at startup, so just ignore (restore normalInfo)
cinfo = normalInfo ;
2008-10-11 14:16:25 -05:00
}
2011-02-04 15:45:59 +01:00
// for instances heroic to normal, other cases attempt to retrieve previous difficulty
2011-02-07 13:11:45 +01:00
if ( diff >= RAID_DIFFICULTY_10MAN_HEROIC && GetMap () -> IsRaid ())
2011-02-04 15:45:59 +01:00
diff -= 2 ; // to normal raid difficulty cases
else
-- diff ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2013-02-13 20:24:23 +01:00
// Initialize loot duplicate count depending on raid difficulty
if ( GetMap () -> IsRaid () && GetMap () -> GetSpawnMode () & RAID_DIFFICULTY_MASK_25MAN )
loot . maxDuplicates = 3 ;
2008-11-20 16:16:57 -06:00
SetEntry ( Entry ); // normal entry always
2008-10-11 14:16:25 -05:00
m_creatureInfo = cinfo ; // map mode related always
2009-10-17 15:51:44 -07:00
2009-05-29 21:24:23 -05:00
// equal to player Race field, but creature does not have race
SetByteValue ( UNIT_FIELD_BYTES_0 , 0 , 0 );
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
// known valid are: CLASS_WARRIOR, CLASS_PALADIN, CLASS_ROGUE, CLASS_MAGE
2009-05-29 21:24:23 -05:00
SetByteValue ( UNIT_FIELD_BYTES_0 , 1 , uint8 ( cinfo -> unit_class ));
2009-10-17 15:51:44 -07:00
2008-10-27 11:48:45 -05:00
// Cancel load if no model defined
if ( ! ( cinfo -> GetFirstValidModelId ()))
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SQL , "Creature (Entry: %u) has no model defined in table `creature_template`, can't load. " , Entry );
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2012-02-27 14:58:47 +01:00
uint32 displayID = sObjectMgr -> ChooseDisplayId ( 0 , GetCreatureTemplate (), data );
2011-09-15 14:08:17 +02:00
CreatureModelInfo const * minfo = sObjectMgr -> GetCreatureModelRandomGender ( & displayID );
2009-06-15 18:02:12 -05:00
if ( ! minfo ) // Cancel load if no model defined
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SQL , "Creature (Entry: %u) has no model defined in table `creature_template`, can't load. " , Entry );
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-04-28 22:11:45 +02:00
SetDisplayId ( displayID );
SetNativeDisplayId ( displayID );
2008-10-11 14:16:25 -05:00
SetByteValue ( UNIT_FIELD_BYTES_0 , 2 , minfo -> gender );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Load creature equipment
2011-02-18 19:48:47 +01:00
if ( ! data || data -> equipmentId == 0 ) // use default from the template
2008-10-11 14:16:25 -05:00
LoadEquipment ( cinfo -> equipmentId );
2011-02-18 19:48:47 +01:00
else if ( data && data -> equipmentId != - 1 ) // override, -1 means no equipment
2008-10-11 14:16:25 -05:00
LoadEquipment ( data -> equipmentId );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SetName ( normalInfo -> Name ); // at normal entry always
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
SetFloatValue ( UNIT_FIELD_BOUNDINGRADIUS , minfo -> bounding_radius );
SetFloatValue ( UNIT_FIELD_COMBATREACH , minfo -> combat_reach );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SetFloatValue ( UNIT_MOD_CAST_SPEED , 1.0f );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
SetSpeed ( MOVE_WALK , cinfo -> speed_walk );
SetSpeed ( MOVE_RUN , cinfo -> speed_run );
2010-03-21 14:57:49 -03:00
SetSpeed ( MOVE_SWIM , 1.0f ); // using 1.0 rate
SetSpeed ( MOVE_FLIGHT , 1.0f ); // using 1.0 rate
2009-10-17 15:51:44 -07:00
2012-05-26 23:00:54 +02:00
SetObjectScale ( cinfo -> scale );
2012-03-12 00:45:58 +01:00
SetFloatValue ( UNIT_FIELD_HOVERHEIGHT , cinfo -> HoverHeight );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// checked at loading
m_defaultMovementType = MovementGeneratorType ( cinfo -> MovementType );
2010-04-07 23:25:02 +02:00
if ( ! m_respawnradius && m_defaultMovementType == RANDOM_MOTION_TYPE )
2008-10-11 14:16:25 -05:00
m_defaultMovementType = IDLE_MOTION_TYPE ;
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( uint8 i = 0 ; i < CREATURE_MAX_SPELLS ; ++ i )
2012-02-27 14:58:47 +01:00
m_spells [ i ] = GetCreatureTemplate () -> spells [ i ];
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
bool Creature :: UpdateEntry ( uint32 Entry , uint32 team , const CreatureData * data )
2008-10-11 14:16:25 -05:00
{
2011-04-29 20:47:02 +02:00
if ( ! InitEntry ( Entry , team , data ))
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2012-02-27 14:58:47 +01:00
CreatureTemplate const * cInfo = GetCreatureTemplate ();
2010-01-10 22:02:03 +01:00
m_regenHealth = cInfo -> RegenHealth ;
2009-10-17 15:51:44 -07:00
2012-04-18 12:44:56 +02:00
// creatures always have melee weapon ready if any unless specified otherwise
if ( ! GetCreatureAddon ())
SetSheath ( SHEATH_STATE_MELEE );
2009-10-17 15:51:44 -07:00
2012-02-27 14:58:47 +01:00
SelectLevel ( GetCreatureTemplate ());
2008-10-11 14:16:25 -05:00
if ( team == HORDE )
2010-01-10 22:02:03 +01:00
setFaction ( cInfo -> faction_H );
2008-10-11 14:16:25 -05:00
else
2010-01-10 22:02:03 +01:00
setFaction ( cInfo -> faction_A );
2009-10-17 15:51:44 -07:00
2010-10-09 17:52:00 +02:00
uint32 npcflag , unit_flags , dynamicflags ;
ObjectMgr :: ChooseCreatureFlags ( cInfo , npcflag , unit_flags , dynamicflags , data );
2010-04-07 19:14:10 +02:00
if ( cInfo -> flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT )
2010-12-22 21:25:23 +01:00
SetUInt32Value ( UNIT_NPC_FLAGS , npcflag | sGameEventMgr -> GetNPCFlag ( this ));
2008-10-14 11:57:03 -05:00
else
2010-10-09 17:52:00 +02:00
SetUInt32Value ( UNIT_NPC_FLAGS , npcflag );
2009-10-17 15:51:44 -07:00
2010-01-10 22:02:03 +01:00
SetAttackTime ( BASE_ATTACK , cInfo -> baseattacktime );
SetAttackTime ( OFF_ATTACK , cInfo -> baseattacktime );
2011-04-29 20:47:02 +02:00
SetAttackTime ( RANGED_ATTACK , cInfo -> rangeattacktime );
2009-10-17 15:51:44 -07:00
2010-10-09 17:52:00 +02:00
SetUInt32Value ( UNIT_FIELD_FLAGS , unit_flags );
2012-08-30 04:52:35 +02:00
SetUInt32Value ( UNIT_FIELD_FLAGS_2 , cInfo -> unit_flags2 );
2010-10-09 17:52:00 +02:00
SetUInt32Value ( UNIT_DYNAMIC_FLAGS , dynamicflags );
2009-10-17 15:51:44 -07:00
2009-01-28 00:25:06 -06:00
RemoveFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_IN_COMBAT );
2009-10-17 15:51:44 -07:00
2010-01-10 22:02:03 +01:00
SetMeleeDamageSchool ( SpellSchools ( cInfo -> dmgschool ));
2010-12-22 21:25:23 +01:00
CreatureBaseStats const * stats = sObjectMgr -> GetCreatureBaseStats ( getLevel (), cInfo -> unit_class );
2010-08-22 12:39:39 -07:00
float armor = ( float ) stats -> GenerateArmor ( cInfo ); // TODO: Why is this treated as uint32 when it's a float?
2010-01-10 22:02:03 +01:00
SetModifierValue ( UNIT_MOD_ARMOR , BASE_VALUE , armor );
2011-04-28 22:57:08 +02:00
SetModifierValue ( UNIT_MOD_RESISTANCE_HOLY , BASE_VALUE , float ( cInfo -> resistance [ SPELL_SCHOOL_HOLY ]));
SetModifierValue ( UNIT_MOD_RESISTANCE_FIRE , BASE_VALUE , float ( cInfo -> resistance [ SPELL_SCHOOL_FIRE ]));
SetModifierValue ( UNIT_MOD_RESISTANCE_NATURE , BASE_VALUE , float ( cInfo -> resistance [ SPELL_SCHOOL_NATURE ]));
SetModifierValue ( UNIT_MOD_RESISTANCE_FROST , BASE_VALUE , float ( cInfo -> resistance [ SPELL_SCHOOL_FROST ]));
SetModifierValue ( UNIT_MOD_RESISTANCE_SHADOW , BASE_VALUE , float ( cInfo -> resistance [ SPELL_SCHOOL_SHADOW ]));
SetModifierValue ( UNIT_MOD_RESISTANCE_ARCANE , BASE_VALUE , float ( cInfo -> resistance [ SPELL_SCHOOL_ARCANE ]));
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SetCanModifyStats ( true );
UpdateAllStats ();
2009-10-17 15:51:44 -07:00
2009-12-19 19:10:14 +01:00
// checked and error show at loading templates
2010-01-10 22:02:03 +01:00
if ( FactionTemplateEntry const * factionTemplate = sFactionTemplateStore . LookupEntry ( cInfo -> faction_A ))
2008-10-11 14:16:25 -05:00
{
2009-12-19 19:10:14 +01:00
if ( factionTemplate -> factionFlags & FACTION_TEMPLATE_FLAG_PVP )
SetPvP ( true );
else
SetPvP ( false );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2012-12-05 23:34:50 +02:00
// updates spell bars for vehicles and set player's faction - should be called here, to overwrite faction that is set from the new template
if ( IsVehicle ())
2012-12-17 05:39:04 +01:00
{
2012-12-05 23:34:50 +02:00
if ( Player * owner = Creature :: GetCharmerOrOwnerPlayerOrPlayerItself ()) // this check comes in case we don't have a player
2012-12-17 05:39:04 +01:00
{
2012-12-05 23:34:50 +02:00
setFaction ( owner -> getFaction ()); // vehicles should have same as owner faction
2012-12-17 05:39:04 +01:00
owner -> VehicleSpellInitialize ();
2012-12-05 23:34:50 +02:00
}
}
2010-04-21 13:55:43 +02:00
// trigger creature is always not selectable and can not be attacked
2010-04-07 19:14:10 +02:00
if ( isTrigger ())
2008-11-06 10:27:58 -06:00
SetFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_NOT_SELECTABLE );
2009-10-17 15:51:44 -07:00
2010-06-27 03:47:18 +02:00
InitializeReactState ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( cInfo -> flags_extra & CREATURE_FLAG_EXTRA_NO_TAUNT )
2009-01-27 15:23:26 -06:00
{
ApplySpellImmune ( 0 , IMMUNITY_STATE , SPELL_AURA_MOD_TAUNT , true );
2011-04-29 20:47:02 +02:00
ApplySpellImmune ( 0 , IMMUNITY_EFFECT , SPELL_EFFECT_ATTACK_ME , true );
2009-01-27 15:23:26 -06:00
}
2009-10-17 15:51:44 -07:00
2012-12-27 19:31:22 +01:00
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
float ground = GetPositionZ ();
GetMap () -> GetWaterOrGroundLevel ( GetPositionX (), GetPositionY (), GetPositionZ (), & ground );
2012-03-12 00:45:58 +01:00
2012-12-29 14:23:23 -05:00
bool isInAir = G3D :: fuzzyGt ( GetPositionZ (), ground + 0.05f ) || G3D :: fuzzyLt ( GetPositionZ (), ground - 0.05f ); // Can be underground too, prevent the falling
2012-03-23 00:48:32 +01:00
2012-12-27 19:31:22 +01:00
if ( cInfo -> InhabitType & INHABIT_AIR && cInfo -> InhabitType & INHABIT_GROUND && isInAir )
SetCanFly ( true );
else if ( cInfo -> InhabitType & INHABIT_AIR && isInAir )
SetDisableGravity ( true );
else
{
SetCanFly ( false );
SetDisableGravity ( false );
}
2012-03-12 00:45:58 +01:00
2012-12-27 19:31:22 +01:00
if ( cInfo -> InhabitType & INHABIT_WATER && IsInWater ())
AddUnitMovementFlag ( MOVEMENTFLAG_SWIMMING );
else
RemoveUnitMovementFlag ( MOVEMENTFLAG_SWIMMING );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: Update ( uint32 diff )
{
2010-11-03 18:33:47 +01:00
if ( IsAIEnabled && TriggerJustRespawned )
{
TriggerJustRespawned = false ;
AI () -> JustRespawned ();
2011-04-22 21:59:37 +02:00
if ( m_vehicleKit )
m_vehicleKit -> Reset ();
2010-11-03 18:33:47 +01:00
}
2012-01-14 15:34:41 +01:00
if ( IsInWater ())
{
if ( canSwim ())
AddUnitMovementFlag ( MOVEMENTFLAG_SWIMMING );
}
else
{
if ( canWalk ())
RemoveUnitMovementFlag ( MOVEMENTFLAG_SWIMMING );
}
2012-12-29 04:01:46 +01:00
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
float ground = GetPositionZ ();
GetMap () -> GetWaterOrGroundLevel ( GetPositionX (), GetPositionY (), GetPositionZ (), & ground );
2012-12-29 14:23:23 -05:00
bool isInAir = G3D :: fuzzyGt ( GetPositionZ (), ground + 0.05f ) || G3D :: fuzzyLt ( GetPositionZ (), ground - 0.05f ); // Can be underground too, prevent the falling
2012-12-29 04:01:46 +01:00
CreatureTemplate const * cinfo = GetCreatureTemplate ();
if ( cinfo -> InhabitType & INHABIT_AIR && cinfo -> InhabitType & INHABIT_GROUND && isInAir )
SetCanFly ( true );
else if ( cinfo -> InhabitType & INHABIT_AIR && isInAir )
SetDisableGravity ( true );
else
{
SetCanFly ( false );
SetDisableGravity ( false );
}
2011-09-29 12:43:05 +02:00
switch ( m_deathState )
2008-10-11 14:16:25 -05:00
{
2012-05-13 11:33:42 -02:30
case JUST_RESPAWNED :
// Must not be called, see Creature::setDeathState JUST_RESPAWNED -> ALIVE promoting.
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "Creature (GUID: %u Entry: %u) in wrong state: JUST_RESPAWNED (4)" , GetGUIDLow (), GetEntry ());
2008-10-11 14:16:25 -05:00
break ;
case JUST_DIED :
2011-07-29 14:18:28 +02:00
// Must not be called, see Creature::setDeathState JUST_DIED -> CORPSE promoting.
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "Creature (GUID: %u Entry: %u) in wrong state: JUST_DEAD (1)" , GetGUIDLow (), GetEntry ());
2008-10-11 14:16:25 -05:00
break ;
case DEAD :
{
2010-12-24 16:18:23 +01:00
time_t now = time ( NULL );
if ( m_respawnTime <= now )
2008-10-11 14:16:25 -05:00
{
2010-12-24 16:18:23 +01:00
bool allowed = IsAIEnabled ? AI () -> CanRespawn () : true ; // First check if there are any scripts that object to us respawning
if ( ! allowed ) // Will be rechecked on next Update call
break ;
2010-12-25 02:22:35 +01:00
uint64 dbtableHighGuid = MAKE_NEW_GUID ( m_DBTableGuid , GetEntry (), HIGHGUID_UNIT );
2012-06-07 23:20:57 +02:00
time_t linkedRespawntime = GetMap () -> GetLinkedRespawnTime ( dbtableHighGuid );
2010-12-24 18:55:50 +01:00
if ( ! linkedRespawntime ) // Can respawn
2009-04-14 14:33:48 +02:00
Respawn ();
2010-12-24 16:18:23 +01:00
else // the master is dead
2008-10-11 14:16:25 -05:00
{
2011-05-16 15:36:02 +02:00
uint64 targetGuid = sObjectMgr -> GetLinkedRespawnGuid ( dbtableHighGuid );
if ( targetGuid == dbtableHighGuid ) // if linking self, never respawn (check delayed to next day)
2010-12-24 18:55:50 +01:00
SetRespawnTime ( DAY );
2009-04-14 14:33:48 +02:00
else
2011-04-29 20:47:02 +02:00
m_respawnTime = ( now > linkedRespawntime ? now : linkedRespawntime ) + urand ( 5 , MINUTE ); // else copy time from master and add a little
2010-12-24 18:55:50 +01:00
SaveRespawnTime (); // also save to DB immediately
2008-10-11 14:16:25 -05:00
}
}
break ;
}
case CORPSE :
{
2012-01-14 15:34:41 +01:00
Unit :: Update ( diff );
2011-07-12 00:19:50 +02:00
// deathstate changed on spells update, prevent problems
if ( m_deathState != CORPSE )
break ;
2010-08-02 17:28:47 +02:00
if ( m_groupLootTimer && lootingGroupLowGUID )
2010-03-11 22:55:02 +01:00
{
if ( m_groupLootTimer <= diff )
{
2011-05-05 10:23:00 +02:00
Group * group = sGroupMgr -> GetGroupByGUID ( lootingGroupLowGUID );
2010-03-11 22:55:02 +01:00
if ( group )
group -> EndRoll ( & loot );
m_groupLootTimer = 0 ;
2010-08-02 17:28:47 +02:00
lootingGroupLowGUID = 0 ;
2010-03-11 22:55:02 +01:00
}
else m_groupLootTimer -= diff ;
}
2010-09-15 06:22:54 +02:00
else if ( m_corpseRemoveTime <= time ( NULL ))
2008-10-11 14:16:25 -05:00
{
2010-09-15 06:22:54 +02:00
RemoveCorpse ( false );
2012-08-03 14:20:18 +02:00
sLog -> outDebug ( LOG_FILTER_UNITS , "Removing corpse... %u " , GetUInt32Value ( OBJECT_FIELD_ENTRY ));
2008-10-11 14:16:25 -05:00
}
break ;
}
case ALIVE :
{
2010-04-07 22:59:46 +02:00
Unit :: Update ( diff );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// creature can be dead after Unit::Update call
// CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
2010-04-07 19:14:10 +02:00
if ( ! isAlive ())
2008-10-11 14:16:25 -05:00
break ;
2009-10-17 15:51:44 -07:00
2009-03-12 14:15:44 -06:00
// if creature is charmed, switch to charmed AI
2010-04-07 19:14:10 +02:00
if ( NeedChangeAI )
2009-03-13 17:48:57 -06:00
{
UpdateCharmAI ();
NeedChangeAI = false ;
IsAIEnabled = true ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! IsInEvadeMode () && IsAIEnabled )
2008-10-11 14:16:25 -05:00
{
// do not allow the AI to be changed during update
m_AI_locked = true ;
2008-11-20 16:16:57 -06:00
i_AI -> UpdateAI ( diff );
2008-10-11 14:16:25 -05:00
m_AI_locked = false ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// creature can be dead after UpdateAI call
// CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
2010-04-07 19:14:10 +02:00
if ( ! isAlive ())
2008-10-11 14:16:25 -05:00
break ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( m_regenTimer > 0 )
2009-10-10 16:26:00 -07:00
{
2010-04-07 19:14:10 +02:00
if ( diff >= m_regenTimer )
2009-10-10 16:26:00 -07:00
m_regenTimer = 0 ;
else
m_regenTimer -= diff ;
}
2009-10-17 15:51:44 -07:00
2009-10-10 16:26:00 -07:00
if ( m_regenTimer != 0 )
break ;
2009-10-17 15:51:44 -07:00
2009-09-27 19:11:52 -07:00
bool bInCombat = isInCombat () && ( ! getVictim () || // if isInCombat() is true and this has no victim
! getVictim () -> GetCharmerOrOwnerPlayerOrPlayerItself () || // or the victim/owner/charmer is not a player
! getVictim () -> GetCharmerOrOwnerPlayerOrPlayerItself () -> isGameMaster ()); // or the victim/owner/charmer is not a GameMaster
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
/*if (m_regenTimer <= diff)
2009-10-10 16:26:00 -07:00
{*/
2010-11-14 04:20:32 +01:00
if ( ! IsInEvadeMode () && ( ! bInCombat || IsPolymorphed ())) // regenerate health if not in combat or if polymorphed
2009-10-10 16:26:00 -07:00
RegenerateHealth ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( getPowerType () == POWER_ENERGY )
2009-10-10 16:26:00 -07:00
{
2010-04-07 19:14:10 +02:00
if ( ! IsVehicle () || GetVehicleKit () -> GetVehicleInfo () -> m_powerType != POWER_PYRITE )
2009-10-10 16:26:00 -07:00
Regenerate ( POWER_ENERGY );
2009-08-23 22:36:51 -05:00
}
2009-10-10 16:26:00 -07:00
else
RegenerateMana ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
/*if (!bIsPolymorphed) // only increase the timer if not polymorphed
2010-01-10 01:23:15 +01:00
m_regenTimer += CREATURE_REGEN_INTERVAL - diff;
2009-10-17 16:20:24 -07:00
}
2009-10-10 16:26:00 -07:00
else
2010-04-07 19:14:10 +02:00
if (!bIsPolymorphed) // if polymorphed, skip the timer
2009-10-10 16:26:00 -07:00
m_regenTimer -= diff;*/
2010-01-10 01:23:15 +01:00
m_regenTimer = CREATURE_REGEN_INTERVAL ;
2008-10-11 14:16:25 -05:00
break ;
}
default :
break ;
}
2010-08-06 19:23:43 +02:00
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnCreatureUpdate ( this , diff );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: RegenerateMana ()
{
uint32 curValue = GetPower ( POWER_MANA );
uint32 maxValue = GetMaxPower ( POWER_MANA );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( curValue >= maxValue )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 addvalue = 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// Combat and any controlled creature
if ( isInCombat () || GetCharmerOrOwnerGUID ())
{
2010-04-07 19:14:10 +02:00
if ( ! IsUnderLastManaUseEffect ())
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
float ManaIncreaseRate = sWorld -> getRate ( RATE_POWER_MANA );
2008-10-11 14:16:25 -05:00
float Spirit = GetStat ( STAT_SPIRIT );
2009-10-17 15:51:44 -07:00
2010-12-11 20:37:38 +06:00
addvalue = uint32 (( Spirit / 5.0f + 17.0f ) * ManaIncreaseRate );
2008-10-11 14:16:25 -05:00
}
}
else
2010-12-11 20:37:38 +06:00
addvalue = maxValue / 3 ;
2009-10-17 15:51:44 -07:00
2010-01-10 01:23:15 +01:00
// Apply modifiers (if any).
AuraEffectList const & ModPowerRegenPCTAuras = GetAuraEffectsByType ( SPELL_AURA_MOD_POWER_REGEN_PERCENT );
for ( AuraEffectList :: const_iterator i = ModPowerRegenPCTAuras . begin (); i != ModPowerRegenPCTAuras . end (); ++ i )
if (( * i ) -> GetMiscValue () == POWER_MANA )
2012-10-02 12:17:42 +02:00
AddPct ( addvalue , ( * i ) -> GetAmount ());
2010-01-10 01:23:15 +01:00
2010-07-12 00:30:17 +02:00
addvalue += GetTotalAuraModifierByMiscValue ( SPELL_AURA_MOD_POWER_REGEN , POWER_MANA ) * CREATURE_REGEN_INTERVAL / ( 5 * IN_MILLISECONDS );
2010-01-10 01:23:15 +01:00
2008-10-11 14:16:25 -05:00
ModifyPower ( POWER_MANA , addvalue );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: RegenerateHealth ()
{
if ( ! isRegeneratingHealth ())
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 curValue = GetHealth ();
uint32 maxValue = GetMaxHealth ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( curValue >= maxValue )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 addvalue = 0 ;
2009-10-17 15:51:44 -07:00
2008-11-14 16:28:45 -06:00
// Not only pet, but any controlled creature
2010-04-07 19:14:10 +02:00
if ( GetCharmerOrOwnerGUID ())
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
float HealthIncreaseRate = sWorld -> getRate ( RATE_HEALTH );
2008-10-11 14:16:25 -05:00
float Spirit = GetStat ( STAT_SPIRIT );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
if ( GetPower ( POWER_MANA ) > 0 )
2008-10-11 14:16:25 -05:00
addvalue = uint32 ( Spirit * 0.25 * HealthIncreaseRate );
else
addvalue = uint32 ( Spirit * 0.80 * HealthIncreaseRate );
}
else
addvalue = maxValue / 3 ;
2009-10-17 15:51:44 -07:00
2010-01-10 01:23:15 +01:00
// Apply modifiers (if any).
AuraEffectList const & ModPowerRegenPCTAuras = GetAuraEffectsByType ( SPELL_AURA_MOD_HEALTH_REGEN_PERCENT );
for ( AuraEffectList :: const_iterator i = ModPowerRegenPCTAuras . begin (); i != ModPowerRegenPCTAuras . end (); ++ i )
2012-10-02 12:17:42 +02:00
AddPct ( addvalue , ( * i ) -> GetAmount ());
2010-01-10 01:23:15 +01:00
2010-07-12 00:30:17 +02:00
addvalue += GetTotalAuraModifier ( SPELL_AURA_MOD_REGEN ) * CREATURE_REGEN_INTERVAL / ( 5 * IN_MILLISECONDS );
2010-01-10 01:23:15 +01:00
2008-10-11 14:16:25 -05:00
ModifyHealth ( addvalue );
}
2009-10-17 15:51:44 -07:00
2009-05-21 10:48:00 -05:00
void Creature :: DoFleeToGetAssistance ()
{
if ( ! getVictim ())
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( HasAuraType ( SPELL_AURA_PREVENTS_FLEEING ))
2009-05-21 10:48:00 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
float radius = sWorld -> getFloatConfig ( CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS );
2009-05-21 10:48:00 -05:00
if ( radius > 0 )
{
2011-10-07 11:08:09 -05:00
Creature * creature = NULL ;
2009-10-17 15:51:44 -07:00
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( GetPositionX (), GetPositionY ()));
2009-05-21 10:48:00 -05:00
Cell cell ( p );
cell . SetNoCreate ();
2009-12-20 15:20:04 +01:00
Trinity :: NearestAssistCreatureInCreatureRangeCheck u_check ( this , getVictim (), radius );
2011-10-07 11:08:09 -05:00
Trinity :: CreatureLastSearcher < Trinity :: NearestAssistCreatureInCreatureRangeCheck > searcher ( this , creature , u_check );
2009-10-17 15:51:44 -07:00
2009-12-20 15:20:04 +01:00
TypeContainerVisitor < Trinity :: CreatureLastSearcher < Trinity :: NearestAssistCreatureInCreatureRangeCheck > , 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 , * GetMap (), * this , radius );
2009-10-17 15:51:44 -07:00
2009-05-21 10:48:00 -05:00
SetNoSearchAssistance ( true );
2010-01-16 19:35:30 +03:00
UpdateSpeed ( MOVE_RUN , false );
2011-10-07 11:08:09 -05:00
if ( ! creature )
2011-09-29 12:43:05 +02:00
//SetFeared(true, getVictim()->GetGUID(), 0, sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY));
2009-05-21 10:48:00 -05:00
//TODO: use 31365
2012-02-03 19:02:17 +02:00
SetControlled ( true , UNIT_STATE_FLEEING );
2009-05-21 10:48:00 -05:00
else
2011-10-07 11:08:09 -05:00
GetMotionMaster () -> MoveSeekAssistance ( creature -> GetPositionX (), creature -> GetPositionY (), creature -> GetPositionZ ());
2009-05-21 10:48:00 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-12-10 20:25:47 -06:00
bool Creature :: AIM_Initialize ( CreatureAI * ai )
2008-10-11 14:16:25 -05:00
{
// make sure nothing can change the AI during AI update
2010-04-07 19:14:10 +02:00
if ( m_AI_locked )
2008-10-11 14:16:25 -05:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_TSCR , "AIM_Initialize: failed to init, locked." );
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
UnitAI * oldAI = i_AI ;
2009-10-17 15:51:44 -07:00
2009-04-06 20:33:52 -05:00
Motion_Initialize ();
2009-10-17 16:20:24 -07:00
2009-04-06 20:33:52 -05:00
i_AI = ai ? ai : FactorySelector :: selectAI ( this );
2010-06-21 23:20:58 +02:00
delete oldAI ;
2009-04-06 20:33:52 -05:00
IsAIEnabled = true ;
2009-04-13 17:53:09 -05:00
i_AI -> InitializeAI ();
2011-04-22 21:59:37 +02:00
// Initialize vehicle
if ( GetVehicleKit ())
GetVehicleKit () -> Reset ();
2009-04-06 20:33:52 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-04-06 20:33:52 -05:00
void Creature :: Motion_Initialize ()
{
2010-04-07 19:14:10 +02:00
if ( ! m_formation )
2009-04-07 10:51:45 +02:00
i_motionMaster . Initialize ();
2010-04-07 19:14:10 +02:00
else if ( m_formation -> getLeader () == this )
2009-10-17 16:20:24 -07:00
{
2009-04-07 10:51:45 +02:00
m_formation -> FormationReset ( false );
i_motionMaster . Initialize ();
}
2010-04-07 19:14:10 +02:00
else if ( m_formation -> isFormed ())
2012-01-13 16:43:49 +01:00
i_motionMaster . MoveIdle (); //wait the order of leader
2009-04-06 20:33:52 -05:00
else
i_motionMaster . Initialize ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
bool Creature :: Create ( uint32 guidlow , Map * map , uint32 phaseMask , uint32 Entry , uint32 vehId , uint32 team , float x , float y , float z , float ang , const CreatureData * data )
2008-10-11 14:16:25 -05:00
{
2009-08-01 00:20:32 +02:00
ASSERT ( map );
SetMap ( map );
2011-04-29 20:47:02 +02:00
SetPhaseMask ( phaseMask , false );
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
CreatureTemplate const * cinfo = sObjectMgr -> GetCreatureTemplate ( Entry );
2010-11-16 14:00:47 +01:00
if ( ! cinfo )
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SQL , "Creature::Create(): creature template (guidlow: %u, entry: %u) does not exist." , guidlow , Entry );
2010-11-16 14:00:47 +01:00
return false ;
}
2012-03-23 00:48:32 +01:00
//! Relocate before CreateFromProto, to initialize coords and allow
//! returning correct zone id for selecting OutdoorPvP/Battlefield script
Relocate ( x , y , z , ang );
2012-03-12 00:45:58 +01:00
//oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0;
if ( ! CreateFromProto ( guidlow , Entry , vehId , team , data ))
return false ;
2010-04-07 19:14:10 +02:00
if ( ! IsPositionValid ())
2009-05-30 22:15:05 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "Creature::Create(): given coordinates for creature (guidlow %d, entry %d) are not valid (X: %f, Y: %f, Z: %f, O: %f)" , guidlow , Entry , x , y , z , ang );
2009-05-30 22:15:05 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2012-02-27 14:58:47 +01:00
switch ( GetCreatureTemplate () -> rank )
2008-10-11 14:16:25 -05:00
{
2011-02-18 19:48:47 +01:00
case CREATURE_ELITE_RARE :
m_corpseDelay = sWorld -> getIntConfig ( CONFIG_CORPSE_DECAY_RARE );
break ;
case CREATURE_ELITE_ELITE :
m_corpseDelay = sWorld -> getIntConfig ( CONFIG_CORPSE_DECAY_ELITE );
break ;
case CREATURE_ELITE_RAREELITE :
m_corpseDelay = sWorld -> getIntConfig ( CONFIG_CORPSE_DECAY_RAREELITE );
break ;
case CREATURE_ELITE_WORLDBOSS :
m_corpseDelay = sWorld -> getIntConfig ( CONFIG_CORPSE_DECAY_WORLDBOSS );
break ;
default :
m_corpseDelay = sWorld -> getIntConfig ( CONFIG_CORPSE_DECAY_NORMAL );
break ;
}
2009-10-17 15:51:44 -07:00
2011-02-18 19:48:47 +01:00
LoadCreaturesAddon ();
2012-03-23 00:48:32 +01:00
//! Need to be called after LoadCreaturesAddon - MOVEMENTFLAG_HOVER is set there
if ( HasUnitMovementFlag ( MOVEMENTFLAG_HOVER ))
2012-04-19 23:19:27 +02:00
{
2012-03-23 00:48:32 +01:00
z += GetFloatValue ( UNIT_FIELD_HOVERHEIGHT );
2012-04-19 23:19:27 +02:00
//! Relocate again with updated Z coord
Relocate ( x , y , z , ang );
}
2012-03-23 00:48:32 +01:00
2011-05-07 20:09:45 +02:00
uint32 displayID = GetNativeDisplayId ();
2011-09-15 14:08:17 +02:00
CreatureModelInfo const * minfo = sObjectMgr -> GetCreatureModelRandomGender ( & displayID );
2011-02-18 19:48:47 +01:00
if ( minfo && ! isTotem ()) // Cancel load if no model defined or if totem
{
2011-04-28 22:11:45 +02:00
SetDisplayId ( displayID );
SetNativeDisplayId ( displayID );
2011-02-18 19:48:47 +01:00
SetByteValue ( UNIT_FIELD_BYTES_0 , 2 , minfo -> gender );
}
2010-02-28 20:30:20 +01:00
2012-02-27 14:58:47 +01:00
LastUsedScriptID = GetCreatureTemplate () -> ScriptID ;
2011-02-18 19:48:47 +01:00
2010-11-13 17:18:09 +01:00
// TODO: Replace with spell, handle from DB
2011-11-07 18:18:59 +01:00
if ( isSpiritHealer () || isSpiritGuide ())
2010-11-13 17:18:09 +01:00
{
m_serverSideVisibility . SetValue ( SERVERSIDE_VISIBILITY_GHOST , GHOST_VISIBILITY_GHOST );
m_serverSideVisibilityDetect . SetValue ( SERVERSIDE_VISIBILITY_GHOST , GHOST_VISIBILITY_GHOST );
}
if ( Entry == VISUAL_WAYPOINT )
2010-11-16 01:13:04 +01:00
SetVisible ( false );
2010-11-13 17:18:09 +01:00
2011-02-18 19:48:47 +01:00
return true ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
bool Creature :: isCanTrainingOf ( Player * player , bool msg ) const
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( ! isTrainer ())
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
TrainerSpellData const * trainer_spells = GetTrainerSpells ();
2009-10-17 15:51:44 -07:00
2012-02-27 14:58:47 +01:00
if (( ! trainer_spells || trainer_spells -> spellList . empty ()) && GetCreatureTemplate () -> trainer_type != TRAINER_TYPE_PETS )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SQL , "Creature %u (Entry: %u) have UNIT_NPC_FLAG_TRAINER but have empty trainer spell list." ,
2011-04-29 20:47:02 +02:00
GetGUIDLow (), GetEntry ());
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2012-02-27 14:58:47 +01:00
switch ( GetCreatureTemplate () -> trainer_type )
2008-10-11 14:16:25 -05:00
{
case TRAINER_TYPE_CLASS :
2012-02-27 14:58:47 +01:00
if ( player -> getClass () != GetCreatureTemplate () -> trainer_class )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( msg )
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
player -> PlayerTalkClass -> ClearMenus ();
2012-02-27 14:58:47 +01:00
switch ( GetCreatureTemplate () -> trainer_class )
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
case CLASS_DRUID : player -> PlayerTalkClass -> SendGossipMenu ( 4913 , GetGUID ()); break ;
case CLASS_HUNTER : player -> PlayerTalkClass -> SendGossipMenu ( 10090 , GetGUID ()); break ;
case CLASS_MAGE : player -> PlayerTalkClass -> SendGossipMenu ( 328 , GetGUID ()); break ;
case CLASS_PALADIN : player -> PlayerTalkClass -> SendGossipMenu ( 1635 , GetGUID ()); break ;
case CLASS_PRIEST : player -> PlayerTalkClass -> SendGossipMenu ( 4436 , GetGUID ()); break ;
case CLASS_ROGUE : player -> PlayerTalkClass -> SendGossipMenu ( 4797 , GetGUID ()); break ;
case CLASS_SHAMAN : player -> PlayerTalkClass -> SendGossipMenu ( 5003 , GetGUID ()); break ;
case CLASS_WARLOCK : player -> PlayerTalkClass -> SendGossipMenu ( 5836 , GetGUID ()); break ;
case CLASS_WARRIOR : player -> PlayerTalkClass -> SendGossipMenu ( 4985 , GetGUID ()); break ;
2008-10-11 14:16:25 -05:00
}
}
return false ;
}
break ;
case TRAINER_TYPE_PETS :
2011-10-07 11:08:09 -05:00
if ( player -> getClass () != CLASS_HUNTER )
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
player -> PlayerTalkClass -> ClearMenus ();
player -> PlayerTalkClass -> SendGossipMenu ( 3620 , GetGUID ());
2008-10-11 14:16:25 -05:00
return false ;
}
break ;
case TRAINER_TYPE_MOUNTS :
2012-02-27 14:58:47 +01:00
if ( GetCreatureTemplate () -> trainer_race && player -> getRace () != GetCreatureTemplate () -> trainer_race )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( msg )
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
player -> PlayerTalkClass -> ClearMenus ();
2012-12-29 21:14:12 +02:00
switch ( GetCreatureTemplate () -> trainer_race )
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
case RACE_DWARF : player -> PlayerTalkClass -> SendGossipMenu ( 5865 , GetGUID ()); break ;
case RACE_GNOME : player -> PlayerTalkClass -> SendGossipMenu ( 4881 , GetGUID ()); break ;
case RACE_HUMAN : player -> PlayerTalkClass -> SendGossipMenu ( 5861 , GetGUID ()); break ;
case RACE_NIGHTELF : player -> PlayerTalkClass -> SendGossipMenu ( 5862 , GetGUID ()); break ;
case RACE_ORC : player -> PlayerTalkClass -> SendGossipMenu ( 5863 , GetGUID ()); break ;
case RACE_TAUREN : player -> PlayerTalkClass -> SendGossipMenu ( 5864 , GetGUID ()); break ;
case RACE_TROLL : player -> PlayerTalkClass -> SendGossipMenu ( 5816 , GetGUID ()); break ;
case RACE_UNDEAD_PLAYER : player -> PlayerTalkClass -> SendGossipMenu ( 624 , GetGUID ()); break ;
case RACE_BLOODELF : player -> PlayerTalkClass -> SendGossipMenu ( 5862 , GetGUID ()); break ;
case RACE_DRAENEI : player -> PlayerTalkClass -> SendGossipMenu ( 5864 , GetGUID ()); break ;
2008-10-11 14:16:25 -05:00
}
}
return false ;
}
break ;
case TRAINER_TYPE_TRADESKILLS :
2012-02-27 14:58:47 +01:00
if ( GetCreatureTemplate () -> trainer_spell && ! player -> HasSpell ( GetCreatureTemplate () -> trainer_spell ))
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( msg )
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
player -> PlayerTalkClass -> ClearMenus ();
player -> PlayerTalkClass -> SendGossipMenu ( 11031 , GetGUID ());
2008-10-11 14:16:25 -05:00
}
return false ;
}
break ;
default :
return false ; // checked and error output at creature_template loading
}
return true ;
}
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
bool Creature :: isCanInteractWithBattleMaster ( Player * player , bool msg ) const
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( ! isBattleMaster ())
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
BattlegroundTypeId bgTypeId = sBattlegroundMgr -> GetBattleMasterBG ( GetEntry ());
2010-04-07 19:14:10 +02:00
if ( ! msg )
2011-10-07 11:08:09 -05:00
return player -> GetBGAccessByLevel ( bgTypeId );
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
if ( ! player -> GetBGAccessByLevel ( bgTypeId ))
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
player -> PlayerTalkClass -> ClearMenus ();
2011-09-29 12:43:05 +02:00
switch ( bgTypeId )
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
case BATTLEGROUND_AV : player -> PlayerTalkClass -> SendGossipMenu ( 7616 , GetGUID ()); break ;
case BATTLEGROUND_WS : player -> PlayerTalkClass -> SendGossipMenu ( 7599 , GetGUID ()); break ;
case BATTLEGROUND_AB : player -> PlayerTalkClass -> SendGossipMenu ( 7642 , GetGUID ()); break ;
2008-10-11 14:16:25 -05:00
case BATTLEGROUND_EY :
case BATTLEGROUND_NA :
case BATTLEGROUND_BE :
case BATTLEGROUND_AA :
2008-12-24 09:58:26 -06:00
case BATTLEGROUND_RL :
case BATTLEGROUND_SA :
case BATTLEGROUND_DS :
2011-10-07 11:08:09 -05:00
case BATTLEGROUND_RV : player -> PlayerTalkClass -> SendGossipMenu ( 10024 , GetGUID ()); break ;
2008-12-24 09:58:26 -06:00
default : break ;
2008-10-11 14:16:25 -05:00
}
return false ;
}
return true ;
}
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
bool Creature :: isCanTrainingAndResetTalentsOf ( Player * player ) const
2008-10-11 14:16:25 -05:00
{
2011-10-07 11:08:09 -05:00
return player -> getLevel () >= 10
2012-02-27 14:58:47 +01:00
&& GetCreatureTemplate () -> trainer_type == TRAINER_TYPE_CLASS
&& player -> getClass () == GetCreatureTemplate () -> trainer_class ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
Player * Creature :: GetLootRecipient () const
2008-10-11 14:16:25 -05:00
{
2010-09-15 13:44:40 +02:00
if ( ! m_lootRecipient )
return NULL ;
return ObjectAccessor :: FindPlayer ( m_lootRecipient );
}
2011-09-15 14:08:17 +02:00
Group * Creature :: GetLootRecipientGroup () const
2010-09-15 13:44:40 +02:00
{
if ( ! m_lootRecipientGroup )
return NULL ;
2011-05-05 10:23:00 +02:00
return sGroupMgr -> GetGroupByGUID ( m_lootRecipientGroup );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
void Creature :: SetLootRecipient ( Unit * unit )
2008-10-11 14:16:25 -05:00
{
// set the player whose group should receive the right
// to loot the creature after it dies
// should be set to NULL after the loot disappears
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( ! unit )
{
m_lootRecipient = 0 ;
2010-09-17 15:10:10 +02:00
m_lootRecipientGroup = 0 ;
2010-03-14 00:22:53 +01:00
RemoveFlag ( UNIT_DYNAMIC_FLAGS , UNIT_DYNFLAG_LOOTABLE | UNIT_DYNFLAG_TAPPED );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-09-13 22:49:20 +02:00
if ( unit -> GetTypeId () != TYPEID_PLAYER && ! unit -> IsVehicle ())
return ;
2008-10-11 14:16:25 -05:00
Player * player = unit -> GetCharmerOrOwnerPlayerOrPlayerItself ();
2010-04-07 19:14:10 +02:00
if ( ! player ) // normal creature, no player involved
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_lootRecipient = player -> GetGUID ();
2011-06-12 01:47:45 +02:00
if ( Group * group = player -> GetGroup ())
2010-09-15 13:44:40 +02:00
m_lootRecipientGroup = group -> GetLowGUID ();
2010-02-14 19:13:14 -07:00
SetFlag ( UNIT_DYNAMIC_FLAGS , UNIT_DYNFLAG_TAPPED );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-03-14 00:22:53 +01:00
// return true if this creature is tapped by the player or by a member of his group.
2011-08-19 14:53:40 +02:00
bool Creature :: isTappedBy ( Player const * player ) const
2010-03-14 00:22:53 +01:00
{
if ( player -> GetGUID () == m_lootRecipient )
return true ;
2011-08-19 14:53:40 +02:00
Group const * playerGroup = player -> GetGroup ();
2010-09-15 13:44:40 +02:00
if ( ! playerGroup || playerGroup != GetLootRecipientGroup ()) // if we dont have a group we arent the recipient
return false ; // if creature doesnt have group bound it means it was solo killed by someone else
2010-03-14 00:22:53 +01:00
return true ;
}
2008-10-11 14:16:25 -05:00
void Creature :: SaveToDB ()
{
// this should only be used when the creature has already been loaded
2008-11-14 16:28:45 -06:00
// preferably after adding to map, because mapid may not be valid otherwise
2011-09-15 14:08:17 +02:00
CreatureData const * data = sObjectMgr -> GetCreatureData ( m_DBTableGuid );
2010-04-07 19:14:10 +02:00
if ( ! data )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "Creature::SaveToDB failed, cannot get creature data!" );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-10-09 17:52:00 +02:00
SaveToDB ( GetMapId (), data -> spawnMask , GetPhaseMask ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-01-31 16:38:50 -06:00
void Creature :: SaveToDB ( uint32 mapid , uint8 spawnMask , uint32 phaseMask )
2008-10-11 14:16:25 -05:00
{
// update in loaded data
if ( ! m_DBTableGuid )
m_DBTableGuid = GetGUIDLow ();
2010-12-22 21:25:23 +01:00
CreatureData & data = sObjectMgr -> NewOrExistCreatureData ( m_DBTableGuid );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 displayId = GetNativeDisplayId ();
2010-10-09 17:52:00 +02:00
uint32 npcflag = GetUInt32Value ( UNIT_NPC_FLAGS );
uint32 unit_flags = GetUInt32Value ( UNIT_FIELD_FLAGS );
uint32 dynamicflags = GetUInt32Value ( UNIT_DYNAMIC_FLAGS );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// check if it's a custom model and if not, use 0 for displayId
2012-02-27 14:58:47 +01:00
CreatureTemplate const * cinfo = GetCreatureTemplate ();
2009-06-15 18:02:12 -05:00
if ( cinfo )
2008-10-11 14:16:25 -05:00
{
2009-09-21 07:52:16 +02:00
if ( displayId == cinfo -> Modelid1 || displayId == cinfo -> Modelid2 ||
displayId == cinfo -> Modelid3 || displayId == cinfo -> Modelid4 )
2009-06-15 18:02:12 -05:00
displayId = 0 ;
2010-10-09 17:52:00 +02:00
if ( npcflag == cinfo -> npcflag )
npcflag = 0 ;
if ( unit_flags == cinfo -> unit_flags )
unit_flags = 0 ;
if ( dynamicflags == cinfo -> dynamicflags )
dynamicflags = 0 ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-29 14:18:28 +02:00
// data->guid = guid must not be updated at save
2008-10-11 14:16:25 -05:00
data . id = GetEntry ();
data . mapid = mapid ;
2009-01-31 16:38:50 -06:00
data . phaseMask = phaseMask ;
2008-10-11 14:16:25 -05:00
data . displayid = displayId ;
data . equipmentId = GetEquipmentId ();
data . posX = GetPositionX ();
data . posY = GetPositionY ();
2012-03-12 00:45:58 +01:00
data . posZ = GetPositionZMinusOffset ();
2008-10-11 14:16:25 -05:00
data . orientation = GetOrientation ();
data . spawntimesecs = m_respawnDelay ;
// prevent add data integrity problems
2012-03-12 00:45:58 +01:00
data . spawndist = GetDefaultMovementType () == IDLE_MOTION_TYPE ? 0.0f : m_respawnradius ;
2008-10-11 14:16:25 -05:00
data . currentwaypoint = 0 ;
data . curhealth = GetHealth ();
data . curmana = GetPower ( POWER_MANA );
// prevent add data integrity problems
2010-04-07 23:25:02 +02:00
data . movementType = ! m_respawnradius && GetDefaultMovementType () == RANDOM_MOTION_TYPE
2008-10-11 14:16:25 -05:00
? IDLE_MOTION_TYPE : GetDefaultMovementType ();
data . spawnMask = spawnMask ;
2010-10-09 17:52:00 +02:00
data . npcflag = npcflag ;
data . unit_flags = unit_flags ;
data . dynamicflags = dynamicflags ;
2009-10-17 15:51:44 -07:00
2011-07-29 14:18:28 +02:00
// update in DB
2010-08-21 03:19:25 +02:00
SQLTransaction trans = WorldDatabase . BeginTransaction ();
2009-10-17 15:51:44 -07:00
2012-03-25 16:22:24 +02:00
PreparedStatement * stmt = WorldDatabase . GetPreparedStatement ( WORLD_DEL_CREATURE );
stmt -> setUInt32 ( 0 , m_DBTableGuid );
trans -> Append ( stmt );
uint8 index = 0 ;
stmt = WorldDatabase . GetPreparedStatement ( WORLD_INS_CREATURE );
stmt -> setUInt32 ( index ++ , m_DBTableGuid );
stmt -> setUInt32 ( index ++ , GetEntry ());
stmt -> setUInt16 ( index ++ , uint16 ( mapid ));
stmt -> setUInt8 ( index ++ , spawnMask );
stmt -> setUInt16 ( index ++ , uint16 ( GetPhaseMask ()));
stmt -> setUInt32 ( index ++ , displayId );
stmt -> setInt32 ( index ++ , int32 ( GetEquipmentId ()));
stmt -> setFloat ( index ++ , GetPositionX ());
stmt -> setFloat ( index ++ , GetPositionY ());
stmt -> setFloat ( index ++ , GetPositionZ ());
stmt -> setFloat ( index ++ , GetOrientation ());
stmt -> setUInt32 ( index ++ , m_respawnDelay );
stmt -> setFloat ( index ++ , m_respawnradius );
stmt -> setUInt32 ( index ++ , 0 );
stmt -> setUInt32 ( index ++ , GetHealth ());
stmt -> setUInt32 ( index ++ , GetPower ( POWER_MANA ));
stmt -> setUInt8 ( index ++ , uint8 ( GetDefaultMovementType ()));
stmt -> setUInt32 ( index ++ , npcflag );
stmt -> setUInt32 ( index ++ , unit_flags );
2012-05-04 16:42:23 +03:00
stmt -> setUInt32 ( index ++ , dynamicflags );
2012-03-25 16:22:24 +02:00
trans -> Append ( stmt );
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02:00
WorldDatabase . CommitTransaction ( trans );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
void Creature :: SelectLevel ( const CreatureTemplate * cinfo )
2008-10-11 14:16:25 -05:00
{
uint32 rank = isPet () ? 0 : cinfo -> rank ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// level
2009-11-01 17:53:07 -08:00
uint8 minlevel = std :: min ( cinfo -> maxlevel , cinfo -> minlevel );
uint8 maxlevel = std :: max ( cinfo -> maxlevel , cinfo -> minlevel );
uint8 level = minlevel == maxlevel ? minlevel : urand ( minlevel , maxlevel );
2008-10-11 14:16:25 -05:00
SetLevel ( level );
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
CreatureBaseStats const * stats = sObjectMgr -> GetCreatureBaseStats ( level , cinfo -> unit_class );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// health
float healthmod = _GetHealthMod ( rank );
2009-10-17 15:51:44 -07:00
2010-01-10 22:02:03 +01:00
uint32 basehp = stats -> GenerateHealth ( cinfo );
2009-12-20 20:23:18 -07:00
uint32 health = uint32 ( basehp * healthmod );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SetCreateHealth ( health );
SetMaxHealth ( health );
SetHealth ( health );
2009-06-11 17:54:59 +02:00
ResetPlayerDamageReq ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// mana
2010-01-10 22:02:03 +01:00
uint32 mana = stats -> GenerateMana ( cinfo );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SetCreateMana ( mana );
SetMaxPower ( POWER_MANA , mana ); //MAX Mana
SetPower ( POWER_MANA , mana );
2009-10-17 15:51:44 -07:00
2009-05-29 21:24:23 -05:00
// TODO: set UNIT_FIELD_POWER*, for some creature class case (energy, etc)
2009-10-17 15:51:44 -07:00
2010-08-22 12:39:39 -07:00
SetModifierValue ( UNIT_MOD_HEALTH , BASE_VALUE , ( float ) health );
SetModifierValue ( UNIT_MOD_MANA , BASE_VALUE , ( float ) mana );
2008-10-11 14:16:25 -05:00
2009-06-22 23:12:53 +02:00
//damage
2009-08-06 10:38:46 -05:00
float damagemod = 1.0f ; //_GetDamageMod(rank);
2009-10-17 15:51:44 -07:00
2010-01-21 18:38:49 -07:00
SetBaseWeaponDamage ( BASE_ATTACK , MINDAMAGE , cinfo -> mindmg * damagemod );
SetBaseWeaponDamage ( BASE_ATTACK , MAXDAMAGE , cinfo -> maxdmg * damagemod );
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
SetFloatValue ( UNIT_FIELD_MINRANGEDDAMAGE , cinfo -> minrangedmg * damagemod );
SetFloatValue ( UNIT_FIELD_MAXRANGEDDAMAGE , cinfo -> maxrangedmg * damagemod );
2009-10-17 15:51:44 -07:00
2010-01-21 18:38:49 -07:00
SetModifierValue ( UNIT_MOD_ATTACK_POWER , BASE_VALUE , cinfo -> attackpower * damagemod );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
float Creature :: _GetHealthMod ( int32 Rank )
{
switch ( Rank ) // define rates for each elite rank
{
case CREATURE_ELITE_NORMAL :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_NORMAL_HP );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_ELITE :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_ELITE_HP );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_RAREELITE :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_RAREELITE_HP );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_WORLDBOSS :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_WORLDBOSS_HP );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_RARE :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_RARE_HP );
2008-10-11 14:16:25 -05:00
default :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_ELITE_HP );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
float Creature :: _GetDamageMod ( int32 Rank )
{
switch ( Rank ) // define rates for each elite rank
{
case CREATURE_ELITE_NORMAL :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_NORMAL_DAMAGE );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_ELITE :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_ELITE_DAMAGE );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_RAREELITE :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_RAREELITE_DAMAGE );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_WORLDBOSS :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_RARE :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_RARE_DAMAGE );
2008-10-11 14:16:25 -05:00
default :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_ELITE_DAMAGE );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
float Creature :: GetSpellDamageMod ( int32 Rank )
{
switch ( Rank ) // define rates for each elite rank
{
case CREATURE_ELITE_NORMAL :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_NORMAL_SPELLDAMAGE );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_ELITE :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_RAREELITE :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_WORLDBOSS :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE );
2008-10-11 14:16:25 -05:00
case CREATURE_ELITE_RARE :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_RARE_SPELLDAMAGE );
2008-10-11 14:16:25 -05:00
default :
2010-12-23 23:25:44 +01:00
return sWorld -> getRate ( RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
bool Creature :: CreateFromProto ( uint32 guidlow , uint32 Entry , uint32 vehId , uint32 team , const CreatureData * data )
2008-10-11 14:16:25 -05:00
{
2009-05-30 22:15:05 -05:00
SetZoneScript ();
2010-04-07 19:14:10 +02:00
if ( m_zoneScript && data )
2009-05-30 22:15:05 -05:00
{
2009-06-03 21:47:38 -05:00
Entry = m_zoneScript -> GetCreatureEntry ( guidlow , data );
2010-04-07 19:14:10 +02:00
if ( ! Entry )
2009-05-30 22:15:05 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
CreatureTemplate const * cinfo = sObjectMgr -> GetCreatureTemplate ( Entry );
2010-04-07 19:14:10 +02:00
if ( ! cinfo )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SQL , "Creature::CreateFromProto(): creature template (guidlow: %u, entry: %u) does not exist." , guidlow , Entry );
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2009-05-31 22:45:32 -05:00
SetOriginalEntry ( Entry );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! vehId )
2009-08-23 22:09:43 -05:00
vehId = cinfo -> VehicleId ;
2009-10-17 15:51:44 -07:00
2011-02-27 03:53:24 +01:00
if ( vehId && ! CreateVehicleKit ( vehId , Entry ))
2009-08-23 22:09:43 -05:00
vehId = 0 ;
2009-10-17 15:51:44 -07:00
2009-08-23 22:09:43 -05:00
Object :: _Create ( guidlow , Entry , vehId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! UpdateEntry ( Entry , team , data ))
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2011-11-28 14:05:25 -05:00
bool Creature :: LoadCreatureFromDB ( uint32 guid , Map * map , bool addToMap )
2008-10-11 14:16:25 -05:00
{
2010-12-22 21:25:23 +01:00
CreatureData const * data = sObjectMgr -> GetCreatureData ( guid );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! data )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SQL , "Creature (GUID: %u) not found in table `creature`, can't load. " , guid );
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_DBTableGuid = guid ;
2009-10-31 02:14:25 -07:00
if ( map -> GetInstanceId () == 0 )
{
2011-04-29 20:47:02 +02:00
if ( map -> GetCreature ( MAKE_NEW_GUID ( guid , data -> id , HIGHGUID_UNIT )))
2009-10-31 02:14:25 -07:00
return false ;
}
else
2010-12-22 21:25:23 +01:00
guid = sObjectMgr -> GenerateLowGuid ( HIGHGUID_UNIT );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint16 team = 0 ;
2011-04-29 20:47:02 +02:00
if ( ! Create ( guid , map , data -> phaseMask , data -> id , 0 , team , data -> posX , data -> posY , data -> posZ , data -> orientation , data ))
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-02-09 08:16:34 -05:00
//We should set first home position, because then AI calls home movement
2011-04-29 20:47:02 +02:00
SetHomePosition ( data -> posX , data -> posY , data -> posZ , data -> orientation );
2009-10-17 15:51:44 -07:00
2009-02-09 08:16:34 -05:00
m_respawnradius = data -> spawndist ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_respawnDelay = data -> spawntimesecs ;
2011-06-27 20:22:53 +02:00
m_deathState = ALIVE ;
2009-10-17 15:51:44 -07:00
2012-06-07 23:20:57 +02:00
m_respawnTime = GetMap () -> GetCreatureRespawnTime ( m_DBTableGuid );
2010-04-07 19:14:10 +02:00
if ( m_respawnTime ) // respawn on Update
2008-12-08 16:34:03 -06:00
{
2008-10-11 14:16:25 -05:00
m_deathState = DEAD ;
2012-03-12 00:45:58 +01:00
if ( CanFly ())
2008-12-08 16:34:03 -06:00
{
2012-02-03 16:03:52 -05:00
float tz = map -> GetHeight ( GetPhaseMask (), data -> posX , data -> posY , data -> posZ , false );
2011-10-17 07:38:27 -03:00
if ( data -> posZ - tz > 0.1f )
2011-04-29 20:47:02 +02:00
Relocate ( data -> posX , data -> posY , tz );
2008-12-08 16:34:03 -06:00
}
}
2009-10-17 15:51:44 -07:00
2010-06-28 06:42:01 -06:00
uint32 curhealth ;
2010-08-08 19:45:53 +02:00
2010-06-28 06:42:01 -06:00
if ( ! m_regenHealth )
2008-10-11 14:16:25 -05:00
{
2010-06-28 06:42:01 -06:00
curhealth = data -> curhealth ;
if ( curhealth )
{
2012-02-27 14:58:47 +01:00
curhealth = uint32 ( curhealth * _GetHealthMod ( GetCreatureTemplate () -> rank ));
2010-06-28 06:42:01 -06:00
if ( curhealth < 1 )
curhealth = 1 ;
}
2011-04-29 20:47:02 +02:00
SetPower ( POWER_MANA , data -> curmana );
2010-06-28 06:42:01 -06:00
}
else
{
curhealth = GetMaxHealth ();
2011-04-29 20:47:02 +02:00
SetPower ( POWER_MANA , GetMaxPower ( POWER_MANA ));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SetHealth ( m_deathState == ALIVE ? curhealth : 0 );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// checked at creature_template loading
m_defaultMovementType = MovementGeneratorType ( data -> movementType );
2009-10-17 15:51:44 -07:00
2009-05-31 21:04:04 -05:00
m_creatureData = data ;
2009-10-17 15:51:44 -07:00
2011-11-28 14:05:25 -05:00
if ( addToMap && ! GetMap () -> AddToMap ( this ))
return false ;
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: LoadEquipment ( uint32 equip_entry , bool force )
{
2010-04-07 19:14:10 +02:00
if ( equip_entry == 0 )
2008-10-11 14:16:25 -05:00
{
if ( force )
{
2009-04-29 00:26:07 -05:00
for ( uint8 i = 0 ; i < 3 ; ++ i )
2008-12-24 09:58:26 -06:00
SetUInt32Value ( UNIT_VIRTUAL_ITEM_SLOT_ID + i , 0 );
2008-10-11 14:16:25 -05:00
m_equipmentId = 0 ;
}
return ;
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
EquipmentInfo const * einfo = sObjectMgr -> GetEquipmentInfo ( equip_entry );
2008-10-11 14:16:25 -05:00
if ( ! einfo )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_equipmentId = equip_entry ;
2009-04-29 00:26:07 -05:00
for ( uint8 i = 0 ; i < 3 ; ++ i )
2011-04-28 22:34:40 +02:00
SetUInt32Value ( UNIT_VIRTUAL_ITEM_SLOT_ID + i , einfo -> ItemEntry [ i ]);
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Creature :: hasQuest ( uint32 quest_id ) const
{
2010-12-22 21:25:23 +01:00
QuestRelationBounds qr = sObjectMgr -> GetCreatureQuestRelationBounds ( GetEntry ());
2010-09-13 13:18:27 +02:00
for ( QuestRelations :: const_iterator itr = qr . first ; itr != qr . second ; ++ itr )
2008-10-11 14:16:25 -05:00
{
2010-04-07 23:25:02 +02:00
if ( itr -> second == quest_id )
2008-10-11 14:16:25 -05:00
return true ;
}
return false ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Creature :: hasInvolvedQuest ( uint32 quest_id ) const
{
2010-12-22 21:25:23 +01:00
QuestRelationBounds qir = sObjectMgr -> GetCreatureQuestInvolvedRelationBounds ( GetEntry ());
2010-09-13 13:18:27 +02:00
for ( QuestRelations :: const_iterator itr = qir . first ; itr != qir . second ; ++ itr )
2008-10-11 14:16:25 -05:00
{
2010-04-07 23:25:02 +02:00
if ( itr -> second == quest_id )
2008-10-11 14:16:25 -05:00
return true ;
}
return false ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: DeleteFromDB ()
{
if ( ! m_DBTableGuid )
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "Trying to delete not saved creature! LowGUID: %u, Entry: %u" , GetGUIDLow (), GetEntry ());
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2012-06-07 23:20:57 +02:00
GetMap () -> RemoveCreatureRespawnTime ( m_DBTableGuid );
2010-12-22 21:25:23 +01:00
sObjectMgr -> DeleteCreatureData ( m_DBTableGuid );
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02:00
SQLTransaction trans = WorldDatabase . BeginTransaction ();
2012-03-25 16:22:24 +02:00
PreparedStatement * stmt = WorldDatabase . GetPreparedStatement ( WORLD_DEL_CREATURE );
stmt -> setUInt32 ( 0 , m_DBTableGuid );
trans -> Append ( stmt );
stmt = WorldDatabase . GetPreparedStatement ( WORLD_DEL_CREATURE_ADDON );
stmt -> setUInt32 ( 0 , m_DBTableGuid );
trans -> Append ( stmt );
stmt = WorldDatabase . GetPreparedStatement ( WORLD_DEL_GAME_EVENT_CREATURE );
stmt -> setUInt32 ( 0 , m_DBTableGuid );
trans -> Append ( stmt );
stmt = WorldDatabase . GetPreparedStatement ( WORLD_DEL_GAME_EVENT_MODEL_EQUIP );
stmt -> setUInt32 ( 0 , m_DBTableGuid );
trans -> Append ( stmt );
2010-08-21 03:19:25 +02:00
WorldDatabase . CommitTransaction ( trans );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-10-13 13:26:27 -04:00
bool Creature :: IsInvisibleDueToDespawn () const
2008-11-06 10:27:58 -06:00
{
2011-10-13 13:26:27 -04:00
if ( Unit :: IsInvisibleDueToDespawn ())
return true ;
2009-10-17 15:51:44 -07:00
2011-06-27 20:22:53 +02:00
if ( isAlive () || m_corpseRemoveTime > time ( NULL ))
2011-10-13 13:26:27 -04:00
return false ;
2009-10-17 15:51:44 -07:00
2011-10-13 13:26:27 -04:00
return true ;
2008-11-06 10:27:58 -06:00
}
2009-10-17 15:51:44 -07:00
2011-10-13 17:01:55 -04:00
bool Creature :: CanAlwaysSee ( WorldObject const * obj ) const
2011-02-10 22:36:35 -03:00
{
if ( IsAIEnabled && AI () -> CanSeeAlways ( obj ))
return true ;
return false ;
}
2009-06-09 19:55:15 -05:00
bool Creature :: canStartAttack ( Unit const * who , bool force ) const
2008-11-21 10:07:11 -06:00
{
2010-04-07 19:14:10 +02:00
if ( isCivilian ())
2009-06-15 12:02:55 -05:00
return false ;
2009-10-17 16:20:24 -07:00
2012-02-03 18:46:05 +01:00
if ( HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_IMMUNE_TO_NPC ))
2011-03-06 12:22:04 +01:00
return false ;
2012-02-16 21:46:37 +01:00
2011-10-01 16:57:10 +01:00
// Do not attack non-combat pets
if ( who -> GetTypeId () == TYPEID_UNIT && who -> GetCreatureType () == CREATURE_TYPE_NON_COMBAT_PET )
return false ;
2011-03-06 12:22:04 +01:00
2012-03-12 00:45:58 +01:00
if ( ! CanFly () && ( GetDistanceZ ( who ) > CREATURE_Z_ATTACK_RANGE + m_CombatDistance ))
2009-06-15 12:02:55 -05:00
//|| who->IsControlledByPlayer() && who->IsFlying()))
// we cannot check flying for other creatures, too much map/vmap calculation
// TODO: should switch to range attack
2008-11-21 10:07:11 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! force )
2009-08-27 13:54:57 -05:00
{
2010-04-07 19:14:10 +02:00
if ( ! _IsTargetAcceptable ( who ))
2009-09-29 01:16:08 -07:00
return false ;
2009-10-17 15:51:44 -07:00
2011-07-03 00:18:33 +02:00
if ( who -> isInCombat () && IsWithinDist ( who , ATTACK_DISTANCE ))
2011-06-12 01:47:45 +02:00
if ( Unit * victim = who -> getAttackerForHelper ())
2010-12-23 23:25:44 +01:00
if ( IsWithinDistInMap ( victim , sWorld -> getFloatConfig ( CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS )))
2009-08-27 13:54:57 -05:00
force = true ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! force && ( IsNeutralToAll () || ! IsWithinDistInMap ( who , GetAttackDistance ( who ) + m_CombatDistance )))
2009-08-27 13:54:57 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! canCreatureAttack ( who , force ))
2008-11-21 10:07:11 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2008-11-21 10:07:11 -06:00
return IsWithinLOSInMap ( who );
}
2009-10-17 15:51:44 -07:00
2011-11-07 11:18:00 -06:00
float Creature :: GetAttackDistance ( Unit const * player ) const
2008-10-11 14:16:25 -05:00
{
2010-12-23 23:25:44 +01:00
float aggroRate = sWorld -> getRate ( RATE_CREATURE_AGGRO );
2010-04-07 23:25:02 +02:00
if ( aggroRate == 0 )
2008-10-11 14:16:25 -05:00
return 0.0f ;
2009-10-17 15:51:44 -07:00
2011-11-07 11:18:00 -06:00
uint32 playerlevel = player -> getLevelForTarget ( this );
uint32 creaturelevel = getLevelForTarget ( player );
2009-10-17 15:51:44 -07:00
2009-09-18 14:10:37 -07:00
int32 leveldif = int32 ( playerlevel ) - int32 ( creaturelevel );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// "The maximum Aggro Radius has a cap of 25 levels under. Example: A level 30 char has the same Aggro Radius of a level 5 char on a level 60 mob."
2010-04-07 22:59:46 +02:00
if ( leveldif < - 25 )
2008-10-11 14:16:25 -05:00
leveldif = - 25 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// "The aggro radius of a mob having the same level as the player is roughly 20 yards"
float RetDistance = 20 ;
2009-10-17 15:51:44 -07:00
2008-11-14 16:28:45 -06:00
// "Aggro Radius varies with level difference at a rate of roughly 1 yard/level"
2008-10-11 14:16:25 -05:00
// radius grow if playlevel < creaturelevel
RetDistance -= ( float ) leveldif ;
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
if ( creaturelevel + 5 <= sWorld -> getIntConfig ( CONFIG_MAX_PLAYER_LEVEL ))
2008-10-11 14:16:25 -05:00
{
// detect range auras
RetDistance += GetTotalAuraModifier ( SPELL_AURA_MOD_DETECT_RANGE );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// detected range auras
2011-11-07 11:18:00 -06:00
RetDistance += player -> GetTotalAuraModifier ( SPELL_AURA_MOD_DETECTED_RANGE );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// "Minimum Aggro Radius for a mob seems to be combat range (5 yards)"
2010-04-07 19:14:10 +02:00
if ( RetDistance < 5 )
2008-10-11 14:16:25 -05:00
RetDistance = 5 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return ( RetDistance * aggroRate );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: setDeathState ( DeathState s )
{
2011-06-27 20:22:53 +02:00
Unit :: setDeathState ( s );
if ( s == JUST_DIED )
2008-10-11 14:16:25 -05:00
{
2010-09-15 06:22:54 +02:00
m_corpseRemoveTime = time ( NULL ) + m_corpseDelay ;
m_respawnTime = time ( NULL ) + m_respawnDelay + m_corpseDelay ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// always save boss respawn time at death to prevent crash cheating
2010-12-23 23:25:44 +01:00
if ( sWorld -> getBoolConfig ( CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY ) || isWorldBoss ())
2008-10-11 14:16:25 -05:00
SaveRespawnTime ();
2009-10-17 15:51:44 -07:00
2011-07-15 12:33:03 +02:00
SetTarget ( 0 ); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState)
2009-06-03 19:29:55 -05:00
SetUInt32Value ( UNIT_NPC_FLAGS , UNIT_NPC_FLAG_NONE );
2009-10-17 15:51:44 -07:00
2009-06-03 19:29:55 -05:00
setActive ( false );
2009-10-17 15:51:44 -07:00
2012-02-27 14:58:47 +01:00
if ( ! isPet () && GetCreatureTemplate () -> SkinLootId )
if ( LootTemplates_Skinning . HaveLootFor ( GetCreatureTemplate () -> SkinLootId ))
2010-09-15 17:44:56 +02:00
if ( hasLootRecipient ())
SetFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SKINNABLE );
2009-10-17 15:51:44 -07:00
2010-01-16 19:35:30 +03:00
if ( HasSearchedAssistance ())
{
SetNoSearchAssistance ( false );
UpdateSpeed ( MOVE_RUN , false );
}
2009-10-17 16:20:24 -07:00
2009-04-07 10:51:45 +02:00
//Dismiss group if is leader
2010-04-07 19:14:10 +02:00
if ( m_formation && m_formation -> getLeader () == this )
2009-04-07 10:51:45 +02:00
m_formation -> FormationReset ( true );
2009-10-17 15:51:44 -07:00
2012-03-12 00:45:58 +01:00
if (( CanFly () || IsFlying ()))
2012-01-14 15:34:41 +01:00
i_motionMaster . MoveFall ();
2009-10-17 15:51:44 -07:00
2009-08-26 19:28:21 -05:00
Unit :: setDeathState ( CORPSE );
2009-04-07 10:51:45 +02:00
}
2012-05-13 11:33:42 -02:30
else if ( s == JUST_RESPAWNED )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
//if (isPet())
2009-02-25 17:53:05 -06:00
// setActive(true);
2010-08-26 01:20:57 +06:00
SetFullHealth ();
2008-10-11 14:16:25 -05:00
SetLootRecipient ( NULL );
2009-06-11 17:54:59 +02:00
ResetPlayerDamageReq ();
2012-02-27 14:58:47 +01:00
CreatureTemplate const * cinfo = GetCreatureTemplate ();
2012-01-14 15:34:41 +01:00
SetWalk ( true );
2012-12-27 19:31:22 +01:00
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
float ground = GetPositionZ ();
GetMap () -> GetWaterOrGroundLevel ( GetPositionX (), GetPositionY (), GetPositionZ (), & ground );
2012-12-29 14:23:23 -05:00
bool isInAir = G3D :: fuzzyGt ( GetPositionZ (), ground + 0.05f ) || G3D :: fuzzyLt ( GetPositionZ (), ground - 0.05f ); // Can be underground too, prevent the falling
2012-12-27 19:31:22 +01:00
if ( cinfo -> InhabitType & INHABIT_AIR && cinfo -> InhabitType & INHABIT_GROUND && isInAir )
2012-03-18 11:35:33 +01:00
SetCanFly ( true );
2012-12-27 19:31:22 +01:00
else if ( cinfo -> InhabitType & INHABIT_AIR && isInAir )
2012-03-12 00:45:58 +01:00
SetDisableGravity ( true );
2012-12-27 19:31:22 +01:00
else
{
SetCanFly ( false );
SetDisableGravity ( false );
}
if ( cinfo -> InhabitType & INHABIT_WATER && IsInWater ())
2010-01-07 22:49:06 -07:00
AddUnitMovementFlag ( MOVEMENTFLAG_SWIMMING );
2012-12-27 19:31:22 +01:00
else
RemoveUnitMovementFlag ( MOVEMENTFLAG_SWIMMING );
2008-10-11 14:16:25 -05:00
SetUInt32Value ( UNIT_NPC_FLAGS , cinfo -> npcflag );
2012-02-03 19:02:17 +02:00
ClearUnitState ( uint32 ( UNIT_STATE_ALL_STATE ));
2008-10-11 14:16:25 -05:00
SetMeleeDamageSchool ( SpellSchools ( cinfo -> dmgschool ));
LoadCreaturesAddon ( true );
2009-04-06 20:33:52 -05:00
Motion_Initialize ();
2010-04-07 19:14:10 +02:00
if ( GetCreatureData () && GetPhaseMask () != GetCreatureData () -> phaseMask )
2009-06-17 01:01:39 -05:00
SetPhaseMask ( GetCreatureData () -> phaseMask , false );
2009-08-25 00:56:23 -05:00
Unit :: setDeathState ( ALIVE );
2009-04-07 10:51:45 +02:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-06-17 01:01:39 -05:00
void Creature :: Respawn ( bool force )
2008-10-11 14:16:25 -05:00
{
2009-06-17 01:01:39 -05:00
DestroyForNearbyPlayers ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( force )
2009-06-17 01:01:39 -05:00
{
2010-04-07 19:14:10 +02:00
if ( isAlive ())
2009-06-17 01:01:39 -05:00
setDeathState ( JUST_DIED );
2010-04-07 19:14:10 +02:00
else if ( getDeathState () != CORPSE )
2009-06-17 01:01:39 -05:00
setDeathState ( CORPSE );
}
2009-10-17 15:51:44 -07:00
2010-09-15 06:22:54 +02:00
RemoveCorpse ( false );
2009-10-17 15:51:44 -07:00
2010-04-07 23:25:02 +02:00
if ( getDeathState () == DEAD )
2008-10-11 14:16:25 -05:00
{
if ( m_DBTableGuid )
2012-06-07 23:20:57 +02:00
GetMap () -> RemoveCreatureRespawnTime ( m_DBTableGuid );
2009-10-17 15:51:44 -07:00
2012-10-24 13:29:34 +02:00
sLog -> outDebug ( LOG_FILTER_UNITS , "Respawning creature %s (GuidLow: %u, Full GUID: " UI64FMTD " Entry: %u)" ,
GetName (). c_str (), GetGUIDLow (), GetGUID (), GetEntry ());
2009-04-14 14:33:48 +02:00
m_respawnTime = 0 ;
lootForPickPocketed = false ;
lootForBody = false ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( m_originalEntry != GetEntry ())
2009-04-14 14:33:48 +02:00
UpdateEntry ( m_originalEntry );
2009-10-17 15:51:44 -07:00
2012-02-27 14:58:47 +01:00
CreatureTemplate const * cinfo = GetCreatureTemplate ();
2009-04-14 14:33:48 +02:00
SelectLevel ( cinfo );
2009-10-17 15:51:44 -07:00
2012-05-13 11:33:42 -02:30
setDeathState ( JUST_RESPAWNED );
2009-10-17 15:51:44 -07:00
2011-05-07 20:09:45 +02:00
uint32 displayID = GetNativeDisplayId ();
2011-09-15 14:08:17 +02:00
CreatureModelInfo const * minfo = sObjectMgr -> GetCreatureModelRandomGender ( & displayID );
2009-09-27 15:14:25 -07:00
if ( minfo ) // Cancel load if no model defined
{
2011-04-28 22:11:45 +02:00
SetDisplayId ( displayID );
SetNativeDisplayId ( displayID );
2009-09-27 15:14:25 -07:00
SetByteValue ( UNIT_FIELD_BYTES_0 , 2 , minfo -> gender );
}
2009-10-17 15:51:44 -07:00
2010-09-15 06:23:25 +02:00
GetMotionMaster () -> InitDefault ();
2009-04-14 14:33:48 +02:00
//Call AI respawn virtual function
2009-12-06 16:41:05 +01:00
if ( IsAIEnabled )
2010-11-03 18:33:47 +01:00
TriggerJustRespawned = true ; //delay event to next tick so all creatures are created on the map before processing
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
uint32 poolid = GetDBTableGUIDLow () ? sPoolMgr -> IsPartOfAPool < Creature > ( GetDBTableGUIDLow ()) : 0 ;
2009-04-15 17:06:38 -05:00
if ( poolid )
2010-12-22 21:25:23 +01:00
sPoolMgr -> UpdatePool < Creature > ( poolid , GetDBTableGUIDLow ());
2010-08-08 19:45:53 +02:00
2010-06-27 03:47:18 +02:00
//Re-initialize reactstate that could be altered by movementgenerators
InitializeReactState ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-02-27 15:25:14 +02:00
UpdateObjectVisibility ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-01-16 19:51:59 +03:00
void Creature :: ForcedDespawn ( uint32 timeMSToDespawn )
2009-06-18 17:05:01 -05:00
{
2010-01-16 19:51:59 +03:00
if ( timeMSToDespawn )
{
2011-09-15 14:08:17 +02:00
ForcedDespawnDelayEvent * pEvent = new ForcedDespawnDelayEvent ( * this );
2010-01-16 19:51:59 +03:00
m_Events . AddEvent ( pEvent , m_Events . CalculateTime ( timeMSToDespawn ));
return ;
}
if ( isAlive ())
setDeathState ( JUST_DIED );
2010-09-15 06:22:54 +02:00
RemoveCorpse ( false );
2009-06-18 17:05:01 -05:00
}
2009-10-17 15:51:44 -07:00
2011-01-02 21:33:37 +01:00
void Creature :: DespawnOrUnsummon ( uint32 msTimeToDespawn /*= 0*/ )
{
if ( TempSummon * summon = this -> ToTempSummon ())
2011-03-07 21:25:34 +01:00
summon -> UnSummon ( msTimeToDespawn );
2011-01-02 21:33:37 +01:00
else
ForcedDespawn ( msTimeToDespawn );
}
2011-07-26 23:09:28 +02:00
bool Creature :: IsImmunedToSpell ( SpellInfo const * spellInfo )
2008-10-11 14:16:25 -05:00
{
if ( ! spellInfo )
return false ;
2009-10-17 15:51:44 -07:00
2012-05-18 21:23:07 +02:00
// Creature is immune to main mechanic of the spell
if ( GetCreatureTemplate () -> MechanicImmuneMask & ( 1 << ( spellInfo -> Mechanic - 1 )))
2011-12-14 16:13:10 +01:00
return true ;
2012-02-27 14:58:47 +01:00
// This check must be done instead of 'if (GetCreatureTemplate()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1)))' for not break
// the check of mechanic immunity on DB (tested) because GetCreatureTemplate()->MechanicImmuneMask and m_spellImmune[IMMUNITY_MECHANIC] don't have same data.
2011-12-14 16:13:10 +01:00
bool immunedToAllEffects = true ;
2012-06-17 23:17:59 +02:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2012-06-17 02:21:40 +02:00
{
2012-06-17 23:17:59 +02:00
if ( ! spellInfo -> Effects [ i ]. IsEffect ())
continue ;
2011-12-14 16:13:10 +01:00
if ( ! IsImmunedToSpellEffect ( spellInfo , i ))
{
immunedToAllEffects = false ;
break ;
}
2012-06-17 02:21:40 +02:00
}
2011-12-14 16:13:10 +01:00
if ( immunedToAllEffects )
2008-10-11 14:16:25 -05:00
return true ;
2009-10-17 15:51:44 -07:00
2009-01-04 16:45:32 -06:00
return Unit :: IsImmunedToSpell ( spellInfo );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
bool Creature :: IsImmunedToSpellEffect ( SpellInfo const * spellInfo , uint32 index ) const
2008-10-11 14:16:25 -05:00
{
2012-02-27 14:58:47 +01:00
if ( GetCreatureTemplate () -> MechanicImmuneMask & ( 1 << ( spellInfo -> Effects [ index ]. Mechanic - 1 )))
2008-10-11 14:16:25 -05:00
return true ;
2009-10-17 15:51:44 -07:00
2012-02-27 14:58:47 +01:00
if ( GetCreatureTemplate () -> type == CREATURE_TYPE_MECHANICAL && spellInfo -> Effects [ index ]. Effect == SPELL_EFFECT_HEAL )
2010-07-28 01:26:18 +02:00
return true ;
2010-01-20 21:10:18 +01:00
return Unit :: IsImmunedToSpellEffect ( spellInfo , index );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2012-03-09 13:42:52 +01:00
SpellInfo const * Creature :: reachWithSpellAttack ( Unit * victim )
2008-10-11 14:16:25 -05:00
{
2012-03-09 13:42:52 +01:00
if ( ! victim )
2008-10-11 14:16:25 -05:00
return NULL ;
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( uint32 i = 0 ; i < CREATURE_MAX_SPELLS ; ++ i )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( ! m_spells [ i ])
2008-10-11 14:16:25 -05:00
continue ;
2011-09-15 14:08:17 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( m_spells [ i ]);
2010-04-07 19:14:10 +02:00
if ( ! spellInfo )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "WORLD: unknown spell id %i" , m_spells [ i ]);
2008-10-11 14:16:25 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool bcontinue = true ;
2010-09-28 08:21:51 +03:00
for ( uint32 j = 0 ; j < MAX_SPELL_EFFECTS ; j ++ )
2008-10-11 14:16:25 -05:00
{
2011-07-26 23:09:28 +02:00
if (( spellInfo -> Effects [ j ]. Effect == SPELL_EFFECT_SCHOOL_DAMAGE ) ||
( spellInfo -> Effects [ j ]. Effect == SPELL_EFFECT_INSTAKILL ) ||
( spellInfo -> Effects [ j ]. Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE ) ||
( spellInfo -> Effects [ j ]. Effect == SPELL_EFFECT_HEALTH_LEECH )
2012-03-17 20:13:37 +08:00
)
2008-10-11 14:16:25 -05:00
{
bcontinue = false ;
break ;
}
}
2012-03-17 20:13:37 +08:00
if ( bcontinue )
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( spellInfo -> ManaCost > GetPower ( POWER_MANA ))
2008-10-11 14:16:25 -05:00
continue ;
2011-07-26 23:09:28 +02:00
float range = spellInfo -> GetMaxRange ( false );
float minrange = spellInfo -> GetMinRange ( false );
2012-03-09 13:42:52 +01:00
float dist = GetDistance ( victim );
2010-04-07 22:59:46 +02:00
if ( dist > range || dist < minrange )
2008-10-11 14:16:25 -05:00
continue ;
2010-04-07 19:14:10 +02:00
if ( spellInfo -> PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SILENCED ))
2009-01-07 11:56:57 -06:00
continue ;
2010-04-07 19:14:10 +02:00
if ( spellInfo -> PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_PACIFIED ))
2008-10-11 14:16:25 -05:00
continue ;
return spellInfo ;
}
return NULL ;
}
2009-10-17 15:51:44 -07:00
2012-03-09 13:42:52 +01:00
SpellInfo const * Creature :: reachWithSpellCure ( Unit * victim )
2008-10-11 14:16:25 -05:00
{
2012-03-09 13:42:52 +01:00
if ( ! victim )
2008-10-11 14:16:25 -05:00
return NULL ;
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( uint32 i = 0 ; i < CREATURE_MAX_SPELLS ; ++ i )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( ! m_spells [ i ])
2008-10-11 14:16:25 -05:00
continue ;
2011-09-15 14:08:17 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( m_spells [ i ]);
2010-04-07 19:14:10 +02:00
if ( ! spellInfo )
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "WORLD: unknown spell id %i" , m_spells [ i ]);
2008-10-11 14:16:25 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool bcontinue = true ;
2010-09-28 08:21:51 +03:00
for ( uint32 j = 0 ; j < MAX_SPELL_EFFECTS ; j ++ )
2008-10-11 14:16:25 -05:00
{
2011-07-26 23:09:28 +02:00
if (( spellInfo -> Effects [ j ]. Effect == SPELL_EFFECT_HEAL ))
2008-10-11 14:16:25 -05:00
{
bcontinue = false ;
break ;
}
}
2012-03-17 20:13:37 +08:00
if ( bcontinue )
continue ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
if ( spellInfo -> ManaCost > GetPower ( POWER_MANA ))
2008-10-11 14:16:25 -05:00
continue ;
2011-07-26 23:09:28 +02:00
float range = spellInfo -> GetMaxRange ( true );
float minrange = spellInfo -> GetMinRange ( true );
2012-03-09 13:42:52 +01:00
float dist = GetDistance ( victim );
//if (!isInFront(victim, range) && spellInfo->AttributesEx)
2008-10-11 14:16:25 -05:00
// continue;
2010-04-07 22:59:46 +02:00
if ( dist > range || dist < minrange )
2008-10-11 14:16:25 -05:00
continue ;
2010-04-07 19:14:10 +02:00
if ( spellInfo -> PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SILENCED ))
2009-01-07 11:56:57 -06:00
continue ;
2010-04-07 19:14:10 +02:00
if ( spellInfo -> PreventionType == SPELL_PREVENTION_TYPE_PACIFY && HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_PACIFIED ))
2008-10-11 14:16:25 -05:00
continue ;
return spellInfo ;
}
return NULL ;
}
2009-10-17 15:51:44 -07:00
2010-04-25 12:59:27 +02:00
// select nearest hostile unit within the given distance (regardless of threat list).
2008-11-20 20:28:17 -06:00
Unit * Creature :: SelectNearestTarget ( float dist ) const
{
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( GetPositionX (), GetPositionY ()));
2008-11-20 20:28:17 -06:00
Cell cell ( p );
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2011-06-12 01:47:45 +02:00
Unit * target = NULL ;
2009-10-17 15:51:44 -07:00
2010-04-25 12:59:27 +02:00
{
2010-11-13 17:18:09 +01:00
if ( dist == 0.0f )
2010-04-25 12:59:27 +02:00
dist = MAX_VISIBILITY_DISTANCE ;
Trinity :: NearestHostileUnitCheck u_check ( this , dist );
Trinity :: UnitLastSearcher < Trinity :: NearestHostileUnitCheck > searcher ( this , target , u_check );
TypeContainerVisitor < Trinity :: UnitLastSearcher < Trinity :: NearestHostileUnitCheck > , WorldTypeMapContainer > world_unit_searcher ( searcher );
TypeContainerVisitor < Trinity :: UnitLastSearcher < Trinity :: NearestHostileUnitCheck > , GridTypeMapContainer > grid_unit_searcher ( searcher );
cell . Visit ( p , world_unit_searcher , * GetMap (), * this , dist );
cell . Visit ( p , grid_unit_searcher , * GetMap (), * this , dist );
}
return target ;
}
// select nearest hostile unit within the given attack distance (i.e. distance is ignored if > than ATTACK_DISTANCE), regardless of threat list.
Unit * Creature :: SelectNearestTargetInAttackDistance ( float dist ) const
{
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( GetPositionX (), GetPositionY ()));
2010-04-25 12:59:27 +02:00
Cell cell ( p );
cell . SetNoCreate ();
2011-06-12 01:47:45 +02:00
Unit * target = NULL ;
2010-04-25 12:59:27 +02:00
2011-06-12 17:13:28 +02:00
if ( dist > MAX_VISIBILITY_DISTANCE )
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "Creature (GUID: %u Entry: %u) SelectNearestTargetInAttackDistance called with dist > MAX_VISIBILITY_DISTANCE. Distance set to ATTACK_DISTANCE." , GetGUIDLow (), GetEntry ());
2011-06-12 17:13:28 +02:00
dist = ATTACK_DISTANCE ;
}
2010-04-25 12:59:27 +02:00
2008-11-20 20:28:17 -06:00
{
Trinity :: NearestHostileUnitInAttackDistanceCheck u_check ( this , dist );
2009-01-31 16:38:50 -06:00
Trinity :: UnitLastSearcher < Trinity :: NearestHostileUnitInAttackDistanceCheck > searcher ( this , target , u_check );
2009-10-17 15:51:44 -07:00
2008-11-20 20:28:17 -06:00
TypeContainerVisitor < Trinity :: UnitLastSearcher < Trinity :: NearestHostileUnitInAttackDistanceCheck > , WorldTypeMapContainer > world_unit_searcher ( searcher );
TypeContainerVisitor < Trinity :: UnitLastSearcher < Trinity :: NearestHostileUnitInAttackDistanceCheck > , GridTypeMapContainer > grid_unit_searcher ( searcher );
2009-10-17 15:51:44 -07:00
2011-06-12 17:13:28 +02:00
cell . Visit ( p , world_unit_searcher , * GetMap (), * this , ATTACK_DISTANCE > dist ? ATTACK_DISTANCE : dist );
cell . Visit ( p , grid_unit_searcher , * GetMap (), * this , ATTACK_DISTANCE > dist ? ATTACK_DISTANCE : dist );
2008-11-21 10:07:11 -06:00
}
2009-10-17 15:51:44 -07:00
2008-11-21 10:07:11 -06:00
return target ;
2008-11-20 20:28:17 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-11 16:17:21 +02:00
Player * Creature :: SelectNearestPlayer ( float distance ) const
{
Player * target = NULL ;
Trinity :: NearestPlayerInObjectRangeCheck checker ( this , distance );
Trinity :: PlayerLastSearcher < Trinity :: NearestPlayerInObjectRangeCheck > searcher ( this , target , checker );
VisitNearbyObject ( distance , searcher );
return target ;
}
2009-12-19 17:43:47 +01:00
void Creature :: SendAIReaction ( AiReaction reactionType )
{
WorldPacket data ( SMSG_AI_REACTION , 12 );
data << uint64 ( GetGUID ());
data << uint32 ( reactionType );
(( WorldObject * ) this ) -> SendMessageToSet ( & data , true );
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "WORLD: Sent SMSG_AI_REACTION, type %u." , reactionType );
2009-12-19 17:43:47 +01:00
}
2009-05-21 10:48:00 -05:00
void Creature :: CallAssistance ()
2008-10-11 14:16:25 -05:00
{
2010-04-07 22:59:46 +02:00
if ( ! m_AlreadyCallAssistance && getVictim () && ! isPet () && ! isCharmed ())
2008-10-11 14:16:25 -05:00
{
2008-11-25 16:36:50 -06:00
SetNoCallAssistance ( true );
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
float radius = sWorld -> getFloatConfig ( CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( radius > 0 )
2008-10-11 14:16:25 -05:00
{
std :: list < Creature *> assistList ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
{
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( GetPositionX (), GetPositionY ()));
2008-10-11 14:16:25 -05:00
Cell cell ( p );
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2009-12-20 15:20:04 +01:00
Trinity :: AnyAssistCreatureInRangeCheck u_check ( this , getVictim (), radius );
Trinity :: CreatureListSearcher < Trinity :: AnyAssistCreatureInRangeCheck > searcher ( this , assistList , u_check );
2009-10-17 15:51:44 -07:00
2008-10-14 11:57:03 -05:00
TypeContainerVisitor < Trinity :: CreatureListSearcher < Trinity :: AnyAssistCreatureInRangeCheck > , 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 , * GetMap (), * this , radius );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-25 16:36:50 -06:00
if ( ! assistList . empty ())
2008-10-11 14:16:25 -05:00
{
2011-09-15 14:08:17 +02:00
AssistDelayEvent * e = new AssistDelayEvent ( getVictim () -> GetGUID (), * this );
2008-11-25 16:36:50 -06:00
while ( ! assistList . empty ())
{
// Pushing guids because in delay can happen some creature gets despawned => invalid pointer
e -> AddAssistant (( * assistList . begin ()) -> GetGUID ());
assistList . pop_front ();
}
2010-12-23 23:25:44 +01:00
m_Events . AddEvent ( e , m_Events . CalculateTime ( sWorld -> getIntConfig ( CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY )));
2008-10-11 14:16:25 -05:00
}
}
}
}
2009-10-17 15:51:44 -07:00
2011-10-19 17:40:44 +01:00
void Creature :: CallForHelp ( float radius )
2009-06-04 16:10:26 -05:00
{
2011-10-19 17:40:44 +01:00
if ( radius <= 0.0f || ! getVictim () || isPet () || isCharmed ())
2009-06-04 16:10:26 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-10-18 10:53:34 -04:00
CellCoord p ( Trinity :: ComputeCellCoord ( GetPositionX (), GetPositionY ()));
2009-06-04 16:10:26 -05:00
Cell cell ( p );
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2011-10-19 17:40:44 +01:00
Trinity :: CallOfHelpCreatureInRangeDo u_do ( this , getVictim (), radius );
2009-12-20 15:20:04 +01:00
Trinity :: CreatureWorker < Trinity :: CallOfHelpCreatureInRangeDo > worker ( this , u_do );
2009-10-17 15:51:44 -07:00
2009-12-20 15:20:04 +01:00
TypeContainerVisitor < Trinity :: CreatureWorker < Trinity :: CallOfHelpCreatureInRangeDo > , GridTypeMapContainer > grid_creature_searcher ( worker );
2009-10-17 15:51:44 -07:00
2011-10-19 17:40:44 +01:00
cell . Visit ( p , grid_creature_searcher , * GetMap (), * this , radius );
2009-06-04 16:10:26 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-21 10:15:09 -05:00
bool Creature :: CanAssistTo ( const Unit * u , const Unit * enemy , bool checkfaction /*= true*/ ) const
2008-11-25 16:36:50 -06:00
{
2008-12-07 09:21:12 -06:00
// is it true?
2010-04-07 19:14:10 +02:00
if ( ! HasReactState ( REACT_AGGRESSIVE ))
2008-11-25 16:36:50 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2008-11-25 16:36:50 -06:00
// we don't need help from zombies :)
2009-05-21 10:15:09 -05:00
if ( ! isAlive ())
2008-11-25 16:36:50 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2009-07-24 09:15:52 +08:00
// we don't need help from non-combatant ;)
if ( isCivilian ())
return false ;
2009-10-17 15:51:44 -07:00
2012-02-03 18:46:05 +01:00
if ( HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_NPC ))
2011-03-06 12:22:04 +01:00
return false ;
2008-11-25 16:36:50 -06:00
// skip fighting creature
2009-05-21 10:15:09 -05:00
if ( isInCombat ())
2008-11-25 16:36:50 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2008-11-25 16:36:50 -06:00
// only free creature
2009-05-21 10:15:09 -05:00
if ( GetCharmerOrOwnerGUID ())
2008-11-25 16:36:50 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2009-05-21 10:15:09 -05:00
// only from same creature faction
if ( checkfaction )
{
if ( getFaction () != u -> getFaction ())
return false ;
}
else
{
if ( ! IsFriendlyTo ( u ))
return false ;
}
2009-10-17 15:51:44 -07:00
2008-11-25 16:36:50 -06:00
// skip non hostile to caster enemy creatures
2009-05-21 10:15:09 -05:00
if ( ! IsHostileTo ( enemy ))
2008-11-25 16:36:50 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2008-11-25 16:36:50 -06:00
return true ;
}
2009-10-17 15:51:44 -07:00
2009-09-29 15:13:46 -07:00
// use this function to avoid having hostile creatures attack
// friendlies and other mobs they shouldn't attack
2011-06-12 01:47:45 +02:00
bool Creature :: _IsTargetAcceptable ( const Unit * target ) const
2009-09-29 15:13:46 -07:00
{
2010-07-30 20:04:28 +02:00
ASSERT ( target );
2009-10-22 02:19:30 -07:00
2009-10-23 23:26:04 -07:00
// if the target cannot be attacked, the target is not acceptable
2009-10-24 14:53:03 -07:00
if ( IsFriendlyTo ( target )
2011-08-19 14:53:40 +02:00
|| ! target -> isTargetableForAttack ( false )
2009-10-24 14:53:03 -07:00
|| ( m_vehicle && ( IsOnVehicle ( target ) || m_vehicle -> GetBase () -> IsOnVehicle ( target ))))
2009-10-23 20:01:15 -07:00
return false ;
2009-10-17 15:51:44 -07:00
2012-02-03 19:02:17 +02:00
if ( target -> HasUnitState ( UNIT_STATE_DIED ))
2011-02-10 22:36:35 -03:00
{
// guards can detect fake death
if ( isGuard () && target -> HasFlag ( UNIT_FIELD_FLAGS_2 , UNIT_FLAG2_FEIGN_DEATH ))
return true ;
else
return false ;
}
2011-09-15 14:08:17 +02:00
const Unit * myVictim = getAttackerForHelper ();
2011-06-12 01:47:45 +02:00
const Unit * targetVictim = target -> getAttackerForHelper ();
2009-10-23 23:29:45 -07:00
2009-10-23 23:26:04 -07:00
// if I'm already fighting target, or I'm hostile towards the target, the target is acceptable
if ( myVictim == target || targetVictim == this || IsHostileTo ( target ))
return true ;
2009-10-17 15:51:44 -07:00
2009-10-10 16:26:00 -07:00
// if the target's victim is friendly, and the target is neutral, the target is acceptable
2009-10-24 14:53:03 -07:00
if ( targetVictim && IsFriendlyTo ( targetVictim ))
2009-10-10 16:26:00 -07:00
return true ;
2009-10-17 15:51:44 -07:00
2009-10-10 16:26:00 -07:00
// if the target's victim is not friendly, or the target is friendly, the target is not acceptable
return false ;
2009-09-29 15:13:46 -07:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: SaveRespawnTime ()
{
2010-08-23 15:11:06 +02:00
if ( isSummon () || ! m_DBTableGuid || ( m_creatureData && ! m_creatureData -> dbData ))
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2012-06-07 23:20:57 +02:00
GetMap () -> SaveCreatureRespawnTime ( m_DBTableGuid , m_respawnTime );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
// this should not be called by petAI or
2012-03-09 13:42:52 +01:00
bool Creature :: canCreatureAttack ( Unit const * victim , bool /*force*/ ) const
2008-10-11 14:16:25 -05:00
{
2012-03-09 13:42:52 +01:00
if ( ! victim -> IsInMap ( this ))
2009-08-15 14:30:14 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2012-03-09 13:42:52 +01:00
if ( ! IsValidAttackTarget ( victim ))
2009-08-15 14:30:14 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2012-03-09 13:42:52 +01:00
if ( ! victim -> isInAccessiblePlaceFor ( this ))
2009-08-15 14:30:14 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2012-03-09 13:42:52 +01:00
if ( IsAIEnabled && ! AI () -> CanAIAttack ( victim ))
2009-08-26 16:54:59 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( sMapStore . LookupEntry ( GetMapId ()) -> IsDungeon ())
2009-08-15 14:30:14 -05:00
return true ;
2009-10-17 15:51:44 -07:00
2008-11-14 16:28:45 -06:00
//Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick.
2012-03-09 13:42:52 +01:00
float dist = std :: max ( GetAttackDistance ( victim ), sWorld -> getFloatConfig ( CONFIG_THREAT_RADIUS )) + m_CombatDistance ;
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
if ( Unit * unit = GetCharmerOrOwner ())
2012-03-09 13:42:52 +01:00
return victim -> IsWithinDist ( unit , dist );
2009-08-15 14:30:14 -05:00
else
2012-03-09 13:42:52 +01:00
return victim -> IsInDist ( & m_homePosition , dist );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-04-28 22:46:40 +02:00
CreatureAddon const * Creature :: GetCreatureAddon () const
2008-10-11 14:16:25 -05:00
{
if ( m_DBTableGuid )
{
2011-04-28 22:46:40 +02:00
if ( CreatureAddon const * addon = sObjectMgr -> GetCreatureAddon ( m_DBTableGuid ))
2008-10-11 14:16:25 -05:00
return addon ;
}
2009-10-17 15:51:44 -07:00
2009-12-17 11:06:50 +01:00
// dependent from difficulty mode entry
2012-02-27 14:58:47 +01:00
return sObjectMgr -> GetCreatureTemplateAddon ( GetCreatureTemplate () -> Entry );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//creature_addon table
bool Creature :: LoadCreaturesAddon ( bool reload )
{
2011-09-15 14:08:17 +02:00
CreatureAddon const * cainfo = GetCreatureAddon ();
2010-04-07 19:14:10 +02:00
if ( ! cainfo )
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( cainfo -> mount != 0 )
Mount ( cainfo -> mount );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( cainfo -> bytes1 != 0 )
2009-05-31 15:58:58 -05:00
{
// 0 StandState
// 1 FreeTalentPoints Pet only, so always 0 for default creature
// 2 StandFlags
// 3 StandMiscFlags
2009-10-17 15:51:44 -07:00
2009-05-31 15:58:58 -05:00
SetByteValue ( UNIT_FIELD_BYTES_1 , 0 , uint8 ( cainfo -> bytes1 & 0xFF ));
//SetByteValue(UNIT_FIELD_BYTES_1, 1, uint8((cainfo->bytes1 >> 8) & 0xFF));
SetByteValue ( UNIT_FIELD_BYTES_1 , 1 , 0 );
SetByteValue ( UNIT_FIELD_BYTES_1 , 2 , uint8 (( cainfo -> bytes1 >> 16 ) & 0xFF ));
SetByteValue ( UNIT_FIELD_BYTES_1 , 3 , uint8 (( cainfo -> bytes1 >> 24 ) & 0xFF ));
2012-03-12 00:45:58 +01:00
//! Suspected correlation between UNIT_FIELD_BYTES_1, offset 3, value 0x2:
//! If no inhabittype_fly (if no MovementFlag_DisableGravity flag found in sniffs)
//! Set MovementFlag_Hover. Otherwise do nothing.
if ( GetByteValue ( UNIT_FIELD_BYTES_1 , 3 ) & UNIT_BYTE1_FLAG_HOVER && ! IsLevitating ())
AddUnitMovementFlag ( MOVEMENTFLAG_HOVER );
2009-05-31 15:58:58 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( cainfo -> bytes2 != 0 )
2009-05-31 15:58:58 -05:00
{
// 0 SheathState
// 1 Bytes2Flags
// 2 UnitRename Pet only, so always 0 for default creature
// 3 ShapeshiftForm Must be determined/set by shapeshift spell/aura
2009-10-17 15:51:44 -07:00
2009-05-31 15:58:58 -05:00
SetByteValue ( UNIT_FIELD_BYTES_2 , 0 , uint8 ( cainfo -> bytes2 & 0xFF ));
2009-12-19 19:10:14 +01:00
//SetByteValue(UNIT_FIELD_BYTES_2, 1, uint8((cainfo->bytes2 >> 8) & 0xFF));
2009-05-31 15:58:58 -05:00
//SetByteValue(UNIT_FIELD_BYTES_2, 2, uint8((cainfo->bytes2 >> 16) & 0xFF));
SetByteValue ( UNIT_FIELD_BYTES_2 , 2 , 0 );
//SetByteValue(UNIT_FIELD_BYTES_2, 3, uint8((cainfo->bytes2 >> 24) & 0xFF));
SetByteValue ( UNIT_FIELD_BYTES_2 , 3 , 0 );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( cainfo -> emote != 0 )
SetUInt32Value ( UNIT_NPC_EMOTESTATE , cainfo -> emote );
2009-10-17 15:51:44 -07:00
2009-09-19 12:13:08 -07:00
//Load Path
if ( cainfo -> path_id != 0 )
m_path_id = cainfo -> path_id ;
2009-10-17 15:51:44 -07:00
2011-04-28 22:46:40 +02:00
if ( ! cainfo -> auras . empty ())
2008-10-11 14:16:25 -05:00
{
2011-04-28 22:46:40 +02:00
for ( std :: vector < uint32 >:: const_iterator itr = cainfo -> auras . begin (); itr != cainfo -> auras . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2011-09-15 14:08:17 +02:00
SpellInfo const * AdditionalSpellInfo = sSpellMgr -> GetSpellInfo ( * itr );
2008-10-11 14:16:25 -05:00
if ( ! AdditionalSpellInfo )
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_SQL , "Creature (GUID: %u Entry: %u) has wrong spell %u defined in `auras` field." , GetGUIDLow (), GetEntry (), * itr );
2008-10-11 14:16:25 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// skip already applied aura
2011-04-28 22:46:40 +02:00
if ( HasAura ( * itr ))
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( ! reload )
2013-01-16 01:17:13 +00:00
sLog -> outError ( LOG_FILTER_SQL , "Creature (GUID: %u Entry: %u) has duplicate aura (spell %u) in `auras` field." , GetDBTableGUIDLow (), GetEntry (), * itr );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-04-28 22:46:40 +02:00
AddAura ( * itr , this );
sLog -> outDebug ( LOG_FILTER_UNITS , "Spell: %u added to creature (GUID: %u Entry: %u)" , * itr , GetGUIDLow (), GetEntry ());
2008-10-11 14:16:25 -05:00
}
}
2012-03-12 00:45:58 +01:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2008-11-14 16:28:45 -06:00
/// Send a message to LocalDefense channel for players opposition team in the zone
2008-10-11 14:16:25 -05:00
void Creature :: SendZoneUnderAttackMessage ( Player * attacker )
{
uint32 enemy_team = attacker -> GetTeam ();
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
WorldPacket data ( SMSG_ZONE_UNDER_ATTACK , 4 );
2009-08-12 07:16:20 -05:00
data << ( uint32 ) GetAreaId ();
2011-04-29 20:47:02 +02:00
sWorld -> SendGlobalMessage ( & data , NULL , ( enemy_team == ALLIANCE ? HORDE : ALLIANCE ));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-06-27 15:37:33 -05:00
void Creature :: SetInCombatWithZone ()
{
if ( ! CanHaveThreatList ())
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "Creature entry %u call SetInCombatWithZone but creature cannot have threat list." , GetEntry ());
2009-06-27 15:37:33 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-10-07 19:45:43 -05:00
Map * map = GetMap ();
2009-10-17 15:51:44 -07:00
2011-10-07 19:45:43 -05:00
if ( ! map -> IsDungeon ())
2009-06-27 15:37:33 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_UNITS , "Creature entry %u call SetInCombatWithZone for map (id: %u) that isn't an instance." , GetEntry (), map -> GetId ());
2009-06-27 15:37:33 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-10-07 19:45:43 -05:00
Map :: PlayerList const & PlList = map -> GetPlayers ();
2009-10-17 15:51:44 -07:00
2009-06-27 15:37:33 -05:00
if ( PlList . isEmpty ())
return ;
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( Map :: PlayerList :: const_iterator i = PlList . begin (); i != PlList . end (); ++ i )
2009-06-27 15:37:33 -05:00
{
2011-10-07 11:08:09 -05:00
if ( Player * player = i -> getSource ())
2009-06-27 15:37:33 -05:00
{
2011-10-07 11:08:09 -05:00
if ( player -> isGameMaster ())
2009-06-27 15:37:33 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2011-10-07 11:08:09 -05:00
if ( player -> isAlive ())
2009-06-27 15:37:33 -05:00
{
2011-10-07 11:08:09 -05:00
this -> SetInCombatWith ( player );
player -> SetInCombatWith ( this );
AddThreat ( player , 0.0f );
2009-06-27 15:37:33 -05:00
}
}
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: _AddCreatureSpellCooldown ( uint32 spell_id , time_t end_time )
{
m_CreatureSpellCooldowns [ spell_id ] = end_time ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: _AddCreatureCategoryCooldown ( uint32 category , time_t apply_time )
{
m_CreatureCategoryCooldowns [ category ] = apply_time ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: AddCreatureSpellCooldown ( uint32 spellid )
{
2011-09-15 14:08:17 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( spellid );
2010-04-07 19:14:10 +02:00
if ( ! spellInfo )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-07-26 23:09:28 +02:00
uint32 cooldown = spellInfo -> GetRecoveryTime ();
2011-09-15 14:08:17 +02:00
if ( Player * modOwner = GetSpellModOwner ())
2009-08-17 14:36:36 +02:00
modOwner -> ApplySpellMod ( spellid , SPELLMOD_COOLDOWN , cooldown );
2009-10-17 16:20:24 -07:00
2010-04-07 19:14:10 +02:00
if ( cooldown )
2010-07-12 00:30:17 +02:00
_AddCreatureSpellCooldown ( spellid , time ( NULL ) + cooldown / IN_MILLISECONDS );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( spellInfo -> Category )
2009-12-24 10:20:15 +01:00
_AddCreatureCategoryCooldown ( spellInfo -> Category , time ( NULL ));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Creature :: HasCategoryCooldown ( uint32 spell_id ) const
{
2011-09-15 14:08:17 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( spell_id );
2010-04-07 19:14:10 +02:00
if ( ! spellInfo )
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
CreatureSpellCooldowns :: const_iterator itr = m_CreatureCategoryCooldowns . find ( spellInfo -> Category );
2010-07-12 00:30:17 +02:00
return ( itr != m_CreatureCategoryCooldowns . end () && time_t ( itr -> second + ( spellInfo -> CategoryRecoveryTime / IN_MILLISECONDS )) > time ( NULL ));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool Creature :: HasSpellCooldown ( uint32 spell_id ) const
{
CreatureSpellCooldowns :: const_iterator itr = m_CreatureSpellCooldowns . find ( spell_id );
2009-12-24 10:20:15 +01:00
return ( itr != m_CreatureSpellCooldowns . end () && itr -> second > time ( NULL )) || HasCategoryCooldown ( spell_id );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2012-09-07 02:05:09 +01:00
void Creature :: ProhibitSpellSchool ( SpellSchoolMask idSchoolMask , uint32 unTimeMs )
2012-09-04 23:04:59 -04:00
{
time_t curTime = time ( NULL );
for ( uint8 i = 0 ; i < CREATURE_MAX_SPELLS ; ++ i )
{
if ( m_spells [ i ] == 0 )
continue ;
2012-09-06 19:59:27 +01:00
2012-09-04 23:04:59 -04:00
uint32 unSpellId = m_spells [ i ];
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( unSpellId );
if ( ! spellInfo )
{
ASSERT ( spellInfo );
continue ;
}
// Not send cooldown for this spells
if ( spellInfo -> Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE )
continue ;
if ( spellInfo -> PreventionType != SPELL_PREVENTION_TYPE_SILENCE )
continue ;
if (( idSchoolMask & spellInfo -> GetSchoolMask ()) && GetCreatureSpellCooldownDelay ( unSpellId ) < unTimeMs )
{
_AddCreatureSpellCooldown ( unSpellId , curTime + unTimeMs / IN_MILLISECONDS );
2012-09-07 02:05:09 +01:00
if ( UnitAI * ai = GetAI ())
2012-09-04 23:04:59 -04:00
ai -> SpellInterrupted ( unSpellId , unTimeMs );
}
}
}
2008-10-11 14:16:25 -05:00
bool Creature :: HasSpell ( uint32 spellID ) const
{
uint8 i ;
2009-10-17 16:20:24 -07:00
for ( i = 0 ; i < CREATURE_MAX_SPELLS ; ++ i )
2010-04-07 19:14:10 +02:00
if ( spellID == m_spells [ i ])
2008-10-11 14:16:25 -05:00
break ;
return i < CREATURE_MAX_SPELLS ; //broke before end of iteration of known spells
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
time_t Creature :: GetRespawnTimeEx () const
{
2009-12-24 10:20:15 +01:00
time_t now = time ( NULL );
2010-09-15 06:22:54 +02:00
if ( m_respawnTime > now )
2008-10-11 14:16:25 -05:00
return m_respawnTime ;
else
return now ;
}
2009-10-17 15:51:44 -07:00
2011-10-18 10:53:34 -04:00
void Creature :: GetRespawnPosition ( float & x , float & y , float & z , float * ori , float * dist ) const
2008-10-11 14:16:25 -05:00
{
if ( m_DBTableGuid )
{
2010-12-22 21:25:23 +01:00
if ( CreatureData const * data = sObjectMgr -> GetCreatureData ( GetDBTableGUIDLow ()))
2008-10-11 14:16:25 -05:00
{
x = data -> posX ;
y = data -> posY ;
z = data -> posZ ;
2010-04-07 19:14:10 +02:00
if ( ori )
2008-10-11 14:16:25 -05:00
* ori = data -> orientation ;
2010-04-07 19:14:10 +02:00
if ( dist )
2008-10-11 14:16:25 -05:00
* dist = data -> spawndist ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return ;
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
x = GetPositionX ();
y = GetPositionY ();
z = GetPositionZ ();
2010-04-07 19:14:10 +02:00
if ( ori )
2008-10-11 14:16:25 -05:00
* ori = GetOrientation ();
2010-04-07 19:14:10 +02:00
if ( dist )
2008-10-11 14:16:25 -05:00
* dist = 0 ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void Creature :: AllLootRemovedFromCorpse ()
{
if ( ! HasFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SKINNABLE ))
{
2010-09-15 06:22:54 +02:00
time_t now = time ( NULL );
2011-06-12 02:30:32 +02:00
if ( m_corpseRemoveTime <= now )
2010-09-15 06:22:54 +02:00
return ;
2009-10-17 15:51:44 -07:00
2010-09-15 06:22:54 +02:00
float decayRate ;
2012-02-27 14:58:47 +01:00
CreatureTemplate const * cinfo = GetCreatureTemplate ();
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
decayRate = sWorld -> getRate ( RATE_CORPSE_DECAY_LOOTED );
2010-09-16 13:28:16 +06:00
uint32 diff = uint32 (( m_corpseRemoveTime - now ) * decayRate );
2009-10-17 15:51:44 -07:00
2010-09-15 06:22:54 +02:00
m_respawnTime -= diff ;
2010-09-17 15:16:26 +02:00
// corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
if ( cinfo && cinfo -> SkinLootId )
m_corpseRemoveTime = time ( NULL );
else
m_corpseRemoveTime -= diff ;
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2010-12-14 22:45:23 +01:00
uint8 Creature :: getLevelForTarget ( WorldObject const * target ) const
2008-10-11 14:16:25 -05:00
{
2010-12-14 22:45:23 +01:00
if ( ! isWorldBoss () || ! target -> ToUnit ())
2008-10-11 14:16:25 -05:00
return Unit :: getLevelForTarget ( target );
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
uint16 level = target -> ToUnit () -> getLevel () + sWorld -> getIntConfig ( CONFIG_WORLD_BOSS_LEVEL_DIFF );
2010-04-07 19:14:10 +02:00
if ( level < 1 )
2008-10-11 14:16:25 -05:00
return 1 ;
2010-04-07 19:14:10 +02:00
if ( level > 255 )
2008-10-11 14:16:25 -05:00
return 255 ;
2010-08-26 01:20:57 +06:00
return uint8 ( level );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-04-14 18:31:31 -05:00
std :: string Creature :: GetAIName () const
{
2011-04-28 22:57:08 +02:00
return sObjectMgr -> GetCreatureTemplate ( GetEntry ()) -> AIName ;
2009-04-14 18:31:31 -05:00
}
2009-10-17 15:51:44 -07:00
2009-04-14 18:31:31 -05:00
std :: string Creature :: GetScriptName () const
2008-10-11 14:16:25 -05:00
{
2010-12-22 21:25:23 +01:00
return sObjectMgr -> GetScriptName ( GetScriptId ());
2008-11-20 16:16:57 -06:00
}
2009-10-17 15:51:44 -07:00
2009-04-14 18:31:31 -05:00
uint32 Creature :: GetScriptId () const
2008-11-20 16:16:57 -06:00
{
2011-04-28 22:57:08 +02:00
return sObjectMgr -> GetCreatureTemplate ( GetEntry ()) -> ScriptID ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
VendorItemData const * Creature :: GetVendorItems () const
{
2010-12-22 21:25:23 +01:00
return sObjectMgr -> GetNpcVendorItemList ( GetEntry ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 Creature :: GetVendorItemCurrentCount ( VendorItem const * vItem )
{
2010-04-07 19:14:10 +02:00
if ( ! vItem -> maxcount )
2008-10-11 14:16:25 -05:00
return vItem -> maxcount ;
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
VendorItemCounts :: iterator itr = m_vendorItemCounts . begin ();
for (; itr != m_vendorItemCounts . end (); ++ itr )
2010-04-07 23:25:02 +02:00
if ( itr -> itemId == vItem -> item )
2009-12-24 10:20:15 +01:00
break ;
2010-04-07 19:14:10 +02:00
if ( itr == m_vendorItemCounts . end ())
2008-10-11 14:16:25 -05:00
return vItem -> maxcount ;
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
VendorItemCount * vCount = &* itr ;
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
time_t ptime = time ( NULL );
2009-10-17 15:51:44 -07:00
2010-08-23 15:11:06 +02:00
if ( time_t ( vCount -> lastIncrementTime + vItem -> incrtime ) <= ptime )
2008-10-11 14:16:25 -05:00
{
2011-04-28 22:42:33 +02:00
ItemTemplate const * pProto = sObjectMgr -> GetItemTemplate ( vItem -> item );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 diff = uint32 (( ptime - vCount -> lastIncrementTime ) / vItem -> incrtime );
2010-04-07 22:59:46 +02:00
if (( vCount -> count + diff * pProto -> BuyCount ) >= vItem -> maxcount )
2008-10-11 14:16:25 -05:00
{
2008-11-04 09:23:06 -06:00
m_vendorItemCounts . erase ( itr );
2008-10-11 14:16:25 -05:00
return vItem -> maxcount ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
vCount -> count += diff * pProto -> BuyCount ;
vCount -> lastIncrementTime = ptime ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return vCount -> count ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 Creature :: UpdateVendorItemCurrentCount ( VendorItem const * vItem , uint32 used_count )
{
2010-04-07 19:14:10 +02:00
if ( ! vItem -> maxcount )
2008-10-11 14:16:25 -05:00
return 0 ;
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
VendorItemCounts :: iterator itr = m_vendorItemCounts . begin ();
for (; itr != m_vendorItemCounts . end (); ++ itr )
2010-04-07 23:25:02 +02:00
if ( itr -> itemId == vItem -> item )
2009-12-24 10:20:15 +01:00
break ;
2010-04-07 19:14:10 +02:00
if ( itr == m_vendorItemCounts . end ())
2008-10-11 14:16:25 -05:00
{
2010-08-23 15:11:06 +02:00
uint32 new_count = vItem -> maxcount > used_count ? vItem -> maxcount - used_count : 0 ;
2011-04-29 20:47:02 +02:00
m_vendorItemCounts . push_back ( VendorItemCount ( vItem -> item , new_count ));
2008-10-11 14:16:25 -05:00
return new_count ;
}
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
VendorItemCount * vCount = &* itr ;
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
time_t ptime = time ( NULL );
2009-10-17 15:51:44 -07:00
2010-08-30 15:25:15 +02:00
if ( time_t ( vCount -> lastIncrementTime + vItem -> incrtime ) <= ptime )
2008-10-11 14:16:25 -05:00
{
2011-04-28 22:42:33 +02:00
ItemTemplate const * pProto = sObjectMgr -> GetItemTemplate ( vItem -> item );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 diff = uint32 (( ptime - vCount -> lastIncrementTime ) / vItem -> incrtime );
2010-04-07 22:59:46 +02:00
if (( vCount -> count + diff * pProto -> BuyCount ) < vItem -> maxcount )
2008-10-11 14:16:25 -05:00
vCount -> count += diff * pProto -> BuyCount ;
else
vCount -> count = vItem -> maxcount ;
}
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
vCount -> count = vCount -> count > used_count ? vCount -> count - used_count : 0 ;
2008-10-11 14:16:25 -05:00
vCount -> lastIncrementTime = ptime ;
return vCount -> count ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
TrainerSpellData const * Creature :: GetTrainerSpells () const
{
2010-12-22 21:25:23 +01:00
return sObjectMgr -> GetNpcTrainerSpells ( GetEntry ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-14 17:03:03 -06:00
// overwrite WorldObject function for proper name localization
2012-10-24 13:29:34 +02:00
std :: string const & Creature :: GetNameForLocaleIdx ( LocaleConstant loc_idx ) const
2008-11-14 17:03:03 -06:00
{
2010-09-17 07:04:29 +02:00
if ( loc_idx != DEFAULT_LOCALE )
2008-11-14 17:03:03 -06:00
{
2010-08-23 15:11:06 +02:00
uint8 uloc_idx = uint8 ( loc_idx );
2011-09-15 14:08:17 +02:00
CreatureLocale const * cl = sObjectMgr -> GetCreatureLocale ( GetEntry ());
2008-11-14 17:03:03 -06:00
if ( cl )
{
2010-08-23 15:11:06 +02:00
if ( cl -> Name . size () > uloc_idx && ! cl -> Name [ uloc_idx ]. empty ())
2012-10-24 13:29:34 +02:00
return cl -> Name [ uloc_idx ];
2008-11-14 17:03:03 -06:00
}
}
2009-10-17 15:51:44 -07:00
2008-11-14 17:03:03 -06:00
return GetName ();
}
2009-10-17 15:51:44 -07:00
2011-10-10 17:59:52 -04:00
//Do not if this works or not, moving creature to another map is very dangerous
2010-10-24 02:55:50 +02:00
void Creature :: FarTeleportTo ( Map * map , float X , float Y , float Z , float O )
{
2011-10-10 17:59:52 -04:00
CleanupBeforeRemoveFromMap ( false );
GetMap () -> RemoveFromMap ( this , false );
Relocate ( X , Y , Z , O );
2010-10-24 02:55:50 +02:00
SetMap ( map );
2011-10-10 17:59:52 -04:00
GetMap () -> AddToMap ( this );
2011-10-10 17:08:01 -04:00
}
void Creature :: SetPosition ( float x , float y , float z , float o )
{
// prevent crash when a bad coord is sent by the client
if ( ! Trinity :: IsValidMapCoord ( x , y , z , o ))
{
sLog -> outDebug ( LOG_FILTER_UNITS , "Creature::SetPosition(%f, %f, %f) .. bad coordinates!" , x , y , z );
return ;
}
GetMap () -> CreatureRelocation ( ToCreature (), x , y , z , o );
if ( IsVehicle ())
2012-09-10 15:44:12 +02:00
GetVehicleKit () -> RelocatePassengers ();
2010-10-24 02:55:50 +02:00
}
2011-02-09 16:28:56 +01:00
bool Creature :: IsDungeonBoss () const
{
2011-09-15 14:08:17 +02:00
CreatureTemplate const * cinfo = sObjectMgr -> GetCreatureTemplate ( GetEntry ());
2011-02-09 16:28:56 +01:00
return cinfo && ( cinfo -> flags_extra & CREATURE_FLAG_EXTRA_DUNGEON_BOSS );
}
2012-01-14 15:34:41 +01:00
2012-02-23 13:01:16 +01:00
bool Creature :: SetWalk ( bool enable )
2012-01-14 15:34:41 +01:00
{
2012-02-23 13:01:16 +01:00
if ( ! Unit :: SetWalk ( enable ))
return false ;
2012-01-14 15:34:41 +01:00
WorldPacket data ( enable ? SMSG_SPLINE_MOVE_SET_WALK_MODE : SMSG_SPLINE_MOVE_SET_RUN_MODE , 9 );
data . append ( GetPackGUID ());
2012-03-12 00:45:58 +01:00
SendMessageToSet ( & data , false );
return true ;
}
bool Creature :: SetDisableGravity ( bool disable , bool packetOnly /*=false*/ )
{
//! It's possible only a packet is sent but moveflags are not updated
//! Need more research on this
if ( ! packetOnly && ! Unit :: SetDisableGravity ( disable ))
return false ;
if ( ! movespline -> Initialized ())
return true ;
WorldPacket data ( disable ? SMSG_SPLINE_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE , 9 );
data . append ( GetPackGUID ());
SendMessageToSet ( & data , false );
2012-02-23 13:01:16 +01:00
return true ;
2012-01-14 15:34:41 +01:00
}
2012-03-12 00:45:58 +01:00
bool Creature :: SetHover ( bool enable )
2012-01-14 15:34:41 +01:00
{
2012-03-12 00:45:58 +01:00
if ( ! Unit :: SetHover ( enable ))
2012-02-23 13:01:16 +01:00
return false ;
2012-03-12 00:45:58 +01:00
//! Unconfirmed for players:
if ( enable )
SetByteFlag ( UNIT_FIELD_BYTES_1 , 3 , UNIT_BYTE1_FLAG_HOVER );
else
RemoveByteFlag ( UNIT_FIELD_BYTES_1 , 3 , UNIT_BYTE1_FLAG_HOVER );
if ( ! movespline -> Initialized ())
return true ;
//! Not always a packet is sent
WorldPacket data ( enable ? SMSG_SPLINE_MOVE_SET_HOVER : SMSG_SPLINE_MOVE_UNSET_HOVER , 9 );
2012-01-14 15:34:41 +01:00
data . append ( GetPackGUID ());
2012-03-12 00:45:58 +01:00
SendMessageToSet ( & data , false );
2012-02-23 13:01:16 +01:00
return true ;
2012-01-14 15:34:41 +01:00
}
2012-12-06 09:58:32 -05:00
float Creature :: GetAggroRange ( Unit const * target ) const
{
// Determines the aggro range for creatures (usually pets), used mainly for aggressive pet target selection.
// Based on data from wowwiki due to lack of 3.3.5a data
if ( target && this -> isPet ())
{
uint32 targetLevel = 0 ;
2012-12-14 01:23:53 +00:00
2012-12-06 09:58:32 -05:00
if ( target -> GetTypeId () == TYPEID_PLAYER )
targetLevel = target -> getLevelForTarget ( this );
else if ( target -> GetTypeId () == TYPEID_UNIT )
targetLevel = target -> ToCreature () -> getLevelForTarget ( this );
uint32 myLevel = getLevelForTarget ( target );
int32 levelDiff = int32 ( targetLevel ) - int32 ( myLevel );
2012-12-14 01:23:53 +00:00
2012-12-06 09:58:32 -05:00
// The maximum Aggro Radius is capped at 45 yards (25 level difference)
if ( levelDiff < - 25 )
levelDiff = - 25 ;
// The base aggro radius for mob of same level
float aggroRadius = 20 ;
// Aggro Radius varies with level difference at a rate of roughly 1 yard/level
aggroRadius -= ( float ) levelDiff ;
// detect range auras
aggroRadius += GetTotalAuraModifier ( SPELL_AURA_MOD_DETECT_RANGE );
// detected range auras
aggroRadius += target -> GetTotalAuraModifier ( SPELL_AURA_MOD_DETECTED_RANGE );
// Just in case, we don't want pets running all over the map
if ( aggroRadius > MAX_AGGRO_RADIUS )
aggroRadius = MAX_AGGRO_RADIUS ;
// Minimum Aggro Radius for a mob seems to be combat range (5 yards)
// hunter pets seem to ignore minimum aggro radius so we'll default it a little higher
if ( aggroRadius < 10 )
aggroRadius = 10 ;
return ( aggroRadius );
}
// Default
return 0.0f ;
}
Unit * Creature :: SelectNearestHostileUnitInAggroRange ( bool useLOS ) const
{
// Selects nearest hostile target within creature's aggro range. Used primarily by
// pets set to aggressive. Will not return neutral or friendly targets.
Unit * target = NULL ;
{
Trinity :: NearestHostileUnitInAggroRangeCheck u_check ( this , useLOS );
Trinity :: UnitSearcher < Trinity :: NearestHostileUnitInAggroRangeCheck > searcher ( this , target , u_check );
VisitNearbyGridObject ( MAX_AGGRO_RADIUS , searcher );
}
return target ;
}