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

Revision 203, 49.4 kB (checked in by yumileroy, 17 years ago)

[svn] Send AttackStart? package when update visibility.
Update DoMeleeAttackIfReady? to support dual wield.
Show player modelid2 instead id3 of triggers. This should fix the bug that gameobject::castspell summon a human model.
Remove the correct flag to make creature attackable. This should fix the bug that Illidan and Magtheridon are unattackable.
Add NullCreatureAI for trinityscript.
Fix channeler's soul transfer.
Some update of black temple scripts.

Original author: megamage
Date: 2008-11-09 14:54:13-06: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                        {
605                            if(cinfo->Modelid2)
606                                *data << cinfo->Modelid1;
607                            else
608                                *data << 17519; // world invisible trigger's model
609                        }
610                        else
611                        {
612                            if(cinfo->Modelid2)
613                                *data << cinfo->Modelid2;
614                            else
615                                *data << 11686; // world invisible trigger's model
616                        }
617                    }
618                    else
619                        *data << m_uint32Values[ index ];
620                }
621                // hide lootable animation for unallowed players
622                else if(index == UNIT_DYNAMIC_FLAGS && GetTypeId() == TYPEID_UNIT)
623                {
624                    if(!target->isAllowedToLoot((Creature*)this))
625                        *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_LOOTABLE);
626                    else
627                        *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_OTHER_TAGGER);
628                }
629                else
630                {
631                    // send in current format (float as float, uint32 as uint32)
632                    *data << m_uint32Values[ index ];
633                }
634            }
635        }
636    }
637    else if(isType(TYPEMASK_GAMEOBJECT))                    // gameobject case
638    {
639        for( uint16 index = 0; index < m_valuesCount; index ++ )
640        {
641            if( updateMask->GetBit( index ) )
642            {
643                // send in current format (float as float, uint32 as uint32)
644                if ( index == GAMEOBJECT_DYN_FLAGS )
645                {
646                    if(IsActivateToQuest )
647                    {
648                        switch(((GameObject*)this)->GetGoType())
649                        {
650                            case GAMEOBJECT_TYPE_CHEST:
651                                *data << uint32(9);         // enable quest object. Represent 9, but 1 for client before 2.3.0
652                                break;
653                            case GAMEOBJECT_TYPE_GOOBER:
654                                *data << uint32(1);
655                                break;
656                            default:
657                                *data << uint32(0);         //unknown. not happen.
658                                break;
659                        }
660                    }
661                    else
662                        *data << uint32(0);                 // disable quest object
663                }
664                else
665                    *data << m_uint32Values[ index ];       // other cases
666            }
667        }
668    }
669    else                                                    // other objects case (no special index checks)
670    {
671        for( uint16 index = 0; index < m_valuesCount; index ++ )
672        {
673            if( updateMask->GetBit( index ) )
674            {
675                // send in current format (float as float, uint32 as uint32)
676                *data << m_uint32Values[ index ];
677            }
678        }
679    }
680}
681
682void Object::ClearUpdateMask(bool remove)
683{
684    for( uint16 index = 0; index < m_valuesCount; index ++ )
685    {
686        if(m_uint32Values_mirror[index]!= m_uint32Values[index])
687            m_uint32Values_mirror[index] = m_uint32Values[index];
688    }
689    if(m_objectUpdated)
690    {
691        if(remove)
692            ObjectAccessor::Instance().RemoveUpdateObject(this);
693        m_objectUpdated = false;
694    }
695}
696
697// Send current value fields changes to all viewers
698void Object::SendUpdateObjectToAllExcept(Player* exceptPlayer)
699{
700    // changes will be send in create packet
701    if(!IsInWorld())
702        return;
703
704    // nothing do
705    if(!m_objectUpdated)
706        return;
707
708    ObjectAccessor::UpdateObject(this,exceptPlayer);
709}
710
711bool Object::LoadValues(const char* data)
712{
713    if(!m_uint32Values) _InitValues();
714
715    Tokens tokens = StrSplit(data, " ");
716
717    if(tokens.size() != m_valuesCount)
718        return false;
719
720    Tokens::iterator iter;
721    int index;
722    for (iter = tokens.begin(), index = 0; index < m_valuesCount; ++iter, ++index)
723    {
724        m_uint32Values[index] = atol((*iter).c_str());
725    }
726
727    return true;
728}
729
730void Object::_SetUpdateBits(UpdateMask *updateMask, Player* /*target*/) const
731{
732    for( uint16 index = 0; index < m_valuesCount; index ++ )
733    {
734        if(m_uint32Values_mirror[index]!= m_uint32Values[index])
735            updateMask->SetBit(index);
736    }
737}
738
739void Object::_SetCreateBits(UpdateMask *updateMask, Player* /*target*/) const
740{
741    for( uint16 index = 0; index < m_valuesCount; index++ )
742    {
743        if(GetUInt32Value(index) != 0)
744            updateMask->SetBit(index);
745    }
746}
747
748void Object::SetInt32Value( uint16 index, int32 value )
749{
750    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
751
752    if(m_int32Values[ index ] != value)
753    {
754        m_int32Values[ index ] = value;
755
756        if(m_inWorld)
757        {
758            if(!m_objectUpdated)
759            {
760                ObjectAccessor::Instance().AddUpdateObject(this);
761                m_objectUpdated = true;
762            }
763        }
764    }
765}
766
767void Object::SetUInt32Value( uint16 index, uint32 value )
768{
769    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
770
771    if(m_uint32Values[ index ] != value)
772    {
773        m_uint32Values[ index ] = value;
774
775        if(m_inWorld)
776        {
777            if(!m_objectUpdated)
778            {
779                ObjectAccessor::Instance().AddUpdateObject(this);
780                m_objectUpdated = true;
781            }
782        }
783    }
784}
785
786void Object::SetUInt64Value( uint16 index, const uint64 &value )
787{
788    ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
789    if(*((uint64*)&(m_uint32Values[ index ])) != value)
790    {
791        m_uint32Values[ index ] = *((uint32*)&value);
792        m_uint32Values[ index + 1 ] = *(((uint32*)&value) + 1);
793
794        if(m_inWorld)
795        {
796            if(!m_objectUpdated)
797            {
798                ObjectAccessor::Instance().AddUpdateObject(this);
799                m_objectUpdated = true;
800            }
801        }
802    }
803}
804
805void Object::SetFloatValue( uint16 index, float value )
806{
807    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
808
809    if(m_floatValues[ index ] != value)
810    {
811        m_floatValues[ index ] = value;
812
813        if(m_inWorld)
814        {
815            if(!m_objectUpdated)
816            {
817                ObjectAccessor::Instance().AddUpdateObject(this);
818                m_objectUpdated = true;
819            }
820        }
821    }
822}
823
824void Object::SetByteValue( uint16 index, uint8 offset, uint8 value )
825{
826    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
827
828    if(offset > 4)
829    {
830        sLog.outError("Object::SetByteValue: wrong offset %u", offset);
831        return;
832    }
833
834    if(uint8(m_uint32Values[ index ] >> (offset * 8)) != value)
835    {
836        m_uint32Values[ index ] &= ~uint32(uint32(0xFF) << (offset * 8));
837        m_uint32Values[ index ] |= uint32(uint32(value) << (offset * 8));
838
839        if(m_inWorld)
840        {
841            if(!m_objectUpdated)
842            {
843                ObjectAccessor::Instance().AddUpdateObject(this);
844                m_objectUpdated = true;
845            }
846        }
847    }
848}
849
850void Object::SetUInt16Value( uint16 index, uint8 offset, uint16 value )
851{
852    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
853
854    if(offset > 2)
855    {
856        sLog.outError("Object::SetUInt16Value: wrong offset %u", offset);
857        return;
858    }
859
860    if(uint8(m_uint32Values[ index ] >> (offset * 16)) != value)
861    {
862        m_uint32Values[ index ] &= ~uint32(uint32(0xFFFF) << (offset * 16));
863        m_uint32Values[ index ] |= uint32(uint32(value) << (offset * 16));
864
865        if(m_inWorld)
866        {
867            if(!m_objectUpdated)
868            {
869                ObjectAccessor::Instance().AddUpdateObject(this);
870                m_objectUpdated = true;
871            }
872        }
873    }
874}
875
876void Object::SetStatFloatValue( uint16 index, float value)
877{
878    if(value < 0)
879        value = 0.0f;
880
881    SetFloatValue(index, value);
882}
883
884void Object::SetStatInt32Value( uint16 index, int32 value)
885{
886    if(value < 0)
887        value = 0;
888
889    SetUInt32Value(index, uint32(value));
890}
891
892void Object::ApplyModUInt32Value(uint16 index, int32 val, bool apply)
893{
894    int32 cur = GetUInt32Value(index);
895    cur += (apply ? val : -val);
896    if(cur < 0)
897        cur = 0;
898    SetUInt32Value(index,cur);
899}
900
901void Object::ApplyModInt32Value(uint16 index, int32 val, bool apply)
902{
903    int32 cur = GetInt32Value(index);
904    cur += (apply ? val : -val);
905    SetInt32Value(index,cur);
906}
907
908void Object::ApplyModSignedFloatValue(uint16 index, float  val, bool apply)
909{
910    float cur = GetFloatValue(index);
911    cur += (apply ? val : -val);
912    SetFloatValue(index,cur);
913}
914
915void Object::ApplyModPositiveFloatValue(uint16 index, float  val, bool apply)
916{
917    float cur = GetFloatValue(index);
918    cur += (apply ? val : -val);
919    if(cur < 0)
920        cur = 0;
921    SetFloatValue(index,cur);
922}
923
924void Object::SetFlag( uint16 index, uint32 newFlag )
925{
926    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
927    uint32 oldval = m_uint32Values[ index ];
928    uint32 newval = oldval | newFlag;
929
930    if(oldval != newval)
931    {
932        m_uint32Values[ index ] = newval;
933
934        if(m_inWorld)
935        {
936            if(!m_objectUpdated)
937            {
938                ObjectAccessor::Instance().AddUpdateObject(this);
939                m_objectUpdated = true;
940            }
941        }
942    }
943}
944
945void Object::RemoveFlag( uint16 index, uint32 oldFlag )
946{
947    ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
948    uint32 oldval = m_uint32Values[ index ];
949    uint32 newval = oldval & ~oldFlag;
950
951    if(oldval != newval)
952    {
953        m_uint32Values[ index ] = newval;
954
955        if(m_inWorld)
956        {
957            if(!m_objectUpdated)
958            {
959                ObjectAccessor::Instance().AddUpdateObject(this);
960                m_objectUpdated = true;
961            }
962        }
963    }
964}
965
966bool Object::PrintIndexError(uint32 index, bool set) const
967{
968    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);
969
970    // assert must fail after function call
971    return false;
972}
973
974WorldObject::WorldObject()
975{
976    m_positionX         = 0.0f;
977    m_positionY         = 0.0f;
978    m_positionZ         = 0.0f;
979    m_orientation       = 0.0f;
980
981    m_mapId             = 0;
982    m_InstanceId        = 0;
983
984    m_name = "";
985
986    mSemaphoreTeleport  = false;
987
988    m_isActive          = false;
989}
990
991WorldObject::~WorldObject()
992{
993    if(m_isActive && IsInWorld())
994        ObjectAccessor::Instance().RemoveActiveObject(this);
995}
996
997void WorldObject::setActive(bool isActive)
998{
999    // if already in the same activity state as we try to set, do nothing
1000    if(isActive == m_isActive)
1001        return;
1002    m_isActive = isActive;
1003    if(IsInWorld())
1004    {
1005        if(isActive)
1006            ObjectAccessor::Instance().AddActiveObject(this);
1007        else
1008            ObjectAccessor::Instance().RemoveActiveObject(this);
1009    }
1010}
1011
1012void WorldObject::AddToWorld()
1013{
1014    Object::AddToWorld();
1015    if(m_isActive)
1016        ObjectAccessor::Instance().AddActiveObject(this);
1017}
1018
1019void WorldObject::RemoveFromWorld()
1020{
1021    if(m_isActive)
1022        ObjectAccessor::Instance().RemoveActiveObject(this);
1023    Object::RemoveFromWorld();
1024}
1025
1026void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid )
1027{
1028    Object::_Create(guidlow, 0, guidhigh);
1029
1030    m_mapId = mapid;
1031}
1032
1033uint32 WorldObject::GetZoneId() const
1034{
1035    return MapManager::Instance().GetBaseMap(m_mapId)->GetZoneId(m_positionX,m_positionY);
1036}
1037
1038uint32 WorldObject::GetAreaId() const
1039{
1040    return MapManager::Instance().GetBaseMap(m_mapId)->GetAreaId(m_positionX,m_positionY);
1041}
1042
1043InstanceData* WorldObject::GetInstanceData()
1044{
1045    Map *map = MapManager::Instance().GetMap(m_mapId, this);
1046    return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL;
1047}
1048
1049                                                            //slow
1050float WorldObject::GetDistance(const WorldObject* obj) const
1051{
1052    float dx = GetPositionX() - obj->GetPositionX();
1053    float dy = GetPositionY() - obj->GetPositionY();
1054    float dz = GetPositionZ() - obj->GetPositionZ();
1055    float sizefactor = GetObjectSize() + obj->GetObjectSize();
1056    float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
1057    return ( dist > 0 ? dist : 0);
1058}
1059
1060float WorldObject::GetDistance2d(float x, float y) const
1061{
1062    float dx = GetPositionX() - x;
1063    float dy = GetPositionY() - y;
1064    float sizefactor = GetObjectSize();
1065    float dist = sqrt((dx*dx) + (dy*dy)) - sizefactor;
1066    return ( dist > 0 ? dist : 0);
1067}
1068
1069float WorldObject::GetDistance(const float x, const float y, const float z) const
1070{
1071    float dx = GetPositionX() - x;
1072    float dy = GetPositionY() - y;
1073    float dz = GetPositionZ() - z;
1074    float sizefactor = GetObjectSize();
1075    float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
1076    return ( dist > 0 ? dist : 0);
1077}
1078
1079float WorldObject::GetDistance2d(const WorldObject* obj) const
1080{
1081    float dx = GetPositionX() - obj->GetPositionX();
1082    float dy = GetPositionY() - obj->GetPositionY();
1083    float sizefactor = GetObjectSize() + obj->GetObjectSize();
1084    float dist = sqrt((dx*dx) + (dy*dy)) - sizefactor;
1085    return ( dist > 0 ? dist : 0);
1086}
1087
1088float WorldObject::GetDistanceZ(const WorldObject* obj) const
1089{
1090    float dz = fabs(GetPositionZ() - obj->GetPositionZ());
1091    float sizefactor = GetObjectSize() + obj->GetObjectSize();
1092    float dist = dz - sizefactor;
1093    return ( dist > 0 ? dist : 0);
1094}
1095
1096bool WorldObject::IsWithinDistInMap(const WorldObject* obj, const float dist2compare) const
1097{
1098    if (!obj || !IsInMap(obj)) return false;
1099
1100    float dx = GetPositionX() - obj->GetPositionX();
1101    float dy = GetPositionY() - obj->GetPositionY();
1102    float dz = GetPositionZ() - obj->GetPositionZ();
1103    float distsq = dx*dx + dy*dy + dz*dz;
1104    float sizefactor = GetObjectSize() + obj->GetObjectSize();
1105    float maxdist = dist2compare + sizefactor;
1106
1107    return distsq < maxdist * maxdist;
1108}
1109
1110bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
1111{
1112    if (!IsInMap(obj)) return false;
1113    float ox,oy,oz;
1114    obj->GetPosition(ox,oy,oz);
1115    return(IsWithinLOS(ox, oy, oz ));
1116}
1117
1118bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) const
1119{
1120    float x,y,z;
1121    GetPosition(x,y,z);
1122    VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
1123    return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);
1124}
1125
1126float WorldObject::GetAngle(const WorldObject* obj) const
1127{
1128    if(!obj) return 0;
1129    return GetAngle( obj->GetPositionX(), obj->GetPositionY() );
1130}
1131
1132// Return angle in range 0..2*pi
1133float WorldObject::GetAngle( const float x, const float y ) const
1134{
1135    float dx = x - GetPositionX();
1136    float dy = y - GetPositionY();
1137
1138    float ang = atan2(dy, dx);
1139    ang = (ang >= 0) ? ang : 2 * M_PI + ang;
1140    return ang;
1141}
1142
1143bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
1144{
1145    float arc = arcangle;
1146
1147    // move arc to range 0.. 2*pi
1148    while( arc >= 2.0f * M_PI )
1149        arc -=  2.0f * M_PI;
1150    while( arc < 0 )
1151        arc +=  2.0f * M_PI;
1152
1153    float angle = GetAngle( obj );
1154    angle -= m_orientation;
1155
1156    // move angle to range -pi ... +pi
1157    while( angle > M_PI)
1158        angle -= 2.0f * M_PI;
1159    while(angle < -M_PI)
1160        angle += 2.0f * M_PI;
1161
1162    float lborder =  -1 * (arc/2.0f);                       // in range -pi..0
1163    float rborder = (arc/2.0f);                             // in range 0..pi
1164    return (( angle >= lborder ) && ( angle <= rborder ));
1165}
1166
1167void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const
1168{
1169    if(distance==0)
1170    {
1171        rand_x = x;
1172        rand_y = y;
1173        rand_z = z;
1174        return;
1175    }
1176
1177    // angle to face `obj` to `this`
1178    float angle = rand_norm()*2*M_PI;
1179    float new_dist = rand_norm()*distance;
1180
1181    rand_x = x + new_dist * cos(angle);
1182    rand_y = y + new_dist * sin(angle);
1183    rand_z = z;
1184
1185    Trinity::NormalizeMapCoord(rand_x);
1186    Trinity::NormalizeMapCoord(rand_y);
1187    UpdateGroundPositionZ(rand_x,rand_y,rand_z);            // update to LOS height if available
1188}
1189
1190void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const
1191{
1192    float new_z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(x,y,z,true);
1193    if(new_z > INVALID_HEIGHT)
1194        z = new_z+ 0.05f;                                   // just to be sure that we are not a few pixel under the surface
1195}
1196
1197bool WorldObject::IsPositionValid() const
1198{
1199    return Trinity::IsValidMapCoord(m_positionX,m_positionY,m_positionZ,m_orientation);
1200}
1201
1202void WorldObject::MonsterSay(const char* text, uint32 language, uint64 TargetGuid)
1203{
1204    WorldPacket data(SMSG_MESSAGECHAT, 200);
1205    BuildMonsterChat(&data,CHAT_MSG_MONSTER_SAY,text,language,GetName(),TargetGuid);
1206    SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),true);
1207}
1208
1209void WorldObject::MonsterYell(const char* text, uint32 language, uint64 TargetGuid)
1210{
1211    WorldPacket data(SMSG_MESSAGECHAT, 200);
1212    BuildMonsterChat(&data,CHAT_MSG_MONSTER_YELL,text,language,GetName(),TargetGuid);
1213    SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),true);
1214}
1215
1216void WorldObject::MonsterTextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote)
1217{
1218    WorldPacket data(SMSG_MESSAGECHAT, 200);
1219    BuildMonsterChat(&data,IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE,text,LANG_UNIVERSAL,GetName(),TargetGuid);
1220    SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
1221}
1222
1223void WorldObject::MonsterWhisper(const char* text, uint64 receiver, bool IsBossWhisper)
1224{
1225    Player *player = objmgr.GetPlayer(receiver);
1226    if(!player || !player->GetSession())
1227        return;
1228
1229    WorldPacket data(SMSG_MESSAGECHAT, 200);
1230    BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
1231
1232    player->GetSession()->SendPacket(&data);
1233}
1234
1235void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf)
1236{
1237    WorldPacket data(SMSG_PLAY_SOUND, 4);
1238    data << Sound;
1239    if (OnlySelf && GetTypeId() == TYPEID_PLAYER )
1240        ((Player*)this)->GetSession()->SendPacket( &data );
1241    else
1242        SendMessageToSet( &data, true ); // ToSelf ignored in this case
1243}
1244
1245namespace Trinity
1246{
1247    class MessageChatLocaleCacheDo
1248    {
1249        public:
1250            MessageChatLocaleCacheDo(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, uint64 targetGUID, float dist)
1251                : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), 
1252                i_targetGUID(targetGUID), i_dist(dist)
1253            {
1254            }
1255
1256            ~MessageChatLocaleCacheDo()
1257            {
1258                for(int i = 0; i < i_data_cache.size(); ++i)
1259                    delete i_data_cache[i];
1260            }
1261
1262            void operator()(Player* p)
1263            {
1264                // skip far away players
1265                if(p->GetDistance(&i_object) > i_dist)
1266                    return;
1267
1268                uint32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex();
1269                uint32 cache_idx = loc_idx+1;
1270                WorldPacket* data;
1271
1272                // create if not cached yet
1273                if(i_data_cache.size() < cache_idx+1 || !i_data_cache[cache_idx])
1274                {
1275                    if(i_data_cache.size() < cache_idx+1)
1276                        i_data_cache.resize(cache_idx+1);
1277
1278                    char const* text = objmgr.GetTrinityString(i_textId,loc_idx);
1279
1280                    data = new WorldPacket(SMSG_MESSAGECHAT, 200);
1281
1282                    // TODO: i_object.GetName() also must be localized?
1283                    i_object.BuildMonsterChat(data,i_msgtype,text,i_language,i_object.GetName(),i_targetGUID);
1284
1285                    i_data_cache[cache_idx] = data;
1286                }
1287                else
1288                    data = i_data_cache[cache_idx];
1289
1290                p->SendDirectMessage(data);
1291            }
1292
1293        private:
1294            WorldObject const& i_object;
1295            ChatMsg i_msgtype;
1296            int32 i_textId;
1297            uint32 i_language;
1298            uint64 i_targetGUID;
1299            float i_dist;
1300            std::vector<WorldPacket*> i_data_cache;             // 0 = default, i => i-1 locale index
1301    };
1302}                                                           // namespace Trinity
1303
1304void WorldObject::MonsterSay(int32 textId, uint32 language, uint64 TargetGuid)
1305{
1306    CellPair p = Trinity::ComputeCellPair(GetPositionX(), GetPositionY());
1307
1308    Cell cell(p);
1309    cell.data.Part.reserved = ALL_DISTRICT;
1310    cell.SetNoCreate();
1311
1312    Trinity::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY));
1313    Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
1314    TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
1315    CellLock<GridReadGuard> cell_lock(cell, p);
1316    cell_lock->Visit(cell_lock, message, *GetMap());
1317}
1318
1319void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid)
1320{
1321    CellPair p = Trinity::ComputeCellPair(GetPositionX(), GetPositionY());
1322
1323    Cell cell(p);
1324    cell.data.Part.reserved = ALL_DISTRICT;
1325    cell.SetNoCreate();
1326
1327    Trinity::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL));
1328    Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
1329    TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
1330    CellLock<GridReadGuard> cell_lock(cell, p);
1331    cell_lock->Visit(cell_lock, message, *GetMap());
1332}
1333
1334void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote)
1335{
1336    CellPair p = Trinity::ComputeCellPair(GetPositionX(), GetPositionY());
1337
1338    Cell cell(p);
1339    cell.data.Part.reserved = ALL_DISTRICT;
1340    cell.SetNoCreate();
1341
1342    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));
1343    Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo> say_worker(say_do);
1344    TypeContainerVisitor<Trinity::PlayerWorker<Trinity::MessageChatLocaleCacheDo>, WorldTypeMapContainer > message(say_worker);
1345    CellLock<GridReadGuard> cell_lock(cell, p);
1346    cell_lock->Visit(cell_lock, message, *GetMap());
1347}
1348
1349void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisper)
1350{
1351    Player *player = objmgr.GetPlayer(receiver);
1352    if(!player || !player->GetSession())
1353        return;
1354
1355    uint32 loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
1356    char const* text = objmgr.GetTrinityString(textId,loc_idx);
1357
1358    WorldPacket data(SMSG_MESSAGECHAT, 200);
1359    BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
1360
1361    player->GetSession()->SendPacket(&data);
1362}
1363
1364void WorldObject::BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const* text, uint32 language, char const* name, uint64 targetGuid) const
1365{
1366    bool pre = (msgtype==CHAT_MSG_MONSTER_EMOTE || msgtype==CHAT_MSG_RAID_BOSS_EMOTE);
1367
1368    *data << (uint8)msgtype;
1369    *data << (uint32)language;
1370    *data << (uint64)GetGUID();
1371    *data << (uint32)0;                                     //2.1.0
1372    *data << (uint32)(strlen(name)+1);
1373    *data << name;
1374    *data << (uint64)targetGuid;                            //Unit Target
1375    if( targetGuid && !IS_PLAYER_GUID(targetGuid) )
1376    {
1377        *data << (uint32)1;                                 // target name length
1378        *data << (uint8)0;                                  // target name
1379    }
1380    *data << (uint32)(strlen(text)+1+(pre?3:0));
1381    if(pre)
1382        data->append("%s ",3);
1383    *data << text;
1384    *data << (uint8)0;                                      // ChatTag
1385}
1386
1387void WorldObject::BuildHeartBeatMsg(WorldPacket *data) const
1388{
1389    //Heartbeat message cannot be used for non-units
1390    if (!isType(TYPEMASK_UNIT))
1391        return;
1392
1393    data->Initialize(MSG_MOVE_HEARTBEAT, 32);
1394    data->append(GetPackGUID());
1395    *data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
1396    *data << uint8(0);                                      // 2.3.0
1397    *data << getMSTime();                                   // time
1398    *data << m_positionX;
1399    *data << m_positionY;
1400    *data << m_positionZ;
1401    *data << m_orientation;
1402    *data << uint32(0);
1403}
1404
1405void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float z, float ang) const
1406{
1407    //TeleportAck message cannot be used for non-units
1408    if (!isType(TYPEMASK_UNIT))
1409        return;
1410
1411    data->Initialize(MSG_MOVE_TELEPORT_ACK, 41);
1412    data->append(GetPackGUID());
1413    *data << uint32(0);                                     // this value increments every time
1414    *data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
1415    *data << uint8(0);                                      // 2.3.0
1416    *data << getMSTime();                                   // time
1417    *data << x;
1418    *data << y;
1419    *data << z;
1420    *data << ang;
1421    *data << uint32(0);
1422}
1423
1424void WorldObject::SendMessageToSet(WorldPacket *data, bool /*fake*/, bool bToPossessor)
1425{
1426    MapManager::Instance().GetMap(m_mapId, this)->MessageBroadcast(this, data, bToPossessor);
1427}
1428
1429void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/, bool bToPossessor)
1430{
1431    MapManager::Instance().GetMap(m_mapId, this)->MessageDistBroadcast(this, data, dist, bToPossessor);
1432}
1433
1434void WorldObject::SendObjectDeSpawnAnim(uint64 guid)
1435{
1436    WorldPacket data(SMSG_GAMEOBJECT_DESPAWN_ANIM, 8);
1437    data << guid;
1438    SendMessageToSet(&data, true);
1439}
1440
1441Map* WorldObject::GetMap() const
1442{
1443    return MapManager::Instance().GetMap(GetMapId(), this);
1444}
1445
1446Map const* WorldObject::GetBaseMap() const
1447{
1448    return MapManager::Instance().GetBaseMap(GetMapId());
1449}
1450
1451void WorldObject::AddObjectToRemoveList()
1452{
1453    Map* map = GetMap();
1454    if(!map)
1455    {
1456        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());
1457        return;
1458    }
1459
1460    map->AddObjectToRemoveList(this);
1461}
1462
1463Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
1464{
1465    TemporarySummon* pCreature = new TemporarySummon(GetGUID());
1466
1467    pCreature->SetInstanceId(GetInstanceId());
1468    uint32 team = 0;
1469    if (GetTypeId()==TYPEID_PLAYER)
1470        team = ((Player*)this)->GetTeam();
1471
1472    if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMap(), id, team))
1473    {
1474        delete pCreature;
1475        return NULL;
1476    }
1477
1478    if (x == 0.0f && y == 0.0f && z == 0.0f)
1479        GetClosePoint(x, y, z, pCreature->GetObjectSize());
1480
1481    pCreature->Relocate(x, y, z, ang);
1482
1483    if(!pCreature->IsPositionValid())
1484    {
1485        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());
1486        delete pCreature;
1487        return NULL;
1488    }
1489
1490    pCreature->Summon(spwtype, despwtime);
1491
1492    if(GetTypeId()==TYPEID_UNIT && ((Creature*)this)->AI())
1493        ((Creature*)this)->AI()->JustSummoned(pCreature);
1494
1495    if(pCreature->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER && pCreature->m_spells[0])
1496    {
1497        if(GetTypeId() == TYPEID_UNIT || GetTypeId() == TYPEID_PLAYER)
1498            pCreature->setFaction(((Unit*)this)->getFaction());
1499        pCreature->CastSpell(pCreature, pCreature->m_spells[0], false, 0, 0, GetGUID());
1500    }
1501
1502    //return the creature therewith the summoner has access to it
1503    return pCreature;
1504}
1505
1506GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
1507{
1508    if(!IsInWorld())
1509        return NULL;
1510    Map * map = GetMap();
1511    if(!map)
1512        return NULL;
1513    GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry);
1514    if(!goinfo)
1515    {
1516        sLog.outErrorDb("Gameobject template %u not found in database!", entry);
1517        return NULL;
1518    }
1519    GameObject *go = new GameObject();
1520    if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry,map,x,y,z,ang,rotation0,rotation1,rotation2,rotation3,100,1))
1521        return NULL;
1522    go->SetRespawnTime(respawnTime);
1523    if(GetTypeId()==TYPEID_PLAYER || GetTypeId()==TYPEID_UNIT) //not sure how to handle this
1524        ((Unit*)this)->AddGameObject(go);
1525    else
1526        go->SetSpawnedByDefault(false);
1527    map->Add(go);
1528
1529    return go;
1530}
1531
1532void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const
1533{
1534    x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle);
1535    y = GetPositionY() + (GetObjectSize() + distance2d) * sin(absAngle);
1536
1537    Trinity::NormalizeMapCoord(x);
1538    Trinity::NormalizeMapCoord(y);
1539}
1540
1541void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle ) const
1542{
1543    GetNearPoint2D(x,y,distance2d+searcher_size,absAngle);
1544   
1545        z = GetPositionZ();
1546
1547        UpdateGroundPositionZ(x,y,z);
1548}
Note: See TracBrowser for help on using the browser.