2010-10-07 15:35:36 +02:00
/*
2014-01-01 00:07:53 +01:00
* Copyright (C) 2008-2014 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
2010-10-24 22:03:53 +02:00
#include "GameObjectAI.h"
2013-08-07 10:31:13 +02:00
#include "Battleground.h"
2013-06-15 15:16:36 +02:00
#include "CellImpl.h"
#include "CreatureAISelector.h"
#include "DynamicTree.h"
#include "GameObjectModel.h"
#include "GridNotifiersImpl.h"
#include "Group.h"
2011-05-05 10:23:00 +02:00
#include "GroupMgr.h"
2013-06-15 15:16:36 +02:00
#include "ObjectMgr.h"
#include "OutdoorPvPMgr.h"
2010-06-25 03:50:19 -06:00
#include "PoolMgr.h"
2013-06-15 15:16:36 +02:00
#include "ScriptMgr.h"
2008-10-11 14:16:25 -05:00
#include "SpellMgr.h"
2013-06-15 15:16:36 +02:00
#include "UpdateFieldFlags.h"
2008-10-11 14:16:25 -05:00
#include "World.h"
2013-10-16 18:37:29 +02:00
#include "Transport.h"
2014-07-20 16:06:35 +02:00
#include <G3D/Quat.h>
2012-02-03 16:03:52 -05:00
2013-10-16 18:37:29 +02:00
GameObject :: GameObject () : WorldObject ( false ), MapObject (),
m_model ( NULL ), m_goValue (), m_AI ( NULL )
2008-10-11 14:16:25 -05:00
{
m_objectType |= TYPEMASK_GAMEOBJECT ;
m_objectTypeId = TYPEID_GAMEOBJECT ;
2009-10-17 15:51:44 -07:00
2012-07-12 21:20:34 +02:00
m_updateFlag = ( UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_valuesCount = GAMEOBJECT_END ;
m_respawnTime = 0 ;
2010-01-30 08:05:08 -07:00
m_respawnDelayTime = 300 ;
2008-10-11 14:16:25 -05:00
m_lootState = GO_NOT_READY ;
m_spawnedByDefault = true ;
m_usetimes = 0 ;
m_spellId = 0 ;
m_cooldownTime = 0 ;
m_goInfo = NULL ;
2009-05-31 21:04:04 -05:00
m_goData = NULL ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_DBTableGuid = 0 ;
2009-06-11 00:45:59 -05:00
m_rotation = 0 ;
2009-10-28 16:31:19 -07:00
2012-05-30 08:01:02 +02:00
m_lootRecipientGroup = 0 ;
2010-03-11 22:55:02 +01:00
m_groupLootTimer = 0 ;
2010-08-02 17:28:47 +02:00
lootingGroupLowGUID = 0 ;
2010-03-11 22:55:02 +01:00
2009-10-28 16:31:19 -07:00
ResetLootMode (); // restore default loot mode
2013-12-01 16:19:30 +01:00
m_stationaryPosition . Relocate ( 0.0f , 0.0f , 0.0f , 0.0f );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
GameObject ::~ GameObject ()
{
2011-10-18 09:51:55 +02:00
delete m_AI ;
2012-02-03 16:03:52 -05:00
delete m_model ;
2014-09-29 20:10:08 +02:00
if ( m_goInfo -> type == GAMEOBJECT_TYPE_TRANSPORT )
delete m_goValue . Transport . StopFrames ;
2010-04-07 19:14:10 +02:00
//if (m_uint32Values) // field array can be not exist if GameOBject not loaded
2009-07-01 18:23:36 -05:00
// CleanupsBeforeDelete();
}
2009-10-17 15:51:44 -07:00
2010-10-23 23:31:37 +02:00
bool GameObject :: AIM_Initialize ()
{
2014-09-19 03:30:02 +01:00
delete m_AI ;
2010-10-23 23:31:37 +02:00
m_AI = FactorySelector :: SelectGameObjectAI ( this );
2011-10-18 09:51:55 +02:00
if ( ! m_AI )
return false ;
2010-10-23 23:31:37 +02:00
m_AI -> InitializeAI ();
return true ;
}
std :: string GameObject :: GetAIName () const
{
2013-05-30 13:14:06 +02:00
if ( GameObjectTemplate const * got = sObjectMgr -> GetGameObjectTemplate ( GetEntry ()))
return got -> AIName ;
return "" ;
2010-10-23 23:31:37 +02:00
}
2014-06-13 11:16:17 +02:00
void GameObject :: CleanupsBeforeDelete ( bool finalCleanup )
2009-07-01 18:23:36 -05:00
{
2014-06-13 11:16:17 +02:00
WorldObject :: CleanupsBeforeDelete ( finalCleanup );
2010-02-14 19:13:14 -07:00
2010-04-07 19:14:10 +02:00
if ( m_uint32Values ) // field array can be not exist if GameOBject not loaded
2011-10-31 10:46:39 -04:00
RemoveFromOwner ();
}
2009-10-17 15:51:44 -07:00
2011-10-31 10:46:39 -04:00
void GameObject :: RemoveFromOwner ()
{
2014-09-14 16:14:12 +02:00
ObjectGuid ownerGUID = GetOwnerGUID ();
2011-10-31 10:46:39 -04:00
if ( ! ownerGUID )
return ;
if ( Unit * owner = ObjectAccessor :: GetUnit ( * this , ownerGUID ))
{
owner -> RemoveGameObject ( this , false );
ASSERT ( ! GetOwnerGUID ());
return ;
2009-07-01 18:23:36 -05:00
}
2011-10-31 10:46:39 -04:00
2014-09-14 16:14:12 +02:00
TC_LOG_FATAL ( "misc" , "Removed GameObject (GUID: %u Entry: %u SpellId: %u LinkedGO: %u) that just lost any reference to the owner (%s) GO list" ,
GetGUIDLow (), GetGOInfo () -> entry , m_spellId , GetGOInfo () -> GetLinkedGameObjectEntry (), ownerGUID . ToString (). c_str ());
SetOwnerGUID ( ObjectGuid :: Empty );
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 GameObject :: AddToWorld ()
{
///- Register the gameobject for guid lookup
2010-04-07 19:14:10 +02:00
if ( ! IsInWorld ())
2009-03-25 15:54:23 -06:00
{
2010-04-07 19:14:10 +02:00
if ( m_zoneScript )
2010-12-05 18:04:10 +01:00
m_zoneScript -> OnGameObjectCreate ( this );
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sObjectAccessor -> AddObject ( this );
2012-09-04 14:04:47 -04:00
2012-05-30 08:01:02 +02:00
// The state can be changed after GameObject::Create but before GameObject::AddToWorld
2014-03-23 00:23:30 +01:00
bool toggledState = GetGoType () == GAMEOBJECT_TYPE_CHEST ? getLootState () == GO_READY : ( GetGoState () == GO_STATE_READY || IsTransport ());
2012-02-12 08:41:59 -05:00
if ( m_model )
2014-08-16 01:06:30 +02:00
{
if ( Transport * trans = ToTransport ())
trans -> SetDelayedAddModelToMap ();
else
GetMap () -> InsertGameObjectModel ( * m_model );
}
2012-02-12 08:41:59 -05:00
2012-09-04 14:04:47 -04:00
EnableCollision ( toggledState );
2009-03-25 15:54:23 -06:00
WorldObject :: AddToWorld ();
}
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 GameObject :: RemoveFromWorld ()
{
///- Remove the gameobject from the accessor
2010-04-07 19:14:10 +02:00
if ( IsInWorld ())
2009-03-25 15:54:23 -06:00
{
2010-04-07 19:14:10 +02:00
if ( m_zoneScript )
2010-12-05 18:04:10 +01:00
m_zoneScript -> OnGameObjectRemove ( this );
2009-10-17 15:51:44 -07:00
2011-10-31 10:46:39 -04:00
RemoveFromOwner ();
2012-02-03 16:03:52 -05:00
if ( m_model )
2012-08-19 11:07:21 -05:00
if ( GetMap () -> ContainsGameObjectModel ( * m_model ))
GetMap () -> RemoveGameObjectModel ( * m_model );
2009-03-25 15:54:23 -06:00
WorldObject :: RemoveFromWorld ();
2010-12-23 23:25:44 +01:00
sObjectAccessor -> RemoveObject ( this );
2009-03-25 15:54:23 -06:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-06-28 22:43:35 +02:00
bool GameObject :: Create ( uint32 guidlow , uint32 name_id , Map * map , uint32 /*phaseMask*/ , float x , float y , float z , float ang , float rotation0 , float rotation1 , float rotation2 , float rotation3 , uint32 animprogress , GOState go_state , uint32 artKit )
2008-10-11 14:16:25 -05:00
{
2009-07-16 11:49:00 +08:00
ASSERT ( map );
SetMap ( map );
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
Relocate ( x , y , z , ang );
2013-10-16 18:37:29 +02:00
m_stationaryPosition . Relocate ( x , y , z , ang );
2010-04-07 19:14:10 +02:00
if ( ! IsPositionValid ())
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "Gameobject (GUID: %u Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)" , guidlow , name_id , x , y );
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2010-09-02 10:40:32 +02:00
SetZoneScript ();
if ( m_zoneScript )
{
name_id = m_zoneScript -> GetGameObjectEntry ( guidlow , name_id );
if ( ! name_id )
return false ;
}
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * goinfo = sObjectMgr -> GetGameObjectTemplate ( name_id );
2008-10-11 14:16:25 -05:00
if ( ! goinfo )
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "Gameobject (GUID: %u Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)" , guidlow , name_id , map -> GetId (), x , y , z );
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2013-10-16 18:37:29 +02:00
if ( goinfo -> type == GAMEOBJECT_TYPE_TRANSPORT )
2013-10-26 17:06:50 +02:00
m_updateFlag |= UPDATEFLAG_TRANSPORT ;
2013-10-16 18:37:29 +02:00
2011-04-28 22:54:30 +02:00
Object :: _Create ( guidlow , goinfo -> entry , HIGHGUID_GAMEOBJECT );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_goInfo = goinfo ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( goinfo -> type >= MAX_GAMEOBJECT_TYPE )
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "Gameobject (GUID: %u Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created." , guidlow , name_id , goinfo -> type );
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
SetFloatValue ( GAMEOBJECT_PARENTROTATION + 0 , rotation0 );
SetFloatValue ( GAMEOBJECT_PARENTROTATION + 1 , rotation1 );
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
UpdateRotationFields ( rotation2 , rotation3 ); // GAMEOBJECT_FACING, GAMEOBJECT_ROTATION, GAMEOBJECT_PARENTROTATION+2/3
2009-10-17 15:51:44 -07:00
2012-05-30 08:01:02 +02:00
SetObjectScale ( goinfo -> size );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SetUInt32Value ( GAMEOBJECT_FACTION , goinfo -> faction );
SetUInt32Value ( GAMEOBJECT_FLAGS , goinfo -> flags );
2009-10-17 15:51:44 -07:00
2011-04-28 22:54:30 +02:00
SetEntry ( goinfo -> entry );
2009-10-17 15:51:44 -07:00
2011-07-22 21:22:05 +02:00
// set name for logs usage, doesn't affect anything ingame
SetName ( goinfo -> name );
2012-02-03 16:03:52 -05:00
SetDisplayId ( goinfo -> displayId );
2009-10-17 15:51:44 -07:00
2012-10-12 09:33:34 -05:00
m_model = GameObjectModel :: Create ( * this );
2009-09-04 05:11:27 +02:00
// GAMEOBJECT_BYTES_1, index at 0, 1, 2 and 3
2008-10-11 14:16:25 -05:00
SetGoType ( GameobjectTypes ( goinfo -> type ));
2012-02-03 16:03:52 -05:00
SetGoState ( go_state );
2012-05-30 08:01:02 +02:00
SetGoArtKit ( artKit );
2009-10-17 15:51:44 -07:00
2011-07-22 21:22:05 +02:00
switch ( goinfo -> type )
2009-05-29 00:18:41 -05:00
{
2013-03-02 23:59:42 +01:00
case GAMEOBJECT_TYPE_FISHINGHOLE :
SetGoAnimProgress ( animprogress );
m_goValue . FishingHole . MaxOpens = urand ( GetGOInfo () -> fishinghole . minSuccessOpens , GetGOInfo () -> fishinghole . maxSuccessOpens );
break ;
2009-05-29 00:18:41 -05:00
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING :
2012-10-24 13:29:34 +02:00
m_goValue . Building . Health = goinfo -> building . intactNumHits + goinfo -> building . damagedNumHits ;
m_goValue . Building . MaxHealth = m_goValue . Building . Health ;
2010-05-09 06:25:06 +02:00
SetGoAnimProgress ( 255 );
2012-07-24 15:28:41 +02:00
SetUInt32Value ( GAMEOBJECT_PARENTROTATION , m_goInfo -> building . destructibleData );
2009-05-29 00:18:41 -05:00
break ;
2009-11-27 01:41:26 +01:00
case GAMEOBJECT_TYPE_TRANSPORT :
2014-09-29 20:10:08 +02:00
{
2013-10-16 18:37:29 +02:00
m_goValue . Transport . AnimationInfo = sTransportMgr -> GetTransportAnimInfo ( goinfo -> entry );
2014-09-30 22:48:04 +02:00
m_goValue . Transport . PathProgress = getMSTime ();
if ( m_goValue . Transport . AnimationInfo )
m_goValue . Transport . PathProgress -= m_goValue . Transport . PathProgress % GetTransportPeriod (); // align to period
2013-10-16 18:37:29 +02:00
m_goValue . Transport . CurrentSeg = 0 ;
2014-09-29 20:10:08 +02:00
m_goValue . Transport . StateUpdateTimer = 0 ;
m_goValue . Transport . StopFrames = new std :: vector < uint32 > ();
if ( goinfo -> transport . stopFrame1 > 0 )
m_goValue . Transport . StopFrames -> push_back ( goinfo -> transport . stopFrame1 );
if ( goinfo -> transport . stopFrame2 > 0 )
2014-09-30 16:59:42 +02:00
m_goValue . Transport . StopFrames -> push_back ( goinfo -> transport . stopFrame2 );
2014-09-29 20:10:08 +02:00
if ( goinfo -> transport . stopFrame3 > 0 )
m_goValue . Transport . StopFrames -> push_back ( goinfo -> transport . stopFrame3 );
if ( goinfo -> transport . stopFrame4 > 0 )
m_goValue . Transport . StopFrames -> push_back ( goinfo -> transport . stopFrame4 );
if ( goinfo -> transport . startOpen )
SetTransportState ( GO_STATE_TRANSPORT_STOPPED , goinfo -> transport . startOpen - 1 );
else
SetTransportState ( GO_STATE_TRANSPORT_ACTIVE );
SetGoAnimProgress ( animprogress );
2010-05-10 12:48:35 +02:00
break ;
2014-09-29 20:10:08 +02:00
}
2010-05-10 12:48:35 +02:00
case GAMEOBJECT_TYPE_FISHINGNODE :
SetGoAnimProgress ( 0 );
2010-11-13 17:18:09 +01:00
break ;
case GAMEOBJECT_TYPE_TRAP :
if ( GetGOInfo () -> trap . stealthed )
{
2011-06-12 02:30:32 +02:00
m_stealth . AddFlag ( STEALTH_TRAP );
2012-01-08 18:22:46 +01:00
m_stealth . AddValue ( STEALTH_TRAP , 70 );
2010-11-13 17:18:09 +01:00
}
if ( GetGOInfo () -> trap . invisible )
{
2011-06-12 02:30:32 +02:00
m_invisibility . AddFlag ( INVISIBILITY_TRAP );
2012-01-08 18:22:46 +01:00
m_invisibility . AddValue ( INVISIBILITY_TRAP , 300 );
2010-11-13 17:18:09 +01:00
}
2010-05-10 12:48:35 +02:00
break ;
default :
SetGoAnimProgress ( animprogress );
2009-11-27 01:41:26 +01:00
break ;
2009-05-29 00:18:41 -05:00
}
2010-05-16 17:45:45 +02:00
LastUsedScriptID = GetGOInfo () -> ScriptId ;
2010-12-06 04:52:33 +01:00
AIM_Initialize ();
2010-05-16 17:45:45 +02:00
2013-02-13 20:24:23 +01:00
// Initialize loot duplicate count depending on raid difficulty
2013-02-14 11:41:20 +01:00
if ( map -> Is25ManRaid ())
2013-02-13 20:24:23 +01:00
loot . maxDuplicates = 3 ;
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2010-03-11 22:55:02 +01:00
void GameObject :: Update ( uint32 diff )
2008-10-11 14:16:25 -05:00
{
2013-10-16 18:37:29 +02:00
if ( AI ())
2010-10-25 18:11:52 +02:00
AI () -> UpdateAI ( diff );
2013-10-16 18:37:29 +02:00
else if ( ! AIM_Initialize ())
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "Could not initialize GameObjectAI" );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
switch ( m_lootState )
{
case GO_NOT_READY :
{
2011-09-29 12:43:05 +02:00
switch ( GetGoType ())
2008-10-11 14:16:25 -05:00
{
case GAMEOBJECT_TYPE_TRAP :
{
// Arming Time for GAMEOBJECT_TYPE_TRAP (6)
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * goInfo = GetGOInfo ();
2010-02-14 19:13:14 -07:00
// Bombs
2011-04-08 18:33:13 +02:00
if ( goInfo -> trap . type == 2 )
2014-05-05 22:28:45 +02:00
// Hardcoded tooltip value
m_cooldownTime = time ( NULL ) + 10 ;
2010-02-14 19:13:14 -07:00
else if ( Unit * owner = GetOwner ())
2013-06-11 19:54:27 -02:30
if ( owner -> IsInCombat ())
2012-10-06 17:01:29 +01:00
m_cooldownTime = time ( NULL ) + goInfo -> trap . startDelay ;
2014-05-05 22:28:45 +02:00
SetLootState ( GO_READY );
2008-10-11 14:16:25 -05:00
break ;
}
2013-10-16 18:37:29 +02:00
case GAMEOBJECT_TYPE_TRANSPORT :
{
if ( ! m_goValue . Transport . AnimationInfo )
break ;
2014-09-29 20:10:08 +02:00
if ( GetGoState () == GO_STATE_TRANSPORT_ACTIVE )
2013-10-16 18:37:29 +02:00
{
m_goValue . Transport . PathProgress += diff ;
2014-03-21 00:32:03 +01:00
/* TODO: Fix movement in unloaded grid - currently GO will just disappear
2014-09-29 20:10:08 +02:00
uint32 timer = m_goValue.Transport.PathProgress % GetTransportPeriod();
2013-10-16 18:37:29 +02:00
TransportAnimationEntry const* node = m_goValue.Transport.AnimationInfo->GetAnimNode(timer);
if (node && m_goValue.Transport.CurrentSeg != node->TimeSeg)
{
m_goValue.Transport.CurrentSeg = node->TimeSeg;
G3D::Quat rotation = m_goValue.Transport.AnimationInfo->GetAnimRotation(timer);
G3D::Vector3 pos = rotation.toRotationMatrix()
* G3D::Matrix3::fromEulerAnglesZYX(GetOrientation(), 0.0f, 0.0f)
* G3D::Vector3(node->X, node->Y, node->Z);
pos += G3D::Vector3(GetStationaryX(), GetStationaryY(), GetStationaryZ());
G3D::Vector3 src(GetPositionX(), GetPositionY(), GetPositionZ());
2014-03-21 00:32:03 +01:00
TC_LOG_DEBUG("misc", "Src: %s Dest: %s", src.toString().c_str(), pos.toString().c_str());
2013-10-16 18:37:29 +02:00
GetMap()->GameObjectRelocation(this, pos.x, pos.y, pos.z, GetOrientation());
}
2014-03-21 00:32:03 +01:00
*/
2014-09-29 20:10:08 +02:00
if ( ! m_goValue . Transport . StopFrames -> empty ())
{
uint32 visualStateBefore = ( m_goValue . Transport . StateUpdateTimer / 20000 ) & 1 ;
m_goValue . Transport . StateUpdateTimer += diff ;
uint32 visualStateAfter = ( m_goValue . Transport . StateUpdateTimer / 20000 ) & 1 ;
if ( visualStateBefore != visualStateAfter )
{
ForceValuesUpdateAtIndex ( GAMEOBJECT_LEVEL );
ForceValuesUpdateAtIndex ( GAMEOBJECT_BYTES_1 );
}
}
2013-10-16 18:37:29 +02:00
}
break ;
}
2008-10-11 14:16:25 -05:00
case GAMEOBJECT_TYPE_FISHINGNODE :
{
// fishing code (bobber ready)
2010-04-07 22:59:46 +02:00
if ( time ( NULL ) > m_respawnTime - FISHING_BOBBER_READY_TIME )
2008-10-11 14:16:25 -05:00
{
// splash bobber (bobber ready now)
Unit * caster = GetOwner ();
2010-04-07 19:14:10 +02:00
if ( caster && caster -> GetTypeId () == TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
{
2009-04-27 18:36:10 -05:00
SetGoState ( GO_STATE_ACTIVE );
2008-12-12 11:21:28 -06:00
SetUInt32Value ( GAMEOBJECT_FLAGS , GO_FLAG_NODESPAWN );
2009-10-17 15:51:44 -07:00
2011-11-27 16:06:29 +01:00
UpdateData udata ( caster -> GetMapId ());
2008-10-11 14:16:25 -05:00
WorldPacket packet ;
2011-04-29 20:47:02 +02:00
BuildValuesUpdateBlockForPlayer ( & udata , caster -> ToPlayer ());
2008-10-11 14:16:25 -05:00
udata . BuildPacket ( & packet );
2013-08-07 10:31:13 +02:00
caster -> ToPlayer () -> SendDirectMessage ( & packet );
2009-10-17 15:51:44 -07:00
2011-03-02 16:50:09 +01:00
SendCustomAnim ( GetGoAnimProgress ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-14 16:28:45 -06:00
m_lootState = GO_READY ; // can be successfully open with some chance
2008-10-11 14:16:25 -05:00
}
return ;
}
default :
m_lootState = GO_READY ; // for other GOis same switched without delay to GO_READY
break ;
}
// NO BREAK for switch (m_lootState)
}
case GO_READY :
{
if ( m_respawnTime > 0 ) // timer on
{
2010-12-24 18:55:50 +01:00
time_t now = time ( NULL );
if ( m_respawnTime <= now ) // timer expired
2008-10-11 14:16:25 -05:00
{
2014-09-14 16:14:12 +02:00
ObjectGuid dbtableHighGuid ( HIGHGUID_GAMEOBJECT , GetEntry (), m_DBTableGuid );
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't respawn, the master is dead
{
2014-09-14 16:14:12 +02:00
ObjectGuid targetGuid = sObjectMgr -> GetLinkedRespawnGuid ( dbtableHighGuid );
2011-05-16 15:36:02 +02:00
if ( targetGuid == dbtableHighGuid ) // if linking self, never respawn (check delayed to next day)
2010-12-24 18:55:50 +01:00
SetRespawnTime ( DAY );
else
2014-05-05 22:28:45 +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
return ;
}
2008-10-11 14:16:25 -05:00
m_respawnTime = 0 ;
m_SkillupList . clear ();
m_usetimes = 0 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
switch ( GetGoType ())
{
case GAMEOBJECT_TYPE_FISHINGNODE : // can't fish now
{
Unit * caster = GetOwner ();
2010-04-07 19:14:10 +02:00
if ( caster && caster -> GetTypeId () == TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
{
2012-11-03 15:31:14 +01:00
caster -> ToPlayer () -> RemoveGameObject ( this , false );
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
WorldPacket data ( SMSG_FISH_ESCAPED , 0 );
2013-08-07 10:31:13 +02:00
caster -> ToPlayer () -> SendDirectMessage ( & data );
2008-10-11 14:16:25 -05:00
}
// can be delete
m_lootState = GO_JUST_DEACTIVATED ;
return ;
}
case GAMEOBJECT_TYPE_DOOR :
case GAMEOBJECT_TYPE_BUTTON :
2014-05-05 12:35:41 +02:00
// We need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for battlegrounds)
2009-04-27 18:36:10 -05:00
if ( GetGoState () != GO_STATE_READY )
ResetDoorOrButton ();
2013-03-02 23:59:42 +01:00
break ;
case GAMEOBJECT_TYPE_FISHINGHOLE :
// Initialize a new max fish count on respawn
m_goValue . FishingHole . MaxOpens = urand ( GetGOInfo () -> fishinghole . minSuccessOpens , GetGOInfo () -> fishinghole . maxSuccessOpens );
break ;
2008-10-11 14:16:25 -05:00
default :
break ;
}
2013-03-02 23:59:42 +01:00
2014-05-05 12:35:41 +02:00
// Despawn timer
if ( ! m_spawnedByDefault )
2013-03-02 23:59:42 +01:00
{
2014-05-05 12:35:41 +02:00
// Can be despawned or destroyed
2013-03-02 23:59:42 +01:00
SetLootState ( GO_JUST_DEACTIVATED );
return ;
}
2014-05-05 12:35:41 +02:00
// Respawn timer
2013-03-02 23:59:42 +01:00
uint32 poolid = GetDBTableGUIDLow () ? sPoolMgr -> IsPartOfAPool < GameObject > ( GetDBTableGUIDLow ()) : 0 ;
if ( poolid )
sPoolMgr -> UpdatePool < GameObject > ( poolid , GetDBTableGUIDLow ());
else
GetMap () -> AddToMap ( this );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( isSpawned ())
2008-10-11 14:16:25 -05:00
{
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * goInfo = GetGOInfo ();
2010-04-07 19:14:10 +02:00
if ( goInfo -> type == GAMEOBJECT_TYPE_TRAP )
2009-07-24 09:33:56 +08:00
{
2010-04-07 19:14:10 +02:00
if ( m_cooldownTime >= time ( NULL ))
2014-05-04 22:15:11 +02:00
break ;
2009-10-17 15:51:44 -07:00
2014-05-04 22:15:11 +02:00
// Type 2 (bomb) does not need to be triggered by a unit and despawns after casting its spell.
2011-04-08 18:33:13 +02:00
if ( goInfo -> trap . type == 2 )
2010-02-14 19:13:14 -07:00
{
2014-05-04 22:15:11 +02:00
SetLootState ( GO_ACTIVATED );
2010-02-14 19:13:14 -07:00
break ;
}
2009-10-17 15:51:44 -07:00
2014-05-04 22:15:11 +02:00
// Type 0 despawns after being triggered, type 1 does not.
/// @todo This is activation radius. Casting radius must be selected from spell data.
float radius ;
if ( ! goInfo -> trap . diameter )
{
2014-05-05 22:28:45 +02:00
// Battleground traps: data2 == 0 && data5 == 3
if ( goInfo -> trap . cooldown != 3 )
2014-05-04 22:15:11 +02:00
break ;
radius = 3.f ;
2014-05-05 10:06:44 +02:00
}
else
2014-05-04 22:15:11 +02:00
radius = goInfo -> trap . diameter / 2.f ;
2009-10-17 15:51:44 -07:00
2014-05-04 22:15:11 +02:00
// Pointer to appropriate target if found any
Unit * target = NULL ;
/// @todo this hack with search required until GO casting not implemented
2014-05-05 22:28:45 +02:00
if ( Unit * owner = GetOwner ())
2009-07-24 09:33:56 +08:00
{
2014-05-05 22:28:45 +02:00
// Hunter trap: Search units which are unfriendly to the trap's owner
2009-07-24 09:33:56 +08:00
Trinity :: AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker ( this , owner , radius );
2014-05-04 22:15:11 +02:00
Trinity :: UnitSearcher < Trinity :: AnyUnfriendlyNoTotemUnitInObjectRangeCheck > searcher ( this , target , checker );
2009-07-24 09:33:56 +08:00
VisitNearbyGridObject ( radius , searcher );
2014-05-04 22:15:11 +02:00
if ( ! target )
VisitNearbyWorldObject ( radius , searcher );
2009-07-24 09:33:56 +08:00
}
2014-05-04 22:15:11 +02:00
else
2009-07-24 09:33:56 +08:00
{
2014-05-05 22:28:45 +02:00
// Environmental trap: Any player
2009-07-24 09:33:56 +08:00
Player * player = NULL ;
2009-12-20 15:20:04 +01:00
Trinity :: AnyPlayerInObjectRangeCheck checker ( this , radius );
Trinity :: PlayerSearcher < Trinity :: AnyPlayerInObjectRangeCheck > searcher ( this , player , checker );
2009-07-24 09:33:56 +08:00
VisitNearbyWorldObject ( radius , searcher );
2014-05-04 22:15:11 +02:00
target = player ;
2009-07-24 09:33:56 +08:00
}
2009-10-17 15:51:44 -07:00
2014-05-04 22:15:11 +02:00
if ( target )
2014-05-05 22:28:45 +02:00
SetLootState ( GO_ACTIVATED , target );
2009-10-17 15:51:44 -07:00
2009-07-24 09:33:56 +08:00
}
2010-04-07 19:14:10 +02:00
else if ( uint32 max_charges = goInfo -> GetCharges ())
2009-07-24 09:33:56 +08:00
{
if ( m_usetimes >= max_charges )
2008-10-11 14:16:25 -05:00
{
2009-07-24 09:33:56 +08:00
m_usetimes = 0 ;
SetLootState ( GO_JUST_DEACTIVATED ); // can be despawned or destroyed
2008-10-11 14:16:25 -05:00
}
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
break ;
}
case GO_ACTIVATED :
{
2011-09-29 12:43:05 +02:00
switch ( GetGoType ())
2008-10-11 14:16:25 -05:00
{
case GAMEOBJECT_TYPE_DOOR :
case GAMEOBJECT_TYPE_BUTTON :
2014-04-28 22:26:43 +02:00
if ( m_cooldownTime && ( m_cooldownTime < time ( NULL )))
2009-04-27 18:36:10 -05:00
ResetDoorOrButton ();
2008-10-11 14:16:25 -05:00
break ;
2010-01-16 19:31:10 +03:00
case GAMEOBJECT_TYPE_GOOBER :
if ( m_cooldownTime < time ( NULL ))
{
RemoveFlag ( GAMEOBJECT_FLAGS , GO_FLAG_IN_USE );
SetLootState ( GO_JUST_DEACTIVATED );
m_cooldownTime = 0 ;
}
break ;
2010-03-11 22:55:02 +01:00
case GAMEOBJECT_TYPE_CHEST :
if ( m_groupLootTimer )
{
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 ;
}
2014-05-05 10:06:44 +02:00
break ;
2014-05-04 22:15:11 +02:00
case GAMEOBJECT_TYPE_TRAP :
{
GameObjectTemplate const * goInfo = GetGOInfo ();
2014-05-05 22:28:45 +02:00
if ( goInfo -> trap . type == 2 && goInfo -> trap . spellId )
{
2014-05-04 22:15:11 +02:00
/// @todo NULL target won't work for target type 1
CastSpell ( NULL , goInfo -> trap . spellId );
2014-05-05 22:28:45 +02:00
SetLootState ( GO_JUST_DEACTIVATED );
}
2014-05-20 21:21:33 +02:00
else if ( Unit * target = ObjectAccessor :: GetUnit ( * this , m_lootStateUnitGUID ))
2014-05-05 22:28:45 +02:00
{
// Some traps do not have a spell but should be triggered
if ( goInfo -> trap . spellId )
2014-05-06 18:46:08 +02:00
CastSpell ( target , goInfo -> trap . spellId );
2014-05-04 22:15:11 +02:00
2014-05-05 22:28:45 +02:00
// Template value or 4 seconds
2014-05-11 12:35:40 +02:00
m_cooldownTime = time ( NULL ) + ( goInfo -> trap . cooldown ? goInfo -> trap . cooldown : uint32 ( 4 ));
2014-05-05 22:28:45 +02:00
if ( goInfo -> trap . type == 1 )
SetLootState ( GO_JUST_DEACTIVATED );
2014-05-11 12:35:40 +02:00
else if ( ! goInfo -> trap . type )
SetLootState ( GO_READY );
2014-05-04 22:15:11 +02:00
2014-05-05 22:28:45 +02:00
// Battleground gameobjects have data2 == 0 && data5 == 3
if ( ! goInfo -> trap . diameter && goInfo -> trap . cooldown == 3 )
2014-05-06 18:46:08 +02:00
if ( Player * player = target -> ToPlayer ())
2014-05-05 22:28:45 +02:00
if ( Battleground * bg = player -> GetBattleground ())
bg -> HandleTriggerBuff ( GetGUID ());
}
2014-05-04 22:15:11 +02:00
break ;
}
2010-01-16 19:31:10 +03:00
default :
break ;
2008-10-11 14:16:25 -05:00
}
break ;
}
case GO_JUST_DEACTIVATED :
{
//if Gameobject should cast spell, then this, but some GOs (type = 10) should be destroyed
if ( GetGoType () == GAMEOBJECT_TYPE_GOOBER )
{
uint32 spellId = GetGOInfo () -> goober . spellId ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( spellId )
2008-10-11 14:16:25 -05:00
{
2014-09-14 16:14:12 +02:00
for ( GuidSet :: const_iterator it = m_unique_users . begin (); it != m_unique_users . end (); ++ it )
2011-09-17 13:20:21 +02:00
// m_unique_users can contain only player GUIDs
if ( Player * owner = ObjectAccessor :: GetPlayer ( * this , * it ))
2010-01-16 19:31:10 +03:00
owner -> CastSpell ( owner , spellId , false );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_unique_users . clear ();
m_usetimes = 0 ;
}
2010-01-16 19:31:10 +03:00
SetGoState ( GO_STATE_READY );
2008-10-11 14:16:25 -05:00
//any return here in case battleground traps
2011-03-24 01:13:53 +02:00
if ( GetGOInfo () -> flags & GO_FLAG_NODESPAWN )
return ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-03-24 01:13:53 +02:00
loot . clear ();
2011-10-08 13:13:09 +02:00
//! If this is summoned by a spell with ie. SPELL_EFFECT_SUMMON_OBJECT_WILD, with or without owner, we check respawn criteria based on spell
//! The GetOwnerGUID() check is mostly for compatibility with hacky scripts - 99% of the time summoning should be done trough spells.
if ( GetSpellId () || GetOwnerGUID ())
2008-10-11 14:16:25 -05:00
{
2011-10-08 13:13:09 +02:00
SetRespawnTime ( 0 );
Delete ();
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2011-03-24 01:13:53 +02:00
SetLootState ( GO_READY );
2008-10-11 14:16:25 -05:00
//burning flags in some battlegrounds, if you find better condition, just add it
2009-07-16 12:06:07 +08:00
if ( GetGOInfo () -> IsDespawnAtAction () || GetGoAnimProgress () > 0 )
2008-10-11 14:16:25 -05:00
{
2008-12-24 09:58:26 -06:00
SendObjectDeSpawnAnim ( GetGUID ());
2008-10-11 14:16:25 -05:00
//reset flags
SetUInt32Value ( GAMEOBJECT_FLAGS , GetGOInfo () -> flags );
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! m_respawnDelayTime )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! m_spawnedByDefault )
2008-10-11 14:16:25 -05:00
{
m_respawnTime = 0 ;
2010-02-03 16:53:40 +02:00
UpdateObjectVisibility ();
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
m_respawnTime = time ( NULL ) + m_respawnDelayTime ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// if option not set then object will be saved at grid unload
2010-12-23 23:25:44 +01:00
if ( sWorld -> getBoolConfig ( CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY ))
2008-10-11 14:16:25 -05:00
SaveRespawnTime ();
2009-10-17 15:51:44 -07:00
2010-02-03 16:53:40 +02:00
UpdateObjectVisibility ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
break ;
}
}
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnGameObjectUpdate ( 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 GameObject :: Refresh ()
{
2013-12-25 14:16:55 -03:30
// Do not refresh despawned GO from spellcast (GO's from spellcast are destroyed after despawn)
2010-04-07 19:14:10 +02:00
if ( m_respawnTime > 0 && m_spawnedByDefault )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( isSpawned ())
2011-10-10 17:39:34 -04:00
GetMap () -> AddToMap ( this );
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 GameObject :: AddUniqueUse ( Player * player )
{
AddUse ();
2011-09-17 13:20:21 +02:00
m_unique_users . insert ( player -> GetGUID ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-09-02 14:52:52 -05:00
void GameObject :: Delete ()
2009-08-03 14:52:30 +02:00
{
SetLootState ( GO_NOT_READY );
2011-10-31 10:46:39 -04:00
RemoveFromOwner ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
SendObjectDeSpawnAnim ( GetGUID ());
2009-10-17 15:51:44 -07:00
2009-04-27 18:36:10 -05:00
SetGoState ( GO_STATE_READY );
2008-10-11 14:16:25 -05:00
SetUInt32Value ( GAMEOBJECT_FLAGS , GetGOInfo () -> flags );
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
uint32 poolid = GetDBTableGUIDLow () ? sPoolMgr -> IsPartOfAPool < GameObject > ( GetDBTableGUIDLow ()) : 0 ;
2009-02-19 18:44:20 -06:00
if ( poolid )
2010-12-22 21:25:23 +01:00
sPoolMgr -> UpdatePool < GameObject > ( poolid , GetDBTableGUIDLow ());
2009-02-19 18:44:20 -06:00
else
AddObjectToRemoveList ();
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 GameObject :: getFishLoot ( Loot * fishloot , Player * loot_owner )
2008-10-11 14:16:25 -05:00
{
fishloot -> clear ();
2009-10-17 15:51:44 -07:00
2009-03-11 16:17:37 -06:00
uint32 zone , subzone ;
2014-05-10 21:35:05 +08:00
uint32 defaultzone = 1 ;
2011-04-29 20:47:02 +02:00
GetZoneAndAreaId ( zone , subzone );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// if subzone loot exist use it
2014-05-10 21:35:05 +08:00
fishloot -> FillLoot ( subzone , LootTemplates_Fishing , loot_owner , true , true );
if ( fishloot -> empty ()) //use this becase if zone or subzone has set LOOT_MODE_JUNK_FISH,Even if no normal drop, fishloot->FillLoot return true. it wrong.
{
//subzone no result,use zone loot
fishloot -> FillLoot ( zone , LootTemplates_Fishing , loot_owner , true , true );
2014-06-13 11:16:17 +02:00
//use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks.
2014-05-10 21:35:05 +08:00
if ( fishloot -> empty ())
fishloot -> FillLoot ( defaultzone , LootTemplates_Fishing , loot_owner , true , true );
}
}
void GameObject :: getFishLootJunk ( Loot * fishloot , Player * loot_owner )
{
fishloot -> clear ();
uint32 zone , subzone ;
uint32 defaultzone = 1 ;
GetZoneAndAreaId ( zone , subzone );
// if subzone loot exist use it
fishloot -> FillLoot ( subzone , LootTemplates_Fishing , loot_owner , true , true , LOOT_MODE_JUNK_FISH );
if ( fishloot -> empty ()) //use this becase if zone or subzone has normal mask drop, then fishloot->FillLoot return true.
{
//use zone loot
fishloot -> FillLoot ( zone , LootTemplates_Fishing , loot_owner , true , true , LOOT_MODE_JUNK_FISH );
if ( fishloot -> empty ())
//use zone 1 as default
fishloot -> FillLoot ( defaultzone , LootTemplates_Fishing , loot_owner , true , true , LOOT_MODE_JUNK_FISH );
}
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 GameObject :: SaveToDB ()
{
// this should only be used when the gameobject 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
GameObjectData const * data = sObjectMgr -> GetGOData ( m_DBTableGuid );
2010-04-07 19:14:10 +02:00
if ( ! data )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "GameObject::SaveToDB failed, cannot get gameobject data!" );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-01-31 16:38:50 -06:00
SaveToDB ( GetMapId (), data -> spawnMask , data -> phaseMask );
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 GameObject :: SaveToDB ( uint32 mapid , uint8 spawnMask , uint32 phaseMask )
2008-10-11 14:16:25 -05:00
{
2011-09-15 14:08:17 +02:00
const GameObjectTemplate * goI = GetGOInfo ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( ! goI )
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( ! m_DBTableGuid )
m_DBTableGuid = GetGUIDLow ();
// update in loaded data (changing data only in this place)
2010-12-22 21:25:23 +01:00
GameObjectData & data = sObjectMgr -> NewGOData ( m_DBTableGuid );
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 ;
2009-06-11 00:45:59 -05:00
data . posX = GetPositionX ();
data . posY = GetPositionY ();
data . posZ = GetPositionZ ();
data . orientation = GetOrientation ();
2008-12-24 09:58:26 -06:00
data . rotation0 = GetFloatValue ( GAMEOBJECT_PARENTROTATION + 0 );
data . rotation1 = GetFloatValue ( GAMEOBJECT_PARENTROTATION + 1 );
data . rotation2 = GetFloatValue ( GAMEOBJECT_PARENTROTATION + 2 );
data . rotation3 = GetFloatValue ( GAMEOBJECT_PARENTROTATION + 3 );
2008-10-11 14:16:25 -05:00
data . spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : - ( int32 ) m_respawnDelayTime ;
data . animprogress = GetGoAnimProgress ();
data . go_state = GetGoState ();
data . spawnMask = spawnMask ;
2009-08-21 12:31:52 -05:00
data . artKit = GetGoArtKit ();
2009-10-17 15:51:44 -07:00
2012-05-30 08:01:02 +02:00
// Update in DB
2010-08-21 03:19:25 +02:00
SQLTransaction trans = WorldDatabase . BeginTransaction ();
2012-05-30 08:01:02 +02:00
uint8 index = 0 ;
PreparedStatement * stmt = WorldDatabase . GetPreparedStatement ( WORLD_DEL_GAMEOBJECT );
stmt -> setUInt32 ( 0 , m_DBTableGuid );
trans -> Append ( stmt );
stmt = WorldDatabase . GetPreparedStatement ( WORLD_INS_GAMEOBJECT );
stmt -> setUInt32 ( index ++ , m_DBTableGuid );
stmt -> setUInt32 ( index ++ , GetEntry ());
stmt -> setUInt16 ( index ++ , uint16 ( mapid ));
stmt -> setUInt8 ( index ++ , spawnMask );
2013-07-19 04:03:40 +01:00
stmt -> setUInt32 ( index ++ , GetPhaseMask ());
2012-05-30 08:01:02 +02:00
stmt -> setFloat ( index ++ , GetPositionX ());
stmt -> setFloat ( index ++ , GetPositionY ());
stmt -> setFloat ( index ++ , GetPositionZ ());
stmt -> setFloat ( index ++ , GetOrientation ());
stmt -> setFloat ( index ++ , GetFloatValue ( GAMEOBJECT_PARENTROTATION ));
stmt -> setFloat ( index ++ , GetFloatValue ( GAMEOBJECT_PARENTROTATION + 1 ));
stmt -> setFloat ( index ++ , GetFloatValue ( GAMEOBJECT_PARENTROTATION + 2 ));
stmt -> setFloat ( index ++ , GetFloatValue ( GAMEOBJECT_PARENTROTATION + 3 ));
stmt -> setInt32 ( index ++ , int32 ( m_respawnDelayTime ));
stmt -> setUInt8 ( index ++ , GetGoAnimProgress ());
stmt -> setUInt8 ( index ++ , uint8 ( GetGoState ()));
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-11-28 14:05:25 -05:00
bool GameObject :: LoadGameObjectFromDB ( uint32 guid , Map * map , bool addToMap )
2008-10-11 14:16:25 -05:00
{
2010-12-22 21:25:23 +01:00
GameObjectData const * data = sObjectMgr -> GetGOData ( guid );
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
if ( ! data )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "Gameobject (GUID: %u) not found in table `gameobject`, 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
uint32 entry = data -> id ;
2008-12-24 09:58:26 -06:00
//uint32 map_id = data->mapid; // already used before call
2009-01-31 16:38:50 -06:00
uint32 phaseMask = data -> phaseMask ;
2008-10-11 14:16:25 -05:00
float x = data -> posX ;
float y = data -> posY ;
float z = data -> posZ ;
float ang = data -> orientation ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
float rotation0 = data -> rotation0 ;
float rotation1 = data -> rotation1 ;
float rotation2 = data -> rotation2 ;
float rotation3 = data -> rotation3 ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
uint32 animprogress = data -> animprogress ;
2009-04-27 18:36:10 -05:00
GOState go_state = data -> go_state ;
2009-08-21 12:31:52 -05:00
uint32 artKit = data -> artKit ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_DBTableGuid = guid ;
2010-12-22 21:25:23 +01:00
if ( map -> GetInstanceId () != 0 ) guid = sObjectMgr -> GenerateLowGuid ( HIGHGUID_GAMEOBJECT );
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
if ( ! Create ( guid , entry , map , phaseMask , x , y , z , ang , rotation0 , rotation1 , rotation2 , rotation3 , animprogress , go_state , artKit ))
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2014-06-01 22:27:29 -05:00
if ( data -> phaseid )
SetInPhase ( data -> phaseid , false , true );
2014-07-11 10:22:27 +02:00
2014-06-01 22:27:29 -05:00
if ( data -> phaseGroup )
{
// Set the gameobject in all the phases of the phasegroup
for ( auto ph : GetPhasesForGroup ( data -> phaseGroup ))
SetInPhase ( ph , false , true );
}
2010-04-07 19:14:10 +02:00
if ( data -> spawntimesecs >= 0 )
2008-10-11 14:16:25 -05:00
{
2009-04-08 16:35:13 -05:00
m_spawnedByDefault = true ;
2009-10-17 16:20:24 -07:00
2010-04-07 19:14:10 +02:00
if ( ! GetGOInfo () -> GetDespawnPossibility () && ! GetGOInfo () -> IsDespawnAtAction ())
2009-08-17 13:58:43 +02:00
{
SetFlag ( GAMEOBJECT_FLAGS , GO_FLAG_NODESPAWN );
m_respawnDelayTime = 0 ;
m_respawnTime = 0 ;
}
else
2009-04-08 16:35:13 -05:00
{
m_respawnDelayTime = data -> spawntimesecs ;
2012-06-07 23:20:57 +02:00
m_respawnTime = GetMap () -> GetGORespawnTime ( m_DBTableGuid );
2009-10-17 15:51:44 -07:00
2009-04-08 16:35:13 -05:00
// ready to respawn
2010-04-07 19:14:10 +02:00
if ( m_respawnTime && m_respawnTime <= time ( NULL ))
2008-10-11 14:16:25 -05:00
{
m_respawnTime = 0 ;
2012-06-07 23:20:57 +02:00
GetMap () -> RemoveGORespawnTime ( m_DBTableGuid );
2008-10-11 14:16:25 -05:00
}
2009-04-08 16:35:13 -05:00
}
2009-08-17 13:58:43 +02:00
}
else
{
m_spawnedByDefault = false ;
m_respawnDelayTime = - data -> spawntimesecs ;
m_respawnTime = 0 ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-31 21:04:04 -05:00
m_goData = 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 GameObject :: DeleteFromDB ()
{
2012-06-07 23:20:57 +02:00
GetMap () -> RemoveGORespawnTime ( m_DBTableGuid );
2010-12-22 21:25:23 +01:00
sObjectMgr -> DeleteGOData ( m_DBTableGuid );
2011-12-27 00:29:17 +01:00
PreparedStatement * stmt = WorldDatabase . GetPreparedStatement ( WORLD_DEL_GAMEOBJECT );
stmt -> setUInt32 ( 0 , m_DBTableGuid );
WorldDatabase . Execute ( stmt );
stmt = WorldDatabase . GetPreparedStatement ( WORLD_DEL_EVENT_GAMEOBJECT );
stmt -> setUInt32 ( 0 , m_DBTableGuid );
WorldDatabase . Execute ( stmt );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/*********************************************************/
/*** QUEST SYSTEM ***/
/*********************************************************/
bool GameObject :: hasQuest ( uint32 quest_id ) const
{
2010-12-22 21:25:23 +01:00
QuestRelationBounds qr = sObjectMgr -> GetGOQuestRelationBounds ( 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 GameObject :: hasInvolvedQuest ( uint32 quest_id ) const
{
2010-12-22 21:25:23 +01:00
QuestRelationBounds qir = sObjectMgr -> GetGOQuestInvolvedRelationBounds ( 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
bool GameObject :: IsTransport () const
{
// If something is marked as a transport, don't transmit an out of range packet for it.
2011-06-11 22:35:29 +02:00
GameObjectTemplate const * gInfo = GetGOInfo ();
2012-05-30 08:01:02 +02:00
if ( ! gInfo )
return false ;
2014-10-06 18:37:38 -04:00
return gInfo -> type == GAMEOBJECT_TYPE_TRANSPORT || gInfo -> type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-11-27 01:41:26 +01:00
// is Dynamic transport = non-stop Transport
bool GameObject :: IsDynTransport () const
{
// If something is marked as a transport, don't transmit an out of range packet for it.
2011-06-11 22:35:29 +02:00
GameObjectTemplate const * gInfo = GetGOInfo ();
2012-05-30 08:01:02 +02:00
if ( ! gInfo )
return false ;
2014-10-06 18:37:38 -04:00
return gInfo -> type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT || ( gInfo -> type == GAMEOBJECT_TYPE_TRANSPORT && m_goValue . Transport . StopFrames -> empty ());
2009-11-27 01:41:26 +01:00
}
2012-08-21 23:40:38 +01:00
bool GameObject :: IsDestructibleBuilding () const
{
GameObjectTemplate const * gInfo = GetGOInfo ();
2013-08-07 10:31:13 +02:00
if ( ! gInfo )
return false ;
2012-08-21 23:40:38 +01:00
return gInfo -> type == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING ;
}
2010-07-28 00:08:21 +02:00
Unit * GameObject :: GetOwner () const
2008-10-11 14:16:25 -05:00
{
2010-07-28 00:08:21 +02:00
return ObjectAccessor :: GetUnit ( * this , GetOwnerGUID ());
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 GameObject :: SaveRespawnTime ()
{
2010-04-07 19:14:10 +02:00
if ( m_goData && m_goData -> dbData && m_respawnTime > time ( NULL ) && m_spawnedByDefault )
2012-06-07 23:20:57 +02:00
GetMap () -> SaveGORespawnTime ( m_DBTableGuid , m_respawnTime );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-07-07 21:33:58 +02:00
bool GameObject :: IsNeverVisible () const
{
if ( WorldObject :: IsNeverVisible ())
return true ;
if ( GetGoType () == GAMEOBJECT_TYPE_SPELL_FOCUS && GetGOInfo () -> spellFocus . serverOnly == 1 )
return true ;
return false ;
}
2011-10-13 14:02:07 -04:00
bool GameObject :: IsAlwaysVisibleFor ( WorldObject const * seer ) const
2008-10-11 14:16:25 -05:00
{
2011-10-13 14:02:07 -04:00
if ( WorldObject :: IsAlwaysVisibleFor ( seer ))
2008-10-11 14:16:25 -05:00
return true ;
2009-10-17 15:51:44 -07:00
2012-08-21 23:40:38 +01:00
if ( IsTransport () || IsDestructibleBuilding ())
2010-11-13 17:18:09 +01:00
return true ;
2010-12-13 22:37:56 +01:00
2012-01-08 18:22:46 +01:00
if ( ! seer )
return false ;
// Always seen by owner and friendly units
2014-09-14 16:14:12 +02:00
if ( ObjectGuid guid = GetOwnerGUID ())
2012-01-08 18:22:46 +01:00
{
if ( seer -> GetGUID () == guid )
return true ;
Unit * owner = GetOwner ();
2014-09-14 16:14:12 +02:00
if ( Unit const * unitSeer = seer -> ToUnit ())
if ( owner && owner -> IsFriendlyTo ( unitSeer ))
return true ;
2012-01-08 18:22:46 +01:00
}
2010-11-13 17:18:09 +01:00
return false ;
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 GameObject :: IsInvisibleDueToDespawn () const
2009-02-04 19:43:00 +01:00
{
2011-10-13 13:26:27 -04:00
if ( WorldObject :: IsInvisibleDueToDespawn ())
return true ;
2009-10-17 15:51:44 -07:00
2010-11-13 17:18:09 +01:00
// Despawned
if ( ! isSpawned ())
2011-10-13 13:26:27 -04:00
return true ;
2009-10-17 15:51:44 -07:00
2011-10-13 13:26:27 -04:00
return false ;
2009-02-04 19:43:00 +01:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void GameObject :: Respawn ()
{
2010-04-07 19:14:10 +02:00
if ( m_spawnedByDefault && m_respawnTime > 0 )
2008-10-11 14:16:25 -05:00
{
2009-12-24 10:20:15 +01:00
m_respawnTime = time ( NULL );
2012-06-07 23:20:57 +02:00
GetMap () -> RemoveGORespawnTime ( m_DBTableGuid );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-10-07 19:45:43 -05:00
bool GameObject :: ActivateToQuest ( Player * target ) const
2008-10-11 14:16:25 -05:00
{
2011-10-07 19:45:43 -05:00
if ( target -> HasQuestForGO ( GetEntry ()))
2010-10-06 16:46:18 -06:00
return true ;
2010-12-22 21:25:23 +01:00
if ( ! sObjectMgr -> IsGameObjectForQuests ( GetEntry ()))
2008-10-11 14:16:25 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-11-21 17:59:24 -08:00
switch ( GetGoType ())
2008-10-11 14:16:25 -05:00
{
2014-02-06 21:23:18 +01:00
case GAMEOBJECT_TYPE_QUESTGIVER :
{
GameObject * go = const_cast < GameObject *> ( this );
QuestGiverStatus questStatus = target -> GetQuestDialogStatus ( go );
if ( questStatus > DIALOG_STATUS_UNAVAILABLE )
return true ;
break ;
}
2008-10-11 14:16:25 -05:00
case GAMEOBJECT_TYPE_CHEST :
{
2014-02-06 21:23:18 +01:00
// scan GO chest with loot including quest items
2011-10-07 19:45:43 -05:00
if ( LootTemplates_Gameobject . HaveQuestLootForPlayer ( GetGOInfo () -> GetLootId (), target ))
2008-11-21 19:45:49 -06:00
{
2013-08-07 10:31:13 +02:00
if ( Battleground const * bg = target -> GetBattleground ())
return bg -> CanActivateGO ( GetEntry (), target -> GetTeam ());
2008-10-11 14:16:25 -05:00
return true ;
2008-11-21 19:45:49 -06:00
}
2008-10-11 14:16:25 -05:00
break ;
}
2010-10-06 16:36:50 -06:00
case GAMEOBJECT_TYPE_GENERIC :
{
2011-10-07 19:45:43 -05:00
if ( GetGOInfo () -> _generic . questID == - 1 || target -> GetQuestStatus ( GetGOInfo () -> _generic . questID ) == QUEST_STATUS_INCOMPLETE )
2010-10-06 16:36:50 -06:00
return true ;
break ;
}
2008-10-11 14:16:25 -05:00
case GAMEOBJECT_TYPE_GOOBER :
{
2011-10-07 19:45:43 -05:00
if ( GetGOInfo () -> goober . questId == - 1 || target -> GetQuestStatus ( GetGOInfo () -> goober . questId ) == QUEST_STATUS_INCOMPLETE )
2008-10-11 14:16:25 -05:00
return true ;
break ;
}
default :
break ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2009-11-21 17:59:24 -08:00
void GameObject :: TriggeringLinkedGameObject ( uint32 trapEntry , Unit * target )
2008-10-11 14:16:25 -05:00
{
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * trapInfo = sObjectMgr -> GetGameObjectTemplate ( trapEntry );
2009-11-21 17:59:24 -08:00
if ( ! trapInfo || trapInfo -> type != GAMEOBJECT_TYPE_TRAP )
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
SpellInfo const * trapSpell = sSpellMgr -> GetSpellInfo ( trapInfo -> trap . spellId );
2010-04-07 19:14:10 +02:00
if ( ! trapSpell ) // checked at load already
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
float range = float ( target -> GetSpellMaxRangeForTarget ( GetOwner (), trapSpell ));
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// search nearest linked GO
GameObject * trapGO = NULL ;
{
// using original GO distance
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 );
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
Trinity :: NearestGameObjectEntryInObjectRangeCheck go_check ( * target , trapEntry , range );
Trinity :: GameObjectLastSearcher < Trinity :: NearestGameObjectEntryInObjectRangeCheck > checker ( this , trapGO , go_check );
2009-10-17 15:51:44 -07:00
2008-10-14 11:57:03 -05:00
TypeContainerVisitor < Trinity :: GameObjectLastSearcher < Trinity :: NearestGameObjectEntryInObjectRangeCheck > , GridTypeMapContainer > object_checker ( checker );
2010-01-23 22:24:41 +01:00
cell . Visit ( p , object_checker , * GetMap (), * target , 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
// found correct GO
2010-04-07 19:14:10 +02:00
if ( trapGO )
2010-04-30 13:09:38 +02:00
trapGO -> CastSpell ( target , trapInfo -> trap . spellId );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
GameObject * GameObject :: LookupFishingHoleAround ( float range )
{
GameObject * ok = NULL ;
2009-10-17 15:51:44 -07: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 );
2009-12-20 15:20:04 +01:00
Trinity :: NearestGameObjectFishingHole u_check ( * this , range );
Trinity :: GameObjectSearcher < Trinity :: NearestGameObjectFishingHole > checker ( this , ok , u_check );
2009-10-17 15:51:44 -07:00
2008-10-14 11:57:03 -05:00
TypeContainerVisitor < Trinity :: GameObjectSearcher < Trinity :: NearestGameObjectFishingHole > , GridTypeMapContainer > grid_object_checker ( checker );
2010-01-23 22:24:41 +01:00
cell . Visit ( p , grid_object_checker , * GetMap (), * this , range );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return ok ;
}
2009-10-17 15:51:44 -07:00
2009-04-27 18:36:10 -05:00
void GameObject :: ResetDoorOrButton ()
{
if ( m_lootState == GO_READY || m_lootState == GO_JUST_DEACTIVATED )
return ;
2009-10-17 15:51:44 -07:00
2009-04-27 18:36:10 -05:00
SwitchDoorOrButton ( false );
SetLootState ( GO_JUST_DEACTIVATED );
m_cooldownTime = 0 ;
}
2009-10-17 15:51:44 -07:00
2012-01-22 20:36:01 -05:00
void GameObject :: UseDoorOrButton ( uint32 time_to_restore , bool alternative /* = false */ , Unit * user /*=NULL*/ )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( m_lootState != GO_READY )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! time_to_restore )
2009-07-16 12:06:07 +08:00
time_to_restore = GetGOInfo () -> GetAutoCloseTime ();
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
SwitchDoorOrButton ( true , alternative );
2012-01-22 20:36:01 -05:00
SetLootState ( GO_ACTIVATED , user );
2009-10-17 15:51:44 -07:00
2014-05-17 20:05:43 +02:00
m_cooldownTime = time_to_restore ? ( time ( NULL ) + time_to_restore ) : 0 ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-01-04 17:14:34 -06:00
void GameObject :: SetGoArtKit ( uint8 kit )
{
SetByteValue ( GAMEOBJECT_BYTES_1 , 2 , kit );
2011-09-15 14:08:17 +02:00
GameObjectData * data = const_cast < GameObjectData *> ( sObjectMgr -> GetGOData ( m_DBTableGuid ));
2010-04-07 19:14:10 +02:00
if ( data )
2009-08-21 12:31:52 -05:00
data -> artKit = kit ;
}
2009-10-17 15:51:44 -07:00
2011-09-15 14:08:17 +02:00
void GameObject :: SetGoArtKit ( uint8 artkit , GameObject * go , uint32 lowguid )
2009-08-21 12:31:52 -05:00
{
2011-09-15 14:08:17 +02:00
const GameObjectData * data = NULL ;
2010-04-07 19:14:10 +02:00
if ( go )
2009-08-21 12:31:52 -05:00
{
go -> SetGoArtKit ( artkit );
data = go -> GetGOData ();
}
2010-04-07 19:14:10 +02:00
else if ( lowguid )
2010-12-22 21:25:23 +01:00
data = sObjectMgr -> GetGOData ( lowguid );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( data )
2009-08-21 12:31:52 -05:00
const_cast < GameObjectData *> ( data ) -> artKit = artkit ;
2009-01-04 17:14:34 -06:00
}
2009-10-17 15:51:44 -07:00
2009-04-27 18:36:10 -05:00
void GameObject :: SwitchDoorOrButton ( bool activate , bool alternative /* = false */ )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( activate )
2008-10-11 14:16:25 -05:00
SetFlag ( GAMEOBJECT_FLAGS , GO_FLAG_IN_USE );
else
RemoveFlag ( GAMEOBJECT_FLAGS , GO_FLAG_IN_USE );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( GetGoState () == GO_STATE_READY ) //if closed -> open
2009-04-27 18:36:10 -05:00
SetGoState ( alternative ? GO_STATE_ACTIVE_ALTERNATIVE : GO_STATE_ACTIVE );
2008-10-11 14:16:25 -05:00
else //if open -> close
2009-04-27 18:36:10 -05:00
SetGoState ( GO_STATE_READY );
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 GameObject :: Use ( Unit * user )
{
// by default spell caster is user
Unit * spellCaster = user ;
uint32 spellId = 0 ;
2009-02-22 17:48:48 -06:00
bool triggered = false ;
2009-10-17 15:51:44 -07:00
2010-12-26 16:35:29 +01:00
if ( Player * playerUser = user -> ToPlayer ())
{
if ( sScriptMgr -> OnGossipHello ( playerUser , this ))
return ;
2012-09-22 21:28:37 +02:00
if ( AI () -> GossipHello ( playerUser ))
return ;
2010-12-26 16:35:29 +01:00
}
2011-03-14 23:16:34 +01:00
// If cooldown data present in template
if ( uint32 cooldown = GetGOInfo () -> GetCooldown ())
{
if ( m_cooldownTime > sWorld -> GetGameTime ())
return ;
m_cooldownTime = sWorld -> GetGameTime () + cooldown ;
}
switch ( GetGoType ())
2008-10-11 14:16:25 -05:00
{
case GAMEOBJECT_TYPE_DOOR : //0
case GAMEOBJECT_TYPE_BUTTON : //1
//doors/buttons never really despawn, only reset to default state/flags
2012-01-22 20:36:01 -05:00
UseDoorOrButton ( 0 , false , user );
2008-10-11 14:16:25 -05:00
return ;
case GAMEOBJECT_TYPE_QUESTGIVER : //2
{
2009-12-20 13:35:08 +02:00
if ( user -> GetTypeId () != TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-02-22 01:46:19 +06:00
Player * player = user -> ToPlayer ();
2009-10-17 15:51:44 -07:00
2013-04-04 19:32:45 +02:00
player -> PrepareGossipMenu ( this , GetGOInfo () -> questgiver . gossipID , true );
2009-12-20 13:35:08 +02:00
player -> SendPreparedGossip ( this );
2008-10-11 14:16:25 -05:00
return ;
}
2012-10-20 21:56:48 +02:00
case GAMEOBJECT_TYPE_TRAP : //6
{
GameObjectTemplate const * goInfo = GetGOInfo ();
if ( goInfo -> trap . spellId )
CastSpell ( user , goInfo -> trap . spellId );
m_cooldownTime = time ( NULL ) + ( goInfo -> trap . cooldown ? goInfo -> trap . cooldown : uint32 ( 4 )); // template or 4 seconds
if ( goInfo -> trap . type == 1 ) // Deactivate after trigger
SetLootState ( GO_JUST_DEACTIVATED );
return ;
}
2008-10-11 14:16:25 -05:00
//Sitting: Wooden bench, chairs enzz
case GAMEOBJECT_TYPE_CHAIR : //7
{
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * info = GetGOInfo ();
2010-04-07 19:14:10 +02:00
if ( ! info )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( user -> GetTypeId () != TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-07-01 14:58:44 +02:00
if ( ChairListSlots . empty ()) // this is called once at first chair use to make list of available slots
2010-08-23 07:51:19 +02:00
{
2009-11-03 22:28:04 -08:00
if ( info -> chair . slots > 0 ) // sometimes chairs in DB have error in fields and we dont know number of slots
for ( uint32 i = 0 ; i < info -> chair . slots ; ++ i )
2014-09-14 16:14:12 +02:00
ChairListSlots [ i ]. Clear (); // Last user of current slot set to 0 (none sit here yet)
2009-10-28 15:59:45 -07:00
else
2014-09-14 16:14:12 +02:00
ChairListSlots [ 0 ]. Clear (); // error in DB, make one default slot
2010-08-23 07:51:19 +02:00
}
2009-10-28 15:59:45 -07:00
2011-02-22 01:46:19 +06:00
Player * player = user -> ToPlayer ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// a chair may have n slots. we have to calculate their positions and teleport the player to the nearest one
2009-10-17 15:51:44 -07:00
2009-10-28 15:59:45 -07:00
float lowestDist = DEFAULT_VISIBILITY_DISTANCE ;
uint32 nearest_slot = 0 ;
float x_lowest = GetPositionX ();
float y_lowest = GetPositionY ();
// the object orientation + 1/2 pi
// every slot will be on that straight line
2014-08-21 16:56:11 +02:00
float orthogonalOrientation = GetOrientation () + float ( M_PI ) * 0.5f ;
2009-10-28 15:59:45 -07:00
// find nearest slot
bool found_free_slot = false ;
for ( ChairSlotAndUser :: iterator itr = ChairListSlots . begin (); itr != ChairListSlots . end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2009-10-28 15:59:45 -07:00
// the distance between this slot and the center of the go - imagine a 1D space
float relativeDistance = ( info -> size * itr -> first ) - ( info -> size * ( info -> chair . slots - 1 ) / 2.0f );
2009-10-17 15:51:44 -07:00
2012-10-02 15:06:19 +02:00
float x_i = GetPositionX () + relativeDistance * std :: cos ( orthogonalOrientation );
float y_i = GetPositionY () + relativeDistance * std :: sin ( orthogonalOrientation );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( itr -> second )
2010-08-23 07:51:19 +02:00
{
2011-07-27 12:14:27 +02:00
if ( Player * ChairUser = ObjectAccessor :: FindPlayer ( itr -> second ))
2013-10-16 18:37:29 +02:00
{
2010-04-07 19:14:10 +02:00
if ( ChairUser -> IsSitState () && ChairUser -> getStandState () != UNIT_STAND_STATE_SIT && ChairUser -> GetExactDist2d ( x_i , y_i ) < 0.1f )
2009-10-28 15:59:45 -07:00
continue ; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->getStandState() != UNIT_STAND_STATE_SIT check is required.
else
2014-09-14 16:14:12 +02:00
itr -> second . Clear (); // This seat is unoccupied.
2013-10-16 18:37:29 +02:00
}
2009-10-28 15:59:45 -07:00
else
2014-09-14 16:14:12 +02:00
itr -> second . Clear (); // The seat may of had an occupant, but they're offline.
2010-08-23 07:51:19 +02:00
}
2009-10-17 15:51:44 -07:00
2009-10-28 15:59:45 -07:00
found_free_slot = true ;
2009-10-17 15:51:44 -07:00
2009-10-28 15:59:45 -07:00
// calculate the distance between the player and this slot
float thisDistance = player -> GetDistance2d ( x_i , y_i );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( thisDistance <= lowestDist )
2009-10-28 15:59:45 -07:00
{
nearest_slot = itr -> first ;
lowestDist = thisDistance ;
x_lowest = x_i ;
y_lowest = y_i ;
2008-10-11 14:16:25 -05:00
}
}
2009-10-28 15:59:45 -07:00
2010-04-07 19:14:10 +02:00
if ( found_free_slot )
2008-10-11 14:16:25 -05:00
{
2009-10-28 15:59:45 -07:00
ChairSlotAndUser :: iterator itr = ChairListSlots . find ( nearest_slot );
if ( itr != ChairListSlots . end ())
{
itr -> second = player -> GetGUID (); //this slot in now used by player
2011-04-29 20:47:02 +02:00
player -> TeleportTo ( GetMapId (), x_lowest , y_lowest , GetPositionZ (), GetOrientation (), TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET );
2009-10-28 15:59:45 -07:00
player -> SetStandState ( UNIT_STAND_STATE_SIT_LOW_CHAIR + info -> chair . height );
return ;
}
2008-10-11 14:16:25 -05:00
}
2009-10-28 15:59:45 -07:00
2008-10-11 14:16:25 -05:00
return ;
}
//big gun, its a spell/aura
case GAMEOBJECT_TYPE_GOOBER : //10
{
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * info = GetGOInfo ();
2009-10-17 15:51:44 -07:00
2014-04-26 03:40:30 +02:00
if ( Player * player = user -> ToPlayer ())
2008-10-11 14:16:25 -05:00
{
2009-12-25 16:05:18 +01:00
if ( info -> goober . pageId ) // show page...
2008-10-11 14:16:25 -05:00
{
WorldPacket data ( SMSG_GAMEOBJECT_PAGETEXT , 8 );
data << GetGUID ();
2013-08-07 10:31:13 +02:00
player -> SendDirectMessage ( & data );
2008-10-11 14:16:25 -05:00
}
2010-03-11 22:55:02 +01:00
else if ( info -> goober . gossipID )
2009-12-20 13:35:08 +02:00
{
player -> PrepareGossipMenu ( this , info -> goober . gossipID );
player -> SendPreparedGossip ( this );
}
2009-10-17 15:51:44 -07:00
2009-06-01 21:50:12 -05:00
if ( info -> goober . eventId )
2010-01-16 19:31:10 +03:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "maps.script" , "Goober ScriptStart id %u for GO entry %u (GUID %u)." , info -> goober . eventId , GetEntry (), GetDBTableGUIDLow ());
2009-07-31 10:48:34 +08:00
GetMap () -> ScriptsStart ( sEventScripts , info -> goober . eventId , player , this );
2014-04-26 03:40:30 +02:00
EventInform ( info -> goober . eventId , user );
2010-01-16 19:31:10 +03:00
}
// possible quest objective for active quests
2010-12-22 21:25:23 +01:00
if ( info -> goober . questId && sObjectMgr -> GetQuestTemplate ( info -> goober . questId ))
2010-01-16 19:31:10 +03:00
{
//Quest require to be active for GO using
if ( player -> GetQuestStatus ( info -> goober . questId ) != QUEST_STATUS_INCOMPLETE )
break ;
}
2013-08-30 16:42:49 +01:00
player -> KillCreditGO ( info -> entry , GetGUID ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-01-16 19:31:10 +03:00
if ( uint32 trapEntry = info -> goober . linkedTrapId )
TriggeringLinkedGameObject ( trapEntry , user );
SetFlag ( GAMEOBJECT_FLAGS , GO_FLAG_IN_USE );
2012-01-22 20:36:01 -05:00
SetLootState ( GO_ACTIVATED , user );
2010-01-16 19:31:10 +03:00
// this appear to be ok, however others exist in addition to this that should have custom (ex: 190510, 188692, 187389)
2011-10-07 12:05:31 +03:00
if ( info -> goober . customAnim )
2011-03-02 16:50:09 +01:00
SendCustomAnim ( GetGoAnimProgress ());
2010-01-16 19:31:10 +03:00
else
SetGoState ( GO_STATE_ACTIVE );
2011-10-07 12:05:31 +03:00
m_cooldownTime = time ( NULL ) + info -> GetAutoCloseTime ();
2010-01-16 19:31:10 +03:00
2008-10-11 14:16:25 -05:00
// cast this spell later if provided
spellId = info -> goober . spellId ;
2010-04-01 20:08:22 -02:30
spellCaster = NULL ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
break ;
}
case GAMEOBJECT_TYPE_CAMERA : //13
{
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * info = GetGOInfo ();
2010-04-07 19:14:10 +02:00
if ( ! info )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( user -> GetTypeId () != TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-02-22 01:46:19 +06:00
Player * player = user -> ToPlayer ();
2009-10-17 15:51:44 -07:00
2009-04-05 16:25:00 -05:00
if ( info -> camera . cinematicId )
player -> SendCinematicStart ( info -> camera . cinematicId );
2009-10-17 15:51:44 -07:00
2009-06-01 21:50:12 -05:00
if ( info -> camera . eventID )
2009-07-31 10:48:34 +08:00
GetMap () -> ScriptsStart ( sEventScripts , info -> camera . eventID , player , this );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
return ;
}
//fishing bobber
case GAMEOBJECT_TYPE_FISHINGNODE : //17
{
2010-12-26 16:35:29 +01:00
Player * player = user -> ToPlayer ();
if ( ! player )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( player -> GetGUID () != GetOwnerGUID ())
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-12-26 16:35:29 +01:00
switch ( getLootState ())
2008-10-11 14:16:25 -05:00
{
case GO_READY : // ready for loot
{
2009-03-11 16:17:37 -06:00
uint32 zone , subzone ;
2011-04-29 20:47:02 +02:00
GetZoneAndAreaId ( zone , subzone );
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
int32 zone_skill = sObjectMgr -> GetFishingBaseSkillLevel ( subzone );
2010-04-07 19:14:10 +02:00
if ( ! zone_skill )
2010-12-22 21:25:23 +01:00
zone_skill = sObjectMgr -> GetFishingBaseSkillLevel ( zone );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
//provide error, no fishable zone or area should be 0
2010-04-07 19:14:10 +02:00
if ( ! zone_skill )
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "sql.sql" , "Fishable areaId %u are not properly defined in `skill_fishing_base_level`." , subzone );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
int32 skill = player -> GetSkillValue ( SKILL_FISHING );
2010-04-04 00:30:11 +02:00
int32 chance ;
if ( skill < zone_skill )
{
2011-04-29 20:47:02 +02:00
chance = int32 ( pow (( double ) skill / zone_skill , 2 ) * 100 );
2010-04-04 00:30:11 +02:00
if ( chance < 1 )
chance = 1 ;
}
else
chance = 100 ;
2011-04-29 20:47:02 +02:00
int32 roll = irand ( 1 , 100 );
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "misc" , "Fishing check (skill: %i zone min skill: %i chance %i roll: %i" , skill , zone_skill , chance , roll );
2009-10-17 15:51:44 -07:00
2010-04-04 00:30:11 +02:00
// but you will likely cause junk in areas that require a high fishing skill (not yet implemented)
if ( chance >= roll )
2008-10-11 14:16:25 -05:00
{
2009-10-06 21:01:20 +02:00
player -> UpdateFishingSkill ();
2009-10-17 15:51:44 -07:00
2013-03-08 21:41:30 +01:00
/// @todo I do not understand this hack. Need some explanation.
2010-04-04 00:30:11 +02:00
// prevent removing GO at spell cancel
2011-10-31 10:46:39 -04:00
RemoveFromOwner ();
2010-04-04 00:30:11 +02:00
SetOwnerGUID ( player -> GetGUID ());
2014-06-07 17:58:45 +01:00
SetSpellId ( 0 ); // prevent removing unintended auras at Unit::RemoveGameObject
2010-04-04 00:30:11 +02:00
2013-03-08 21:41:30 +01:00
/// @todo find reasonable value for fishing hole search
2010-04-04 00:30:11 +02:00
GameObject * ok = LookupFishingHoleAround ( 20.0f + CONTACT_DISTANCE );
if ( ok )
{
2010-08-09 22:50:30 +06:00
ok -> Use ( player );
2010-04-04 00:30:11 +02:00
SetLootState ( GO_JUST_DEACTIVATED );
2008-10-11 14:16:25 -05:00
}
2010-04-04 00:30:11 +02:00
else
2011-04-29 20:47:02 +02:00
player -> SendLoot ( GetGUID (), LOOT_FISHING );
2008-10-11 14:16:25 -05:00
}
2014-05-10 21:35:05 +08:00
else // else: junk
player -> SendLoot ( GetGUID (), LOOT_FISHING_JUNK );
2008-10-11 14:16:25 -05:00
break ;
}
case GO_JUST_DEACTIVATED : // nothing to do, will be deleted at next update
break ;
default :
{
SetLootState ( GO_JUST_DEACTIVATED );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_FISH_NOT_HOOKED , 0 );
2013-08-07 10:31:13 +02:00
player -> SendDirectMessage ( & data );
2008-10-11 14:16:25 -05:00
break ;
}
}
2009-10-17 15:51:44 -07:00
2009-08-19 16:52:51 -05:00
player -> FinishSpell ( CURRENT_CHANNELED_SPELL );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2014-10-06 18:37:38 -04:00
case GAMEOBJECT_TYPE_RITUAL : //18
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( user -> GetTypeId () != TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-12-26 00:14:13 +01:00
Player * player = user -> ToPlayer ();
2009-10-17 15:51:44 -07:00
2010-08-09 22:50:30 +06:00
Unit * owner = GetOwner ();
2009-10-17 15:51:44 -07:00
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * info = GetGOInfo ();
2009-10-17 15:51:44 -07:00
2014-04-10 20:41:34 +02:00
Player * m_ritualOwner = NULL ;
if ( m_ritualOwnerGUID )
m_ritualOwner = ObjectAccessor :: FindPlayer ( m_ritualOwnerGUID );
2010-08-09 22:50:30 +06:00
// ritual owner is set for GO's without owner (not summoned)
if ( ! m_ritualOwner && ! owner )
2014-04-10 20:41:34 +02:00
{
m_ritualOwnerGUID = player -> GetGUID ();
2010-08-09 22:50:30 +06:00
m_ritualOwner = player ;
2014-04-10 20:41:34 +02:00
}
2009-10-17 15:51:44 -07:00
2010-08-09 22:50:30 +06:00
if ( owner )
{
if ( owner -> GetTypeId () != TYPEID_PLAYER )
return ;
2009-10-17 15:51:44 -07:00
2010-08-09 22:50:30 +06:00
// accept only use by player from same group as owner, excluding owner itself (unique use already added in spell effect)
if ( player == owner -> ToPlayer () || ( info -> summoningRitual . castersGrouped && ! player -> IsInSameRaidWith ( owner -> ToPlayer ())))
return ;
2009-10-17 15:51:44 -07:00
2010-08-09 22:50:30 +06:00
// expect owner to already be channeling, so if not...
if ( ! owner -> GetCurrentSpell ( CURRENT_CHANNELED_SPELL ))
return ;
2009-10-17 15:51:44 -07:00
2010-08-09 22:50:30 +06:00
// in case summoning ritual caster is GO creator
spellCaster = owner ;
}
else
{
if ( player != m_ritualOwner && ( info -> summoningRitual . castersGrouped && ! player -> IsInSameRaidWith ( m_ritualOwner )))
return ;
2009-10-17 15:51:44 -07:00
2010-08-09 22:50:30 +06:00
spellCaster = player ;
}
AddUniqueUse ( player );
2009-10-17 15:51:44 -07:00
2010-08-09 22:50:30 +06:00
if ( info -> summoningRitual . animSpell )
2009-02-22 17:48:48 -06:00
{
2010-08-09 22:50:30 +06:00
player -> CastSpell ( player , info -> summoningRitual . animSpell , true );
// for this case, summoningRitual.spellId is always triggered
2009-02-22 17:48:48 -06:00
triggered = true ;
}
2009-10-17 15:51:44 -07:00
2010-08-09 22:50:30 +06:00
// full amount unique participants including original summoner
if ( GetUniqueUseCount () == info -> summoningRitual . reqParticipants )
{
2012-08-30 22:44:33 +01:00
if ( m_ritualOwner )
spellCaster = m_ritualOwner ;
2010-08-09 22:50:30 +06:00
spellId = info -> summoningRitual . spellId ;
2009-10-17 15:51:44 -07:00
2010-08-09 22:50:30 +06:00
if ( spellId == 62330 ) // GO store nonexistent spell, replace by expected
{
// spell have reagent and mana cost but it not expected use its
2013-12-25 14:16:55 -03:30
// it triggered spell in fact cast at currently channeled GO
2010-08-09 22:50:30 +06:00
spellId = 61993 ;
triggered = true ;
}
2011-09-15 17:51:17 +01:00
// Cast casterTargetSpell at a random GO user
// on the current DB there is only one gameobject that uses this (Ritual of Doom)
// and its required target number is 1 (outter for loop will run once)
if ( info -> summoningRitual . casterTargetSpell && info -> summoningRitual . casterTargetSpell != 1 ) // No idea why this field is a bool in some cases
2011-09-17 13:20:21 +02:00
for ( uint32 i = 0 ; i < info -> summoningRitual . casterTargetSpellTargets ; i ++ )
// m_unique_users can contain only player GUIDs
2012-05-30 08:01:02 +02:00
if ( Player * target = ObjectAccessor :: GetPlayer ( * this , Trinity :: Containers :: SelectRandomContainerElement ( m_unique_users )))
2011-09-15 17:51:17 +01:00
spellCaster -> CastSpell ( target , info -> summoningRitual . casterTargetSpell , true );
2010-08-09 22:50:30 +06:00
// finish owners spell
if ( owner )
owner -> FinishSpell ( CURRENT_CHANNELED_SPELL );
// can be deleted now, if
if ( ! info -> summoningRitual . ritualPersistent )
SetLootState ( GO_JUST_DEACTIVATED );
else
{
// reset ritual for this GO
2014-09-14 16:14:12 +02:00
m_ritualOwnerGUID . Clear ();
2010-08-09 22:50:30 +06:00
m_unique_users . clear ();
m_usetimes = 0 ;
}
}
else
return ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// go to end function to spell casting
break ;
}
case GAMEOBJECT_TYPE_SPELLCASTER : //22
{
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * info = GetGOInfo ();
2010-04-07 19:14:10 +02:00
if ( ! info )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( info -> spellcaster . partyOnly )
2008-10-11 14:16:25 -05:00
{
Unit * caster = GetOwner ();
2010-04-07 22:59:46 +02:00
if ( ! caster || caster -> GetTypeId () != TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( user -> GetTypeId () != TYPEID_PLAYER || ! user -> ToPlayer () -> IsInSameRaidWith ( caster -> ToPlayer ()))
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-12-19 11:56:37 +01:00
user -> RemoveAurasByType ( SPELL_AURA_MOUNTED );
2008-10-11 14:16:25 -05:00
spellId = info -> spellcaster . spellId ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
AddUse ();
break ;
}
case GAMEOBJECT_TYPE_MEETINGSTONE : //23
{
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * info = GetGOInfo ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( user -> GetTypeId () != TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-02-22 01:46:19 +06:00
Player * player = user -> ToPlayer ();
2009-10-17 15:51:44 -07:00
2013-10-03 17:07:25 +02:00
Player * targetPlayer = ObjectAccessor :: FindPlayer ( player -> GetTarget ());
2009-10-17 15:51:44 -07:00
2010-07-24 04:50:35 +02:00
// accept only use by player from same raid as caster, except caster itself
if ( ! targetPlayer || targetPlayer == player || ! targetPlayer -> IsInSameRaidWith ( player ))
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
//required lvl checks!
uint8 level = player -> getLevel ();
2010-02-24 05:03:22 -07:00
if ( level < info -> meetingstone . minLevel )
2008-10-11 14:16:25 -05:00
return ;
level = targetPlayer -> getLevel ();
2010-02-24 05:03:22 -07:00
if ( level < info -> meetingstone . minLevel )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-04-28 22:54:30 +02:00
if ( info -> entry == 194097 )
2009-02-22 17:48:19 -06:00
spellId = 61994 ; // Ritual of Summoning
else
spellId = 59782 ; // Summoning Stone Effect
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
break ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
case GAMEOBJECT_TYPE_FLAGSTAND : // 24
{
2009-11-01 17:53:07 -08:00
if ( user -> GetTypeId () != TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-02-22 01:46:19 +06:00
Player * player = user -> ToPlayer ();
2009-10-17 15:51:44 -07:00
2012-10-17 16:56:35 +02:00
if ( player -> CanUseBattlegroundObject ( this ))
2008-10-11 14:16:25 -05:00
{
// in battleground check
2011-09-15 14:08:17 +02:00
Battleground * bg = player -> GetBattleground ();
2010-04-07 19:14:10 +02:00
if ( ! bg )
2008-10-11 14:16:25 -05:00
return ;
2012-10-17 16:56:35 +02:00
2010-04-30 00:24:25 +02:00
if ( player -> GetVehicle ())
return ;
2012-10-17 16:56:35 +02:00
player -> RemoveAurasByType ( SPELL_AURA_MOD_STEALTH );
player -> RemoveAurasByType ( SPELL_AURA_MOD_INVISIBILITY );
2008-10-11 14:16:25 -05:00
// BG flag click
// AB:
// 15001
// 15002
// 15003
// 15004
// 15005
bg -> EventPlayerClickedOnFlag ( player , this );
return ; //we don;t need to delete flag ... it is despawned!
}
break ;
}
2010-08-09 22:50:30 +06:00
case GAMEOBJECT_TYPE_FISHINGHOLE : // 25
{
if ( user -> GetTypeId () != TYPEID_PLAYER )
return ;
2011-02-22 01:46:19 +06:00
Player * player = user -> ToPlayer ();
2010-08-09 22:50:30 +06:00
player -> SendLoot ( GetGUID (), LOOT_FISHINGHOLE );
2011-04-28 22:54:30 +02:00
player -> UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT , GetGOInfo () -> entry );
2010-08-09 22:50:30 +06:00
return ;
}
2008-10-11 14:16:25 -05:00
case GAMEOBJECT_TYPE_FLAGDROP : // 26
{
2009-11-01 17:53:07 -08:00
if ( user -> GetTypeId () != TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2011-02-22 01:46:19 +06:00
Player * player = user -> ToPlayer ();
2009-10-17 15:51:44 -07:00
2012-10-17 16:56:35 +02:00
if ( player -> CanUseBattlegroundObject ( this ))
2008-10-11 14:16:25 -05:00
{
// in battleground check
2011-06-12 02:30:32 +02:00
Battleground * bg = player -> GetBattleground ();
2009-11-01 17:53:07 -08:00
if ( ! bg )
2008-10-11 14:16:25 -05:00
return ;
2012-10-17 16:56:35 +02:00
2011-06-12 02:30:32 +02:00
if ( player -> GetVehicle ())
2010-04-30 00:24:25 +02:00
return ;
2012-10-17 16:56:35 +02:00
player -> RemoveAurasByType ( SPELL_AURA_MOD_STEALTH );
player -> RemoveAurasByType ( SPELL_AURA_MOD_INVISIBILITY );
2008-10-11 14:16:25 -05:00
// BG flag dropped
// WS:
// 179785 - Silverwing Flag
// 179786 - Warsong Flag
// EotS:
// 184142 - Netherstorm Flag
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * info = GetGOInfo ();
2009-11-01 17:53:07 -08:00
if ( info )
2008-10-11 14:16:25 -05:00
{
2011-09-29 12:43:05 +02:00
switch ( info -> entry )
2008-10-11 14:16:25 -05:00
{
case 179785 : // Silverwing Flag
case 179786 : // Warsong Flag
2011-10-18 09:48:11 +02:00
if ( bg -> GetTypeID ( true ) == BATTLEGROUND_WS )
2008-10-11 14:16:25 -05:00
bg -> EventPlayerClickedOnFlag ( player , this );
break ;
case 184142 : // Netherstorm Flag
2011-10-18 09:48:11 +02:00
if ( bg -> GetTypeID ( true ) == BATTLEGROUND_EY )
2008-10-11 14:16:25 -05:00
bg -> EventPlayerClickedOnFlag ( player , this );
break ;
}
}
//this cause to call return, all flags must be deleted here!!
spellId = 0 ;
Delete ();
}
break ;
}
2008-12-24 09:58:26 -06:00
case GAMEOBJECT_TYPE_BARBER_CHAIR : //32
{
2011-04-28 22:54:30 +02:00
GameObjectTemplate const * info = GetGOInfo ();
2009-11-01 17:53:07 -08:00
if ( ! info )
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-11-01 17:53:07 -08:00
if ( user -> GetTypeId () != TYPEID_PLAYER )
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2011-02-22 01:46:19 +06:00
Player * player = user -> ToPlayer ();
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// fallback, will always work
2011-04-29 20:47:02 +02:00
player -> TeleportTo ( GetMapId (), GetPositionX (), GetPositionY (), GetPositionZ (), GetOrientation (), TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET );
2009-10-17 15:51:44 -07:00
2009-07-08 14:29:40 +02:00
WorldPacket data ( SMSG_ENABLE_BARBER_SHOP , 0 );
2013-08-07 10:31:13 +02:00
player -> SendDirectMessage ( & data );
2009-10-17 15:51:44 -07:00
2009-01-31 14:41:36 -06:00
player -> SetStandState ( UNIT_STAND_STATE_SIT_LOW_CHAIR + info -> barberChair . chairheight );
2008-12-24 09:58:26 -06:00
return ;
}
2008-10-11 14:16:25 -05:00
default :
2011-08-15 15:41:06 +02:00
if ( GetGoType () >= MAX_GAMEOBJECT_TYPE )
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "GameObject::Use(): unit (type: %u, guid: %u, name: %s) tries to use object (guid: %u, entry: %u, name: %s) of unknown type (%u)" ,
2012-10-24 13:29:34 +02:00
user -> GetTypeId (), user -> GetGUIDLow (), user -> GetName (). c_str (), GetGUIDLow (), GetEntry (), GetGOInfo () -> name . c_str (), GetGoType ());
2008-10-11 14:16:25 -05:00
break ;
}
2009-10-17 15:51:44 -07:00
2009-11-01 17:53:07 -08:00
if ( ! spellId )
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
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( spellId );
2009-11-01 17:53:07 -08:00
if ( ! spellInfo )
2008-10-11 14:16:25 -05:00
{
2011-02-22 01:46:19 +06:00
if ( user -> GetTypeId () != TYPEID_PLAYER || ! sOutdoorPvPMgr -> HandleCustomSpell ( user -> ToPlayer (), spellId , this ))
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "WORLD: unknown spell id %u at use action for gameobject (Entry: %u GoType: %u)" , spellId , GetEntry (), GetGoType ());
2008-10-14 11:57:03 -05:00
else
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "outdoorpvp" , "WORLD: %u non-dbc spell was handled by OutdoorPvP" , spellId );
2008-10-11 14:16:25 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-04-01 20:08:22 -02:30
if ( spellCaster )
spellCaster -> CastSpell ( user , spellInfo , triggered );
else
CastSpell ( user , spellId );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-06-14 22:01:50 +02:00
void GameObject :: CastSpell ( Unit * target , uint32 spellId , bool triggered /*= true*/ )
2008-11-02 00:59:44 -05:00
{
2011-07-26 23:09:28 +02:00
SpellInfo const * spellInfo = sSpellMgr -> GetSpellInfo ( spellId );
2009-11-01 17:53:07 -08:00
if ( ! spellInfo )
2009-03-14 21:30:03 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-03-14 21:30:03 -06:00
bool self = false ;
2010-09-28 08:21:51 +03:00
for ( uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++ i )
2009-03-14 21:30:03 -06:00
{
2011-07-27 12:35:59 +02:00
if ( spellInfo -> Effects [ i ]. TargetA . GetTarget () == TARGET_UNIT_CASTER )
2009-03-14 21:30:03 -06:00
{
self = true ;
break ;
}
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( self )
2009-03-14 21:30:03 -06:00
{
2010-04-07 19:14:10 +02:00
if ( target )
2014-06-14 22:01:50 +02:00
target -> CastSpell ( target , spellInfo , triggered );
2009-03-14 21:30:03 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2008-11-02 00:59:44 -05:00
//summon world trigger
2011-07-26 23:09:28 +02:00
Creature * trigger = SummonTrigger ( GetPositionX (), GetPositionY (), GetPositionZ (), 0 , spellInfo -> CalcCastTime () + 100 );
2011-04-18 22:29:17 +02:00
if ( ! trigger )
return ;
2009-10-17 15:51:44 -07:00
2011-04-18 22:29:17 +02:00
if ( Unit * owner = GetOwner ())
2008-11-02 08:44:15 -06:00
{
trigger -> setFaction ( owner -> getFaction ());
2011-08-29 23:49:46 +02:00
// needed for GO casts for proper target validation checks
2012-11-26 11:11:30 +01:00
trigger -> SetOwnerGUID ( owner -> GetGUID ());
2014-08-09 21:32:26 +01:00
trigger -> CastSpell ( target ? target : trigger , spellInfo , triggered , nullptr , nullptr , owner -> GetGUID ());
2008-11-02 08:44:15 -06:00
}
else
{
trigger -> setFaction ( 14 );
2012-05-30 08:01:02 +02:00
// Set owner guid for target if no owner available - needed by trigger auras
2009-06-13 14:01:10 +02:00
// - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell())
2014-09-14 16:14:12 +02:00
trigger -> CastSpell ( target ? target : trigger , spellInfo , triggered , nullptr , nullptr , target ? target -> GetGUID () : ObjectGuid :: Empty );
2008-11-02 08:44:15 -06:00
}
2008-11-14 16:28:45 -06:00
}
2009-10-17 15:51:44 -07:00
2011-03-02 16:50:09 +01:00
void GameObject :: SendCustomAnim ( uint32 anim )
2009-04-30 12:01:08 -05:00
{
2011-04-29 20:47:02 +02:00
WorldPacket data ( SMSG_GAMEOBJECT_CUSTOM_ANIM , 8 + 4 );
2009-04-30 12:01:08 -05:00
data << GetGUID ();
2011-03-02 16:50:09 +01:00
data << uint32 ( anim );
2009-04-30 12:01:08 -05:00
SendMessageToSet ( & data , true );
}
2009-10-17 15:51:44 -07:00
2009-05-21 10:01:03 -05:00
bool GameObject :: IsInRange ( float x , float y , float z , float radius ) const
{
2011-10-04 20:14:30 -03:00
GameObjectDisplayInfoEntry const * info = sGameObjectDisplayInfoStore . LookupEntry ( m_goInfo -> displayId );
2009-11-01 17:53:07 -08:00
if ( ! info )
2009-05-21 10:01:03 -05:00
return IsWithinDist3d ( x , y , z , radius );
2009-10-17 15:51:44 -07:00
2012-10-02 15:06:19 +02:00
float sinA = std :: sin ( GetOrientation ());
float cosA = std :: cos ( GetOrientation ());
2009-05-21 10:01:03 -05:00
float dx = x - GetPositionX ();
float dy = y - GetPositionY ();
float dz = z - GetPositionZ ();
2014-08-21 16:56:11 +02:00
float dist = std :: sqrt ( dx * dx + dy * dy );
2012-09-08 15:24:59 -05:00
//! Check if the distance between the 2 objects is 0, can happen if both objects are on the same position.
//! The code below this check wont crash if dist is 0 because 0/0 in float operations is valid, and returns infinite
if ( G3D :: fuzzyEq ( dist , 0.0f ))
return true ;
2009-05-21 10:01:03 -05:00
float sinB = dx / dist ;
float cosB = dy / dist ;
dx = dist * ( cosA * cosB + sinA * sinB );
dy = dist * ( cosA * sinB - sinA * cosB );
return dx < info -> maxX + radius && dx > info -> minX - radius
&& dy < info -> maxY + radius && dy > info -> minY - radius
&& dz < info -> maxZ + radius && dz > info -> minZ - radius ;
}
2009-10-17 15:51:44 -07:00
2014-04-26 03:40:30 +02:00
void GameObject :: EventInform ( uint32 eventId , WorldObject * invoker /*= NULL*/ )
2009-06-01 12:48:12 -05:00
{
2012-06-11 11:10:46 +02:00
if ( ! eventId )
return ;
if ( AI ())
AI () -> EventInform ( eventId );
2014-04-26 03:40:30 +02:00
if ( GetZoneScript ())
GetZoneScript () -> ProcessEvent ( this , eventId );
if ( BattlegroundMap * bgMap = GetMap () -> ToBattlegroundMap ())
if ( bgMap -> GetBG ())
bgMap -> GetBG () -> ProcessEvent ( this , eventId , invoker );
2009-06-01 12:48:12 -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 & GameObject :: 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 )
2010-08-23 07:51:19 +02:00
{
uint8 uloc_idx = uint8 ( loc_idx );
2011-09-15 14:08:17 +02:00
if ( GameObjectLocale const * cl = sObjectMgr -> GetGameObjectLocale ( GetEntry ()))
2010-08-23 07:51:19 +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 ];
2010-08-23 07:51:19 +02: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
2009-03-18 20:46:21 -06:00
void GameObject :: UpdateRotationFields ( float rotation2 /*=0.0f*/ , float rotation3 /*=0.0f*/ )
{
2009-03-19 15:16:02 -06:00
static double const atan_pow = atan ( pow ( 2.0f , - 20.0f ));
2009-10-17 15:51:44 -07:00
2012-10-02 15:06:19 +02:00
double f_rot1 = std :: sin ( GetOrientation () / 2.0f );
double f_rot2 = std :: cos ( GetOrientation () / 2.0f );
2009-10-17 15:51:44 -07:00
2009-03-19 15:16:02 -06:00
int64 i_rot1 = int64 ( f_rot1 / atan_pow * ( f_rot2 >= 0 ? 1.0f : - 1.0f ));
int64 rotation = ( i_rot1 << 43 >> 43 ) & 0x00000000001FFFFF ;
2009-10-17 15:51:44 -07:00
2012-10-02 15:06:19 +02:00
//float f_rot2 = std::sin(0.0f / 2.0f);
2009-06-11 00:45:59 -05:00
//int64 i_rot2 = f_rot2 / atan(pow(2.0f, -20.0f));
//rotation |= (((i_rot2 << 22) >> 32) >> 11) & 0x000003FFFFE00000;
2009-10-17 15:51:44 -07:00
2012-10-02 15:06:19 +02:00
//float f_rot3 = std::sin(0.0f / 2.0f);
2009-06-11 00:45:59 -05:00
//int64 i_rot3 = f_rot3 / atan(pow(2.0f, -21.0f));
//rotation |= (i_rot3 >> 42) & 0x7FFFFC0000000000;
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
m_rotation = rotation ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( rotation2 == 0.0f && rotation3 == 0.0f )
2009-03-18 20:46:21 -06:00
{
2010-08-22 12:39:39 -07:00
rotation2 = ( float ) f_rot1 ;
rotation3 = ( float ) f_rot2 ;
2009-03-18 20:46:21 -06:00
}
2009-10-17 15:51:44 -07:00
2009-03-18 20:46:21 -06:00
SetFloatValue ( GAMEOBJECT_PARENTROTATION + 2 , rotation2 );
SetFloatValue ( GAMEOBJECT_PARENTROTATION + 3 , rotation3 );
}
2011-07-22 21:22:05 +02:00
void GameObject :: ModifyHealth ( int32 change , Unit * attackerOrHealer /*= NULL*/ , uint32 spellId /*= 0*/ )
{
2012-10-24 13:29:34 +02:00
if ( ! m_goValue . Building . MaxHealth || ! change )
2011-07-22 21:22:05 +02:00
return ;
2011-07-24 23:55:14 +02:00
// prevent double destructions of the same object
2012-10-24 13:29:34 +02:00
if ( change < 0 && ! m_goValue . Building . Health )
2011-07-24 23:55:14 +02:00
return ;
2012-10-24 13:29:34 +02:00
if ( int32 ( m_goValue . Building . Health ) + change <= 0 )
m_goValue . Building . Health = 0 ;
else if ( int32 ( m_goValue . Building . Health ) + change >= int32 ( m_goValue . Building . MaxHealth ))
m_goValue . Building . Health = m_goValue . Building . MaxHealth ;
2011-07-22 21:22:05 +02:00
else
2012-10-24 13:29:34 +02:00
m_goValue . Building . Health += change ;
2011-07-22 21:22:05 +02:00
2011-07-24 23:55:14 +02:00
// Set the health bar, value = 255 * healthPct;
2012-10-24 13:29:34 +02:00
SetGoAnimProgress ( m_goValue . Building . Health * 255 / m_goValue . Building . MaxHealth );
2011-07-22 21:22:05 +02:00
2014-04-26 03:40:30 +02:00
Player * player = attackerOrHealer ? attackerOrHealer -> GetCharmerOrOwnerPlayerOrPlayerItself () : NULL ;
2011-07-22 21:22:05 +02:00
// dealing damage, send packet
2013-05-11 11:40:12 +02:00
if ( player )
2011-07-22 21:22:05 +02:00
{
WorldPacket data ( SMSG_DESTRUCTIBLE_BUILDING_DAMAGE , 8 + 8 + 8 + 4 + 4 );
2014-09-13 01:07:21 +02:00
data << GetPackGUID ();
data << attackerOrHealer -> GetPackGUID ();
data << player -> GetPackGUID ();
2013-05-11 11:40:12 +02:00
data << uint32 ( - change ); // change < 0 triggers SPELL_BUILDING_HEAL combat log event
// change >= 0 triggers SPELL_BUILDING_DAMAGE event
2011-07-22 21:22:05 +02:00
data << uint32 ( spellId );
2013-08-07 10:31:13 +02:00
player -> SendDirectMessage ( & data );
2011-07-22 21:22:05 +02:00
}
2011-07-24 23:55:14 +02:00
GameObjectDestructibleState newState = GetDestructibleState ();
2012-10-24 13:29:34 +02:00
if ( ! m_goValue . Building . Health )
2011-07-24 23:55:14 +02:00
newState = GO_DESTRUCTIBLE_DESTROYED ;
2012-10-24 13:29:34 +02:00
else if ( m_goValue . Building . Health <= GetGOInfo () -> building . damagedNumHits )
2011-07-24 23:55:14 +02:00
newState = GO_DESTRUCTIBLE_DAMAGED ;
2012-10-24 13:29:34 +02:00
else if ( m_goValue . Building . Health == m_goValue . Building . MaxHealth )
2011-07-24 23:55:14 +02:00
newState = GO_DESTRUCTIBLE_INTACT ;
if ( newState == GetDestructibleState ())
return ;
2014-05-01 15:14:42 +02:00
/// @todo: pass attackerOrHealer instead of player
2011-07-24 23:55:14 +02:00
SetDestructibleState ( newState , player , false );
2011-07-22 21:22:05 +02:00
}
void GameObject :: SetDestructibleState ( GameObjectDestructibleState state , Player * eventInvoker /*= NULL*/ , bool setHealth /*= false*/ )
{
// the user calling this must know he is already operating on destructible gameobject
ASSERT ( GetGoType () == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING );
switch ( state )
{
case GO_DESTRUCTIBLE_INTACT :
RemoveFlag ( GAMEOBJECT_FLAGS , GO_FLAG_DAMAGED | GO_FLAG_DESTROYED );
2012-02-03 16:03:52 -05:00
SetDisplayId ( m_goInfo -> displayId );
2011-07-22 21:22:05 +02:00
if ( setHealth )
{
2012-10-24 13:29:34 +02:00
m_goValue . Building . Health = m_goValue . Building . MaxHealth ;
2011-07-22 21:22:05 +02:00
SetGoAnimProgress ( 255 );
}
2012-05-30 08:01:02 +02:00
EnableCollision ( true );
2011-07-22 21:22:05 +02:00
break ;
case GO_DESTRUCTIBLE_DAMAGED :
{
2014-04-26 03:40:30 +02:00
EventInform ( m_goInfo -> building . damagedEvent , eventInvoker );
2011-09-07 15:11:12 +02:00
sScriptMgr -> OnGameObjectDamaged ( this , eventInvoker );
2011-07-22 21:22:05 +02:00
RemoveFlag ( GAMEOBJECT_FLAGS , GO_FLAG_DESTROYED );
SetFlag ( GAMEOBJECT_FLAGS , GO_FLAG_DAMAGED );
uint32 modelId = m_goInfo -> building . damagedDisplayId ;
if ( DestructibleModelDataEntry const * modelData = sDestructibleModelDataStore . LookupEntry ( m_goInfo -> building . destructibleData ))
if ( modelData -> DamagedDisplayId )
modelId = modelData -> DamagedDisplayId ;
2012-02-03 16:03:52 -05:00
SetDisplayId ( modelId );
2011-07-22 21:22:05 +02:00
if ( setHealth )
{
2012-10-24 13:29:34 +02:00
m_goValue . Building . Health = m_goInfo -> building . damagedNumHits ;
uint32 maxHealth = m_goValue . Building . MaxHealth ;
2011-07-22 21:22:05 +02:00
// in this case current health is 0 anyway so just prevent crashing here
if ( ! maxHealth )
maxHealth = 1 ;
2012-10-24 13:29:34 +02:00
SetGoAnimProgress ( m_goValue . Building . Health * 255 / maxHealth );
2011-07-22 21:22:05 +02:00
}
break ;
}
case GO_DESTRUCTIBLE_DESTROYED :
{
2011-09-07 15:11:12 +02:00
sScriptMgr -> OnGameObjectDestroyed ( this , eventInvoker );
2014-04-26 03:40:30 +02:00
EventInform ( m_goInfo -> building . destroyedEvent , eventInvoker );
2011-07-22 21:22:05 +02:00
if ( eventInvoker )
if ( Battleground * bg = eventInvoker -> GetBattleground ())
bg -> DestroyGate ( eventInvoker , this );
RemoveFlag ( GAMEOBJECT_FLAGS , GO_FLAG_DAMAGED );
SetFlag ( GAMEOBJECT_FLAGS , GO_FLAG_DESTROYED );
uint32 modelId = m_goInfo -> building . destroyedDisplayId ;
if ( DestructibleModelDataEntry const * modelData = sDestructibleModelDataStore . LookupEntry ( m_goInfo -> building . destructibleData ))
if ( modelData -> DestroyedDisplayId )
modelId = modelData -> DestroyedDisplayId ;
2012-02-03 16:03:52 -05:00
SetDisplayId ( modelId );
2011-07-22 21:22:05 +02:00
if ( setHealth )
{
2012-10-24 13:29:34 +02:00
m_goValue . Building . Health = 0 ;
2011-07-22 21:22:05 +02:00
SetGoAnimProgress ( 0 );
}
2012-05-30 08:01:02 +02:00
EnableCollision ( false );
2011-07-22 21:22:05 +02:00
break ;
}
case GO_DESTRUCTIBLE_REBUILDING :
2011-07-24 23:55:14 +02:00
{
2014-04-26 03:40:30 +02:00
EventInform ( m_goInfo -> building . rebuildingEvent , eventInvoker );
2011-07-24 23:55:14 +02:00
RemoveFlag ( GAMEOBJECT_FLAGS , GO_FLAG_DAMAGED | GO_FLAG_DESTROYED );
uint32 modelId = m_goInfo -> displayId ;
if ( DestructibleModelDataEntry const * modelData = sDestructibleModelDataStore . LookupEntry ( m_goInfo -> building . destructibleData ))
if ( modelData -> RebuildingDisplayId )
modelId = modelData -> RebuildingDisplayId ;
2012-02-03 16:03:52 -05:00
SetDisplayId ( modelId );
2011-07-24 23:55:14 +02:00
2011-07-22 21:22:05 +02:00
// restores to full health
if ( setHealth )
{
2012-10-24 13:29:34 +02:00
m_goValue . Building . Health = m_goValue . Building . MaxHealth ;
2011-07-22 21:22:05 +02:00
SetGoAnimProgress ( 255 );
}
2012-05-30 08:01:02 +02:00
EnableCollision ( true );
2011-07-22 21:22:05 +02:00
break ;
2011-07-24 23:55:14 +02:00
}
2011-07-22 21:22:05 +02:00
}
}
2012-01-06 11:09:01 -05:00
2012-02-03 16:03:52 -05:00
void GameObject :: SetLootState ( LootState state , Unit * unit )
2012-01-06 11:09:01 -05:00
{
2012-02-03 16:03:52 -05:00
m_lootState = state ;
2014-09-14 16:14:12 +02:00
if ( unit )
m_lootStateUnitGUID = unit -> GetGUID ();
else
m_lootStateUnitGUID . Clear ();
2012-02-03 16:03:52 -05:00
AI () -> OnStateChanged ( state , unit );
2012-05-30 08:01:02 +02:00
sScriptMgr -> OnGameObjectLootStateChanged ( this , state , unit );
2014-05-25 11:35:51 +01:00
if ( GetGoType () == GAMEOBJECT_TYPE_DOOR ) // only set collision for doors on SetGoState
return ;
2012-02-03 16:03:52 -05:00
if ( m_model )
{
2012-09-04 14:04:47 -04:00
bool collision = false ;
2012-05-30 08:01:02 +02:00
// Use the current go state
2012-09-04 12:07:20 -04:00
if (( GetGoState () != GO_STATE_READY && ( state == GO_ACTIVATED || state == GO_JUST_DEACTIVATED )) || state == GO_READY )
2012-09-04 14:04:47 -04:00
collision = ! collision ;
2012-02-03 16:03:52 -05:00
2012-09-04 14:04:47 -04:00
EnableCollision ( collision );
2012-02-03 16:03:52 -05:00
}
2012-01-14 15:34:41 +01:00
}
2012-02-03 16:03:52 -05:00
void GameObject :: SetGoState ( GOState state )
{
SetByteValue ( GAMEOBJECT_BYTES_1 , 0 , state );
2012-05-30 08:01:02 +02:00
sScriptMgr -> OnGameObjectStateChanged ( this , state );
2014-03-23 00:23:30 +01:00
if ( m_model && ! IsTransport ())
2012-02-03 16:03:52 -05:00
{
if ( ! IsInWorld ())
return ;
// startOpen determines whether we are going to add or remove the LoS on activation
2012-09-04 14:04:47 -04:00
bool collision = false ;
if ( state == GO_STATE_READY )
2012-09-04 19:48:29 +01:00
collision = ! collision ;
2012-02-03 16:03:52 -05:00
2012-09-04 14:04:47 -04:00
EnableCollision ( collision );
2012-02-03 16:03:52 -05:00
}
}
2014-09-29 20:10:08 +02:00
uint32 GameObject :: GetTransportPeriod () const
{
ASSERT ( GetGOInfo () -> type == GAMEOBJECT_TYPE_TRANSPORT );
if ( m_goValue . Transport . AnimationInfo )
return m_goValue . Transport . AnimationInfo -> TotalTime ;
// return something that will nicely divide for GAMEOBJECT_DYNAMIC value calculation
return m_goValue . Transport . PathProgress ;
}
void GameObject :: SetTransportState ( GOState state , uint32 stopFrame /*= 0*/ )
{
if ( GetGoState () == state )
return ;
ASSERT ( GetGOInfo () -> type == GAMEOBJECT_TYPE_TRANSPORT );
ASSERT ( state >= GO_STATE_TRANSPORT_ACTIVE );
if ( state == GO_STATE_TRANSPORT_ACTIVE )
{
m_goValue . Transport . StateUpdateTimer = 0 ;
2014-09-30 22:48:04 +02:00
m_goValue . Transport . PathProgress = getMSTime ();
if ( GetGoState () >= GO_STATE_TRANSPORT_STOPPED )
m_goValue . Transport . StopFrames -> at ( GetGoState () - GO_STATE_TRANSPORT_STOPPED );
2014-09-29 20:10:08 +02:00
SetGoState ( GO_STATE_TRANSPORT_ACTIVE );
}
else
{
ASSERT ( state < GO_STATE_TRANSPORT_STOPPED + MAX_GO_STATE_TRANSPORT_STOP_FRAMES );
ASSERT ( stopFrame < m_goValue . Transport . StopFrames -> size ());
m_goValue . Transport . PathProgress = getMSTime () + m_goValue . Transport . StopFrames -> at ( stopFrame );
SetGoState ( GOState ( GO_STATE_TRANSPORT_STOPPED + stopFrame ));
}
}
2012-02-03 16:03:52 -05:00
void GameObject :: SetDisplayId ( uint32 displayid )
{
SetUInt32Value ( GAMEOBJECT_DISPLAYID , displayid );
UpdateModel ();
}
2014-06-01 22:27:29 -05:00
void GameObject :: SetInPhase ( uint32 id , bool update , bool apply )
2012-02-03 16:03:52 -05:00
{
2014-06-01 22:27:29 -05:00
WorldObject :: SetInPhase ( id , update , apply );
2012-09-04 12:07:20 -04:00
if ( m_model && m_model -> isEnabled ())
EnableCollision ( true );
2012-02-03 16:03:52 -05:00
}
void GameObject :: EnableCollision ( bool enable )
2012-01-06 11:09:01 -05:00
{
2012-02-03 16:03:52 -05:00
if ( ! m_model )
return ;
2012-02-10 10:24:56 +01:00
2012-08-19 11:07:21 -05:00
/*if (enable && !GetMap()->ContainsGameObjectModel(*m_model))
GetMap()->InsertGameObjectModel(*m_model);*/
2012-02-03 16:03:52 -05:00
m_model -> enable ( enable ? GetPhaseMask () : 0 );
}
void GameObject :: UpdateModel ()
{
if ( ! IsInWorld ())
return ;
if ( m_model )
2012-08-19 11:07:21 -05:00
if ( GetMap () -> ContainsGameObjectModel ( * m_model ))
GetMap () -> RemoveGameObjectModel ( * m_model );
2012-02-03 16:03:52 -05:00
delete m_model ;
m_model = GameObjectModel :: Create ( * this );
if ( m_model )
2012-08-19 11:07:21 -05:00
GetMap () -> InsertGameObjectModel ( * m_model );
2012-01-14 15:34:41 +01:00
}
2012-05-30 08:01:02 +02:00
Player * GameObject :: GetLootRecipient () const
{
if ( ! m_lootRecipient )
return NULL ;
return ObjectAccessor :: FindPlayer ( m_lootRecipient );
}
Group * GameObject :: GetLootRecipientGroup () const
{
if ( ! m_lootRecipientGroup )
return NULL ;
return sGroupMgr -> GetGroupByGUID ( m_lootRecipientGroup );
}
void GameObject :: SetLootRecipient ( Unit * unit )
{
// 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
if ( ! unit )
{
2014-09-14 16:14:12 +02:00
m_lootRecipient . Clear ();
2012-05-30 08:01:02 +02:00
m_lootRecipientGroup = 0 ;
return ;
}
if ( unit -> GetTypeId () != TYPEID_PLAYER && ! unit -> IsVehicle ())
return ;
Player * player = unit -> GetCharmerOrOwnerPlayerOrPlayerItself ();
if ( ! player ) // normal creature, no player involved
return ;
m_lootRecipient = player -> GetGUID ();
if ( Group * group = player -> GetGroup ())
m_lootRecipientGroup = group -> GetLowGUID ();
}
bool GameObject :: IsLootAllowedFor ( Player const * player ) const
{
if ( ! m_lootRecipient && ! m_lootRecipientGroup )
return true ;
if ( player -> GetGUID () == m_lootRecipient )
return true ;
Group const * playerGroup = player -> GetGroup ();
if ( ! playerGroup || playerGroup != GetLootRecipientGroup ()) // if we dont have a group we arent the recipient
return false ; // if go doesnt have group bound it means it was solo killed by someone else
return true ;
}
2013-06-15 15:16:36 +02:00
void GameObject :: BuildValuesUpdate ( uint8 updateType , ByteBuffer * data , Player * target ) const
{
if ( ! target )
return ;
2014-09-29 20:10:08 +02:00
bool isStoppableTransport = GetGoType () == GAMEOBJECT_TYPE_TRANSPORT && ! m_goValue . Transport . StopFrames -> empty ();
2013-06-15 15:16:36 +02:00
bool forcedFlags = GetGoType () == GAMEOBJECT_TYPE_CHEST && GetGOInfo () -> chest . groupLootRules && HasLootRecipient ();
bool targetIsGM = target -> IsGameMaster ();
ByteBuffer fieldBuffer ;
UpdateMask updateMask ;
updateMask . SetCount ( m_valuesCount );
uint32 * flags = GameObjectUpdateFieldFlags ;
uint32 visibleFlag = UF_FLAG_PUBLIC ;
if ( GetOwnerGUID () == target -> GetGUID ())
visibleFlag |= UF_FLAG_OWNER ;
for ( uint16 index = 0 ; index < m_valuesCount ; ++ index )
{
if ( _fieldNotifyFlags & flags [ index ] ||
(( updateType == UPDATETYPE_VALUES ? _changesMask . GetBit ( index ) : m_uint32Values [ index ]) && ( flags [ index ] & visibleFlag )) ||
( index == GAMEOBJECT_FLAGS && forcedFlags ))
{
updateMask . SetBit ( index );
if ( index == GAMEOBJECT_DYNAMIC )
{
uint16 dynFlags = 0 ;
2013-10-16 18:37:29 +02:00
int16 pathProgress = - 1 ;
2013-06-15 15:16:36 +02:00
switch ( GetGoType ())
{
2014-02-06 21:23:18 +01:00
case GAMEOBJECT_TYPE_QUESTGIVER :
if ( ActivateToQuest ( target ))
dynFlags |= GO_DYNFLAG_LO_ACTIVATE ;
break ;
2013-06-15 15:16:36 +02:00
case GAMEOBJECT_TYPE_CHEST :
case GAMEOBJECT_TYPE_GOOBER :
if ( ActivateToQuest ( target ))
dynFlags |= GO_DYNFLAG_LO_ACTIVATE | GO_DYNFLAG_LO_SPARKLE ;
else if ( targetIsGM )
dynFlags |= GO_DYNFLAG_LO_ACTIVATE ;
break ;
case GAMEOBJECT_TYPE_GENERIC :
if ( ActivateToQuest ( target ))
dynFlags |= GO_DYNFLAG_LO_SPARKLE ;
break ;
2014-09-29 20:10:08 +02:00
case GAMEOBJECT_TYPE_TRANSPORT :
{
float timer = float ( m_goValue . Transport . PathProgress % GetTransportPeriod ());
pathProgress = int16 ( timer / float ( GetTransportPeriod ()) * 65535.0f );
break ;
}
2014-10-06 18:37:38 -04:00
case GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT :
2014-09-29 20:10:08 +02:00
{
float timer = float ( m_goValue . Transport . PathProgress % GetUInt32Value ( GAMEOBJECT_LEVEL ));
pathProgress = int16 ( timer / float ( GetUInt32Value ( GAMEOBJECT_LEVEL )) * 65535.0f );
2013-06-18 16:51:13 +02:00
break ;
2014-09-29 20:10:08 +02:00
}
2013-06-18 16:51:13 +02:00
default :
break ;
2013-06-15 15:16:36 +02:00
}
fieldBuffer << uint16 ( dynFlags );
2013-10-16 18:37:29 +02:00
fieldBuffer << int16 ( pathProgress );
2013-06-15 15:16:36 +02:00
}
else if ( index == GAMEOBJECT_FLAGS )
{
uint32 flags = m_uint32Values [ GAMEOBJECT_FLAGS ];
if ( GetGoType () == GAMEOBJECT_TYPE_CHEST )
if ( GetGOInfo () -> chest . groupLootRules && ! IsLootAllowedFor ( target ))
flags |= GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE ;
fieldBuffer << flags ;
}
2014-09-29 20:10:08 +02:00
else if ( index == GAMEOBJECT_LEVEL )
{
if ( isStoppableTransport )
fieldBuffer << uint32 ( m_goValue . Transport . PathProgress );
else
fieldBuffer << m_uint32Values [ index ];
}
else if ( index == GAMEOBJECT_BYTES_1 )
{
uint32 bytes1 = m_uint32Values [ index ];
if ( isStoppableTransport && GetGoState () == GO_STATE_TRANSPORT_ACTIVE )
{
if (( m_goValue . Transport . StateUpdateTimer / 20000 ) & 1 )
{
bytes1 &= 0xFFFFFF00 ;
bytes1 |= GO_STATE_TRANSPORT_STOPPED ;
}
}
fieldBuffer << bytes1 ;
}
2013-06-15 15:16:36 +02:00
else
fieldBuffer << m_uint32Values [ index ]; // other cases
}
}
* data << uint8 ( updateMask . GetBlockCount ());
updateMask . AppendToPacket ( data );
data -> append ( fieldBuffer );
}
2013-10-16 18:37:29 +02:00
void GameObject :: GetRespawnPosition ( float & x , float & y , float & z , float * ori /* = NULL*/ ) const
{
if ( m_DBTableGuid )
{
if ( GameObjectData const * data = sObjectMgr -> GetGOData ( GetDBTableGUIDLow ()))
{
x = data -> posX ;
y = data -> posY ;
z = data -> posZ ;
if ( ori )
* ori = data -> orientation ;
return ;
}
}
x = GetPositionX ();
y = GetPositionY ();
z = GetPositionZ ();
if ( ori )
* ori = GetOrientation ();
}
2014-01-25 16:59:01 +01:00
2014-01-27 18:44:07 +01:00
float GameObject :: GetInteractionDistance () const
2014-01-25 16:59:01 +01:00
{
switch ( GetGoType ())
{
/// @todo find out how the client calculates the maximal usage distance to spellless working
// gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number
case GAMEOBJECT_TYPE_GUILD_BANK :
case GAMEOBJECT_TYPE_MAILBOX :
return 10.0f ;
case GAMEOBJECT_TYPE_FISHINGHOLE :
2014-01-26 22:46:10 +02:00
case GAMEOBJECT_TYPE_FISHINGNODE :
2014-01-25 16:59:01 +01:00
return 20.0f + CONTACT_DISTANCE ; // max spell range
default :
return INTERACTION_DISTANCE ;
}
}
2014-03-23 00:23:30 +01:00
void GameObject :: UpdateModelPosition ()
{
if ( ! m_model )
return ;
if ( GetMap () -> ContainsGameObjectModel ( * m_model ))
{
GetMap () -> RemoveGameObjectModel ( * m_model );
m_model -> Relocate ( * this );
GetMap () -> InsertGameObjectModel ( * m_model );
}
}