/*
* Copyright (C) 2008-2011 TrinityCore
* Copyright (C) 2005-2009 MaNGOS
*
* 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 .
*/
#include "Common.h"
#include "SharedDefines.h"
#include "WorldPacket.h"
#include "Opcodes.h"
#include "Log.h"
#include "World.h"
#include "Object.h"
#include "Creature.h"
#include "Player.h"
#include "Vehicle.h"
#include "ObjectMgr.h"
#include "UpdateData.h"
#include "UpdateMask.h"
#include "Util.h"
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Log.h"
#include "Transport.h"
#include "TargetedMovementGenerator.h"
#include "WaypointMovementGenerator.h"
#include "VMapFactory.h"
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "SpellAuraEffects.h"
#include "TemporarySummon.h"
#include "Totem.h"
#include "OutdoorPvPMgr.h"
uint32 GuidHigh2TypeId(uint32 guid_hi)
{
switch(guid_hi)
{
case HIGHGUID_ITEM: return TYPEID_ITEM;
//case HIGHGUID_CONTAINER: return TYPEID_CONTAINER; HIGHGUID_CONTAINER == HIGHGUID_ITEM currently
case HIGHGUID_UNIT: return TYPEID_UNIT;
case HIGHGUID_PET: return TYPEID_UNIT;
case HIGHGUID_PLAYER: return TYPEID_PLAYER;
case HIGHGUID_GAMEOBJECT: return TYPEID_GAMEOBJECT;
case HIGHGUID_DYNAMICOBJECT:return TYPEID_DYNAMICOBJECT;
case HIGHGUID_CORPSE: return TYPEID_CORPSE;
case HIGHGUID_MO_TRANSPORT: return TYPEID_GAMEOBJECT;
case HIGHGUID_VEHICLE: return TYPEID_UNIT;
}
return NUM_CLIENT_OBJECT_TYPES; // unknown
}
Object::Object() : m_PackGUID(sizeof(uint64)+1)
{
m_objectTypeId = TYPEID_OBJECT;
m_objectType = TYPEMASK_OBJECT;
m_uint32Values = 0;
m_uint32Values_mirror = 0;
m_valuesCount = 0;
m_inWorld = false;
m_objectUpdated = false;
m_PackGUID.appendPackGUID(0);
}
WorldObject::~WorldObject()
{
// this may happen because there are many !create/delete
if (m_isWorldObject && m_currMap)
{
if (GetTypeId() == TYPEID_CORPSE)
{
sLog->outCrash("Object::~Object Corpse guid="UI64FMTD", type=%d, entry=%u deleted but still in map!!", GetGUID(), ((Corpse*)this)->GetType(), GetEntry());
ASSERT(false);
}
ResetMap();
}
}
Object::~Object()
{
if (IsInWorld())
{
sLog->outCrash("Object::~Object - guid="UI64FMTD", typeid=%d, entry=%u deleted but still in world!!", GetGUID(), GetTypeId(), GetEntry());
if (isType(TYPEMASK_ITEM))
sLog->outCrash("Item slot %u", ((Item*)this)->GetSlot());
ASSERT(false);
RemoveFromWorld();
}
if (m_objectUpdated)
{
sLog->outCrash("Object::~Object - guid="UI64FMTD", typeid=%d, entry=%u deleted but still in update list!!", GetGUID(), GetTypeId(), GetEntry());
ASSERT(false);
sObjectAccessor->RemoveUpdateObject(this);
}
delete [] m_uint32Values;
delete [] m_uint32Values_mirror;
}
void Object::_InitValues()
{
m_uint32Values = new uint32[ m_valuesCount ];
memset(m_uint32Values, 0, m_valuesCount*sizeof(uint32));
m_uint32Values_mirror = new uint32[ m_valuesCount ];
memset(m_uint32Values_mirror, 0, m_valuesCount*sizeof(uint32));
m_objectUpdated = false;
}
void Object::_Create(uint32 guidlow, uint32 entry, HighGuid guidhigh)
{
if (!m_uint32Values) _InitValues();
uint64 guid = MAKE_NEW_GUID(guidlow, entry, guidhigh);
SetUInt64Value(OBJECT_FIELD_GUID, guid);
uint32 type = 0;
switch(m_objectType)
{
//case TYPEID_ITEM: type = 3; break;
//case TYPEID_CONTAINER: type = 7; break; //+4
//case TYPEID_UNIT: type = 9; break; //+2
//case TYPEID_PLAYER: type = 25; break; //+16
//case TYPEID_GAMEOBJECT: type = 33; break; //+8
case TYPEID_DYNAMICOBJECT: type = 65; break; //+32
//case TYPEID_CORPSE: type = 129; break; //+64
default: type = m_objectType; break;
}
SetUInt32Value(OBJECT_FIELD_TYPE, type);
//SetUInt32Value(OBJECT_FIELD_TYPE, m_objectType);
m_PackGUID.wpos(0);
m_PackGUID.appendPackGUID(GetGUID());
}
std::string Object::_ConcatFields(uint16 startIndex, uint16 size) const
{
std::ostringstream ss;
for (uint16 index = 0; index < size; ++index)
ss << GetUInt32Value(index + startIndex) << " ";
return ss.str();
}
void Object::BuildMovementUpdateBlock(UpdateData * data, uint32 flags) const
{
ByteBuffer buf(500);
buf << uint8(UPDATETYPE_MOVEMENT);
buf.append(GetPackGUID());
_BuildMovementUpdate(&buf, flags);
data->AddUpdateBlock(buf);
}
void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const
{
if (!target)
return;
uint8 updatetype = UPDATETYPE_CREATE_OBJECT;
uint16 flags = m_updateFlag;
/** lower flag1 **/
if (target == this) // building packet for yourself
flags |= UPDATEFLAG_SELF;
if (flags & UPDATEFLAG_HAS_POSITION)
{
// UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
if (isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER))
updatetype = UPDATETYPE_CREATE_OBJECT2;
// UPDATETYPE_CREATE_OBJECT2 for pets...
if (target->GetPetGUID() == GetGUID())
updatetype = UPDATETYPE_CREATE_OBJECT2;
// UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
if (isType(TYPEMASK_GAMEOBJECT))
{
switch(((GameObject*)this)->GetGoType())
{
case GAMEOBJECT_TYPE_TRAP:
case GAMEOBJECT_TYPE_DUEL_ARBITER:
case GAMEOBJECT_TYPE_FLAGSTAND:
case GAMEOBJECT_TYPE_FLAGDROP:
updatetype = UPDATETYPE_CREATE_OBJECT2;
break;
case GAMEOBJECT_TYPE_TRANSPORT:
flags |= UPDATEFLAG_TRANSPORT;
break;
default:
break;
}
}
if (isType(TYPEMASK_UNIT))
{
if (((Unit*)this)->getVictim())
flags |= UPDATEFLAG_HAS_TARGET;
}
}
//sLog->outDebug("BuildCreateUpdate: update-type: %u, object-type: %u got flags: %X, flags2: %X", updatetype, m_objectTypeId, flags, flags2);
ByteBuffer buf(500);
buf << (uint8)updatetype;
buf.append(GetPackGUID());
buf << (uint8)m_objectTypeId;
_BuildMovementUpdate(&buf, flags);
UpdateMask updateMask;
updateMask.SetCount(m_valuesCount);
_SetCreateBits(&updateMask, target);
_BuildValuesUpdate(updatetype, &buf, &updateMask, target);
data->AddUpdateBlock(buf);
}
void Object::SendUpdateToPlayer(Player* player)
{
// send create update to player
UpdateData upd;
WorldPacket packet;
BuildCreateUpdateBlockForPlayer(&upd, player);
upd.BuildPacket(&packet);
player->GetSession()->SendPacket(&packet);
}
void Object::BuildValuesUpdateBlockForPlayer(UpdateData *data, Player *target) const
{
ByteBuffer buf(500);
buf << (uint8) UPDATETYPE_VALUES;
buf.append(GetPackGUID());
UpdateMask updateMask;
updateMask.SetCount(m_valuesCount);
_SetUpdateBits(&updateMask, target);
_BuildValuesUpdate(UPDATETYPE_VALUES, &buf, &updateMask, target);
data->AddUpdateBlock(buf);
}
void Object::BuildOutOfRangeUpdateBlock(UpdateData * data) const
{
data->AddOutOfRangeGUID(GetGUID());
}
void Object::DestroyForPlayer(Player *target, bool anim) const
{
ASSERT(target);
WorldPacket data(SMSG_DESTROY_OBJECT, 8 + 1);
data << uint64(GetGUID());
data << uint8(anim ? 1 : 0); // WotLK (bool), may be despawn animation
target->GetSession()->SendPacket(&data);
}
void Object::_BuildMovementUpdate(ByteBuffer * data, uint16 flags) const
{
*data << (uint16)flags; // update flags
// 0x20
if (flags & UPDATEFLAG_LIVING)
{
((Unit*)this)->BuildMovementPacket(data);
*data << ((Unit*)this)->GetSpeed(MOVE_WALK);
*data << ((Unit*)this)->GetSpeed(MOVE_RUN);
*data << ((Unit*)this)->GetSpeed(MOVE_SWIM_BACK);
*data << ((Unit*)this)->GetSpeed(MOVE_SWIM);
*data << ((Unit*)this)->GetSpeed(MOVE_RUN_BACK);
*data << ((Unit*)this)->GetSpeed(MOVE_FLIGHT);
*data << ((Unit*)this)->GetSpeed(MOVE_FLIGHT_BACK);
*data << ((Unit*)this)->GetSpeed(MOVE_TURN_RATE);
*data << ((Unit*)this)->GetSpeed(MOVE_PITCH_RATE);
// 0x08000000
if (GetTypeId() == TYPEID_PLAYER && this->ToPlayer()->isInFlight())
{
//WPAssert(this->ToPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
Player *player = const_cast