2010-10-07 15:35:36 +02:00
/*
2011-01-01 15:01:13 +01:00
* Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2008-10-11 14:16:25 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
#include "Common.h"
#include "QuestDef.h"
2010-10-24 22:03:53 +02:00
#include "GameObjectAI.h"
2008-10-11 14:16:25 -05:00
#include "ObjectMgr.h"
2011-05-05 10:23:00 +02:00
#include "GroupMgr.h"
2010-06-25 03:50:19 -06:00
#include "PoolMgr.h"
2008-10-11 14:16:25 -05:00
#include "SpellMgr.h"
#include "Spell.h"
2010-06-08 15:50:23 -06:00
#include "UpdateMask.h"
#include "Opcodes.h"
#include "WorldPacket.h"
2008-10-11 14:16:25 -05:00
#include "World.h"
2010-06-08 15:50:23 -06:00
#include "DatabaseEnv.h"
2008-10-11 14:16:25 -05:00
#include "LootMgr.h"
2010-06-08 15:50:23 -06:00
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
2010-08-08 22:54:58 +06:00
#include "InstanceScript.h"
2010-08-08 04:37:24 +02:00
#include "Battleground.h"
2010-06-08 15:50:23 -06:00
#include "Util.h"
2008-11-21 19:45:49 -06:00
#include "OutdoorPvPMgr.h"
2010-08-08 04:37:24 +02:00
#include "BattlegroundAV.h"
2010-06-03 15:02:30 +02:00
#include "ScriptMgr.h"
2010-10-23 23:31:37 +02:00
#include "CreatureAISelector.h"
2010-11-29 07:50:31 +01:00
#include "Group.h"
2009-10-17 15:51:44 -07:00
2010-10-23 23:31:37 +02:00
GameObject :: GameObject () : WorldObject (), m_goValue ( new GameObjectValue ), 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
2009-06-11 00:45:59 -05:00
m_updateFlag = ( UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_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 ;
2010-08-09 22:50:30 +06:00
m_ritualOwner = 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
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
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 ()
{
2010-01-16 14:49:09 +01:00
delete m_goValue ;
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 ()
{
m_AI = FactorySelector :: SelectGameObjectAI ( this );
if ( ! m_AI ) return false ;
m_AI -> InitializeAI ();
return true ;
}
std :: string GameObject :: GetAIName () const
{
2011-04-28 22:54:30 +02:00
return sObjectMgr -> GetGameObjectTemplate ( GetEntry ()) -> AIName ;
2010-10-23 23:31:37 +02:00
}
2010-04-19 09:26:37 +02:00
void GameObject :: CleanupsBeforeDelete ( bool /*finalCleanup*/ )
2009-07-01 18:23:36 -05:00
{
2010-02-14 19:13:14 -07:00
if ( IsInWorld ())
RemoveFromWorld ();
2010-04-07 19:14:10 +02:00
if ( m_uint32Values ) // field array can be not exist if GameOBject not loaded
2008-10-11 14:16:25 -05:00
{
2009-02-19 18:44:20 -06:00
// Possible crash at access to deleted GO in Unit::m_gameobj
2010-04-07 19:14:10 +02:00
if ( uint64 owner_guid = GetOwnerGUID ())
2008-10-11 14:16:25 -05:00
{
2011-04-29 20:47:02 +02:00
Unit * owner = ObjectAccessor :: GetUnit ( * this , owner_guid );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( owner )
2011-04-29 20:47:02 +02:00
owner -> RemoveGameObject ( this , false );
2009-06-16 11:19:59 -05:00
else
{
2009-07-12 17:52:27 +08:00
const char * ownerType = "creature" ;
2010-04-07 19:14:10 +02:00
if ( IS_PLAYER_GUID ( owner_guid ))
2009-06-16 11:19:59 -05:00
ownerType = "player" ;
2010-04-07 19:14:10 +02:00
else if ( IS_PET_GUID ( owner_guid ))
2009-06-16 11:19:59 -05:00
ownerType = "pet" ;
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Delete GameObject (GUID: %u Entry: %u SpellId %u LinkedGO %u) that lost references to owner (GUID %u Type '%s') GO list. Crash possible later." ,
2011-04-28 22:54:30 +02:00
GetGUIDLow (), GetGOInfo () -> entry , m_spellId , GetGOInfo () -> GetLinkedGameObjectEntry (), GUID_LOPART ( owner_guid ), ownerType );
2009-06-16 11:19:59 -05:00
}
2008-10-11 14:16:25 -05:00
}
2009-07-01 18:23:36 -05:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void 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 );
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
2009-03-31 09:18:39 -06:00
// Possible crash at access to deleted GO in Unit::m_gameobj
2010-04-07 19:14:10 +02:00
if ( uint64 owner_guid = GetOwnerGUID ())
2009-03-31 09:18:39 -06:00
{
2011-06-11 22:35:29 +02:00
if ( Unit * owner = GetOwner ())
2011-04-29 20:47:02 +02:00
owner -> RemoveGameObject ( this , false );
2010-07-28 00:08:21 +02:00
else
2011-08-19 21:09:12 +02:00
sLog -> outError ( "Delete GameObject (GUID: %u Entry: %u, Name: %s) that have references in not found creature %u GO list. Crash possible later." , GetGUIDLow (), GetGOInfo () -> entry , GetGOInfo () -> name . c_str (), GUID_LOPART ( owner_guid ));
2009-03-31 09:18:39 -06:00
}
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
2009-08-21 12:31:52 -05: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 );
2010-04-07 19:14:10 +02:00
if ( ! IsPositionValid ())
2008-10-11 14:16:25 -05:00
{
2011-04-29 20:47:02 +02:00
sLog -> outError ( "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
2011-04-29 20:47:02 +02:00
SetPhaseMask ( phaseMask , 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 )
{
2011-06-27 19:37:15 +02:00
sLog -> outErrorDb ( "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
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 )
{
2011-06-27 19:37:15 +02:00
sLog -> outErrorDb ( "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
2008-10-11 14:16:25 -05:00
SetFloatValue ( OBJECT_FIELD_SCALE_X , 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 );
2008-10-11 14:16:25 -05:00
SetUInt32Value ( GAMEOBJECT_DISPLAYID , goinfo -> displayId );
2009-10-17 15:51:44 -07:00
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
SetGoState ( go_state );
SetGoType ( GameobjectTypes ( goinfo -> type ));
2009-10-17 15:51:44 -07:00
2009-09-04 05:11:27 +02:00
SetGoArtKit ( 0 ); // unknown what this is
2009-08-21 12:31:52 -05:00
SetByteValue ( GAMEOBJECT_BYTES_1 , 2 , 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
{
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING :
2011-07-22 21:22:05 +02:00
m_goValue -> Building . Health = goinfo -> building . intactNumHits + goinfo -> building . damagedNumHits ;
m_goValue -> Building . MaxHealth = goinfo -> building . intactNumHits + goinfo -> building . damagedNumHits ;
2010-05-09 06:25:06 +02:00
SetGoAnimProgress ( 255 );
2009-05-29 00:18:41 -05:00
break ;
2009-11-27 01:41:26 +01:00
case GAMEOBJECT_TYPE_TRANSPORT :
SetUInt32Value ( GAMEOBJECT_LEVEL , goinfo -> transport . pause );
if ( goinfo -> transport . startOpen )
SetGoState ( GO_STATE_ACTIVE );
2010-05-10 12:48:35 +02:00
SetGoAnimProgress ( animprogress );
break ;
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 );
2010-11-13 17:18:09 +01:00
m_stealth . AddValue ( STEALTH_TRAP , 300 );
}
if ( GetGOInfo () -> trap . invisible )
{
2011-06-12 02:30:32 +02:00
m_invisibility . AddFlag ( INVISIBILITY_TRAP );
2010-11-13 17:18:09 +01:00
m_invisibility . AddValue ( INVISIBILITY_TRAP , 70 );
}
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
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
{
2011-06-12 02:30:32 +02:00
if ( ! AI ())
2010-10-25 18:11:52 +02:00
{
2010-10-23 23:31:37 +02:00
if ( ! AIM_Initialize ())
2010-12-23 23:25:44 +01:00
sLog -> outError ( "Could not initialize GameObjectAI" );
2010-10-25 18:11:52 +02:00
} else
AI () -> UpdateAI ( diff );
2010-10-23 23:31:37 +02:00
2008-10-11 14:16:25 -05:00
if ( IS_MO_TRANSPORT ( GetGUID ()))
{
//((Transport*)this)->Update(p_time);
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
switch ( m_lootState )
{
case GO_NOT_READY :
{
switch ( GetGoType ())
{
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 )
2010-02-14 19:13:14 -07:00
m_cooldownTime = time ( NULL ) + 10 ; // Hardcoded tooltip value
else if ( Unit * owner = GetOwner ())
{
if ( owner -> isInCombat ())
2011-05-02 12:30:05 -04:00
m_cooldownTime = time ( NULL ) + goInfo -> trap . cooldown ;
2010-02-14 19:13:14 -07:00
}
2008-10-11 14:16:25 -05:00
m_lootState = GO_READY ;
break ;
}
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
2008-10-11 14:16:25 -05:00
UpdateData udata ;
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 );
2010-03-07 15:20:19 +01:00
caster -> ToPlayer () -> GetSession () -> SendPacket ( & 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
{
2010-12-25 02:22:35 +01:00
uint64 dbtableHighGuid = MAKE_NEW_GUID ( m_DBTableGuid , GetEntry (), HIGHGUID_GAMEOBJECT );
time_t linkedRespawntime = sObjectMgr -> GetLinkedRespawnTime ( dbtableHighGuid , GetMap () -> GetInstanceId ());
2010-12-24 18:55:50 +01:00
if ( linkedRespawntime ) // Can't respawn, the master is dead
{
2010-12-25 02:22:35 +01:00
uint64 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
2011-04-29 20:47:02 +02:00
m_respawnTime = ( now > linkedRespawntime ? now : linkedRespawntime ) + urand ( 5 , MINUTE ); // else copy time from master and add a little
2010-12-24 18:55:50 +01:00
SaveRespawnTime (); // also save to DB immediately
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
{
2009-08-19 16:52:51 -05:00
caster -> FinishSpell ( CURRENT_CHANNELED_SPELL );
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
WorldPacket data ( SMSG_FISH_ESCAPED , 0 );
2010-03-07 15:20:19 +01:00
caster -> ToPlayer () -> GetSession () -> SendPacket ( & 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 :
//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 ();
2008-10-11 14:16:25 -05:00
//flags in AB are type_button and we need to add them here so no break!
default :
2009-04-27 18:36:10 -05:00
if ( ! m_spawnedByDefault ) // despawn timer
2008-10-11 14:16:25 -05:00
{
// can be despawned or destroyed
SetLootState ( GO_JUST_DEACTIVATED );
return ;
}
// respawn timer
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
GetMap () -> Add ( this );
2008-10-11 14:16:25 -05:00
break ;
}
}
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( isSpawned ())
2008-10-11 14:16:25 -05:00
{
2009-07-24 09:33:56 +08:00
// traps can have time and can not have
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 ))
2009-07-24 09:33:56 +08:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
// Type 2 - Bomb (will go away after casting it's spell)
2011-04-08 18:33:13 +02:00
if ( goInfo -> trap . type == 2 )
2010-02-14 19:13:14 -07:00
{
2010-04-07 19:14:10 +02:00
if ( goInfo -> trap . spellId )
2010-02-14 19:13:14 -07:00
CastSpell ( NULL , goInfo -> trap . spellId ); // FIXME: null target won't work for target type 1
SetLootState ( GO_JUST_DEACTIVATED );
break ;
}
2010-04-07 22:59:46 +02:00
// Type 0 and 1 - trap (type 0 will not get removed after casting a spell)
2009-07-24 09:33:56 +08:00
Unit * owner = GetOwner ();
Unit * ok = NULL ; // pointer to appropriate target if found any
2009-10-17 15:51:44 -07:00
2010-08-08 04:37:24 +02:00
bool IsBattlegroundTrap = false ;
2009-07-24 09:33:56 +08:00
//FIXME: this is activation radius (in different casting radius that must be selected from spell data)
//TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state
2010-08-22 12:39:39 -07:00
float radius = ( float )( goInfo -> trap . radius ) / 2 ; // TODO rename radius to diameter (goInfo->trap.radius) should be (goInfo->trap.diameter)
2010-04-07 19:14:10 +02:00
if ( ! radius )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( goInfo -> trap . cooldown != 3 ) // cast in other case (at some triggering/linked go/etc explicit call)
2009-07-24 09:33:56 +08:00
return ;
else
{
2010-04-07 19:14:10 +02:00
if ( m_respawnTime > 0 )
2009-07-24 09:33:56 +08:00
break ;
2009-10-17 15:51:44 -07:00
2010-08-22 12:39:39 -07:00
radius = ( float ) goInfo -> trap . cooldown ; // battlegrounds gameobjects has data2 == 0 && data5 == 3
2010-08-08 04:37:24 +02:00
IsBattlegroundTrap = true ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! radius )
2009-07-24 09:33:56 +08:00
return ;
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-07-24 09:33:56 +08:00
// Note: this hack with search required until GO casting not implemented
// search unfriendly creature
2010-04-07 19:14:10 +02:00
if ( owner ) // hunter trap
2009-07-24 09:33:56 +08:00
{
Trinity :: AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker ( this , owner , radius );
Trinity :: UnitSearcher < Trinity :: AnyUnfriendlyNoTotemUnitInObjectRangeCheck > searcher ( this , ok , checker );
VisitNearbyGridObject ( radius , searcher );
2010-04-07 19:14:10 +02:00
if ( ! ok ) VisitNearbyWorldObject ( radius , searcher );
2009-07-24 09:33:56 +08:00
}
else // environmental trap
{
// environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support
// affect only players
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 );
ok = player ;
}
2009-10-17 15:51:44 -07:00
2009-07-24 09:33:56 +08:00
if ( ok )
{
// some traps do not have spell but should be triggered
2010-04-07 19:14:10 +02:00
if ( goInfo -> trap . spellId )
2009-07-24 09:33:56 +08:00
CastSpell ( ok , goInfo -> trap . spellId );
2009-10-17 15:51:44 -07:00
2011-05-02 13:36:17 -04:00
m_cooldownTime = time ( NULL ) + ( goInfo -> trap . cooldown ? goInfo -> trap . cooldown : uint32 ( 4 )); // template or 4 seconds
2009-10-17 15:51:44 -07:00
2011-04-08 18:33:13 +02:00
if ( goInfo -> trap . type == 1 )
2009-07-24 09:33:56 +08:00
SetLootState ( GO_JUST_DEACTIVATED );
2009-10-17 15:51:44 -07:00
2010-08-08 04:37:24 +02:00
if ( IsBattlegroundTrap && ok -> GetTypeId () == TYPEID_PLAYER )
2009-07-24 09:33:56 +08:00
{
2010-08-08 04:37:24 +02:00
//Battleground gameobjects case
if ( ok -> ToPlayer () -> InBattleground ())
if ( Battleground * bg = ok -> ToPlayer () -> GetBattleground ())
2009-07-24 09:33:56 +08:00
bg -> HandleTriggerBuff ( GetGUID ());
}
}
}
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 :
{
switch ( GetGoType ())
{
case GAMEOBJECT_TYPE_DOOR :
case GAMEOBJECT_TYPE_BUTTON :
2009-12-24 10:20:15 +01:00
if ( GetGOInfo () -> GetAutoCloseTime () && ( 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 ;
}
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
{
2009-04-29 00:26:07 -05:00
std :: set < uint32 >:: const_iterator it = m_unique_users . begin ();
std :: set < uint32 >:: const_iterator end = m_unique_users . end ();
2009-11-03 22:28:04 -08:00
for (; it != end ; ++ it )
2008-10-11 14:16:25 -05:00
{
2010-01-16 19:31:10 +03:00
if ( Unit * owner = Unit :: GetUnit ( * this , uint64 ( * it )))
owner -> CastSpell ( owner , spellId , false );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
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 ();
2010-04-07 19:14:10 +02:00
if ( GetOwnerGUID ())
2008-10-11 14:16:25 -05:00
{
2010-07-28 00:08:21 +02:00
if ( Unit * owner = GetOwner ())
2009-07-12 13:38:38 +02:00
{
2009-06-06 20:24:50 -05:00
owner -> RemoveGameObject ( this , false );
2009-07-12 13:38:38 +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 ()
{
// not refresh despawned not casted GO (despawned casted GO destroyed in all cases anyway)
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 ())
2008-12-24 09:58:26 -06:00
GetMap () -> Add ( 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 ();
m_unique_users . insert ( player -> GetGUIDLow ());
}
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 );
if ( GetOwnerGUID ())
2011-06-11 22:35:29 +02:00
if ( Unit * owner = GetOwner ())
2009-08-03 14:52:30 +02:00
owner -> RemoveGameObject ( this , false );
2009-10-17 15:51:44 -07:00
2010-07-30 20:04:28 +02:00
ASSERT ( ! GetOwnerGUID ());
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
2009-02-08 21:45:31 -06: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 ;
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
2009-12-16 18:58:36 +02:00
if ( ! fishloot -> FillLoot ( subzone , LootTemplates_Fishing , loot_owner , true , true ))
// else use zone loot (must exist in like case)
2011-04-29 20:47:02 +02:00
fishloot -> FillLoot ( zone , LootTemplates_Fishing , loot_owner , true );
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
2010-12-22 21:25:23 +01: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
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "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-04-28 22:54:30 +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
2011-07-29 14:18:28 +02:00
// update in DB
2008-10-11 14:16:25 -05:00
std :: ostringstream ss ;
2010-04-07 22:59:46 +02:00
ss << "INSERT INTO gameobject VALUES ("
2011-07-29 14:18:28 +02:00
<< m_DBTableGuid << ','
<< GetEntry () << ','
<< mapid << ','
<< uint32 ( spawnMask ) << ',' // cast to prevent save as symbol
<< uint16 ( GetPhaseMask ()) << ',' // prevent out of range error
<< GetPositionX () << ','
<< GetPositionY () << ','
<< GetPositionZ () << ','
<< GetOrientation () << ','
<< GetFloatValue ( GAMEOBJECT_PARENTROTATION ) << ','
<< GetFloatValue ( GAMEOBJECT_PARENTROTATION + 1 ) << ','
<< GetFloatValue ( GAMEOBJECT_PARENTROTATION + 2 ) << ','
<< GetFloatValue ( GAMEOBJECT_PARENTROTATION + 3 ) << ','
<< m_respawnDelayTime << ','
<< uint32 ( GetGoAnimProgress ()) << ','
<< uint32 ( GetGoState ()) << ')' ;
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02:00
SQLTransaction trans = WorldDatabase . BeginTransaction ();
trans -> PAppend ( "DELETE FROM gameobject WHERE guid = '%u'" , m_DBTableGuid );
trans -> Append ( ss . str (). c_str ());
WorldDatabase . CommitTransaction ( trans );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
bool GameObject :: LoadFromDB ( uint32 guid , Map * map )
{
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
{
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "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
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 ;
2010-12-22 21:25:23 +01:00
m_respawnTime = sObjectMgr -> GetGORespawnTime ( m_DBTableGuid , map -> GetInstanceId ());
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 ;
2010-12-23 05:49:23 +01:00
sObjectMgr -> RemoveGORespawnTime ( m_DBTableGuid , GetInstanceId ());
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
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 ()
{
2010-12-23 05:49:23 +01:00
sObjectMgr -> RemoveGORespawnTime ( m_DBTableGuid , GetInstanceId ());
2010-12-22 21:25:23 +01:00
sObjectMgr -> DeleteGOData ( m_DBTableGuid );
2010-08-18 02:25:52 +02:00
WorldDatabase . PExecute ( "DELETE FROM gameobject WHERE guid = '%u'" , m_DBTableGuid );
WorldDatabase . PExecute ( "DELETE FROM game_event_gameobject WHERE guid = '%u'" , m_DBTableGuid );
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 :: GetGameObject ( WorldObject & object , uint64 guid )
{
2009-04-20 20:28:19 -05:00
return object . GetMap () -> GetGameObject ( guid );
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 ();
2010-04-07 19:14:10 +02:00
if ( ! gInfo ) return false ;
2008-10-11 14:16:25 -05:00
return gInfo -> type == GAMEOBJECT_TYPE_TRANSPORT || gInfo -> type == GAMEOBJECT_TYPE_MO_TRANSPORT ;
}
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 ();
2010-04-07 19:14:10 +02:00
if ( ! gInfo ) return false ;
2009-11-27 01:41:26 +01:00
return gInfo -> type == GAMEOBJECT_TYPE_MO_TRANSPORT || ( gInfo -> type == GAMEOBJECT_TYPE_TRANSPORT && ! gInfo -> transport . pause );
}
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 )
2011-04-29 20:47:02 +02:00
sObjectMgr -> SaveGORespawnTime ( m_DBTableGuid , GetInstanceId (), m_respawnTime );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-11-13 17:18:09 +01:00
bool GameObject :: isAlwaysVisibleFor ( WorldObject const * seer ) const
2008-10-11 14:16:25 -05:00
{
2010-11-13 17:18:09 +01:00
if ( WorldObject :: isAlwaysVisibleFor ( seer ))
2008-10-11 14:16:25 -05:00
return true ;
2009-10-17 15:51:44 -07:00
2011-06-28 13:05:15 +02:00
if ( IsTransport ())
2010-11-13 17:18:09 +01:00
return true ;
2010-12-13 22:37:56 +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
2010-11-13 17:18:09 +01:00
bool GameObject :: isVisibleForInState ( WorldObject const * seer ) const
2009-02-04 19:43:00 +01:00
{
2010-11-13 17:18:09 +01:00
if ( ! WorldObject :: isVisibleForInState ( seer ))
2009-02-04 19:43:00 +01:00
return false ;
2009-10-17 15:51:44 -07:00
2010-11-13 17:18:09 +01:00
// Despawned
if ( ! isSpawned ())
return false ;
2009-10-17 15:51:44 -07:00
2010-11-13 17:18:09 +01:00
return true ;
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 );
2010-12-23 05:49:23 +01:00
sObjectMgr -> RemoveGORespawnTime ( m_DBTableGuid , GetInstanceId ());
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2009-11-21 17:59:24 -08:00
bool GameObject :: ActivateToQuest ( Player * pTarget ) const
2008-10-11 14:16:25 -05:00
{
2010-10-06 16:46:18 -06:00
if ( pTarget -> HasQuestForGO ( GetEntry ()))
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
{
// scan GO chest with loot including quest items
case GAMEOBJECT_TYPE_CHEST :
{
2009-11-21 17:59:24 -08:00
if ( LootTemplates_Gameobject . HaveQuestLootForPlayer ( GetGOInfo () -> GetLootId (), pTarget ))
2008-11-21 19:45:49 -06:00
{
//TODO: fix this hack
//look for battlegroundAV for some objects which are only activated after mine gots captured by own team
2009-11-21 17:59:24 -08:00
if ( GetEntry () == BG_AV_OBJECTID_MINE_N || GetEntry () == BG_AV_OBJECTID_MINE_S )
2010-08-08 04:37:24 +02:00
if ( Battleground * bg = pTarget -> GetBattleground ())
2011-04-29 20:47:02 +02:00
if ( bg -> GetTypeID ( true ) == BATTLEGROUND_AV && ! ((( BattlegroundAV * ) bg ) -> PlayerCanDoMineQuest ( GetEntry (), pTarget -> GetTeam ())))
2008-11-21 19:45:49 -06:00
return false ;
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 :
{
2010-10-25 11:25:42 +02:00
if ( GetGOInfo () -> _generic . questID == - 1 || pTarget -> 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 :
{
2010-10-25 11:25:42 +02:00
if ( GetGOInfo () -> goober . questId == - 1 || pTarget -> 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
2008-10-14 11:57:03 -05:00
CellPair p ( Trinity :: ComputeCellPair ( GetPositionX (), GetPositionY ()));
2008-10-11 14:16:25 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
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-04-29 20:47:02 +02:00
CellPair p ( Trinity :: ComputeCellPair ( GetPositionX (), GetPositionY ()));
2008-10-11 14:16:25 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
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
2009-04-27 18:36:10 -05:00
void GameObject :: UseDoorOrButton ( uint32 time_to_restore , bool alternative /* = false */ )
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 );
2008-10-11 14:16:25 -05:00
SetLootState ( GO_ACTIVATED );
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
m_cooldownTime = time ( NULL ) + time_to_restore ;
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 );
2010-12-22 21:25:23 +01: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
2009-08-21 12:31:52 -05:00
void GameObject :: SetGoArtKit ( uint8 artkit , GameObject * go , uint32 lowguid )
{
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 ;
AI () -> GossipHello ( playerUser );
}
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
UseDoorOrButton ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// activate script
2009-07-31 10:48:34 +08:00
GetMap () -> ScriptsStart ( sGameObjectScripts , GetDBTableGUIDLow (), spellCaster , this );
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
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
2009-12-20 13:35:08 +02:00
player -> PrepareGossipMenu ( this , GetGOInfo () -> questgiver . gossipID );
player -> SendPreparedGossip ( this );
2008-10-11 14:16:25 -05:00
return ;
}
//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 )
ChairListSlots [ i ] = 0 ; // Last user of current slot set to 0 (none sit here yet)
2009-10-28 15:59:45 -07:00
else
2009-11-03 22:28:04 -08:00
ChairListSlots [ 0 ] = 0 ; // 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
float orthogonalOrientation = GetOrientation () + M_PI * 0.5f ;
// 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
2009-10-28 15:59:45 -07:00
float x_i = GetPositionX () + relativeDistance * cos ( orthogonalOrientation );
float y_i = GetPositionY () + relativeDistance * 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 ))
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
itr -> second = 0 ; // This seat is unoccupied.
else
itr -> second = 0 ; // 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
2009-10-28 15:59:45 -07:00
/* debug code. It will spawn a npc on each slot to visualize them.
Creature* helper = player->SummonCreature(14496, x_i, y_i, GetPositionZ(), GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 10000);
std::ostringstream output;
output << i << ": thisDist: " << thisDistance;
helper->MonsterSay(output.str().c_str(), LANG_UNIVERSAL, 0);
*/
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
//else
//player->GetSession()->SendNotification("There's nowhere left for you to sit.");
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
2010-04-07 19:14:10 +02:00
if ( user -> GetTypeId () == TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
{
2011-02-22 01:46:19 +06:00
Player * player = user -> ToPlayer ();
2009-10-17 15:51:44 -07: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 ();
player -> GetSession () -> SendPacket ( & data );
}
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
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_MAPSCRIPTS , "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 );
2010-04-11 23:49:00 +02:00
EventInform ( info -> goober . eventId );
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 ;
}
2010-08-08 04:37:24 +02:00
if ( Battleground * bg = player -> GetBattleground ())
2010-04-11 23:49:00 +02:00
bg -> EventPlayerUsedGO ( player , this );
2010-02-14 19:13:14 -07:00
2011-04-28 22:54:30 +02:00
player -> CastedCreatureOrGO ( info -> entry , GetGUID (), 0 );
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 );
SetLootState ( GO_ACTIVATED );
uint32 time_to_restore = info -> GetAutoCloseTime ();
// this appear to be ok, however others exist in addition to this that should have custom (ex: 190510, 188692, 187389)
if ( time_to_restore && 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 );
m_cooldownTime = time ( NULL ) + time_to_restore ;
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 )
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "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
2011-04-29 20:47:02 +02:00
sLog -> outStaticDebug ( "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
2010-04-04 00:30:11 +02:00
// prevent removing GO at spell cancel
2011-04-29 20:47:02 +02:00
player -> RemoveGameObject ( this , false );
2010-04-04 00:30:11 +02:00
SetOwnerGUID ( player -> GetGUID ());
//TODO: find reasonable value for fishing hole search
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
}
2010-04-04 00:30:11 +02:00
// TODO: else: 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 );
player -> GetSession () -> SendPacket ( & data );
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
2008-10-11 14:16:25 -05:00
case GAMEOBJECT_TYPE_SUMMONING_RITUAL : //18
{
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
2010-08-09 22:50:30 +06:00
// ritual owner is set for GO's without owner (not summoned)
if ( ! m_ritualOwner && ! owner )
m_ritualOwner = player ;
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 )
{
spellCaster = m_ritualOwner ? m_ritualOwner : spellCaster ;
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
// it triggered spell in fact casted at currently channeled GO
spellId = 61993 ;
triggered = true ;
}
// 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
m_ritualOwner = NULL ;
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
2008-10-11 14:16:25 -05:00
Player * targetPlayer = ObjectAccessor :: FindPlayer ( player -> GetSelection ());
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
2010-08-08 04:37:24 +02:00
if ( player -> CanUseBattlegroundObject ())
2008-10-11 14:16:25 -05:00
{
// in battleground check
2010-08-08 04:37:24 +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 ;
2010-04-30 00:24:25 +02:00
if ( player -> GetVehicle ())
return ;
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
2010-08-08 04:37:24 +02:00
if ( player -> CanUseBattlegroundObject ())
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 ;
2011-06-12 02:30:32 +02:00
if ( player -> GetVehicle ())
2010-04-30 00:24:25 +02:00
return ;
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-04-28 22:54:30 +02:00
switch ( info -> entry )
2008-10-11 14:16:25 -05:00
{
case 179785 : // Silverwing Flag
// check if it's correct bg
2010-12-16 18:08:23 +01:00
if ( bg -> IsRandom () ? bg -> GetTypeID ( true ) : bg -> GetTypeID ( false ) == BATTLEGROUND_WS )
2008-10-11 14:16:25 -05:00
bg -> EventPlayerClickedOnFlag ( player , this );
break ;
case 179786 : // Warsong Flag
2010-12-16 18:08:23 +01:00
if ( bg -> IsRandom () ? bg -> GetTypeID ( true ) : bg -> GetTypeID ( false ) == BATTLEGROUND_WS )
2008-10-11 14:16:25 -05:00
bg -> EventPlayerClickedOnFlag ( player , this );
break ;
case 184142 : // Netherstorm Flag
2010-12-16 18:08:23 +01:00
if ( bg -> IsRandom () ? bg -> GetTypeID ( true ) : bg -> GetTypeID ( false ) == 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 );
2008-12-24 09:58:26 -06:00
player -> GetSession () -> SendPacket ( & 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 )
sLog -> outError ( "GameObject::Use(): unit (type: %u, guid: %u, name: %s) tries to use object (guid: %u, entry: %u, name: %s) of unknown type (%u)" ,
user -> GetTypeId (), user -> GetGUIDLow (), user -> GetName (), 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 ))
2011-04-29 20:47:02 +02:00
sLog -> outError ( "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
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_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
2009-03-14 21:30:03 -06:00
void GameObject :: CastSpell ( Unit * target , uint32 spellId )
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 )
2009-05-06 00:06:38 -05:00
target -> CastSpell ( target , spellInfo , true );
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
trigger -> SetUInt64Value ( UNIT_FIELD_SUMMONEDBY , owner -> GetGUID ());
2010-02-14 19:13:14 -07:00
trigger -> CastSpell ( target ? target : trigger , spellInfo , true , 0 , 0 , owner -> GetGUID ());
2008-11-02 08:44:15 -06:00
}
else
{
trigger -> setFaction ( 14 );
2009-10-17 16:20:24 -07:00
// Set owner guid for target if no owner avalible - needed by trigger auras
2009-06-13 14:01:10 +02:00
// - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell())
2010-02-14 19:13:14 -07:00
trigger -> CastSpell ( target ? target : trigger , spellInfo , true , 0 , 0 , target ? target -> GetGUID () : 0 );
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-06-11 22:35:29 +02:00
GameObjectDisplayInfoEntry const * info = sGameObjectDisplayInfoStore . LookupEntry ( GetUInt32Value ( GAMEOBJECT_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
2009-05-21 10:01:03 -05:00
float sinA = sin ( GetOrientation ());
float cosA = cos ( GetOrientation ());
float dx = x - GetPositionX ();
float dy = y - GetPositionY ();
float dz = z - GetPositionZ ();
float dist = sqrt ( dx * dx + dy * dy );
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
2009-06-01 12:48:12 -05:00
void GameObject :: EventInform ( uint32 eventId )
{
2010-04-07 19:14:10 +02:00
if ( eventId && m_zoneScript )
2009-06-01 12:48:12 -05:00
m_zoneScript -> ProcessEvent ( this , eventId );
}
2009-10-17 15:51:44 -07:00
2008-11-14 17:03:03 -06:00
// overwrite WorldObject function for proper name localization
2010-09-17 07:04:29 +02:00
const char * 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 );
2010-12-22 21:25:23 +01: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 ())
return cl -> Name [ uloc_idx ]. c_str ();
}
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
2009-03-18 20:46:21 -06:00
double f_rot1 = sin ( GetOrientation () / 2.0f );
2009-03-19 15:16:02 -06:00
double f_rot2 = 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
2009-06-11 00:45:59 -05:00
//float f_rot2 = sin(0.0f / 2.0f);
//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
2009-06-11 00:45:59 -05:00
//float f_rot3 = sin(0.0f / 2.0f);
//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*/ )
{
if ( ! GetGOValue () -> Building . MaxHealth || ! change )
return ;
2011-07-24 23:55:14 +02:00
// prevent double destructions of the same object
if ( change < 0 && ! GetGOValue () -> Building . Health )
return ;
2011-07-22 21:22:05 +02:00
if ( int32 ( GetGOValue () -> Building . Health ) + change <= 0 )
GetGOValue () -> Building . Health = 0 ;
else if ( int32 ( GetGOValue () -> Building . Health ) + change >= int32 ( GetGOValue () -> Building . MaxHealth ))
GetGOValue () -> Building . Health = GetGOValue () -> Building . MaxHealth ;
else
GetGOValue () -> Building . Health += change ;
2011-07-24 23:55:14 +02:00
// Set the health bar, value = 255 * healthPct;
2011-07-22 21:22:05 +02:00
SetGoAnimProgress ( GetGOValue () -> Building . Health * 255 / GetGOValue () -> Building . MaxHealth );
Player * player = attackerOrHealer -> GetCharmerOrOwnerPlayerOrPlayerItself ();
// dealing damage, send packet
// TODO: is there any packet for healing?
if ( change < 0 && player )
{
WorldPacket data ( SMSG_DESTRUCTIBLE_BUILDING_DAMAGE , 8 + 8 + 8 + 4 + 4 );
data . appendPackGUID ( GetGUID ());
data . appendPackGUID ( attackerOrHealer -> GetGUID ());
data . appendPackGUID ( player -> GetGUID ());
data << uint32 ( - change );
data << uint32 ( spellId );
player -> GetSession () -> SendPacket ( & data );
}
2011-07-24 23:55:14 +02:00
GameObjectDestructibleState newState = GetDestructibleState ();
2011-07-22 21:22:05 +02:00
if ( ! GetGOValue () -> Building . Health )
2011-07-24 23:55:14 +02:00
newState = GO_DESTRUCTIBLE_DESTROYED ;
2011-07-22 21:22:05 +02:00
else if ( GetGOValue () -> Building . Health <= GetGOInfo () -> building . damagedNumHits )
2011-07-24 23:55:14 +02:00
newState = GO_DESTRUCTIBLE_DAMAGED ;
2011-07-22 21:42:17 +02:00
else if ( GetGOValue () -> Building . Health == GetGOValue () -> Building . MaxHealth )
2011-07-24 23:55:14 +02:00
newState = GO_DESTRUCTIBLE_INTACT ;
if ( newState == GetDestructibleState ())
return ;
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 );
SetUInt32Value ( GAMEOBJECT_DISPLAYID , m_goInfo -> displayId );
if ( setHealth )
{
m_goValue -> Building . Health = m_goValue -> Building . MaxHealth ;
SetGoAnimProgress ( 255 );
}
break ;
case GO_DESTRUCTIBLE_DAMAGED :
{
EventInform ( m_goInfo -> building . damagedEvent );
2011-09-07 15:11:12 +02:00
sScriptMgr -> OnGameObjectDamaged ( this , eventInvoker );
2011-07-22 21:22:05 +02:00
if ( eventInvoker )
if ( Battleground * bg = eventInvoker -> GetBattleground ())
bg -> EventPlayerDamagedGO ( eventInvoker , this , m_goInfo -> building . damagedEvent );
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 ;
SetUInt32Value ( GAMEOBJECT_DISPLAYID , modelId );
if ( setHealth )
{
m_goValue -> Building . Health = m_goInfo -> building . damagedNumHits ;
uint32 maxHealth = m_goValue -> Building . MaxHealth ;
// in this case current health is 0 anyway so just prevent crashing here
if ( ! maxHealth )
maxHealth = 1 ;
SetGoAnimProgress ( m_goValue -> Building . Health * 255 / maxHealth );
}
break ;
}
case GO_DESTRUCTIBLE_DESTROYED :
{
2011-09-07 15:11:12 +02:00
sScriptMgr -> OnGameObjectDestroyed ( this , eventInvoker );
2011-07-22 21:22:05 +02:00
EventInform ( m_goInfo -> building . destroyedEvent );
if ( eventInvoker )
{
if ( Battleground * bg = eventInvoker -> GetBattleground ())
{
bg -> EventPlayerDamagedGO ( eventInvoker , this , m_goInfo -> building . destroyedEvent );
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 ;
SetUInt32Value ( GAMEOBJECT_DISPLAYID , modelId );
if ( setHealth )
{
m_goValue -> Building . Health = 0 ;
SetGoAnimProgress ( 0 );
}
break ;
}
case GO_DESTRUCTIBLE_REBUILDING :
2011-07-24 23:55:14 +02:00
{
2011-07-22 21:22:05 +02:00
EventInform ( m_goInfo -> building . rebuildingEvent );
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 ;
SetUInt32Value ( GAMEOBJECT_DISPLAYID , modelId );
2011-07-22 21:22:05 +02:00
// restores to full health
if ( setHealth )
{
m_goValue -> Building . Health = m_goValue -> Building . MaxHealth ;
SetGoAnimProgress ( 255 );
}
break ;
2011-07-24 23:55:14 +02:00
}
2011-07-22 21:22:05 +02:00
}
}