aboutsummaryrefslogtreecommitdiff
path: root/src/game/Object.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Object.cpp')
-rw-r--r--src/game/Object.cpp1118
1 files changed, 792 insertions, 326 deletions
diff --git a/src/game/Object.cpp b/src/game/Object.cpp
index 04f6646bea1..f94ee52efdb 100644
--- a/src/game/Object.cpp
+++ b/src/game/Object.cpp
@@ -27,8 +27,8 @@
#include "Object.h"
#include "Creature.h"
#include "Player.h"
+#include "Vehicle.h"
#include "ObjectMgr.h"
-#include "WorldSession.h"
#include "UpdateData.h"
#include "UpdateMask.h"
#include "Util.h"
@@ -44,6 +44,8 @@
#include "GridNotifiersImpl.h"
#include "TemporarySummon.h"
+#include "Totem.h"
+#include "OutdoorPvPMgr.h"
uint32 GuidHigh2TypeId(uint32 guid_hi)
{
@@ -58,11 +60,12 @@ uint32 GuidHigh2TypeId(uint32 guid_hi)
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 10; // unknown
+ return NUM_CLIENT_OBJECT_TYPES; // unknown
}
-Object::Object( )
+Object::Object( ) : m_PackGUID(sizeof(uint64)+1)
{
m_objectTypeId = TYPEID_OBJECT;
m_objectType = TYPEMASK_OBJECT;
@@ -74,7 +77,6 @@ Object::Object( )
m_inWorld = false;
m_objectUpdated = false;
- m_PackGUID.clear();
m_PackGUID.appendPackGUID(0);
}
@@ -83,17 +85,16 @@ Object::~Object( )
//if(m_objectUpdated)
// ObjectAccessor::Instance().RemoveUpdateObject(this);
- if(m_uint32Values)
+ if(IsInWorld())
{
- if(IsInWorld())
- {
- ///- Do NOT call RemoveFromWorld here, if the object is a player it will crash
- sLog.outError("Object::~Object - guid="I64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId());
- assert(false);
- }
+ sLog.outCrash("Object::~Object - guid="UI64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId());
+ assert(false);
+ }
- assert(!m_objectUpdated);
+ assert(!m_objectUpdated);
+ if(m_uint32Values)
+ {
//DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
delete [] m_uint32Values;
delete [] m_uint32Values_mirror;
@@ -118,21 +119,21 @@ void Object::_Create( uint32 guidlow, uint32 entry, HighGuid guidhigh )
{
if(!m_uint32Values) _InitValues();
- uint64 guid = MAKE_NEW_GUID(guidlow, entry, guidhigh); // required more changes to make it working
+ uint64 guid = MAKE_NEW_GUID(guidlow, entry, guidhigh);
SetUInt64Value( OBJECT_FIELD_GUID, guid );
SetUInt32Value( OBJECT_FIELD_TYPE, m_objectType );
- m_PackGUID.clear();
+ m_PackGUID.wpos(0);
m_PackGUID.appendPackGUID(GetGUID());
}
void Object::BuildMovementUpdateBlock(UpdateData * data, uint32 flags ) const
{
- ByteBuffer buf(500);
+ ByteBuffer buf(50);
buf << uint8( UPDATETYPE_MOVEMENT );
- buf << GetGUID();
+ buf.append(GetPackGUID());
- _BuildMovementUpdate(&buf, flags, 0x00000000);
+ _BuildMovementUpdate(&buf, flags);
data->AddUpdateBlock(buf);
}
@@ -140,19 +141,16 @@ void Object::BuildMovementUpdateBlock(UpdateData * data, uint32 flags ) const
void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const
{
if(!target)
- {
return;
- }
uint8 updatetype = UPDATETYPE_CREATE_OBJECT;
uint8 flags = m_updateFlag;
- uint32 flags2 = 0;
/** lower flag1 **/
- if(target == this) // building packet for oneself
+ if(target == this) // building packet for yourself
flags |= UPDATEFLAG_SELF;
- if(flags & UPDATEFLAG_HASPOSITION)
+ if(flags & UPDATEFLAG_HAS_POSITION)
{
// UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
if(isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER))
@@ -176,24 +174,31 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) c
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);
+ ByteBuffer buf(50);
buf << (uint8)updatetype;
- //buf.append(GetPackGUID()); //client crashes when using this
- buf << (uint8)0xFF << GetGUID();
+ buf.append(GetPackGUID());
buf << (uint8)m_objectTypeId;
- _BuildMovementUpdate(&buf, flags, flags2);
+ _BuildMovementUpdate(&buf, flags);
UpdateMask updateMask;
updateMask.SetCount( m_valuesCount );
_SetCreateBits( &updateMask, target );
- _BuildValuesUpdate(updatetype, &buf, &updateMask, target );
+ _BuildValuesUpdate(updatetype, &buf, &updateMask, target);
data->AddUpdateBlock(buf);
}
@@ -215,24 +220,20 @@ void Object::SendUpdateToPlayer(Player* player)
BuildCreateUpdateBlockForPlayer(&upd, player);
upd.BuildPacket(&packet);
player->GetSession()->SendPacket(&packet);
-
- // now object updated/(create updated)
}
void Object::BuildValuesUpdateBlockForPlayer(UpdateData *data, Player *target) const
{
- ByteBuffer buf(500);
+ ByteBuffer buf(50);
buf << (uint8) UPDATETYPE_VALUES;
- //buf.append(GetPackGUID()); //client crashes when using this. but not have crash in debug mode
- buf << (uint8)0xFF;
- buf << GetGUID();
+ buf.append(GetPackGUID());
UpdateMask updateMask;
updateMask.SetCount( m_valuesCount );
_SetUpdateBits( &updateMask, target );
- _BuildValuesUpdate(UPDATETYPE_VALUES, &buf, &updateMask, target );
+ _BuildValuesUpdate(UPDATETYPE_VALUES, &buf, &updateMask, target);
data->AddUpdateBlock(buf);
}
@@ -247,35 +248,30 @@ void Object::DestroyForPlayer(Player *target) const
ASSERT(target);
WorldPacket data(SMSG_DESTROY_OBJECT, 8);
- data << GetGUID();
+ data << uint64(GetGUID());
+ data << uint8(0); // WotLK (bool)
target->GetSession()->SendPacket( &data );
}
-void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2 ) const
+void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags) const
{
*data << (uint8)flags; // update flags
// 0x20
if (flags & UPDATEFLAG_LIVING)
{
+ uint32 flags2 = ((Unit*)this)->GetUnitMovementFlags();
switch(GetTypeId())
{
case TYPEID_UNIT:
{
- flags2 = ((Unit*)this)->GetUnitMovementFlags();
- flags2 &= ~MOVEMENTFLAG_ONTRANSPORT;
flags2 &= ~MOVEMENTFLAG_SPLINE2;
+ if(((Creature*)this)->isVehicle())
+ ((Unit*)this)->m_movementInfo.unk1 |= 0x20; // always allow pitch
}
break;
case TYPEID_PLAYER:
{
- flags2 = ((Player*)this)->GetUnitMovementFlags();
-
- if(((Player*)this)->GetTransport())
- flags2 |= MOVEMENTFLAG_ONTRANSPORT;
- else
- flags2 &= ~MOVEMENTFLAG_ONTRANSPORT;
-
// remove unknown, unused etc flags for now
flags2 &= ~MOVEMENTFLAG_SPLINE2; // will be set manually
@@ -289,12 +285,12 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
}
*data << uint32(flags2); // movement flags
- *data << uint8(0); // unk 2.3.0
+ *data << uint16(((Unit*)this)->m_movementInfo.unk1);// unknown 2.3.0
*data << uint32(getMSTime()); // time (in milliseconds)
}
// 0x40
- if (flags & UPDATEFLAG_HASPOSITION)
+ if (flags & UPDATEFLAG_HAS_POSITION)
{
// 0x02
if(flags & UPDATEFLAG_TRANSPORT && ((GameObject*)this)->GetGoType() == GAMEOBJECT_TYPE_MO_TRANSPORT)
@@ -316,62 +312,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
// 0x20
if(flags & UPDATEFLAG_LIVING)
{
- // 0x00000200
- if(flags2 & MOVEMENTFLAG_ONTRANSPORT)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- {
- *data << (uint64)((Player*)this)->GetTransport()->GetGUID();
- *data << (float)((Player*)this)->GetTransOffsetX();
- *data << (float)((Player*)this)->GetTransOffsetY();
- *data << (float)((Player*)this)->GetTransOffsetZ();
- *data << (float)((Player*)this)->GetTransOffsetO();
- *data << (uint32)((Player*)this)->GetTransTime();
- }
- //TrinIty currently not have support for other than player on transport
- }
-
- // 0x02200000
- if(flags2 & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2))
- {
- if(GetTypeId() == TYPEID_PLAYER)
- *data << (float)((Player*)this)->m_movementInfo.s_pitch;
- else
- *data << (float)0; // is't part of movement packet, we must store and send it...
- }
-
- if(GetTypeId() == TYPEID_PLAYER)
- *data << (uint32)((Player*)this)->m_movementInfo.fallTime;
- else
- *data << (uint32)0; // last fall time
-
- // 0x00001000
- if(flags2 & MOVEMENTFLAG_JUMPING)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- {
- *data << (float)((Player*)this)->m_movementInfo.j_unk;
- *data << (float)((Player*)this)->m_movementInfo.j_sinAngle;
- *data << (float)((Player*)this)->m_movementInfo.j_cosAngle;
- *data << (float)((Player*)this)->m_movementInfo.j_xyspeed;
- }
- else
- {
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- }
- }
-
- // 0x04000000
- if(flags2 & MOVEMENTFLAG_SPLINE)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- *data << (float)((Player*)this)->m_movementInfo.u_unk1;
- else
- *data << (float)0;
- }
+ ((Unit*)this)->BuildMovementPacket(data);
*data << ((Unit*)this)->GetSpeed( MOVE_WALK );
*data << ((Unit*)this)->GetSpeed( MOVE_RUN );
@@ -381,22 +322,11 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
*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(flags2 & MOVEMENTFLAG_SPLINE2)
+ if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isInFlight())
{
- if(GetTypeId() != TYPEID_PLAYER)
- {
- sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 for non-player");
- return;
- }
-
- if(!((Player*)this)->isInFlight())
- {
- sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 but not in flight");
- return;
- }
-
WPAssert(((Player*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
FlightPathMovementGenerator *fmg = (FlightPathMovementGenerator*)(((Player*)this)->GetMotionMaster()->top());
@@ -445,6 +375,8 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
*data << path.GetNodes()[i].z;
}
+ *data << uint8(0); // added in 3.0.8
+
/*for(uint32 i = 0; i < poscount; i++)
{
// path points
@@ -482,7 +414,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
break;
case TYPEID_PLAYER:
if(flags & UPDATEFLAG_SELF)
- *data << uint32(0x00000015); // unk, can be 0x15 or 0x22
+ *data << uint32(0x0000002F); // unk, can be 0x15 or 0x22
else
*data << uint32(0x00000008); // unk, can be 0x7 or 0x8
break;
@@ -505,6 +437,15 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
case TYPEID_CORPSE:
*data << uint32(GetGUIDHigh()); // GetGUIDHigh()
break;
+ case TYPEID_UNIT:
+ *data << uint32(0x0000000B); // unk, can be 0xB or 0xC
+ break;
+ case TYPEID_PLAYER:
+ if(flags & UPDATEFLAG_SELF)
+ *data << uint32(0x0000002F); // unk, can be 0x15 or 0x22
+ else
+ *data << uint32(0x00000008); // unk, can be 0x7 or 0x8
+ break;
default:
*data << uint32(0x00000000); // unk
break;
@@ -512,9 +453,12 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
}
// 0x4
- if(flags & UPDATEFLAG_FULLGUID)
+ if(flags & UPDATEFLAG_HAS_TARGET) // packed guid (current target guid)
{
- *data << uint8(0); // packed guid (probably target guid)
+ if(Unit *victim = ((Unit*)this)->getVictim())
+ data->append(victim->GetPackGUID());
+ else
+ *data << uint8(0);
}
// 0x2
@@ -522,6 +466,13 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2
{
*data << uint32(getMSTime()); // ms time
}
+
+ // 0x80
+ if(flags & UPDATEFLAG_VEHICLE) // unused for now
+ {
+ *data << uint32(((Vehicle*)this)->GetVehicleInfo()->m_ID); // vehicle id
+ *data << float(0); // facing adjustment
+ }
}
void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask *updateMask, Player *target) const
@@ -537,13 +488,13 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
if ( ((GameObject*)this)->ActivateToQuest(target) || target->isGameMaster())
{
IsActivateToQuest = true;
- updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
+ updateMask->SetBit(GAMEOBJECT_DYNAMIC);
}
- if (GetUInt32Value(GAMEOBJECT_ARTKIT))
- updateMask->SetBit(GAMEOBJECT_ARTKIT);
+ if (((GameObject*)this)->GetGoArtKit())
+ updateMask->SetBit(GAMEOBJECT_BYTES_1);
}
}
- else //case UPDATETYPE_VALUES
+ else // case UPDATETYPE_VALUES
{
if (isType(TYPEMASK_GAMEOBJECT) && !((GameObject*)this)->IsTransport())
{
@@ -551,8 +502,8 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
{
IsActivateToQuest = true;
}
- updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
- updateMask->SetBit(GAMEOBJECT_ANIMPROGRESS);
+ updateMask->SetBit(GAMEOBJECT_DYNAMIC);
+ updateMask->SetBit(GAMEOBJECT_BYTES_1);
}
}
@@ -568,9 +519,16 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
{
if( updateMask->GetBit( index ) )
{
- // remove custom flag before send
if( index == UNIT_NPC_FLAGS )
- *data << uint32(m_uint32Values[ index ] & ~(UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP));
+ {
+ // remove custom flag before sending
+ uint32 appendValue = m_uint32Values[ index ] & ~(UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP);
+
+ if (GetTypeId() == TYPEID_UNIT && !target->canSeeSpellClickOn((Creature*)this))
+ appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
+
+ *data << uint32(appendValue);
+ }
// FIXME: Some values at server stored in float format but must be sent to client in uint32 format
else if(index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
{
@@ -578,83 +536,93 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
*data << uint32(m_floatValues[ index ] < 0 ? 0 : m_floatValues[ index ]);
}
// there are some float values which may be negative or can't get negative due to other checks
- else if(index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4 ||
- index >= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 6) ||
- index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6) ||
- index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4)
+ else if ((index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4) ||
+ (index >= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 6)) ||
+ (index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6)) ||
+ (index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4))
{
*data << uint32(m_floatValues[ index ]);
}
// Gamemasters should be always able to select units - remove not selectable flag
- else if(index == UNIT_FIELD_FLAGS && target->isGameMaster())
+ else if(index == UNIT_FIELD_FLAGS)
{
- *data << (m_uint32Values[ index ] & ~UNIT_FLAG_NOT_SELECTABLE);
+ if(target->isGameMaster())
+ *data << (m_uint32Values[ index ] & ~UNIT_FLAG_NOT_SELECTABLE);
+ else
+ *data << m_uint32Values[ index ];
}
// use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures
- else if(index == UNIT_FIELD_DISPLAYID && GetTypeId() == TYPEID_UNIT)
+ else if(index == UNIT_FIELD_DISPLAYID)
{
- const CreatureInfo* cinfo = ((Creature*)this)->GetCreatureInfo();
- if(cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
+ if(GetTypeId() == TYPEID_UNIT)
{
- if(target->isGameMaster())
+ const CreatureInfo* cinfo = ((Creature*)this)->GetCreatureInfo();
+ if(cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
{
- if(cinfo->Modelid_A2)
- *data << cinfo->Modelid_A1;
+ if(target->isGameMaster())
+ {
+ if(cinfo->Modelid_A1)
+ *data << cinfo->Modelid_A1;
+ else
+ *data << 17519; // world invisible trigger's model
+ }
else
- *data << 17519; // world invisible trigger's model
+ {
+ if(cinfo->Modelid_A2)
+ *data << cinfo->Modelid_A2;
+ else
+ *data << 11686; // world invisible trigger's model
+ }
}
else
- {
- if(cinfo->Modelid_A2)
- *data << cinfo->Modelid_A2;
- else
- *data << 11686; // world invisible trigger's model
- }
+ *data << m_uint32Values[ index ];
}
else
*data << m_uint32Values[ index ];
}
// hide lootable animation for unallowed players
- else if(index == UNIT_DYNAMIC_FLAGS && GetTypeId() == TYPEID_UNIT)
+ else if(index == UNIT_DYNAMIC_FLAGS)
{
- if(!target->isAllowedToLoot((Creature*)this))
- *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_LOOTABLE);
+ if(GetTypeId() == TYPEID_UNIT)
+ {
+ if(!target->isAllowedToLoot((Creature*)this))
+ *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_LOOTABLE);
+ else
+ *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_OTHER_TAGGER);
+ }
else
- *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_OTHER_TAGGER);
+ *data << m_uint32Values[ index ];
}
// FG: pretend that OTHER players in own group are friendly ("blue")
else if(index == UNIT_FIELD_BYTES_2 || index == UNIT_FIELD_FACTIONTEMPLATE)
{
- bool ch = false;
- if(target->GetTypeId() == TYPEID_PLAYER && GetTypeId() == TYPEID_PLAYER && target != this)
- {
- if(target->IsInSameGroupWith((Player*)this) || target->IsInSameRaidWith((Player*)this))
+ if(((Unit*)this)->IsControlledByPlayer() && target != this && sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && ((Unit*)this)->IsInRaidWith(target))
{
- if(index == UNIT_FIELD_BYTES_2)
+ FactionTemplateEntry const *ft1, *ft2;
+ ft1 = ((Unit*)this)->getFactionTemplateEntry();
+ ft2 = target->getFactionTemplateEntry();
+ if(ft1 && ft2 && !ft1->IsFriendlyTo(*ft2))
{
- DEBUG_LOG("-- VALUES_UPDATE: Sending '%s' the blue-group-fix from '%s' (flag)", target->GetName(), ((Player*)this)->GetName());
- *data << ( m_uint32Values[ index ] & ((UNIT_BYTE2_FLAG_SANCTUARY | UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5) << 8) ); // this flag is at uint8 offset 1 !!
-
- ch = true;
- }
- else if(index == UNIT_FIELD_FACTIONTEMPLATE)
- {
- FactionTemplateEntry const *ft1, *ft2;
- ft1 = ((Player*)this)->getFactionTemplateEntry();
- ft2 = ((Player*)target)->getFactionTemplateEntry();
- if(ft1 && ft2 && !ft1->IsFriendlyTo(*ft2))
+ if(index == UNIT_FIELD_BYTES_2)
{
- uint32 faction = ((Player*)target)->getFaction(); // pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
+ // Allow targetting opposite faction in party when enabled in config
+ DEBUG_LOG("-- VALUES_UPDATE: Sending '%s' the blue-group-fix from '%s' (flag)", target->GetName(), ((Player*)this)->GetName());
+ *data << ( m_uint32Values[ index ] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8) ); // this flag is at uint8 offset 1 !!
+ }
+ else
+ {
+ // pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
+ uint32 faction = target->getFaction();
DEBUG_LOG("-- VALUES_UPDATE: Sending '%s' the blue-group-fix from '%s' (faction %u)", target->GetName(), ((Player*)this)->GetName(), faction);
*data << uint32(faction);
- ch = true;
}
}
+ else
+ *data << m_uint32Values[ index ];
}
- }
- if(!ch)
+ else
*data << m_uint32Values[ index ];
- }
+ }
else
{
// send in current format (float as float, uint32 as uint32)
@@ -670,7 +638,7 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
if( updateMask->GetBit( index ) )
{
// send in current format (float as float, uint32 as uint32)
- if ( index == GAMEOBJECT_DYN_FLAGS )
+ if (index == GAMEOBJECT_DYNAMIC )
{
if(IsActivateToQuest )
{
@@ -683,7 +651,7 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
*data << uint32(1);
break;
default:
- *data << uint32(0); // unknown. not happen.
+ *data << uint32(0); // unknown, not happen.
break;
}
}
@@ -710,11 +678,10 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask
void Object::ClearUpdateMask(bool remove)
{
- for( uint16 index = 0; index < m_valuesCount; index ++ )
- {
- if(m_uint32Values_mirror[index]!= m_uint32Values[index])
- m_uint32Values_mirror[index] = m_uint32Values[index];
- }
+ uint32 *temp = m_uint32Values;
+
+ memcpy(m_uint32Values_mirror, m_uint32Values, m_valuesCount*sizeof(uint32));
+
if(m_objectUpdated)
{
if(remove)
@@ -758,18 +725,23 @@ bool Object::LoadValues(const char* data)
void Object::_SetUpdateBits(UpdateMask *updateMask, Player* /*target*/) const
{
- for( uint16 index = 0; index < m_valuesCount; index ++ )
+ uint32 *value = m_uint32Values;
+ uint32 *mirror = m_uint32Values_mirror;
+
+ for(uint16 index = 0; index < m_valuesCount; ++index, ++value, ++mirror)
{
- if(m_uint32Values_mirror[index]!= m_uint32Values[index])
+ if(*mirror != *value)
updateMask->SetBit(index);
}
}
void Object::_SetCreateBits(UpdateMask *updateMask, Player* /*target*/) const
{
- for( uint16 index = 0; index < m_valuesCount; index++ )
+ uint32 *value = m_uint32Values;
+
+ for(uint16 index = 0; index < m_valuesCount; ++index, ++value)
{
- if(GetUInt32Value(index) != 0)
+ if(*value)
updateMask->SetBit(index);
}
}
@@ -831,6 +803,48 @@ void Object::SetUInt64Value( uint16 index, const uint64 &value )
}
}
+bool Object::AddUInt64Value(uint16 index, const uint64 &value)
+{
+ ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
+ if(value && !*((uint64*)&(m_uint32Values[index])))
+ {
+ m_uint32Values[ index ] = *((uint32*)&value);
+ m_uint32Values[ index + 1 ] = *(((uint32*)&value) + 1);
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Object::RemoveUInt64Value(uint16 index, const uint64 &value)
+{
+ ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
+ if(value && *((uint64*)&(m_uint32Values[index])) == value)
+ {
+ m_uint32Values[ index ] = 0;
+ m_uint32Values[ index + 1 ] = 0;
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
void Object::SetFloatValue( uint16 index, float value )
{
ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
@@ -924,21 +938,21 @@ void Object::ApplyModUInt32Value(uint16 index, int32 val, bool apply)
cur += (apply ? val : -val);
if(cur < 0)
cur = 0;
- SetUInt32Value(index,cur);
+ SetUInt32Value(index, cur);
}
void Object::ApplyModInt32Value(uint16 index, int32 val, bool apply)
{
int32 cur = GetInt32Value(index);
cur += (apply ? val : -val);
- SetInt32Value(index,cur);
+ SetInt32Value(index, cur);
}
void Object::ApplyModSignedFloatValue(uint16 index, float val, bool apply)
{
float cur = GetFloatValue(index);
cur += (apply ? val : -val);
- SetFloatValue(index,cur);
+ SetFloatValue(index, cur);
}
void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply)
@@ -947,7 +961,7 @@ void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply)
cur += (apply ? val : -val);
if(cur < 0)
cur = 0;
- SetFloatValue(index,cur);
+ SetFloatValue(index, cur);
}
void Object::SetFlag( uint16 index, uint32 newFlag )
@@ -1051,30 +1065,20 @@ bool Object::PrintIndexError(uint32 index, bool set) const
}
WorldObject::WorldObject()
+ : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL),
+ m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f)
+ , m_map(NULL), m_zoneScript(NULL)
+ , m_isActive(false), IsTempWorldObject(false)
+ , m_name("")
{
- m_positionX = 0.0f;
- m_positionY = 0.0f;
- m_positionZ = 0.0f;
- m_orientation = 0.0f;
-
- m_mapId = 0;
- m_InstanceId = 0;
- m_map = NULL;
-
- m_name = "";
-
- mSemaphoreTeleport = false;
-
- m_isActive = false;
- IsTempWorldObject = false;
}
void WorldObject::SetWorldObject(bool on)
{
if(!IsInWorld())
return;
-
- GetMap()->AddObjectToSwitchList(this, on);
+
+ GetMap()->AddObjectToSwitchList(this, on);
}
void WorldObject::setActive( bool on )
@@ -1110,21 +1114,27 @@ void WorldObject::setActive( bool on )
}
}
-void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid )
+void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid, uint32 phaseMask )
{
Object::_Create(guidlow, 0, guidhigh);
m_mapId = mapid;
+ m_phaseMask = phaseMask;
}
uint32 WorldObject::GetZoneId() const
{
- return MapManager::Instance().GetBaseMap(m_mapId)->GetZoneId(m_positionX,m_positionY);
+ return MapManager::Instance().GetBaseMap(m_mapId)->GetZoneId(m_positionX, m_positionY, m_positionZ);
}
uint32 WorldObject::GetAreaId() const
{
- return MapManager::Instance().GetBaseMap(m_mapId)->GetAreaId(m_positionX,m_positionY);
+ return MapManager::Instance().GetBaseMap(m_mapId)->GetAreaId(m_positionX, m_positionY, m_positionZ);
+}
+
+void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const
+{
+ MapManager::Instance().GetBaseMap(m_mapId)->GetZoneAndAreaId(zoneid, areaid, m_positionX, m_positionY, m_positionZ);
}
InstanceData* WorldObject::GetInstanceData()
@@ -1132,7 +1142,6 @@ InstanceData* WorldObject::GetInstanceData()
Map *map = GetMap();
return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL;
}
-
//slow
float WorldObject::GetDistance(const WorldObject* obj) const
{
@@ -1160,7 +1169,7 @@ float WorldObject::GetExactDistance2d(const float x, const float y) const
return sqrt((dx*dx) + (dy*dy));
}
-float WorldObject::GetDistance(const float x, const float y, const float z) const
+float WorldObject::GetDistance(float x, float y, float z) const
{
float dx = GetPositionX() - x;
float dy = GetPositionY() - y;
@@ -1178,6 +1187,14 @@ float WorldObject::GetDistanceSq(const float &x, const float &y, const float &z)
return dx*dx + dy*dy + dz*dz;
}
+float WorldObject::GetDistanceSq(const WorldObject *obj) const
+{
+ float dx = GetPositionX() - obj->GetPositionX();
+ float dy = GetPositionY() - obj->GetPositionY();
+ float dz = GetPositionZ() - obj->GetPositionZ();
+ return dx*dx + dy*dy + dz*dz;
+}
+
float WorldObject::GetDistance2d(const WorldObject* obj) const
{
float dx = GetPositionX() - obj->GetPositionX();
@@ -1195,10 +1212,33 @@ float WorldObject::GetDistanceZ(const WorldObject* obj) const
return ( dist > 0 ? dist : 0);
}
-bool WorldObject::IsWithinDistInMap(const WorldObject* obj, const float dist2compare, const bool is3D) const
+bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist2compare) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float dz = GetPositionZ() - z;
+ float distsq = dx*dx + dy*dy + dz*dz;
+
+ float sizefactor = GetObjectSize();
+ float maxdist = dist2compare + sizefactor;
+
+ return distsq < maxdist * maxdist;
+}
+
+bool WorldObject::IsWithinDist2d(float x, float y, float dist2compare) const
{
- if (!obj || !IsInMap(obj)) return false;
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float distsq = dx*dx + dy*dy;
+
+ float sizefactor = GetObjectSize();
+ float maxdist = dist2compare + sizefactor;
+
+ return distsq < maxdist * maxdist;
+}
+bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const
+{
float dx = GetPositionX() - obj->GetPositionX();
float dy = GetPositionY() - obj->GetPositionY();
float distsq = dx*dx + dy*dy;
@@ -1221,7 +1261,7 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
return(IsWithinLOS(ox, oy, oz ));
}
-bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) const
+bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
{
float x,y,z;
GetPosition(x,y,z);
@@ -1229,6 +1269,95 @@ bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) c
return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);
}
+bool WorldObject::GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D /* = true */) const
+{
+ float dx1 = GetPositionX() - obj1->GetPositionX();
+ float dy1 = GetPositionY() - obj1->GetPositionY();
+ float distsq1 = dx1*dx1 + dy1*dy1;
+ if(is3D)
+ {
+ float dz1 = GetPositionZ() - obj1->GetPositionZ();
+ distsq1 += dz1*dz1;
+ }
+
+ float dx2 = GetPositionX() - obj2->GetPositionX();
+ float dy2 = GetPositionY() - obj2->GetPositionY();
+ float distsq2 = dx2*dx2 + dy2*dy2;
+ if(is3D)
+ {
+ float dz2 = GetPositionZ() - obj2->GetPositionZ();
+ distsq2 += dz2*dz2;
+ }
+
+ return distsq1 < distsq2;
+}
+
+bool WorldObject::IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D /* = true */) const
+{
+ float dx = GetPositionX() - obj->GetPositionX();
+ float dy = GetPositionY() - obj->GetPositionY();
+ float distsq = dx*dx + dy*dy;
+ if(is3D)
+ {
+ float dz = GetPositionZ() - obj->GetPositionZ();
+ distsq += dz*dz;
+ }
+
+ float sizefactor = GetObjectSize() + obj->GetObjectSize();
+
+ // check only for real range
+ if(minRange > 0.0f)
+ {
+ float mindist = minRange + sizefactor;
+ if(distsq < mindist * mindist)
+ return false;
+ }
+
+ float maxdist = maxRange + sizefactor;
+ return distsq < maxdist * maxdist;
+}
+
+bool WorldObject::IsInRange2d(float x, float y, float minRange, float maxRange) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float distsq = dx*dx + dy*dy;
+
+ float sizefactor = GetObjectSize();
+
+ // check only for real range
+ if(minRange > 0.0f)
+ {
+ float mindist = minRange + sizefactor;
+ if(distsq < mindist * mindist)
+ return false;
+ }
+
+ float maxdist = maxRange + sizefactor;
+ return distsq < maxdist * maxdist;
+}
+
+bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float maxRange) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float dz = GetPositionZ() - z;
+ float distsq = dx*dx + dy*dy + dz*dz;
+
+ float sizefactor = GetObjectSize();
+
+ // check only for real range
+ if(minRange > 0.0f)
+ {
+ float mindist = minRange + sizefactor;
+ if(distsq < mindist * mindist)
+ return false;
+ }
+
+ float maxdist = maxRange + sizefactor;
+ return distsq < maxdist * maxdist;
+}
+
float WorldObject::GetAngle(const WorldObject* obj) const
{
if(!obj) return 0;
@@ -1246,6 +1375,25 @@ float WorldObject::GetAngle( const float x, const float y ) const
return ang;
}
+void WorldObject::GetSinCos(const float x, const float y, float &vsin, float &vcos)
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+
+ if(dx < 0.001f && dy < 0.001f)
+ {
+ float angle = rand_norm()*2*M_PI;
+ vcos = cos(angle);
+ vsin = sin(angle);
+ }
+ else
+ {
+ float dist = sqrt((dx*dx) + (dy*dy));
+ vcos = dx / dist;
+ vsin = dy / dist;
+ }
+}
+
bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
{
// always have self in arc
@@ -1263,6 +1411,15 @@ bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
float angle = GetAngle( obj );
angle -= m_orientation;
+ //if(angle > 100 || angle < -100)
+ //{
+ // sLog.outCrash("Invalid Angle %f: this %u %u %f %f %f %f, that %u %u %f %f %f %f", angle,
+ // GetEntry(), GetGUIDLow(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(),
+ // obj->GetEntry(), obj->GetGUIDLow(), obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation());
+ // assert(false);
+ // return false;
+ //}
+
// move angle to range -pi ... +pi
while( angle > M_PI)
angle -= 2.0f * M_PI;
@@ -1274,6 +1431,21 @@ bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
return (( angle >= lborder ) && ( angle <= rborder ));
}
+bool WorldObject::IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size) const
+{
+ if(GetPositionX() > std::max(obj1->GetPositionX(), obj2->GetPositionX())
+ || GetPositionX() < std::min(obj1->GetPositionX(), obj2->GetPositionX())
+ || GetPositionY() > std::max(obj1->GetPositionY(), obj2->GetPositionY())
+ || GetPositionY() < std::min(obj1->GetPositionY(), obj2->GetPositionY()))
+ return false;
+
+ if(!size)
+ size = GetObjectSize() / 2;
+
+ float angle = obj1->GetAngle(this) - obj1->GetAngle(obj2);
+ return abs(sin(angle)) * GetExactDistance2d(obj1->GetPositionX(), obj1->GetPositionY()) < size;
+}
+
void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const
{
if(distance==0)
@@ -1285,8 +1457,8 @@ void WorldObject::GetRandomPoint( float x, float y, float z, float distance, flo
}
// angle to face `obj` to `this`
- float angle = GetMap()->rand_norm()*2*M_PI;
- float new_dist = GetMap()->rand_norm()*distance;
+ float angle = rand_norm()*2*M_PI;
+ float new_dist = rand_norm()*distance;
rand_x = x + new_dist * cos(angle);
rand_y = y + new_dist * sin(angle);
@@ -1367,50 +1539,17 @@ void Object::ForceValuesUpdateAtIndex(uint32 i)
namespace Trinity
{
- class MessageChatLocaleCacheDo
+ class MonsterChatBuilder
{
public:
- MessageChatLocaleCacheDo(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, uint64 targetGUID, float dist)
- : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language),
- i_targetGUID(targetGUID), i_dist(dist)
+ MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, uint64 targetGUID)
+ : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), i_targetGUID(targetGUID) {}
+ void operator()(WorldPacket& data, int32 loc_idx)
{
- }
-
- ~MessageChatLocaleCacheDo()
- {
- for(int i = 0; i < i_data_cache.size(); ++i)
- delete i_data_cache[i];
- }
-
- void operator()(Player* p)
- {
- // skip far away players
- if(p->GetDistance(&i_object) > i_dist)
- return;
-
- uint32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex();
- uint32 cache_idx = loc_idx+1;
- WorldPacket* data;
+ char const* text = objmgr.GetMangosString(i_textId,loc_idx);
- // create if not cached yet
- if(i_data_cache.size() < cache_idx+1 || !i_data_cache[cache_idx])
- {
- if(i_data_cache.size() < cache_idx+1)
- i_data_cache.resize(cache_idx+1);
-
- char const* text = objmgr.GetTrinityString(i_textId,loc_idx);
-
- data = new WorldPacket(SMSG_MESSAGECHAT, 200);
-
- // TODO: i_object.GetName() also must be localized?
- i_object.BuildMonsterChat(data,i_msgtype,text,i_language,i_object.GetNameForLocaleIdx(loc_idx),i_targetGUID);
-
- i_data_cache[cache_idx] = data;
- }
- else
- data = i_data_cache[cache_idx];
-
- p->SendDirectMessage(data);
+ // TODO: i_object.GetName() also must be localized?
+ i_object.BuildMonsterChat(&data,i_msgtype,text,i_language,i_object.GetNameForLocaleIdx(loc_idx),i_targetGUID);
}
private:
@@ -1419,8 +1558,6 @@ namespace Trinity
int32 i_textId;
uint32 i_language;
uint64 i_targetGUID;
- float i_dist;
- std::vector<WorldPacket*> i_data_cache; // 0 = default, i => i-1 locale index
};
} // namespace Trinity
@@ -1432,9 +1569,10 @@ void WorldObject::MonsterSay(int32 textId, uint32 language, uint64 TargetGuid)
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
- Trinity::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY));
- Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
- TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
+ MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid);
+ MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
+ MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),say_do);
+ TypeContainerVisitor<MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> >, WorldTypeMapContainer > message(say_worker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *GetMap());
}
@@ -1447,13 +1585,27 @@ void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid)
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
- Trinity::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL));
- Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
- TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
+ MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid);
+ MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
+ MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),say_do);
+ TypeContainerVisitor<MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> >, WorldTypeMapContainer > message(say_worker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *GetMap());
}
+void WorldObject::MonsterYellToZone(int32 textId, uint32 language, uint64 TargetGuid)
+{
+ MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid);
+ MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
+
+ uint32 zoneid = GetZoneId();
+
+ Map::PlayerList const& pList = GetMap()->GetPlayers();
+ for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
+ if(itr->getSource()->GetZoneId()==zoneid)
+ say_do(itr->getSource());
+}
+
void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote)
{
CellPair p = Trinity::ComputeCellPair(GetPositionX(), GetPositionY());
@@ -1462,9 +1614,10 @@ void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossE
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
- Trinity::MessageChatLocaleCacheDo say_do(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId,LANG_UNIVERSAL,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
- Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
- TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
+ MaNGOS::MonsterChatBuilder say_build(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId,LANG_UNIVERSAL,TargetGuid);
+ MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
+ MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),say_do);
+ TypeContainerVisitor<MaNGOS::PlayerDistWorker<MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> >, WorldTypeMapContainer > message(say_worker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, message, *GetMap());
}
@@ -1479,7 +1632,7 @@ void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisp
char const* text = objmgr.GetTrinityString(textId,loc_idx);
WorldPacket data(SMSG_MESSAGECHAT, 200);
- BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
+ BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetNameForLocaleIdx(loc_idx),receiver);
player->GetSession()->SendPacket(&data);
}
@@ -1491,10 +1644,10 @@ void WorldObject::BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const*
*data << (uint8)msgtype;
*data << (uint32)language;
*data << (uint64)GetGUID();
- *data << (uint32)0; //2.1.0
+ *data << (uint32)0; // 2.1.0
*data << (uint32)(strlen(name)+1);
*data << name;
- *data << (uint64)targetGuid; //Unit Target
+ *data << (uint64)targetGuid; // Unit Target
if( targetGuid && !IS_PLAYER_GUID(targetGuid) )
{
*data << (uint32)1; // target name length
@@ -1516,13 +1669,14 @@ void WorldObject::BuildHeartBeatMsg(WorldPacket *data) const
data->Initialize(MSG_MOVE_HEARTBEAT, 32);
data->append(GetPackGUID());
*data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
- *data << uint8(0); // 2.3.0
- *data << getMSTime(); // time
+ *data << uint16(0); // 2.3.0
+ *data << uint32(getMSTime()); // time
*data << m_positionX;
*data << m_positionY;
*data << m_positionZ;
*data << m_orientation;
- *data << uint32(0);
+
+ ((Unit*)this)->BuildMovementPacket(data);
}
void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float z, float ang) const
@@ -1535,23 +1689,24 @@ void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float
data->append(GetPackGUID());
*data << uint32(0); // this value increments every time
*data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
- *data << uint8(0); // 2.3.0
- *data << getMSTime(); // time
+ *data << uint16(0); // 2.3.0
+ *data << uint32(getMSTime()); // time
*data << x;
*data << y;
*data << z;
*data << ang;
- *data << uint32(0);
+
+ ((Unit*)this)->BuildMovementPacket(data);
}
-void WorldObject::SendMessageToSet(WorldPacket *data, bool /*fake*/, bool bToPossessor)
+void WorldObject::SendMessageToSet(WorldPacket *data, bool /*fake*/)
{
- MapManager::Instance().GetMap(m_mapId, this)->MessageBroadcast(this, data, bToPossessor);
+ GetMap()->MessageBroadcast(this, data);
}
-void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/, bool bToPossessor)
+void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/)
{
- MapManager::Instance().GetMap(m_mapId, this)->MessageDistBroadcast(this, data, dist, bToPossessor);
+ GetMap()->MessageDistBroadcast(this, data, dist);
}
void WorldObject::SendObjectDeSpawnAnim(uint64 guid)
@@ -1590,60 +1745,133 @@ void WorldObject::AddObjectToRemoveList()
map->AddObjectToRemoveList(this);
}
-Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
+TempSummon *Map::SummonCreature(uint32 entry, float x, float y, float z, float angle, SummonPropertiesEntry const *properties, uint32 duration, Unit *summoner)
{
- TemporarySummon* pCreature = new TemporarySummon(GetGUID());
+ uint32 mask = SUMMON_MASK_SUMMON;
+ if(properties)
+ {
+ if(properties->Category == SUMMON_CATEGORY_PET
+ || properties->Type == SUMMON_TYPE_GUARDIAN
+ || properties->Type == SUMMON_TYPE_MINION)
+ mask = SUMMON_MASK_GUARDIAN;
+ else if(properties->Type == SUMMON_TYPE_TOTEM)
+ mask = SUMMON_MASK_TOTEM;
+ else if(properties->Category == SUMMON_CATEGORY_VEHICLE
+ || properties->Type == SUMMON_TYPE_VEHICLE
+ || properties->Type == SUMMON_TYPE_VEHICLE2)
+ mask = SUMMON_MASK_VEHICLE;
+ else if(properties->Category == SUMMON_CATEGORY_PUPPET)
+ mask = SUMMON_MASK_PUPPET;
+ else if(properties->Type == SUMMON_TYPE_MINIPET)
+ mask = SUMMON_MASK_MINION;
+ }
- uint32 team = 0;
- if (GetTypeId()==TYPEID_PLAYER)
- team = ((Player*)this)->GetTeam();
+ uint32 phase = PHASEMASK_NORMAL, team = 0;
+ if(summoner)
+ {
+ phase = summoner->GetPhaseMask();
+ if(summoner->GetTypeId() == TYPEID_PLAYER)
+ team = ((Player*)summoner)->GetTeam();
+ }
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMap(), id, team))
+ TempSummon *summon = NULL;
+ switch(mask)
{
- delete pCreature;
+ case SUMMON_MASK_SUMMON: summon = new TempSummon (properties, summoner); break;
+ case SUMMON_MASK_GUARDIAN: summon = new Guardian (properties, summoner); break;
+ case SUMMON_MASK_PUPPET: summon = new Puppet (properties, summoner); break;
+ case SUMMON_MASK_TOTEM: summon = new Totem (properties, summoner); break;
+ case SUMMON_MASK_MINION: summon = new Minion (properties, summoner); break;
+ default: return NULL;
+ }
+
+ if(!summon->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), this, phase, entry, team, x, y, z, angle))
+ {
+ delete summon;
return NULL;
}
- if (x == 0.0f && y == 0.0f && z == 0.0f)
- GetClosePoint(x, y, z, pCreature->GetObjectSize());
+ summon->SetHomePosition(x, y, z, angle);
- pCreature->Relocate(x, y, z, ang);
+ summon->InitStats(duration);
+ Add((Creature*)summon);
+ summon->InitSummon();
- if(!pCreature->IsPositionValid())
+ //ObjectAccessor::UpdateObjectVisibility(summon);
+
+ return summon;
+}
+
+void WorldObject::SetZoneScript()
+{
+ if(Map *map = FindMap())
{
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
- delete pCreature;
- return NULL;
+ if(map->IsDungeon())
+ m_zoneScript = (ZoneScript*)((InstanceMap*)map)->GetInstanceData();
+ else if(!map->IsBattleGroundOrArena())
+ m_zoneScript = sOutdoorPvPMgr.GetZoneScript(GetZoneId());
}
+}
- pCreature->SetHomePosition(x, y, z, ang);
- pCreature->Summon(spwtype, despwtime);
+TempSummon* WorldObject::SummonCreature(uint32 entry, float x, float y, float z, float ang, TempSummonType spwtype, uint32 duration)
+{
+ Map *map = FindMap();
+ if(!map)
+ return NULL;
- if(GetTypeId()==TYPEID_UNIT && ((Creature*)this)->IsAIEnabled)
- ((Creature*)this)->AI()->JustSummoned(pCreature);
+ if (x == 0.0f && y == 0.0f && z == 0.0f)
+ GetClosePoint(x, y, z, GetObjectSize());
- if(pCreature->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER && pCreature->m_spells[0])
+ TempSummon *pCreature = map->SummonCreature(entry, x, y, z, ang, NULL, duration, isType(TYPEMASK_UNIT) ? (Unit*)this : NULL);
+ if(!pCreature)
+ return NULL;
+
+ pCreature->SetTempSummonType(spwtype);
+
+ return pCreature;
+}
+
+Vehicle* WorldObject::SummonVehicle(uint32 entry, float x, float y, float z, float ang)
+{
+ CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry);
+ if(!ci)
+ return NULL;
+
+ uint32 id = ci->VehicleId; //temp store id here
+ if(!id) id = 156;
+ VehicleEntry const *ve = sVehicleStore.LookupEntry(id);
+ if(!ve)
+ return NULL;
+
+ Vehicle *v = new Vehicle;
+ Map *map = GetMap();
+ uint32 team = 0;
+ if (GetTypeId()==TYPEID_PLAYER)
+ team = ((Player*)this)->GetTeam();
+ if(!v->Create(objmgr.GenerateLowGuid(HIGHGUID_VEHICLE), map, GetPhaseMask(), entry, id, team, x, y, z, ang))
{
- if(GetTypeId() == TYPEID_UNIT || GetTypeId() == TYPEID_PLAYER)
- pCreature->setFaction(((Unit*)this)->getFaction());
- pCreature->CastSpell(pCreature, pCreature->m_spells[0], false, 0, 0, GetGUID());
+ delete v;
+ return NULL;
}
- //return the creature therewith the summoner has access to it
- return pCreature;
+ map->Add((Creature*)v);
+
+ //ObjectAccessor::UpdateObjectVisibility(v);
+
+ return v;
}
Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 duration)
{
- Pet* pet = new Pet(petType);
+ Pet* pet = new Pet(this, petType);
if(petType == SUMMON_PET && pet->LoadPetFromDB(this, entry))
{
// Remove Demonic Sacrifice auras (known pet)
- Unit::AuraList const& auraClassScripts = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
+ Unit::AuraEffectList const& auraClassScripts = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraEffectList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
{
- if((*itr)->GetModifier()->m_miscvalue==2228)
+ if((*itr)->GetMiscValue()==2228)
{
RemoveAurasDueToSpell((*itr)->GetId());
itr = auraClassScripts.begin();
@@ -1667,7 +1895,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
Map *map = GetMap();
uint32 pet_number = objmgr.GeneratePetNumber();
- if(!pet->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, entry, pet_number))
+ if(!pet->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, GetPhaseMask(), entry, pet_number))
{
sLog.outError("no such creature entry %u", entry);
delete pet;
@@ -1683,38 +1911,38 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
return NULL;
}
- pet->SetOwnerGUID(GetGUID());
pet->SetCreatorGUID(GetGUID());
pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction());
- // this enables pet details window (Shift+P)
- pet->GetCharmInfo()->SetPetNumber(pet_number, false);
-
- pet->AIM_Initialize();
-
- map->Add((Creature*)pet);
-
pet->setPowerType(POWER_MANA);
pet->SetUInt32Value(UNIT_NPC_FLAGS , 0);
pet->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
pet->InitStatsForLevel(getLevel());
+ SetMinion(pet, true);
+
switch(petType)
{
- case GUARDIAN_PET:
- case POSSESSED_PET:
- pet->SetUInt32Value(UNIT_FIELD_FLAGS,0);
- AddGuardian(pet);
- break;
case SUMMON_PET:
+ // this enables pet details window (Shift+P)
+ pet->GetCharmInfo()->SetPetNumber(pet_number, true);
pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
pet->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
pet->SetHealth(pet->GetMaxHealth());
pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA));
+ pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
+ break;
+ }
+
+ map->Add((Creature*)pet);
+
+ switch(petType)
+ {
+ case SUMMON_PET:
pet->InitPetCreateSpells();
+ pet->InitTalentForLevel();
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
- SetPet(pet);
PetSpellInitialize();
break;
}
@@ -1722,10 +1950,10 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
if(petType == SUMMON_PET)
{
// Remove Demonic Sacrifice auras (known pet)
- Unit::AuraList const& auraClassScripts = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
+ Unit::AuraEffectList const& auraClassScripts = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(Unit::AuraEffectList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
{
- if((*itr)->GetModifier()->m_miscvalue==2228)
+ if((*itr)->GetMiscValue()==2228)
{
RemoveAurasDueToSpell((*itr)->GetId());
itr = auraClassScripts.begin();
@@ -1738,6 +1966,8 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
if(duration > 0)
pet->SetDuration(duration);
+ //ObjectAccessor::UpdateObjectVisibility(pet);
+
return pet;
}
@@ -1754,7 +1984,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float
}
Map *map = GetMap();
GameObject *go = new GameObject();
- if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry,map,x,y,z,ang,rotation0,rotation1,rotation2,rotation3,100,1))
+ if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, map, GetPhaseMask(), x,y,z,ang,rotation0,rotation1,rotation2,rotation3,100,GO_STATE_READY))
{
delete go;
return NULL;
@@ -1788,6 +2018,99 @@ Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint3
return summon;
}
+Creature* WorldObject::FindNearestCreature(uint32 entry, float range, bool alive)
+{
+ Creature *creature = NULL;
+ Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck checker(*this, entry, alive, range);
+ Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(this, creature, checker);
+ VisitNearbyObject(range, searcher);
+ return creature;
+}
+
+GameObject* WorldObject::FindNearestGameObject(uint32 entry, float range)
+{
+ GameObject *go = NULL;
+ Trinity::NearestGameObjectEntryInObjectRangeCheck checker(*this, entry, range);
+ Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> searcher(this, go, checker);
+ VisitNearbyGridObject(range, searcher);
+ return go;
+}
+
+/*
+namespace MaNGOS
+{
+ class NearUsedPosDo
+ {
+ public:
+ NearUsedPosDo(WorldObject const& obj, WorldObject const* searcher, float angle, ObjectPosSelector& selector)
+ : i_object(obj), i_searcher(searcher), i_angle(angle), i_selector(selector) {}
+
+ void operator()(Corpse*) const {}
+ void operator()(DynamicObject*) const {}
+
+ void operator()(Creature* c) const
+ {
+ // skip self or target
+ if(c==i_searcher || c==&i_object)
+ return;
+
+ float x,y,z;
+
+ if( !c->isAlive() || c->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) ||
+ !c->GetMotionMaster()->GetDestination(x,y,z) )
+ {
+ x = c->GetPositionX();
+ y = c->GetPositionY();
+ }
+
+ add(c,x,y);
+ }
+
+ template<class T>
+ void operator()(T* u) const
+ {
+ // skip self or target
+ if(u==i_searcher || u==&i_object)
+ return;
+
+ float x,y;
+
+ x = u->GetPositionX();
+ y = u->GetPositionY();
+
+ add(u,x,y);
+ }
+
+ // we must add used pos that can fill places around center
+ void add(WorldObject* u, float x, float y) const
+ {
+ // u is too nearest/far away to i_object
+ if(!i_object.IsInRange2d(x,y,i_selector.m_dist - i_selector.m_size,i_selector.m_dist + i_selector.m_size))
+ return;
+
+ float angle = i_object.GetAngle(u)-i_angle;
+
+ // move angle to range -pi ... +pi
+ while( angle > M_PI)
+ angle -= 2.0f * M_PI;
+ while(angle < -M_PI)
+ angle += 2.0f * M_PI;
+
+ // dist include size of u
+ float dist2d = i_object.GetDistance2d(x,y);
+ i_selector.AddUsedPos(u->GetObjectSize(),angle,dist2d + i_object.GetObjectSize());
+ }
+ private:
+ WorldObject const& i_object;
+ WorldObject const* i_searcher;
+ float i_angle;
+ ObjectPosSelector& i_selector;
+ };
+} // namespace MaNGOS
+*/
+
+//===================================================================================================
+
void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const
{
x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle);
@@ -1800,10 +2123,127 @@ void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float abs
void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle ) const
{
GetNearPoint2D(x,y,distance2d+searcher_size,absAngle);
-
z = GetPositionZ();
-
UpdateGroundPositionZ(x,y,z);
+
+ /*
+ // if detection disabled, return first point
+ if(!sWorld.getConfig(CONFIG_DETECT_POS_COLLISION))
+ {
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+ return;
+ }
+
+ // or remember first point
+ float first_x = x;
+ float first_y = y;
+ bool first_los_conflict = false; // first point LOS problems
+
+ // prepare selector for work
+ ObjectPosSelector selector(GetPositionX(),GetPositionY(),GetObjectSize(),distance2d+searcher_size);
+
+ // adding used positions around object
+ {
+ CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ MaNGOS::NearUsedPosDo u_do(*this,searcher,absAngle,selector);
+ MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo> worker(this,u_do);
+
+ TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, GridTypeMapContainer > grid_obj_worker(worker);
+ TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, WorldTypeMapContainer > world_obj_worker(worker);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap());
+ cell_lock->Visit(cell_lock, world_obj_worker, *GetMap());
+ }
+
+ // maybe can just place in primary position
+ if( selector.CheckOriginal() )
+ {
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+
+ first_los_conflict = true; // first point have LOS problems
+ }
+
+ float angle; // candidate of angle for free pos
+
+ // special case when one from list empty and then empty side preferred
+ if(selector.FirstAngle(angle))
+ {
+ GetNearPoint2D(x,y,distance2d,absAngle+angle);
+ z = GetPositionZ();
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+ }
+
+ // set first used pos in lists
+ selector.InitializeAngle();
+
+ // select in positions after current nodes (selection one by one)
+ while(selector.NextAngle(angle)) // angle for free pos
+ {
+ GetNearPoint2D(x,y,distance2d,absAngle+angle);
+ z = GetPositionZ();
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+ }
+
+ // BAD NEWS: not free pos (or used or have LOS problems)
+ // Attempt find _used_ pos without LOS problem
+
+ if(!first_los_conflict)
+ {
+ x = first_x;
+ y = first_y;
+
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+ return;
+ }
+
+ // special case when one from list empty and then empty side preferred
+ if( selector.IsNonBalanced() )
+ {
+ if(!selector.FirstAngle(angle)) // _used_ pos
+ {
+ GetNearPoint2D(x,y,distance2d,absAngle+angle);
+ z = GetPositionZ();
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+ }
+ }
+
+ // set first used pos in lists
+ selector.InitializeAngle();
+
+ // select in positions after current nodes (selection one by one)
+ while(selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem
+ {
+ GetNearPoint2D(x,y,distance2d,absAngle+angle);
+ z = GetPositionZ();
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+
+ if(IsWithinLOS(x,y,z))
+ return;
+ }
+
+ // BAD BAD NEWS: all found pos (free and used) have LOS problem :(
+ x = first_x;
+ y = first_y;
+
+ UpdateGroundPositionZ(x,y,z); // update to LOS height if available
+ */
}
void WorldObject::GetGroundPoint(float &x, float &y, float &z, float dist, float angle)
@@ -1816,5 +2256,31 @@ void WorldObject::GetGroundPoint(float &x, float &y, float &z, float dist, float
UpdateGroundPositionZ(x, y, z);
}
+void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update)
+{
+ m_phaseMask = newPhaseMask;
+ if(update && IsInWorld())
+ ObjectAccessor::UpdateObjectVisibility(this);
+}
+void WorldObject::PlayDistanceSound( uint32 sound_id, Player* target /*= NULL*/ )
+{
+ WorldPacket data(SMSG_PLAY_OBJECT_SOUND,4+8);
+ data << uint32(sound_id);
+ data << uint64(GetGUID());
+ if (target)
+ target->SendDirectMessage( &data );
+ else
+ SendMessageToSet( &data, true );
+}
+
+void WorldObject::PlayDirectSound( uint32 sound_id, Player* target /*= NULL*/ )
+{
+ WorldPacket data(SMSG_PLAY_SOUND, 4);
+ data << uint32(sound_id);
+ if (target)
+ target->SendDirectMessage( &data );
+ else
+ SendMessageToSet( &data, true );
+}