root/trunk/src/game/Object.cpp @ 139

Revision 138, 49.6 kB (checked in by yumileroy, 17 years ago)

[svn] Enable linked spells: cast spells/remove auras when spells casted/spells hitting/auras removed. Add new table "spell_linked_spell". Some illustrations provided in sql.
Let trigger creature cast AOE spells when summoned. Illustration provided in sql.
Let active creatures always visible if possible. (seems does not work for now, need to find out why)

Original author: megamage
Date: 2008-10-30 11:32:10-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "Common.h"
22#include "SharedDefines.h"
23#include "WorldPacket.h"
24#include "Opcodes.h"
25#include "Log.h"
26#include "World.h"
27#include "Object.h"
28#include "Creature.h"
29#include "Player.h"
30#include "ObjectMgr.h"
31#include "WorldSession.h"
32#include "UpdateData.h"
33#include "UpdateMask.h"
34#include "Util.h"
35#include "MapManager.h"
36#include "ObjectAccessor.h"
37#include "Log.h"
38#include "Transports.h"
39#include "TargetedMovementGenerator.h"
40#include "WaypointMovementGenerator.h"
41#include "VMapFactory.h"
42#include "CellImpl.h"
43#include "GridNotifiers.h"
44#include "GridNotifiersImpl.h"
45
46#include "TemporarySummon.h"
47
48uint32 GuidHigh2TypeId(uint32 guid_hi)
49{
50    switch(guid_hi)
51    {
52        case HIGHGUID_ITEM:         return TYPEID_ITEM;
53        //case HIGHGUID_CONTAINER:    return TYPEID_CONTAINER; HIGHGUID_CONTAINER==HIGHGUID_ITEM currently
54        case HIGHGUID_UNIT:         return TYPEID_UNIT;
55        case HIGHGUID_PET:          return TYPEID_UNIT;
56        case HIGHGUID_PLAYER:       return TYPEID_PLAYER;
57        case HIGHGUID_GAMEOBJECT:   return TYPEID_GAMEOBJECT;
58        case HIGHGUID_DYNAMICOBJECT:return TYPEID_DYNAMICOBJECT;
59        case HIGHGUID_CORPSE:       return TYPEID_CORPSE;
60        case HIGHGUID_MO_TRANSPORT: return TYPEID_GAMEOBJECT;
61    }
62    return 10;                                              // unknown
63}
64
65Object::Object( )
66{
67    m_objectTypeId      = TYPEID_OBJECT;
68    m_objectType        = TYPEMASK_OBJECT;
69
70    m_uint32Values      = 0;
71    m_uint32Values_mirror = 0;
72    m_valuesCount       = 0;
73
74    m_inWorld           = false;
75    m_objectUpdated     = false;
76
77    m_PackGUID.clear();
78    m_PackGUID.appendPackGUID(0);
79}
80
81Object::~Object( )
82{
83    if(m_objectUpdated)
84        ObjectAccessor::Instance().RemoveUpdateObject(this);
85
86    if(m_uint32Values)
87    {
88        if(IsInWorld())
89        {
90            ///- Do NOT call RemoveFromWorld here, if the object is a player it will crash
91            sLog.outError("Object::~Object - guid="I64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId());
92            //assert(0);
93        }
94
95        //DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
96        delete [] m_uint32Values;
97        delete [] m_uint32Values_mirror;
98        //DEBUG_LOG("Object desctr 2 check (%p)",(void*)this);
99    }
100}
101
102void Object::_InitValues()
103{
104    m_uint32Values = new uint32[ m_valuesCount ];
105    memset(m_uint32Values, 0, m_valuesCount*sizeof(uint32));
106
107    m_uint32Values_mirror = new uint32[ m_valuesCount ];
108    memset(m_uint32Values_mirror, 0, m_valuesCount*sizeof(uint32));
109
110    m_objectUpdated = false;
111}
112
113void Object::_Create( uint32 guidlow, uint32 entry, HighGuid guidhigh )
114{
115    if(!m_uint32Values) _InitValues();
116
117    uint64 guid = MAKE_NEW_GUID(guidlow, entry, guidhigh);  // required more changes to make it working
118    SetUInt64Value( OBJECT_FIELD_GUID, guid );
119    SetUInt32Value( OBJECT_FIELD_TYPE, m_objectType );
120    m_PackGUID.clear();
121    m_PackGUID.appendPackGUID(GetGUID());
122}
123
124void Object::BuildMovementUpdateBlock(UpdateData * data, uint32 flags ) const
125{
126    ByteBuffer buf(500);
127
128    buf << uint8( UPDATETYPE_MOVEMENT );
129    buf << GetGUID();
130
131    _BuildMovementUpdate(&buf, flags, 0x00000000);
132
133    data->AddUpdateBlock(buf);
134}
135
136void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const
137{
138    if(!target)
139    {
140        return;
141    }
142
143    uint8  updatetype = UPDATETYPE_CREATE_OBJECT;
144    uint8  flags      = m_updateFlag;
145    uint32 flags2     = 0;
146
147    /** lower flag1 **/
148    if(target == this)                                      // building packet for oneself
149    {
150        flags |= UPDATEFLAG_SELF;
151
152        /*** temporary reverted - until real source of stack corruption will not found
153        updatetype = UPDATETYPE_CREATE_OBJECT2;
154        ****/
155    }
156
157    if(flags & UPDATEFLAG_HASPOSITION)
158    {
159        // UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
160        if(isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER))
161            updatetype = UPDATETYPE_CREATE_OBJECT2;
162
163        // UPDATETYPE_CREATE_OBJECT2 for pets...
164        if(target->GetPetGUID() == GetGUID())
165            updatetype = UPDATETYPE_CREATE_OBJECT2;
166
167        // UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
168        if(isType(TYPEMASK_GAMEOBJECT))
169        {
170            switch(((GameObject*)this)->GetGoType())
171            {
172                case GAMEOBJECT_TYPE_TRAP:
173                case GAMEOBJECT_TYPE_DUEL_ARBITER:
174                case GAMEOBJECT_TYPE_FLAGSTAND:
175                case GAMEOBJECT_TYPE_FLAGDROP:
176                    updatetype = UPDATETYPE_CREATE_OBJECT2;
177                    break;
178                case GAMEOBJECT_TYPE_TRANSPORT:
179                    flags |= UPDATEFLAG_TRANSPORT;
180                    break;
181            }
182        }
183    }
184
185    //sLog.outDebug("BuildCreateUpdate: update-type: %u, object-type: %u got flags: %X, flags2: %X", updatetype, m_objectTypeId, flags, flags2);
186
187    ByteBuffer buf(500);
188    buf << (uint8)updatetype;
189    //buf.append(GetPackGUID());    //client crashes when using this
190    buf << (uint8)0xFF << GetGUID();
191    buf << (uint8)m_objectTypeId;
192
193    _BuildMovementUpdate(&buf, flags, flags2);
194
195    UpdateMask updateMask;
196    updateMask.SetCount( m_valuesCount );
197    _SetCreateBits( &updateMask, target );
198    _BuildValuesUpdate(updatetype, &buf, &updateMask, target );
199    data->AddUpdateBlock(buf);
200}
201
202void Object::BuildUpdate(UpdateDataMapType &update_players)
203{
204    ObjectAccessor::_buildUpdateObject(this,update_players);
205    ClearUpdateMask(true);
206}
207
208void Object::SendUpdateToPlayer(Player* player)
209{
210    // send update to another players
211    SendUpdateObjectToAllExcept(player);
212
213    // send create update to player
214    UpdateData upd;
215    WorldPacket packet;
216
217    upd.Clear();
218    BuildCreateUpdateBlockForPlayer(&upd, player);
219    upd.BuildPacket(&packet);
220    player->GetSession()->SendPacket(&packet);
221
222    // now object updated/(create updated)
223}
224
225void Object::BuildValuesUpdateBlockForPlayer(UpdateData *data, Player *target) const
226{
227    ByteBuffer buf(500);
228
229    buf << (uint8) UPDATETYPE_VALUES;
230    //buf.append(GetPackGUID());    //client crashes when using this. but not have crash in debug mode
231    buf << (uint8)0xFF;
232    buf << GetGUID();
233
234    UpdateMask updateMask;
235    updateMask.SetCount( m_valuesCount );
236
237    _SetUpdateBits( &updateMask, target );
238    _BuildValuesUpdate(UPDATETYPE_VALUES, &buf, &updateMask, target );
239
240    data->AddUpdateBlock(buf);
241}
242
243void Object::BuildOutOfRangeUpdateBlock(UpdateData * data) const
244{
245    data->AddOutOfRangeGUID(GetGUID());
246}
247
248void Object::DestroyForPlayer(Player *target) const
249{
250    ASSERT(target);
251
252    WorldPacket data(SMSG_DESTROY_OBJECT, 8);
253    data << GetGUID();
254    target->GetSession()->SendPacket( &data );
255}
256
257void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2 ) const
258{
259    *data << (uint8)flags;                                  // update flags
260
261    // 0x20
262    if (flags & UPDATEFLAG_LIVING)
263    {
264        switch(GetTypeId())
265        {
266            case TYPEID_UNIT:
267            {
268                flags2 = ((Unit*)this)->GetUnitMovementFlags();
269                flags2 &= ~MOVEMENTFLAG_ONTRANSPORT;
270                flags2 &= ~MOVEMENTFLAG_SPLINE2;
271            }
272            break;
273            case TYPEID_PLAYER:
274            {
275                flags2 = ((Player*)this)->GetUnitMovementFlags();
276
277                if(((Player*)this)->GetTransport())
278                    flags2 |= MOVEMENTFLAG_ONTRANSPORT;
279                else
280                    flags2 &= ~MOVEMENTFLAG_ONTRANSPORT;
281
282                // remove unknown, unused etc flags for now
283                flags2 &= ~MOVEMENTFLAG_SPLINE2;            // will be set manually
284
285                if(((Player*)this)->isInFlight())
286                {
287                    WPAssert(((Player*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
288                    flags2 = (MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_SPLINE2);
289                }
290            }
291            break;
292        }
293
294        *data << uint32(flags2);                            // movement flags
295        *data << uint8(0);                                  // unk 2.3.0
296        *data << uint32(getMSTime());                       // time (in milliseconds)
297    }
298
299    // 0x40
300    if (flags & UPDATEFLAG_HASPOSITION)
301    {
302        // 0x02
303        if(flags & UPDATEFLAG_TRANSPORT && ((GameObject*)this)->GetGoType() == GAMEOBJECT_TYPE_MO_TRANSPORT)
304        {
305            *data << (float)0;
306            *data << (float)0;
307            *data << (float)0;
308            *data << ((WorldObject *)this)->GetOrientation();
309        }
310        else
311        {
312            *data << ((WorldObject *)this)->GetPositionX();
313            *data << ((WorldObject *)this)->GetPositionY();
314            *data << ((WorldObject *)this)->GetPositionZ();
315            *data << ((WorldObject *)this)->GetOrientation();
316        }
317    }
318
319    // 0x20
320    if(flags & UPDATEFLAG_LIVING)
321    {
322        // 0x00000200
323        if(flags2 & MOVEMENTFLAG_ONTRANSPORT)
324        {
325            if(GetTypeId() == TYPEID_PLAYER)
326            {
327                *data << (uint64)((Player*)this)->GetTransport()->GetGUID();
328                *data << (float)((Player*)this)->GetTransOffsetX();
329                *data << (float)((Player*)this)->GetTransOffsetY();
330                *data << (float)((Player*)this)->GetTransOffsetZ();
331                *data << (float)((Player*)this)->GetTransOffsetO();
332                *data << (uint32)((Player*)this)->GetTransTime();
333            }
334            //TrinIty currently not have support for other than player on transport
335        }
336
337        // 0x02200000
338        if(flags2 & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2))
339        {
340            if(GetTypeId() == TYPEID_PLAYER)
341                *data << (float)((Player*)this)->m_movementInfo.s_pitch;
342            else
343                *data << (float)0;                          // is't part of movement packet, we must store and send it...
344        }
345
346        if(GetTypeId() == TYPEID_PLAYER)
347            *data << (uint32)((Player*)this)->m_movementInfo.fallTime;
348        else
349            *data << (uint32)0;                             // last fall time
350
351        // 0x00001000
352        if(flags2 & MOVEMENTFLAG_JUMPING)
353        {
354            if(GetTypeId() == TYPEID_PLAYER)
355            {
356                *data << (float)((Player*)this)->m_movementInfo.j_unk;
357                *data << (float)((Player*)this)->m_movementInfo.j_sinAngle;
358                *data << (float)((Player*)this)->m_movementInfo.j_cosAngle;
359                *data << (float)((Player*)this)->m_movementInfo.j_xyspeed;
360            }
361            else
362            {
363                *data << (float)0;
364                *data << (float)0;
365                *data << (float)0;
366                *data << (float)0;
367            }
368        }
369
370        // 0x04000000
371        if(flags2 & MOVEMENTFLAG_SPLINE)
372        {
373            if(GetTypeId() == TYPEID_PLAYER)
374                *data << (float)((Player*)this)->m_movementInfo.u_unk1;
375            else
376                *data << (float)0;
377        }
378
379        *data << ((Unit*)this)->GetSpeed( MOVE_WALK );
380        *data << ((Unit*)this)->GetSpeed( MOVE_RUN );
381        *data << ((Unit*)this)->GetSpeed( MOVE_SWIMBACK );
382        *data << ((Unit*)this)->GetSpeed( MOVE_SWIM );
383        *data << ((Unit*)this)->GetSpeed( MOVE_WALKBACK );
384        *data << ((Unit*)this)->GetSpeed( MOVE_FLY );
385        *data << ((Unit*)this)->GetSpeed( MOVE_FLYBACK );
386        *data << ((Unit*)this)->GetSpeed( MOVE_TURN );
387
388        // 0x08000000
389        if(flags2 & MOVEMENTFLAG_SPLINE2)
390        {
391            if(GetTypeId() != TYPEID_PLAYER)
392            {
393                sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 for non-player");
394                return;
395            }
396
397            if(!((Player*)this)->isInFlight())
398            {
399                sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 but not in flight");
400                return;
401            }
402
403            WPAssert(((Player*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
404
405            FlightPathMovementGenerator *fmg = (FlightPathMovementGenerator*)(((Player*)this)->GetMotionMaster()->top());
406
407            uint32 flags3 = 0x00000300;
408
409            *data << uint32(flags3);                        // splines flag?
410
411            if(flags3 & 0x10000)                            // probably x,y,z coords there
412            {
413                *data << (float)0;
414                *data << (float)0;
415                *data << (float)0;
416            }
417
418            if(flags3 & 0x20000)                            // probably guid there
419            {
420                *data << uint64(0);
421            }
422
423            if(flags3 & 0x40000)                            // may be orientation
424            {
425                *data << (float)0;
426            }
427
428            Path &path = fmg->GetPath();
429
430            float x, y, z;
431            ((Player*)this)->GetPosition(x, y, z);
432
433            uint32 inflighttime = uint32(path.GetPassedLength(fmg->GetCurrentNode(), x, y, z) * 32);
434            uint32 traveltime = uint32(path.GetTotalLength() * 32);
435
436            *data << uint32(inflighttime);                  // passed move time?
437            *data << uint32(traveltime);                    // full move time?
438            *data << uint32(0);                             // ticks count?
439
440            uint32 poscount = uint32(path.Size());
441
442            *data << uint32(poscount);                      // points count
443
444            for(uint32 i = 0; i < poscount; ++i)
445            {
446                *data << path.GetNodes()[i].x;
447                *data << path.GetNodes()[i].y;
448                *data << path.GetNodes()[i].z;
449            }
450
451            /*for(uint32 i = 0; i < poscount; i++)
452            {
453                // path points
454                *data << (float)0;
455                *data << (float)0;
456                *data << (float)0;
457            }*/
458
459            *data << path.GetNodes()[poscount-1].x;
460            *data << path.GetNodes()[poscount-1].y;
461            *data << path.GetNodes()[poscount-1].z;
462
463            // target position (path end)
464            /**data << ((Unit*)this)->GetPositionX();
465             *data << ((Unit*)this)->GetPositionY();
466             *data << ((Unit*)this)->GetPositionZ();*/
467        }
468    }
469
470    // 0x8
471    if(flags & UPDATEFLAG_LOWGUID)
472    {
473        switch(GetTypeId())
474        {
475            case TYPEID_OBJECT:
476            case TYPEID_ITEM:
477            case TYPEID_CONTAINER:
478            case TYPEID_GAMEOBJECT:
479            case TYPEID_DYNAMICOBJECT:
480            case TYPEID_CORPSE:
481                *data << uint32(GetGUIDLow());              // GetGUIDLow()
482                break;
483            case TYPEID_UNIT:
484                *data << uint32(0x0000000B);                // unk, can be 0xB or 0xC
485                break;
486            case TYPEID_PLAYER:
487                if(flags & UPDATEFLAG_SELF)
488                    *data << uint32(0x00000015);            // unk, can be 0x15 or 0x22
489                else
490                    *data << uint32(0x00000008);            // unk, can be 0x7 or 0x8
491                break;
492            default:
493                *data << uint32(0x00000000);                // unk
494                break;
495        }
496    }
497
498    // 0x10
499    if(flags & UPDATEFLAG_HIGHGUID)
500    {
501        switch(GetTypeId())
502        {
503            case TYPEID_OBJECT:
504            case TYPEID_ITEM:
505            case TYPEID_CONTAINER:
506            case TYPEID_GAMEOBJECT:
507            case TYPEID_DYNAMICOBJECT:
508            case TYPEID_CORPSE:
509                *data << uint32(GetGUIDHigh());             // GetGUIDHigh()
510                break;
511            default:
512                *data << uint32(0x00000000);                // unk
513                break;
514        }
515    }
516
517    // 0x4
518    if(flags & UPDATEFLAG_FULLGUID)
519    {
520        *data << uint8(0);                                  // packed guid (probably target guid)
521    }
522
523    // 0x2
524    if(flags & UPDATEFLAG_TRANSPORT)
525    {
526        *data << uint32(getMSTime());                       // ms time
527    }
528}
529
530void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask *updateMask, Player *target) const
531{
532    if(!target)
533        return;
534
535    bool IsActivateToQuest = false;
536    if (updatetype == UPDATETYPE_CREATE_OBJECT || updatetype == UPDATETYPE_CREATE_OBJECT2)
537    {
538        if (isType(TYPEMASK_GAMEOBJECT) && !((GameObject*)this)->IsTransport())
539        {
540            if ( ((GameObject*)this)->ActivateToQuest(target) || target->isGameMaster())
541            {
542                IsActivateToQuest = true;
543                updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
544            }
545            if (GetUInt32Value(GAMEOBJECT_ARTKIT))
546                updateMask->SetBit(GAMEOBJECT_ARTKIT);
547        }
548    }
549    else                                                    //case UPDATETYPE_VALUES
550    {
551        if (isType(TYPEMASK_GAMEOBJECT) && !((GameObject*)this)->IsTransport())
552        {
553            if ( ((GameObject*)this)->ActivateToQuest(target) || target->isGameMaster())
554            {
555                IsActivateToQuest = true;
556            }
557            updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
558            updateMask->SetBit(GAMEOBJECT_ANIMPROGRESS);
559        }
560    }
561
562    WPAssert(updateMask && updateMask->GetCount() == m_valuesCount);
563
564    *data << (uint8)updateMask->GetBlockCount();
565    data->append( updateMask->GetMask(), updateMask->GetLength() );
566
567    // 2 specialized loops for speed optimization in non-unit case
568    if(isType(TYPEMASK_UNIT))                               // unit (creature/player) case
569    {
570        for( uint16 index = 0; index < m_valuesCount; index ++ )
571        {
572            if( updateMask->GetBit( index ) )
573            {
574                // remove custom flag before send
575
576                if( index == UNIT_NPC_FLAGS )
577                    *data << uint32(m_uint32Values[ index ] & ~(UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP));
578                // FIXME: Some values at server stored in float format but must be sent to client in uint32 format
579                else if(index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
580                {
581                    // convert from float to uint32 and send
582                    *data << uint32(m_floatValues[ index ] < 0 ? 0 : m_floatValues[ index ]);
583                }
584                // there are some float values which may be negative or can't get negative due to other checks
585                else if(index >= UNIT_FIELD_NEGSTAT0   && index <= UNIT_FIELD_NEGSTAT4 ||
586                    index >= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE  && index <= (UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 6) ||
587                    index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE  && index <= (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6) ||
588                    index >= UNIT_FIELD_POSSTAT0   && index <= UNIT_FIELD_POSSTAT4)
589                {
590                    *data << uint32(m_floatValues[ index ]);
591                }
592                // Gamemasters should be always able to select units - remove not selectable flag
593                else if(index == UNIT_FIELD_FLAGS && target->isGameMaster())
594                {
595                    *data << (m_uint32Values[ index ] & ~UNIT_FLAG_NOT_SELECTABLE);
596                }
597                // use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures
598                else if(index == UNIT_FIELD_DISPLAYID && GetTypeId() == TYPEID_UNIT)
599                {
600                    const CreatureInfo* cinfo = ((Creature*)this)->GetCreatureInfo();
601                    if(cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
602                    {
603                        if(target->isGameMaster())
604                            *data << cinfo->Modelid1;
605                        else
606                            *data << cinfo->Modelid3;
607                    }
608                    else
609                        *data << m_uint32Values[ index ];
610                }
611                // hide lootable animation for unallowed players
612                else if(index == UNIT_DYNAMIC_FLAGS && GetTypeId() == TYPEID_UNIT)
613                {
614                    if(!target->isAllowedToLoot((Creature*)this))
615                        *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_LOOTABLE);
616                    else
617                        *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_OTHER_TAGGER);
618                }
619                else
620                {
621                    // send in current format (float as float, uint32 as uint32)
622                    *data << m_uint32Values[ index ];
623                }
624            }
625        }
626    }
627    else if(isType(TYPEMASK_GAMEOBJECT))                    // gameobject case
628    {
629        for( uint16 index = 0; index < m_valuesCount; index ++ )
630        {
631            if( updateMask->GetBit( index ) )
632            {
633                // send in current format (float as float, uint32 as uint32)
634                if ( index == GAMEOBJECT_DYN_FLAGS )
635                {
636                    if(IsActivateToQuest )
637                    {
638                        switch(((GameObject*)this)->GetGoType())
639                        {
640                            case GAMEOBJECT_TYPE_CHEST:
641                                *data << uint32(9);         // enable quest object. Represent 9, but 1 for client before 2.3.0
642                                break;
643                            case GAMEOBJECT_TYPE_GOOBER:
644                                *data << uint32(1);
645                                break;
646                            default:
647                                *data << uint32(0);         //unknown. not happen.
648                                break;
649                        }
650                    }
651                    else
652                        *data << uint32(0);                 // disable quest object
653                }
654                else
655                    *data << m_uint32Values[ index ];       // other cases
656            }
657        }
658    }
659    else                                                    // other objects case (no special index checks)
660    {
661        for( uint16 index = 0; index < m_valuesCount; index ++ )
662        {
663            if( updateMask->GetBit( index ) )
664            {
665                // send in current format (float as float, uint32 as uint32)
666                *data << m_uint32Values[ index ];
667            }
668        }
669    }
670}
671
672void Object::ClearUpdateMask(bool remove)
673{
674    for( uint16 index = 0; index < m_valuesCount; index ++ )
675    {
676        if(m_uint32Values_mirror[index]!= m_uint32Values[index])
677            m_uint32Values_mirror[index] = m_uint32Values[index];
678    }
679    if(m_objectUpdated)
680    {
681        if(remove)
682            ObjectAccessor::Instance().RemoveUpdateObject(this);
683        m_objectUpdated = false;
684    }
685}
686
687// Send current value fields changes to all viewers
688void Object::SendUpdateObjectToAllExcept(Player* exceptPlayer)
689{
690    // changes will be send in create packet
691    if(!IsInWorld())
692        return;
693
694    // nothing do
695    if(!m_objectUpdated)
696        return;
697
698    ObjectAccessor::UpdateObject(this,exceptPlayer);
699}
700
701bool Object::LoadValues(const char* data)
702{
703    if(!m_uint32Values) _InitValues();
704
705    Tokens tokens = StrSplit(data, " ");
706
707    if(tokens.size() != m_valuesCount)
708        return false;
709
710    Tokens::iterator iter;
711    int index;
712    for (iter = tokens.begin(), index = 0; index < m_valuesCount; ++iter, ++index)
713    {
714        m_uint32Values[index] = atol((*iter).c_str());
715    }
716
717    return true;
718}
719
720void Object::_SetUpdateBits(UpdateMask *updateMask, Player* /*target*/) const
721{
722    for( uint16 index = 0; index < m_valuesCount; index ++ )
723    {
724        if(m_uint32Values_mirror[index]!= m_uint32Values[index])
725            updateMask->SetBit(index);
726    }
727}
728
729void Object::_SetCreateBits(UpdateMask *updateMask, Player* /*target*/) const
730{
731    for( uint16 index = 0; index < m_valuesCount; index++ )
732    {
733        if(GetUInt32Value(index) != 0)
734            updateMask->SetBit(index);
735    }
736}
737
738void Object::SetInt32Value( uint16 index, int32 value )
739{
740    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
741
742    if(m_int32Values[ index ] != value)
743    {
744        m_int32Values[ index ] = value;
745
746        if(m_inWorld)
747        {
748            if(!m_objectUpdated)
749            {
750                ObjectAccessor::Instance().AddUpdateObject(this);
751                m_objectUpdated = true;
752            }
753        }
754    }
755}
756
757void Object::SetUInt32Value( uint16 index, uint32 value )
758{
759    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
760
761    if(m_uint32Values[ index ] != value)
762    {
763        m_uint32Values[ index ] = value;
764
765        if(m_inWorld)
766        {
767            if(!m_objectUpdated)
768            {
769                ObjectAccessor::Instance().AddUpdateObject(this);
770                m_objectUpdated = true;
771            }
772        }
773    }
774}
775
776void Object::SetUInt64Value( uint16 index, const uint64 &value )
777{
778    ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
779    if(*((uint64*)&(m_uint32Values[ index ])) != value)
780    {
781        m_uint32Values[ index ] = *((uint32*)&value);
782        m_uint32Values[ index + 1 ] = *(((uint32*)&value) + 1);
783
784        if(m_inWorld)
785        {
786            if(!m_objectUpdated)
787            {
788                ObjectAccessor::Instance().AddUpdateObject(this);
789                m_objectUpdated = true;
790            }
791        }
792    }
793}
794
795void Object::SetFloatValue( uint16 index, float value )
796{
797    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
798
799    if(m_floatValues[ index ] != value)
800    {
801        m_floatValues[ index ] = value;
802
803        if(m_inWorld)
804        {
805            if(!m_objectUpdated)
806            {
807                ObjectAccessor::Instance().AddUpdateObject(this);
808                m_objectUpdated = true;
809            }
810        }
811    }
812}
813
814void Object::SetByteValue( uint16 index, uint8 offset, uint8 value )
815{
816    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
817
818    if(offset > 4)
819    {
820        sLog.outError("Object::SetByteValue: wrong offset %u", offset);
821        return;
822    }
823
824    if(uint8(m_uint32Values[ index ] >> (offset * 8)) != value)
825    {
826        m_uint32Values[ index ] &= ~uint32(uint32(0xFF) << (offset * 8));
827        m_uint32Values[ index ] |= uint32(uint32(value) << (offset * 8));
828
829        if(m_inWorld)
830        {
831            if(!m_objectUpdated)
832            {
833                ObjectAccessor::Instance().AddUpdateObject(this);
834                m_objectUpdated = true;
835            }
836        }
837    }
838}
839
840void Object::SetUInt16Value( uint16 index, uint8 offset, uint16 value )
841{
842    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
843
844    if(offset > 2)
845    {
846        sLog.outError("Object::SetUInt16Value: wrong offset %u", offset);
847        return;
848    }
849
850    if(uint8(m_uint32Values[ index ] >> (offset * 16)) != value)
851    {
852        m_uint32Values[ index ] &= ~uint32(uint32(0xFFFF) << (offset * 16));
853        m_uint32Values[ index ] |= uint32(uint32(value) << (offset * 16));
854
855        if(m_inWorld)
856        {
857            if(!m_objectUpdated)
858            {
859                ObjectAccessor::Instance().AddUpdateObject(this);
860                m_objectUpdated = true;
861            }
862        }
863    }
864}
865
866void Object::SetStatFloatValue( uint16 index, float value)
867{
868    if(value < 0)
869        value = 0.0f;
870
871    SetFloatValue(index, value);
872}
873
874void Object::SetStatInt32Value( uint16 index, int32 value)
875{
876    if(value < 0)
877        value = 0;
878
879    SetUInt32Value(index, uint32(value));
880}
881
882void Object::ApplyModUInt32Value(uint16 index, int32 val, bool apply)
883{
884    int32 cur = GetUInt32Value(index);
885    cur += (apply ? val : -val);
886    if(cur < 0)
887        cur = 0;
888    SetUInt32Value(index,cur);
889}
890
891void Object::ApplyModInt32Value(uint16 index, int32 val, bool apply)
892{
893    int32 cur = GetInt32Value(index);
894    cur += (apply ? val : -val);
895    SetInt32Value(index,cur);
896}
897
898void Object::ApplyModSignedFloatValue(uint16 index, float  val, bool apply)
899{
900    float cur = GetFloatValue(index);
901    cur += (apply ? val : -val);
902    SetFloatValue(index,cur);
903}
904
905void Object::ApplyModPositiveFloatValue(uint16 index, float  val, bool apply)
906{
907    float cur = GetFloatValue(index);
908    cur += (apply ? val : -val);
909    if(cur < 0)
910        cur = 0;
911    SetFloatValue(index,cur);
912}
913
914void Object::SetFlag( uint16 index, uint32 newFlag )
915{
916    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
917    uint32 oldval = m_uint32Values[ index ];
918    uint32 newval = oldval | newFlag;
919
920    if(oldval != newval)
921    {
922        m_uint32Values[ index ] = newval;
923
924        if(m_inWorld)
925        {
926            if(!m_objectUpdated)
927            {
928                ObjectAccessor::Instance().AddUpdateObject(this);
929                m_objectUpdated = true;
930            }
931        }
932    }
933}
934
935void Object::RemoveFlag( uint16 index, uint32 oldFlag )
936{
937    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
938    uint32 oldval = m_uint32Values[ index ];
939    uint32 newval = oldval & ~oldFlag;
940
941    if(oldval != newval)
942    {
943        m_uint32Values[ index ] = newval;
944
945        if(m_inWorld)
946        {
947            if(!m_objectUpdated)
948            {
949                ObjectAccessor::Instance().AddUpdateObject(this);
950                m_objectUpdated = true;
951            }
952        }
953    }
954}
955
956bool Object::PrintIndexError(uint32 index, bool set) const
957{
958    sLog.outError("ERROR: Attempt %s non-existed value field: %u (count: %u) for object typeid: %u type mask: %u",(set ? "set value to" : "get value from"),index,m_valuesCount,GetTypeId(),m_objectType);
959
960    // assert must fail after function call
961    return false;
962}
963
964WorldObject::WorldObject()
965{
966    m_positionX         = 0.0f;
967    m_positionY         = 0.0f;
968    m_positionZ         = 0.0f;
969    m_orientation       = 0.0f;
970
971    m_mapId             = 0;
972    m_InstanceId        = 0;
973
974    m_name = "";
975
976    mSemaphoreTeleport  = false;
977
978    m_isActive          = false;
979}
980
981WorldObject::~WorldObject()
982{
983    if(m_isActive && IsInWorld())
984        ObjectAccessor::Instance().RemoveActiveObject(this);
985}
986
987void WorldObject::setActive(bool isActive)
988{
989    // if already in the same activity state as we try to set, do nothing
990    if(isActive == m_isActive)
991        return;
992    m_isActive = isActive;
993    if(IsInWorld())
994    {
995        if(isActive)
996            ObjectAccessor::Instance().AddActiveObject(this);
997        else
998            ObjectAccessor::Instance().RemoveActiveObject(this);
999    }
1000}
1001
1002void WorldObject::AddToWorld()
1003{
1004    Object::AddToWorld();
1005    if(m_isActive)
1006        ObjectAccessor::Instance().AddActiveObject(this);
1007}
1008
1009void WorldObject::RemoveFromWorld()
1010{
1011    if(m_isActive)
1012        ObjectAccessor::Instance().RemoveActiveObject(this);
1013    Object::RemoveFromWorld();
1014}
1015
1016void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid )
1017{
1018    Object::_Create(guidlow, 0, guidhigh);
1019
1020    m_mapId = mapid;
1021}
1022
1023uint32 WorldObject::GetZoneId() const
1024{
1025    return MapManager::Instance().GetBaseMap(m_mapId)->GetZoneId(m_positionX,m_positionY);
1026}
1027
1028uint32 WorldObject::GetAreaId() const
1029{
1030    return MapManager::Instance().GetBaseMap(m_mapId)->GetAreaId(m_positionX,m_positionY);
1031}
1032
1033InstanceData* WorldObject::GetInstanceData()
1034{
1035    Map *map = MapManager::Instance().GetMap(m_mapId, this);
1036    return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL;
1037}
1038
1039                                                            //slow
1040float WorldObject::GetDistance(const WorldObject* obj) const
1041{
1042    float dx = GetPositionX() - obj->GetPositionX();
1043    float dy = GetPositionY() - obj->GetPositionY();
1044    float dz = GetPositionZ() - obj->GetPositionZ();
1045    float sizefactor = GetObjectSize() + obj->GetObjectSize();
1046    float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
1047    return ( dist > 0 ? dist : 0);
1048}
1049
1050float WorldObject::GetDistance2d(float x, float y) const
1051{
1052    float dx = GetPositionX() - x;
1053    float dy = GetPositionY() - y;
1054    float sizefactor = GetObjectSize();
1055    float dist = sqrt((dx*dx) + (dy*dy)) - sizefactor;
1056    return ( dist > 0 ? dist : 0);
1057}
1058
1059float WorldObject::GetDistance(const float x, const float y, const float z) const
1060{
1061    float dx = GetPositionX() - x;
1062    float dy = GetPositionY() - y;
1063    float dz = GetPositionZ() - z;
1064    float sizefactor = GetObjectSize();
1065    float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
1066    return ( dist > 0 ? dist : 0);
1067}
1068
1069float WorldObject::GetDistance2d(const WorldObject* obj) const
1070{
1071    float dx = GetPositionX() - obj->GetPositionX();
1072    float dy = GetPositionY() - obj->GetPositionY();
1073    float sizefactor = GetObjectSize() + obj->GetObjectSize();
1074    float dist = sqrt((dx*dx) + (dy*dy)) - sizefactor;
1075    return ( dist > 0 ? dist : 0);
1076}
1077
1078float WorldObject::GetDistanceZ(const WorldObject* obj) const
1079{
1080    float dz = fabs(GetPositionZ() - obj->GetPositionZ());
1081    float sizefactor = GetObjectSize() + obj->GetObjectSize();
1082    float dist = dz - sizefactor;
1083    return ( dist > 0 ? dist : 0);
1084}
1085
1086bool WorldObject::IsWithinDistInMap(const WorldObject* obj, const float dist2compare) const
1087{
1088    if (!obj || !IsInMap(obj)) return false;
1089
1090    float dx = GetPositionX() - obj->GetPositionX();
1091    float dy = GetPositionY() - obj->GetPositionY();
1092    float dz = GetPositionZ() - obj->GetPositionZ();
1093    float distsq = dx*dx + dy*dy + dz*dz;
1094    float sizefactor = GetObjectSize() + obj->GetObjectSize();
1095    float maxdist = dist2compare + sizefactor;
1096
1097    return distsq < maxdist * maxdist;
1098}
1099
1100bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
1101{
1102    if (!IsInMap(obj)) return false;
1103    float ox,oy,oz;
1104    obj->GetPosition(ox,oy,oz);
1105    return(IsWithinLOS(ox, oy, oz ));
1106}
1107
1108bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) const
1109{
1110    float x,y,z;
1111    GetPosition(x,y,z);
1112    VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
1113    return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);
1114}
1115
1116float WorldObject::GetAngle(const WorldObject* obj) const
1117{
1118    if(!obj) return 0;
1119    return GetAngle( obj->GetPositionX(), obj->GetPositionY() );
1120}
1121
1122// Return angle in range 0..2*pi
1123float WorldObject::GetAngle( const float x, const float y ) const
1124{
1125    float dx = x - GetPositionX();
1126    float dy = y - GetPositionY();
1127
1128    float ang = atan2(dy, dx);
1129    ang = (ang >= 0) ? ang : 2 * M_PI + ang;
1130    return ang;
1131}
1132
1133bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
1134{
1135    float arc = arcangle;
1136
1137    // move arc to range 0.. 2*pi
1138    while( arc >= 2.0f * M_PI )
1139        arc -=  2.0f * M_PI;
1140    while( arc < 0 )
1141        arc +=  2.0f * M_PI;
1142
1143    float angle = GetAngle( obj );
1144    angle -= m_orientation;
1145
1146    // move angle to range -pi ... +pi
1147    while( angle > M_PI)
1148        angle -= 2.0f * M_PI;
1149    while(angle < -M_PI)
1150        angle += 2.0f * M_PI;
1151
1152    float lborder =  -1 * (arc/2.0f);                       // in range -pi..0
1153    float rborder = (arc/2.0f);                             // in range 0..pi
1154    return (( angle >= lborder ) && ( angle <= rborder ));
1155}
1156
1157void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const
1158{
1159    if(distance==0)
1160    {
1161        rand_x = x;
1162        rand_y = y;
1163        rand_z = z;
1164        return;
1165    }
1166
1167    // angle to face `obj` to `this`
1168    float angle = rand_norm()*2*M_PI;
1169    float new_dist = rand_norm()*distance;
1170
1171    rand_x = x + new_dist * cos(angle);
1172    rand_y = y + new_dist * sin(angle);
1173    rand_z = z;
1174
1175    Trinity::NormalizeMapCoord(rand_x);
1176    Trinity::NormalizeMapCoord(rand_y);
1177    UpdateGroundPositionZ(rand_x,rand_y,rand_z);            // update to LOS height if available
1178}
1179
1180void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const
1181{
1182    float new_z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(x,y,z,true);
1183    if(new_z > INVALID_HEIGHT)
1184        z = new_z+ 0.05f;                                   // just to be sure that we are not a few pixel under the surface
1185}
1186
1187bool WorldObject::IsPositionValid() const
1188{
1189    return Trinity::IsValidMapCoord(m_positionX,m_positionY,m_positionZ,m_orientation);
1190}
1191
1192void WorldObject::MonsterSay(const char* text, uint32 language, uint64 TargetGuid)
1193{
1194    WorldPacket data(SMSG_MESSAGECHAT, 200);
1195    BuildMonsterChat(&data,CHAT_MSG_MONSTER_SAY,text,language,GetName(),TargetGuid);
1196    SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),true);
1197}
1198
1199void WorldObject::MonsterYell(const char* text, uint32 language, uint64 TargetGuid)
1200{
1201    WorldPacket data(SMSG_MESSAGECHAT, 200);
1202    BuildMonsterChat(&data,CHAT_MSG_MONSTER_YELL,text,language,GetName(),TargetGuid);
1203    SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),true);
1204}
1205
1206void WorldObject::MonsterTextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote)
1207{
1208    WorldPacket data(SMSG_MESSAGECHAT, 200);
1209    BuildMonsterChat(&data,IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE,text,LANG_UNIVERSAL,GetName(),TargetGuid);
1210    SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
1211}
1212
1213void WorldObject::MonsterWhisper(const char* text, uint64 receiver, bool IsBossWhisper)
1214{
1215    Player *player = objmgr.GetPlayer(receiver);
1216    if(!player || !player->GetSession())
1217        return;
1218
1219    WorldPacket data(SMSG_MESSAGECHAT, 200);
1220    BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
1221
1222    player->GetSession()->SendPacket(&data);
1223}
1224
1225void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf)
1226{
1227    WorldPacket data(SMSG_PLAY_SOUND, 4);
1228    data << Sound;
1229    if (OnlySelf && GetTypeId() == TYPEID_PLAYER )
1230        ((Player*)this)->GetSession()->SendPacket( &data );
1231    else
1232        SendMessageToSet( &data, true ); // ToSelf ignored in this case
1233}
1234
1235namespace Trinity
1236{
1237    class MessageChatLocaleCacheDo
1238    {
1239        public:
1240            MessageChatLocaleCacheDo(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, uint64 targetGUID, float dist)
1241                : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), 
1242                i_targetGUID(targetGUID), i_dist(dist)
1243            {
1244            }
1245
1246            ~MessageChatLocaleCacheDo()
1247            {
1248                for(int i = 0; i < i_data_cache.size(); ++i)
1249                    delete i_data_cache[i];
1250            }
1251
1252            void operator()(Player* p)
1253            {
1254                // skip far away players
1255                if(p->GetDistance(&i_object) > i_dist)
1256                    return;
1257
1258                uint32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex();
1259                uint32 cache_idx = loc_idx+1;
1260                WorldPacket* data;
1261
1262                // create if not cached yet
1263                if(i_data_cache.size() < cache_idx+1 || !i_data_cache[cache_idx])
1264                {
1265                    if(i_data_cache.size() < cache_idx+1)
1266                        i_data_cache.resize(cache_idx+1);
1267
1268                    char const* text = objmgr.GetTrinityString(i_textId,loc_idx);
1269
1270                    data = new WorldPacket(SMSG_MESSAGECHAT, 200);
1271
1272                    // TODO: i_object.GetName() also must be localized?
1273                    i_object.BuildMonsterChat(data,i_msgtype,text,i_language,i_object.GetName(),i_targetGUID);
1274
1275                    i_data_cache[cache_idx] = data;
1276                }
1277                else
1278                    data = i_data_cache[cache_idx];
1279
1280                p->SendDirectMessage(data);
1281            }
1282
1283        private:
1284            WorldObject const& i_object;
1285            ChatMsg i_msgtype;
1286            int32 i_textId;
1287            uint32 i_language;
1288            uint64 i_targetGUID;
1289            float i_dist;
1290            std::vector<WorldPacket*> i_data_cache;             // 0 = default, i => i-1 locale index
1291    };
1292}                                                           // namespace Trinity
1293
1294void WorldObject::MonsterSay(int32 textId, uint32 language, uint64 TargetGuid)
1295{
1296    CellPair p = Trinity::ComputeCellPair(GetPositionX(), GetPositionY());
1297
1298    Cell cell(p);
1299    cell.data.Part.reserved = ALL_DISTRICT;
1300    cell.SetNoCreate();
1301
1302    Trinity::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY));
1303    Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
1304    TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
1305    CellLock<GridReadGuard> cell_lock(cell, p);
1306    cell_lock->Visit(cell_lock, message, *GetMap());
1307}
1308
1309void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid)
1310{
1311    CellPair p = Trinity::ComputeCellPair(GetPositionX(), GetPositionY());
1312
1313    Cell cell(p);
1314    cell.data.Part.reserved = ALL_DISTRICT;
1315    cell.SetNoCreate();
1316
1317    Trinity::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL));
1318    Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
1319    TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
1320    CellLock<GridReadGuard> cell_lock(cell, p);
1321    cell_lock->Visit(cell_lock, message, *GetMap());
1322}
1323
1324void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote)
1325{
1326    CellPair p = Trinity::ComputeCellPair(GetPositionX(), GetPositionY());
1327
1328    Cell cell(p);
1329    cell.data.Part.reserved = ALL_DISTRICT;
1330    cell.SetNoCreate();
1331
1332    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));
1333    Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
1334    TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
1335    CellLock<GridReadGuard> cell_lock(cell, p);
1336    cell_lock->Visit(cell_lock, message, *GetMap());
1337}
1338
1339void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisper)
1340{
1341    Player *player = objmgr.GetPlayer(receiver);
1342    if(!player || !player->GetSession())
1343        return;
1344
1345    uint32 loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
1346    char const* text = objmgr.GetTrinityString(textId,loc_idx);
1347
1348    WorldPacket data(SMSG_MESSAGECHAT, 200);
1349    BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
1350
1351    player->GetSession()->SendPacket(&data);
1352}
1353
1354void WorldObject::BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const* text, uint32 language, char const* name, uint64 targetGuid) const
1355{
1356    bool pre = (msgtype==CHAT_MSG_MONSTER_EMOTE || msgtype==CHAT_MSG_RAID_BOSS_EMOTE);
1357
1358    *data << (uint8)msgtype;
1359    *data << (uint32)language;
1360    *data << (uint64)GetGUID();
1361    *data << (uint32)0;                                     //2.1.0
1362    *data << (uint32)(strlen(name)+1);
1363    *data << name;
1364    *data << (uint64)targetGuid;                            //Unit Target
1365    if( targetGuid && !IS_PLAYER_GUID(targetGuid) )
1366    {
1367        *data << (uint32)1;                                 // target name length
1368        *data << (uint8)0;                                  // target name
1369    }
1370    *data << (uint32)(strlen(text)+1+(pre?3:0));
1371    if(pre)
1372        data->append("%s ",3);
1373    *data << text;
1374    *data << (uint8)0;                                      // ChatTag
1375}
1376
1377void WorldObject::BuildHeartBeatMsg(WorldPacket *data) const
1378{
1379    //Heartbeat message cannot be used for non-units
1380    if (!isType(TYPEMASK_UNIT))
1381        return;
1382
1383    data->Initialize(MSG_MOVE_HEARTBEAT, 32);
1384    data->append(GetPackGUID());
1385    *data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
1386    *data << uint8(0);                                      // 2.3.0
1387    *data << getMSTime();                                   // time
1388    *data << m_positionX;
1389    *data << m_positionY;
1390    *data << m_positionZ;
1391    *data << m_orientation;
1392    *data << uint32(0);
1393}
1394
1395void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float z, float ang) const
1396{
1397    //TeleportAck message cannot be used for non-units
1398    if (!isType(TYPEMASK_UNIT))
1399        return;
1400
1401    data->Initialize(MSG_MOVE_TELEPORT_ACK, 41);
1402    data->append(GetPackGUID());
1403    *data << uint32(0);                                     // this value increments every time
1404    *data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
1405    *data << uint8(0);                                      // 2.3.0
1406    *data << getMSTime();                                   // time
1407    *data << x;
1408    *data << y;
1409    *data << z;
1410    *data << ang;
1411    *data << uint32(0);
1412}
1413
1414void WorldObject::SendMessageToSet(WorldPacket *data, bool /*bToSelf*/)
1415{
1416    MapManager::Instance().GetMap(m_mapId, this)->MessageBroadcast(this, data);
1417}
1418
1419void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/)
1420{
1421    MapManager::Instance().GetMap(m_mapId, this)->MessageDistBroadcast(this, data, dist);
1422}
1423
1424void WorldObject::SendObjectDeSpawnAnim(uint64 guid)
1425{
1426    WorldPacket data(SMSG_GAMEOBJECT_DESPAWN_ANIM, 8);
1427    data << guid;
1428    SendMessageToSet(&data, true);
1429}
1430
1431Map* WorldObject::GetMap() const
1432{
1433    return MapManager::Instance().GetMap(GetMapId(), this);
1434}
1435
1436Map const* WorldObject::GetBaseMap() const
1437{
1438    return MapManager::Instance().GetBaseMap(GetMapId());
1439}
1440
1441void WorldObject::AddObjectToRemoveList()
1442{
1443    Map* map = GetMap();
1444    if(!map)
1445    {
1446        sLog.outError("Object (TypeId: %u Entry: %u GUID: %u) at attempt add to move list not have valid map (Id: %u).",GetTypeId(),GetEntry(),GetGUIDLow(),GetMapId());
1447        return;
1448    }
1449
1450    map->AddObjectToRemoveList(this);
1451}
1452
1453Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
1454{
1455    TemporarySummon* pCreature = new TemporarySummon(GetGUID());
1456
1457    pCreature->SetInstanceId(GetInstanceId());
1458    uint32 team = 0;
1459    if (GetTypeId()==TYPEID_PLAYER)
1460        team = ((Player*)this)->GetTeam();
1461
1462    if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMap(), id, team))
1463    {
1464        delete pCreature;
1465        return NULL;
1466    }
1467
1468    if (x == 0.0f && y == 0.0f && z == 0.0f)
1469        GetClosePoint(x, y, z, pCreature->GetObjectSize());
1470
1471    pCreature->Relocate(x, y, z, ang);
1472
1473    if(!pCreature->IsPositionValid())
1474    {
1475        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());
1476        delete pCreature;
1477        return NULL;
1478    }
1479
1480    pCreature->Summon(spwtype, despwtime);
1481
1482    if(GetTypeId()==TYPEID_UNIT && ((Creature*)this)->AI())
1483        ((Creature*)this)->AI()->JustSummoned(pCreature);
1484
1485    if(pCreature->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER && pCreature->m_spells[0])
1486        pCreature->CastSpell(pCreature, pCreature->m_spells[0], true, 0, 0, GetGUID());
1487
1488    //return the creature therewith the summoner has access to it
1489    return pCreature;
1490}
1491
1492GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
1493{
1494    if(!IsInWorld())
1495        return NULL;
1496    Map * map = GetMap();
1497    if(!map)
1498        return NULL;
1499    GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry);
1500    if(!goinfo)
1501    {
1502        sLog.outErrorDb("Gameobject template %u not found in database!", entry);
1503        return NULL;
1504    }
1505    GameObject *go = new GameObject();
1506    if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry,map,x,y,z,ang,rotation0,rotation1,rotation2,rotation3,100,1))
1507        return NULL;
1508    go->SetRespawnTime(respawnTime);
1509    if(GetTypeId()==TYPEID_PLAYER || GetTypeId()==TYPEID_UNIT) //not sure how to handle this
1510        ((Unit*)this)->AddGameObject(go);
1511    else
1512        go->SetSpawnedByDefault(false);
1513    map->Add(go);
1514
1515    return go;
1516}
1517
1518void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const
1519{
1520    x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle);
1521    y = GetPositionY() + (GetObjectSize() + distance2d) * sin(absAngle);
1522
1523    Trinity::NormalizeMapCoord(x);
1524    Trinity::NormalizeMapCoord(y);
1525}
1526
1527void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle ) const
1528{
1529    GetNearPoint2D(x,y,distance2d+searcher_size,absAngle);
1530   
1531        z = GetPositionZ();
1532
1533        UpdateGroundPositionZ(x,y,z);
1534}
1535
1536void WorldObject::GetRandomContactPoint( const WorldObject* obj, float &x, float &y, float &z, float distance2dMin, float distance2dMax ) const
1537{
1538        float object_size = obj->GetObjectSize();//here we use object_size to determine the angle offset, the bigger object the smaller angle offset, then this makes mob move naturally in visual.
1539        //let assume 12.0f is the max size for object to have 0 angle offset.
1540        float angle_offset_ratio = 1 - object_size/12.0f;
1541        if (angle_offset_ratio < 0.05) angle_offset_ratio = 0.05;
1542        // angle to face `obj` to `this`plus a random angle offset(from -90 degree to 90 degree)*angle_offset_ratio using distance from distance2dMin to distance2dMax includes size of `obj`
1543        GetNearPoint(obj,x,y,z,object_size,distance2dMin+(distance2dMax-distance2dMin)*rand_norm(), GetAngle( obj ) + (M_PI/2 - M_PI * rand_norm()) * angle_offset_ratio);
1544}
Note: See TracBrowser for help on using the browser.