root/trunk/src/arcemu-world/Object.cpp @ 3150

Revision 3150, 100.5 kB (checked in by jackpoz, 7 months ago)

MODIFIED: Better fix for r3149, thanks Wayland.

  • Property svn:eol-style set to native
  • Property ff set to
    *.cpp = svn:eol-style=native
    Makefile = svn:eol-style=native
    README = svn:eol-style=native
    CHANGELOG = svn:eol-style=native
    LICENSE = svn:eol-style=native
  • Property svn:keywords set to Date Author Rev
Line 
1/*
2 * ArcEmu MMORPG Server
3 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
4 * Copyright (C) 2008-2010 <http://www.ArcEmu.org/>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * 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 Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "StdAfx.h"
22#include "Unit.h"
23using namespace std;
24
25//#define DEG2RAD (M_PI/180.0)
26#define M_PI            3.14159265358979323846
27#define M_H_PI          1.57079632679489661923
28#define M_Q_PI          0.785398163397448309615
29
30void Object::SetRotation( uint64 guid )
31{
32        WorldPacket data(SMSG_AI_REACTION, 12);
33        data << guid;
34        data << uint32(2);
35        SendMessageToSet(&data, false);
36}
37
38Object::Object() : m_position(0,0,0,0), m_spawnLocation(0,0,0,0)
39{
40        m_mapId = 0;
41        m_zoneId = 0;
42
43        m_uint32Values = 0;
44        m_objectUpdated = false;
45
46
47        m_valuesCount = 0;
48
49        //official Values
50        m_walkSpeed = 2.5f;
51        m_runSpeed = 7.0f;
52        m_base_runSpeed = m_runSpeed;
53        m_base_walkSpeed = m_walkSpeed;
54
55        m_flySpeed = 7.0f;
56        m_backFlySpeed = 4.5f;
57
58        m_backWalkSpeed = 4.5f; // this should really be named m_backRunSpeed
59        m_swimSpeed = 4.722222f;
60        m_backSwimSpeed = 2.5f;
61        m_turnRate = 3.141593f;
62
63        m_phase = 1; //Set the default phase: 00000000 00000000 00000000 00000001
64
65        m_mapMgr = 0;
66        m_mapCell = 0;
67
68        mSemaphoreTeleport = false;
69
70
71        m_faction = NULL;
72        m_factionDBC = NULL;
73
74        m_instanceId = 0;
75        Active = false;
76        m_inQueue = false;
77        m_extensions = NULL;
78        m_loadedFromDB = false;
79
80        m_faction = dbcFactionTemplate.LookupRow( 0 );
81        m_factionDBC = dbcFaction.LookupRow( 0 );
82
83        m_objectsInRange.clear();
84        m_inRangePlayers.clear();
85        m_oppFactsInRange.clear();
86        m_sameFactsInRange.clear();
87
88        Active = false;
89}
90
91Object::~Object( )
92{
93        if(m_objectTypeId != TYPEID_ITEM)
94                Arcemu::Util::ARCEMU_ASSERT(   !m_inQueue);
95
96        Arcemu::Util::ARCEMU_ASSERT( !IsInWorld() );
97
98        // for linux
99        m_instanceId = -1;
100        m_objectTypeId=TYPEID_UNUSED;
101
102        if( m_extensions != NULL )
103                delete m_extensions;
104
105        //avoid leaving traces in eventmanager. Have to work on the speed. Not all objects ever had events so list iteration can be skipped
106        sEventMgr.RemoveEvents( this );
107}
108
109
110void Object::_Create( uint32 mapid, float x, float y, float z, float ang )
111{
112        m_mapId = mapid;
113        m_position.ChangeCoords(x, y, z, ang);
114        m_spawnLocation.ChangeCoords(x, y, z, ang);
115        m_lastMapUpdatePosition.ChangeCoords(x,y,z,ang);
116}
117
118uint32 Object::BuildCreateUpdateBlockForPlayer(ByteBuffer *data, Player *target)
119{
120        uint16 flags = 0;
121        uint32 flags2 = 0;
122
123        uint8 updatetype = UPDATETYPE_CREATE_OBJECT;
124        if(m_objectTypeId == TYPEID_CORPSE)
125        {
126                if(static_cast<Corpse*>(this)->GetDisplayId() == 0)
127                        return 0;
128                updatetype = UPDATETYPE_CREATE_YOURSELF;
129        }
130
131        // any other case
132        switch(m_objectTypeId)
133        {
134                // items + containers: 0x8
135        case TYPEID_ITEM:
136        case TYPEID_CONTAINER:
137                flags = 0x10;
138                break;
139
140                // player/unit: 0x68 (except self)
141        case TYPEID_UNIT:
142                flags = 0x70;
143                break;
144
145        case TYPEID_PLAYER:
146                flags = 0x70;
147                break;
148
149                // gameobject/dynamicobject
150        case TYPEID_GAMEOBJECT:
151                flags = 0x0350;
152                if( static_cast<GameObject*>(this)->GetDisplayId()==3831 ) flags= 0x0252; //Deeprun Tram proper flags as of 3.2.0.
153                break;
154
155        case TYPEID_DYNAMICOBJECT:
156                flags = 0x0150;
157                break;
158
159        case TYPEID_CORPSE:
160                flags = 0x0150;
161                break;
162                // anyone else can get fucked and die!
163        }
164
165        if(target == this)
166        {
167                // player creating self
168                flags |= 0x01;
169                updatetype = UPDATETYPE_CREATE_YOURSELF;
170        }
171
172        // gameobject stuff
173        if(m_objectTypeId == TYPEID_GAMEOBJECT)
174        {
175//              switch( GetByte(GAMEOBJECT_BYTES_1,GAMEOBJECT_BYTES_TYPEID) )
176                switch(m_uint32Values[GAMEOBJECT_BYTES_1])
177                {
178                        case GAMEOBJECT_TYPE_MO_TRANSPORT: 
179                                {
180                                        if(GetTypeFromGUID() != HIGHGUID_TYPE_TRANSPORTER)
181                                                return 0;   // bad transporter
182                                        else
183                                                flags = 0x0352;
184                                }break;
185
186                        case GAMEOBJECT_TYPE_TRANSPORT:
187                                {
188                                        /* deeprun tram, etc */
189                                        flags = 0x252;
190                                }break;
191
192                        case GAMEOBJECT_TYPE_DUEL_ARBITER:
193                                {
194                                        // duel flags have to stay as updatetype 3, otherwise
195                                        // it won't animate
196                                        updatetype = UPDATETYPE_CREATE_YOURSELF;
197                                }break;
198                }
199                //The above 3 checks FAIL to identify transports, thus their flags remain 0x58, and this is BAAAAAAD! Later they don't get position x,y,z,o updates, so they appear randomly by a client-calculated path, they always face north, etc... By: VLack
200                if( flags != 0x0352 && GetTypeId() == TYPEID_GAMEOBJECT && static_cast<GameObject*>(this)->GetInfo()->Type == GAMEOBJECT_TYPE_TRANSPORT && !(static_cast<GameObject*>(this)->GetOverrides() & GAMEOBJECT_OVERRIDE_PARENTROT) )
201                        flags = 0x0352;
202        }
203
204        // build our actual update
205        *data << updatetype;
206
207        // we shouldn't be here, under any circumstances, unless we have a wowguid..
208        Arcemu::Util::ARCEMU_ASSERT(   m_wowGuid.GetNewGuidLen() > 0);
209        *data << m_wowGuid;
210       
211        *data << m_objectTypeId;
212
213        _BuildMovementUpdate(data, flags, flags2, target);
214
215        // we have dirty data, or are creating for ourself.
216        UpdateMask updateMask;
217        updateMask.SetCount( m_valuesCount );
218        _SetCreateBits( &updateMask, target );
219
220        if(GetTypeId() == TYPEID_GAMEOBJECT && (static_cast<GameObject*>(this)->GetOverrides() & GAMEOBJECT_OVERRIDE_PARENTROT) )
221        {
222                updateMask.SetBit(GAMEOBJECT_PARENTROTATION_02);
223                updateMask.SetBit(GAMEOBJECT_PARENTROTATION_03);
224        }
225
226        // this will cache automatically if needed
227        _BuildValuesUpdate( data, &updateMask, target );
228
229        // update count: 1 ;)
230        return 1;
231}
232
233
234//That is dirty fix it actually creates update of 1 field with
235//the given value ignoring existing changes in fields and so on
236//useful if we want update this field for certain players
237//NOTE: it does not change fields. This is also very fast method
238WorldPacket *Object::BuildFieldUpdatePacket( uint32 index,uint32 value)
239{
240   // uint64 guidfields = GetGUID();
241   // uint8 guidmask = 0;
242        WorldPacket * packet=new WorldPacket(1500);
243        packet->SetOpcode( SMSG_UPDATE_OBJECT );
244
245        *packet << (uint32)1;//number of update/create blocks
246//      *packet << (uint8)0;//unknown //VLack: removed for 3.1
247
248        *packet << (uint8) UPDATETYPE_VALUES;           // update type == update
249        *packet << GetNewGUID();
250
251        uint32 mBlocks = index/32+1;
252        *packet << (uint8)mBlocks;
253
254        for(uint32 dword_n=mBlocks-1;dword_n;dword_n--)
255        *packet <<(uint32)0;
256
257        *packet <<(((uint32)(1))<<(index%32));
258        *packet << value;
259
260        return packet;
261}
262
263void Object::BuildFieldUpdatePacket(Player* Target, uint32 Index, uint32 Value)
264{
265        ByteBuffer buf(500);
266        buf << uint8(UPDATETYPE_VALUES);
267        buf << GetNewGUID();
268
269        uint32 mBlocks = Index/32+1;
270        buf << (uint8)mBlocks;
271
272        for(uint32 dword_n=mBlocks-1;dword_n;dword_n--)
273                buf <<(uint32)0;
274
275        buf <<(((uint32)(1))<<(Index%32));
276        buf << Value;
277
278        Target->PushUpdateData(&buf, 1);
279}
280
281void Object::BuildFieldUpdatePacket(ByteBuffer * buf, uint32 Index, uint32 Value)
282{
283        *buf << uint8(UPDATETYPE_VALUES);
284        *buf << GetNewGUID();
285
286        uint32 mBlocks = Index/32+1;
287        *buf << (uint8)mBlocks;
288
289        for(uint32 dword_n=mBlocks-1;dword_n;dword_n--)
290                *buf <<(uint32)0;
291
292        *buf <<(((uint32)(1))<<(Index%32));
293        *buf << Value;
294}
295
296uint32 Object::BuildValuesUpdateBlockForPlayer(ByteBuffer *data, Player *target)
297{
298        UpdateMask updateMask;
299        updateMask.SetCount( m_valuesCount );
300        _SetUpdateBits( &updateMask, target );
301        for(uint32 x = 0; x < m_valuesCount; ++x)
302        {
303                if(updateMask.GetBit(x))
304                {
305                        *data << (uint8) UPDATETYPE_VALUES;             // update type == update
306                        Arcemu::Util::ARCEMU_ASSERT(   m_wowGuid.GetNewGuidLen() > 0);
307                        *data << m_wowGuid;
308
309                        _BuildValuesUpdate( data, &updateMask, target );
310                        return 1;
311                }
312        }
313
314        return 0;
315}
316
317uint32 Object::BuildValuesUpdateBlockForPlayer(ByteBuffer * buf, UpdateMask * mask )
318{
319        // returns: update count
320        // update type == update
321        *buf << (uint8) UPDATETYPE_VALUES;             
322
323        Arcemu::Util::ARCEMU_ASSERT(   m_wowGuid.GetNewGuidLen() > 0);
324        *buf << m_wowGuid;
325
326        _BuildValuesUpdate( buf, mask, 0 );
327
328        // 1 update.
329        return 1;
330}
331
332void Object::DestroyForPlayer(Player * target) const
333{
334        // If the target doesn't exist, return. If the target exists, but it session is null return
335         if( target == NULL || target->GetSession() == NULL )
336                return;
337
338        Arcemu::Util::ARCEMU_ASSERT(   target != NULL );
339
340        WorldPacket data( SMSG_DESTROY_OBJECT, 9 );
341        data << GetGUID();
342        data << uint8( 0 ); //TODO: unk bool
343
344        target->GetSession()->SendPacket( &data );
345}
346
347
348///////////////////////////////////////////////////////////////
349/// Build the Movement Data portion of the update packet
350/// Fills the data with this object's movement/speed info
351/// TODO: rewrite this stuff, document unknown fields and flags
352uint32 TimeStamp();
353
354void Object::_BuildMovementUpdate(ByteBuffer * data, uint16 flags, uint32 flags2, Player* target )
355{
356        /* ByteBuffer *splinebuf = (m_objectTypeId == TYPEID_UNIT) ? target->GetAndRemoveSplinePacket(GetGUID()) : 0; */
357        uint16 flag16 = 0;      // some other flag
358
359        *data << (uint16)flags;
360
361        Player * pThis = NULL;
362        MovementInfo* moveinfo = NULL;
363        if(GetTypeId() == TYPEID_PLAYER)
364        {
365                pThis = static_cast< Player* >( this );
366                if(pThis->GetSession())
367                        moveinfo = pThis->GetSession()->GetMovementInfo();
368                if(target == this)
369                {
370                        // Updating our last speeds.
371                        pThis->UpdateLastSpeeds();
372                }
373        }
374        Creature * uThis = NULL;
375        if (GetTypeId() == TYPEID_UNIT)
376                uThis = static_cast<Creature*>(this);
377
378        if (flags & UPDATEFLAG_LIVING) //0x20
379        {
380                if(pThis && pThis->m_TransporterGUID != 0)
381                        flags2 |= MOVEFLAG_TAXI; //0x200
382                else if(uThis != NULL && uThis->m_transportGuid != 0 && uThis->m_transportPosition != NULL)
383                        flags2 |= MOVEFLAG_TAXI; //0x200
384
385                if(uThis != NULL)
386                {
387                        //               Don't know what this is, but I've only seen it applied to spirit healers.
388                        //               maybe some sort of invisibility flag? :/
389                        switch(GetEntry())
390                        {
391                        case 6491:  // Spirit Healer
392                        case 13116: // Alliance Spirit Guide
393                        case 13117: // Horde Spirit Guide
394                                {
395                                        flags2 |= MOVEFLAG_WATER_WALK; //0x10000000
396                                }break;
397                        }
398
399                        if(uThis->GetAIInterface()->IsFlying())
400                                flags2 |= MOVEFLAG_NO_COLLISION; //0x400 Zack : Teribus the Cursed had flag 400 instead of 800 and he is flying all the time
401                        if(uThis->GetProto() && uThis->GetProto()->extra_a9_flags)
402                        {
403//do not send shit we can't honor
404#define UNKNOWN_FLAGS2 ( 0x00002000 | 0x04000000 | 0x08000000 )
405                                uint32 inherit = uThis->GetProto()->extra_a9_flags & UNKNOWN_FLAGS2;
406                                flags2 |= inherit;
407                        }
408                }
409
410                *data << (uint32)flags2;
411
412                *data << (uint16)flag16;
413
414                *data << getMSTime(); // this appears to be time in ms but can be any thing. Maybe packet serializer ?
415
416                // this stuff:
417                //   0x01 -> Enable Swimming?
418                //   0x04 -> ??
419                //   0x10 -> disables movement compensation and causes players to jump around all the place
420                //   0x40 -> disables movement compensation and causes players to jump around all the place
421
422                //Send position data, every living thing has these
423                *data << (float)m_position.x;
424                *data << (float)m_position.y;
425                *data << (float)m_position.z;
426                *data << (float)m_position.o;
427
428                if(flags2 & MOVEFLAG_TAXI) //0x0200
429                {
430                        if(pThis)
431                        {
432                                WoWGuid wowguid(pThis->m_TransporterGUID);
433                                *data << wowguid;
434                                *data << pThis->m_TransporterX << pThis->m_TransporterY << pThis->m_TransporterZ << pThis->m_TransporterO;
435                                *data << pThis->m_TransporterUnk;
436                                *data << (uint8)0;
437                        }
438                        else if(uThis != NULL && uThis->m_transportPosition != NULL)
439                        {
440                                uint64 tguid = ((uint64)HIGHGUID_TYPE_TRANSPORTER << 32) | uThis->m_transportGuid;
441                                WoWGuid wowguid( tguid );
442                                *data << wowguid;
443                                *data << uThis->m_transportPosition->x << uThis->m_transportPosition->y <<
444                                        uThis->m_transportPosition->z << uThis->m_transportPosition->o;
445                                *data << uint32(0);
446                                *data << uint8(0);
447                        }
448                }
449
450                if( (flags2 & (MOVEFLAG_SWIMMING | MOVEFLAG_AIR_SWIMMING)) || (flag16 & 0x20) ) // 0x2000000+0x0200000 flying/swimming, && unk sth to do with vehicles?
451                {
452                        if(pThis && moveinfo)
453                                *data << moveinfo->pitch;
454                        else 
455                                *data << (float)0; //pitch
456                }
457
458                if(pThis && moveinfo)
459                        *data << moveinfo->unklast;
460                else
461                        *data << (uint32)0; //last fall time
462
463                if( flags2 & MOVEFLAG_JUMPING ) // 0x00001000
464                {
465
466                                *data << (float)0;
467                                *data << (float)1.0;
468                                *data << (float)0;
469                                *data << (float)0;                     
470                }
471
472                if( flags2 & MOVEFLAG_SPLINE_MOVER ) // 0x4000000
473                {
474                        int err1, err2; err2= 0; err1=10/err2; //FAIL please with divide by zero :)
475                }
476
477                if( m_walkSpeed == 0 )
478                        *data << 8.0f;
479                else
480                        *data << m_walkSpeed;   // walk speed
481                if( m_runSpeed == 0 )
482                        *data << 8.0f;
483                else
484                        *data << m_runSpeed;    // run speed
485                *data << m_backWalkSpeed;       // backwards walk speed
486                *data << m_swimSpeed;           // swim speed
487                *data << m_backSwimSpeed;       // backwards swim speed
488                if( m_flySpeed == 0 )
489                        *data << 8.0f;
490                else
491                        *data << m_flySpeed;    // fly speed
492                *data << m_backFlySpeed;        // back fly speed
493                *data << m_turnRate;            // turn rate
494                *data << float(7);              // pitch rate, now a constant...
495
496                if( flags2 & 0x08000000 ) //VLack: On Mangos this is a nice spline movement code, but we never had such... Also, at this point we haven't got this flag, that's for sure, but fail just in case...
497                {
498                        int err1, err2; err2= 0; err1=10/err2; //FAIL please with divide by zero :)
499                }
500        }
501        else //----------------------------------- No UPDATEFLAG_LIVING -----------------------------------
502        {
503                if( flags & UPDATEFLAG_POSITION ) //0x0100
504                {
505                        *data << uint8( 0 ); //some say it is like parent guid ?
506                        *data << (float)m_position.x;
507                        *data << (float)m_position.y;
508                        *data << (float)m_position.z;
509                        *data << (float)m_position.x;
510                        *data << (float)m_position.y;
511                        *data << (float)m_position.z;
512                        *data << (float)m_position.o;
513
514                        if (m_objectTypeId == TYPEID_CORPSE)
515                                *data << (float)m_position.o; //VLack: repeat the orientation!
516                        else
517                                *data << (float)0;
518                }
519                else if (flags & UPDATEFLAG_HAS_POSITION) //0x40
520                {
521                        if(flags & UPDATEFLAG_TRANSPORT && m_uint32Values[GAMEOBJECT_BYTES_1]==GAMEOBJECT_TYPE_MO_TRANSPORT)
522                        {
523                                *data << (float)0;
524                                *data << (float)0;
525                                *data << (float)0;
526                        }
527                        else
528                        {
529                                *data << (float)m_position.x;
530                                *data << (float)m_position.y;
531                                *data << (float)m_position.z;
532                        }
533                        *data << (float)m_position.o;
534                }
535        }
536
537
538        if( flags & UPDATEFLAG_LOWGUID ) //0x08
539                *data << GetLowGUID();
540
541        if( flags & UPDATEFLAG_HIGHGUID ) //0x10
542                *data << GetHighGUID();
543
544        if( flags & UPDATEFLAG_HAS_TARGET ) //0x04
545        {
546                if (IsUnit())
547                        FastGUIDPack(*data, TO_UNIT(this)->GetTargetGUID());    //some compressed GUID
548                else
549                        *data << uint64( 0 );
550        }
551
552
553        if( flags & UPDATEFLAG_TRANSPORT ) //0x2
554        {
555        *data << getMSTime();
556    }
557        if( flags & UPDATEFLAG_VEHICLE ) //0x80
558        {
559                *data << uint32( 0 ); //Vehicle ID
560                *data << float( 0 ); //Facing
561        }
562
563        if( flags & UPDATEFLAG_ROTATION ) //0x0200
564        {
565                if( IsGameObject() )
566                        *data << static_cast< GameObject* >( this )->m_rotation;
567                else
568                        *data << uint64( 0 ); //?
569        }
570}
571
572
573//=======================================================================================
574//  Creates an update block with the values of this object as
575//  determined by the updateMask.
576//=======================================================================================
577void Object::_BuildValuesUpdate(ByteBuffer * data, UpdateMask *updateMask, Player* target)
578{
579        bool activate_quest_object = false;
580        bool reset = false;
581        uint32 oldflags = 0;
582
583        if(updateMask->GetBit(OBJECT_FIELD_GUID) && target)        // We're creating.
584        {
585                Creature * pThis = static_cast<Creature*>(this);
586                if(GetTypeId() == TYPEID_UNIT && pThis->Tagged && (pThis->loot.gold || pThis->loot.items.size()))
587                {
588                        // Let's see if we're the tagger or not.
589                        oldflags = m_uint32Values[UNIT_DYNAMIC_FLAGS];
590                        uint32 Flags = m_uint32Values[UNIT_DYNAMIC_FLAGS];
591                        uint32 oldFlags = 0;
592
593                        if(pThis->TaggerGuid == target->GetGUID())
594                        {
595                                // Our target is our tagger.
596                                oldFlags = U_DYN_FLAG_TAGGED_BY_OTHER;
597
598                                if(Flags & U_DYN_FLAG_TAGGED_BY_OTHER)
599                                        Flags &= ~oldFlags;
600
601                                if( !(Flags & U_DYN_FLAG_LOOTABLE) && pThis->HasLootForPlayer( target ) )
602                                        Flags |= U_DYN_FLAG_LOOTABLE;
603                        }
604                        else
605                        {
606                                // Target is not the tagger.
607                                oldFlags = U_DYN_FLAG_LOOTABLE;
608
609                                if(!(Flags & U_DYN_FLAG_TAGGED_BY_OTHER))
610                                        Flags |= U_DYN_FLAG_TAGGED_BY_OTHER;
611
612                                if(Flags & U_DYN_FLAG_LOOTABLE)
613                                        Flags &= ~oldFlags;
614                        }
615
616                        m_uint32Values[UNIT_DYNAMIC_FLAGS] = Flags;
617
618                        updateMask->SetBit(UNIT_DYNAMIC_FLAGS);
619
620                        reset = true;
621                }
622
623                if( target && GetTypeId() == TYPEID_GAMEOBJECT )
624                {
625                        GameObject *go = ((GameObject*)this);
626                        QuestLogEntry *qle;
627                        GameObjectInfo *info;
628                        if( go->HasQuests() )
629                        {
630                                std::list<QuestRelation *>::iterator itr;
631                                for( itr = go->QuestsBegin(); itr != go->QuestsEnd(); ++itr ) {
632                                        QuestRelation * qr = (*itr);
633                                        if( qr != NULL )
634                                        {
635                                                Quest * qst = qr->qst;
636                                                if( qst != NULL )
637                                                {
638                                                        if(             ( qr->type & QUESTGIVER_QUEST_START && !target->HasQuest(qst->id) ) 
639                                                                ||      ( qr->type & QUESTGIVER_QUEST_END && target->HasQuest(qst->id) )
640                                                                )
641                                                        {
642                                                                activate_quest_object = true;
643                                                                break;
644                                                        }
645                                                }
646                                        }
647                                }
648                        }
649                        else
650                        {
651                                info = go->GetInfo();
652                                if( info && ( info->goMap.size() || info->itemMap.size() ) )
653                                {
654                                        for( GameObjectGOMap::iterator itr = go->GetInfo()->goMap.begin(); itr != go->GetInfo()->goMap.end(); ++itr )
655                                        {
656                                                qle = target->GetQuestLogForEntry( itr->first->id );
657                                                if( qle != NULL )
658                                                {
659                                                        if( qle->GetQuest()->count_required_mob == 0 )
660                                                                continue;
661                                                        for( uint32 i = 0; i < 4; ++i )
662                                                        {
663                                                                if( qle->GetQuest()->required_mob[i] == static_cast<int32>( go->GetEntry() ) && qle->GetMobCount(i) < qle->GetQuest()->required_mobcount[i])
664                                                                {
665                                                                        activate_quest_object = true;
666                                                                        break;
667                                                                }
668                                                        }
669                                                        if( activate_quest_object )
670                                                                break;
671                                                }
672                                        }
673
674                                        if( !activate_quest_object )
675                                        {
676                                                for( GameObjectItemMap::iterator itr = go->GetInfo()->itemMap.begin();
677                                                        itr != go->GetInfo()->itemMap.end();
678                                                        ++itr )
679                                                {
680                                                        for( std::map<uint32, uint32>::iterator it2 = itr->second.begin();
681                                                                it2 != itr->second.end();
682                                                                ++it2 )
683                                                        {
684                                                                if( ( qle = target->GetQuestLogForEntry( itr->first->id ) ) != 0 )
685                                                                {
686                                                                        if( target->GetItemInterface()->GetItemCount(it2->first) < it2->second )
687                                                                        {
688                                                                                activate_quest_object = true;
689                                                                                break;
690                                                                        }
691                                                                }
692                                                        }
693                                                        if( activate_quest_object )
694                                                                break;
695                                                }
696                                        }
697                                }
698                        }
699                }
700        }
701
702
703        if(activate_quest_object)
704        {
705                oldflags = m_uint32Values[GAMEOBJECT_DYNAMIC];
706                if(!updateMask->GetBit(GAMEOBJECT_DYNAMIC))
707                        updateMask->SetBit(GAMEOBJECT_DYNAMIC);
708                m_uint32Values[GAMEOBJECT_DYNAMIC] = 1 | 8; // 8 to show sparkles
709                reset = true;
710        }
711
712        Arcemu::Util::ARCEMU_ASSERT(    updateMask && updateMask->GetCount()  == m_valuesCount );
713        uint32 bc;
714        uint32 values_count;
715        if( m_valuesCount > ( 2 * 0x20 ) )//if number of blocks > 2->  unit and player+item container
716        {
717                bc = updateMask->GetUpdateBlockCount();
718                values_count = min<uint32>( bc * 32, m_valuesCount );
719
720        }
721        else
722        {
723                bc=updateMask->GetBlockCount();
724                values_count=m_valuesCount;
725        }
726
727        *data << (uint8)bc;
728        data->append( updateMask->GetMask(), bc*4 );
729
730        for( uint32 index = 0; index < values_count; index ++ )
731        {
732                if( updateMask->GetBit( index ) )
733                {
734                        *data << m_uint32Values[ index ];
735                }
736        }
737
738        if(reset)
739        {
740                switch(GetTypeId())
741                {
742                case TYPEID_UNIT:
743                        m_uint32Values[UNIT_DYNAMIC_FLAGS] = oldflags;
744                        break;
745                case TYPEID_GAMEOBJECT:
746                        m_uint32Values[GAMEOBJECT_DYNAMIC] = oldflags;
747                        break;
748                }
749        }
750}
751
752void Object::BuildHeartBeatMsg(WorldPacket *data) const
753{
754        data->Initialize(MSG_MOVE_HEARTBEAT);
755
756        *data << GetGUID();
757
758        *data << uint32(0); // flags
759//      *data << uint32(0); // mysterious value #1
760        *data << getMSTime();
761        *data << m_position;
762        *data << m_position.o;
763}
764
765bool Object::SetPosition(const LocationVector & v, bool allowPorting /* = false */)
766{
767        bool updateMap = false, result = true;
768
769        if (m_position.x != v.x || m_position.y != v.y)
770                updateMap = true;
771
772        m_position = const_cast<LocationVector&>(v);
773
774        if (!allowPorting && v.z < -500)
775        {
776                m_position.z = 500;
777                sLog.outError( "setPosition: fell through map; height ported" );
778
779                result = false;
780        }
781
782        if (IsInWorld() && updateMap)
783        {
784                m_mapMgr->ChangeObjectLocation(this);
785        }
786
787        return result;
788}
789
790bool Object::SetPosition( float newX, float newY, float newZ, float newOrientation, bool allowPorting )
791{
792        bool updateMap = false, result = true;
793
794        //It's a good idea to push through EVERY transport position change, no matter how small they are. By: VLack aka. VLsoft
795        if( GetTypeId() == TYPEID_GAMEOBJECT && static_cast<GameObject*>(this)->GetInfo()->Type == GAMEOBJECT_TYPE_TRANSPORT )
796                updateMap = true;
797
798        //if (m_position.x != newX || m_position.y != newY)
799                //updateMap = true;
800        if(m_lastMapUpdatePosition.Distance2DSq(newX, newY) > 4.0f)             /* 2.0f */
801                updateMap = true;
802
803        m_position.ChangeCoords(newX, newY, newZ, newOrientation);
804
805        if (!allowPorting && newZ < -500)
806        {
807                m_position.z = 500;
808                sLog.outError( "setPosition: fell through map; height ported" );
809
810                result = false;
811        }
812
813        if (IsInWorld() && updateMap)
814        {
815                m_lastMapUpdatePosition.ChangeCoords(newX,newY,newZ,newOrientation);
816                m_mapMgr->ChangeObjectLocation(this);
817
818                if( m_objectTypeId == TYPEID_PLAYER && static_cast< Player* >( this )->GetGroup() && static_cast< Player* >( this )->m_last_group_position.Distance2DSq(m_position) > 25.0f ) // distance of 5.0
819                {
820            static_cast< Player* >( this )->GetGroup()->HandlePartialChange( PARTY_UPDATE_FLAG_POSITION, static_cast< Player* >( this ) );
821                }
822        }
823
824        return result;
825}
826
827////////////////////////////////////////////////////////////////////////////
828/// Fill the object's Update Values from a space delimitated list of values.
829void Object::LoadValues(const char* data)
830{
831        // thread-safe ;) strtok is not.
832        std::string ndata = data;
833        std::string::size_type last_pos = 0, pos = 0;
834        uint32 index = 0;
835        uint32 val;
836        do
837        {
838                // prevent overflow
839                if(index >= m_valuesCount)
840                {
841                        break;
842                }
843                pos = ndata.find(" ", last_pos);
844                val = atol(ndata.substr(last_pos, (pos-last_pos)).c_str());
845                if(m_uint32Values[index] == 0)
846                        m_uint32Values[index] = val;
847                last_pos = pos+1;
848                ++index;
849        } while(pos != std::string::npos);
850}
851
852void Object::_SetUpdateBits(UpdateMask *updateMask, Player *target) const
853{
854        *updateMask = m_updateMask;
855}
856
857
858void Object::_SetCreateBits(UpdateMask *updateMask, Player *target) const
859{
860
861        for(uint32 i = 0; i < m_valuesCount; ++i)
862                if(m_uint32Values[i] != 0)
863                        updateMask->SetBit(i);
864}
865
866void Object::AddToWorld()
867{
868        MapMgr *mapMgr = sInstanceMgr.GetInstance(this);
869        if(!mapMgr)
870                return;
871
872        if( IsPlayer() )
873        {
874                Player *plr = static_cast< Player* >( this );
875                if(mapMgr->pInstance != NULL && !plr->bGMTagOn)
876                {
877                        // Player limit?
878                        if(mapMgr->GetMapInfo()->playerlimit && mapMgr->GetPlayerCount() >= mapMgr->GetMapInfo()->playerlimit)
879                                return;
880                        Group* group = plr->GetGroup();
881                        // Player in group?
882                        if(group == NULL && mapMgr->pInstance->m_creatorGuid == 0)
883                                return;
884                        // If set: Owns player the instance?
885                        if(mapMgr->pInstance->m_creatorGuid != 0 && mapMgr->pInstance->m_creatorGuid != plr->GetLowGUID())
886                                return;
887
888                        if (group != NULL) {
889                                // Is instance empty or owns our group the instance?
890                                if(mapMgr->pInstance->m_creatorGroup != 0 && mapMgr->pInstance->m_creatorGroup != group->GetID())
891                                {
892                                        // Player not in group or another group is already playing this instance.
893                                        sChatHandler.SystemMessageToPlr(plr, "Another group is already inside this instance of the dungeon.");
894                                        if(plr->GetSession()->GetPermissionCount() > 0)
895                                                sChatHandler.BlueSystemMessageToPlr(plr, "Enable your GameMaster flag to ignore this rule.");
896                                        return;
897                                }
898                                else if(mapMgr->pInstance->m_creatorGroup == 0)
899                                        // Players group now "owns" the instance.
900                                        mapMgr->pInstance->m_creatorGroup = group->GetID();
901                        }
902                }
903        }
904
905        m_mapMgr = mapMgr;
906        m_inQueue = true;
907
908        // correct incorrect instance id's
909        m_instanceId = m_mapMgr->GetInstanceID();
910
911        mapMgr->AddObject(this);
912
913        mSemaphoreTeleport = false;
914}
915
916void Object::AddToWorld(MapMgr * pMapMgr)
917{
918        if( !pMapMgr|| (pMapMgr->GetMapInfo()->playerlimit && this->IsPlayer() && pMapMgr->GetPlayerCount() >= pMapMgr->GetMapInfo()->playerlimit) )
919                return; //instance add failed
920
921        m_mapMgr = pMapMgr;
922        m_inQueue = true;
923
924        pMapMgr->AddObject(this);
925
926        // correct incorrect instance id's
927        m_instanceId = pMapMgr->GetInstanceID();
928
929        mSemaphoreTeleport = false;
930}
931
932//Unlike addtoworld it pushes it directly ignoring add pool
933//this can only be called from the thread of mapmgr!!!
934void Object::PushToWorld(MapMgr*mgr)
935{
936        if(!mgr/* || (m_mapMgr != NULL && m_mapCell != NULL) */)
937        {
938                Log.Debug("Object", "Invalid push to world");
939                return; //instance add failed
940        }
941
942        m_mapId=mgr->GetMapId();
943        m_instanceId = mgr->GetInstanceID();
944
945        m_mapMgr = mgr;
946        OnPrePushToWorld();
947
948        mgr->PushObject(this);
949
950        // correct incorrect instance id's
951        mSemaphoreTeleport = false;
952        m_inQueue = false;
953
954        event_Relocate();
955
956        // call virtual function to handle stuff.. :P
957        OnPushToWorld();
958}
959
960//! Remove object from world
961void Object::RemoveFromWorld(bool free_guid)
962{
963        Arcemu::Util::ARCEMU_ASSERT(   m_mapMgr != NULL );
964        MapMgr * m = m_mapMgr;
965        m_mapMgr = NULL;
966
967        mSemaphoreTeleport = true;
968
969        m->RemoveObject(this, free_guid);
970
971        // update our event holder
972        event_Relocate();
973}
974
975
976
977//! Set uint32 property
978void Object::SetUInt32Value( const uint32 index, const uint32 value )
979{
980        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
981        //! Save updating when val isn't changing.
982        if(m_uint32Values[index] == value)
983                return;
984
985        m_uint32Values[ index ] = value;
986
987        if(IsInWorld())
988        {
989                m_updateMask.SetBit( index );
990
991                if(!m_objectUpdated)
992                {
993                        m_mapMgr->ObjectUpdated(this);
994                        m_objectUpdated = true;
995                }
996        }
997
998        //! Group update handling
999        if(m_objectTypeId == TYPEID_PLAYER)
1000        {
1001                if(IsInWorld())
1002                {
1003                        Group* pGroup = static_cast< Player* >( this )->GetGroup();
1004                        if( pGroup != NULL )
1005                                pGroup->HandleUpdateFieldChange( index, static_cast< Player* >( this ) );
1006                }
1007
1008#ifdef OPTIMIZED_PLAYER_SAVING
1009                switch(index)
1010                {
1011                case UNIT_FIELD_LEVEL:
1012                case PLAYER_XP:
1013                        static_cast< Player* >( this )->save_LevelXP();
1014                        break;
1015
1016                case PLAYER_FIELD_COINAGE:
1017                        static_cast< Player* >( this )->save_Gold();
1018                        break;
1019                }
1020#endif
1021
1022                switch (index)
1023                {
1024                        case UNIT_FIELD_POWER1:
1025                        case UNIT_FIELD_POWER2:
1026                        case UNIT_FIELD_POWER4:
1027                        case UNIT_FIELD_POWER7:
1028                                static_cast< Unit* >( this )->SendPowerUpdate(true);
1029                                break;
1030                        default:
1031                                break;
1032                }
1033        }
1034        else if(m_objectTypeId == TYPEID_UNIT)
1035        {
1036                switch(index)
1037                {
1038                        case UNIT_FIELD_POWER1:
1039                        case UNIT_FIELD_POWER2:
1040                        case UNIT_FIELD_POWER3:
1041                        case UNIT_FIELD_POWER4:
1042                        case UNIT_FIELD_POWER7:
1043                                static_cast< Unit* >( this )->SendPowerUpdate(false);
1044                                break;
1045                        default:
1046                                break;
1047                }
1048        }
1049}
1050
1051uint32 Object::GetModPUInt32Value(const uint32 index, const int32 value)
1052{
1053        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
1054        int32 basevalue = (int32)m_uint32Values[ index ];
1055        return ((basevalue*value)/100);
1056}
1057
1058void Object::ModUnsigned32Value(uint32 index, int32 mod)
1059{
1060        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
1061        if(mod == 0)
1062                return;
1063
1064        m_uint32Values[ index ] += mod;
1065        if( (int32)m_uint32Values[index] < 0 )
1066                m_uint32Values[index] = 0;
1067
1068        if(IsInWorld())
1069        {
1070                m_updateMask.SetBit( index );
1071
1072                if(!m_objectUpdated)
1073                {
1074                        m_mapMgr->ObjectUpdated(this);
1075                        m_objectUpdated = true;
1076                }
1077        }
1078
1079        if(m_objectTypeId == TYPEID_PLAYER)
1080        {
1081#ifdef OPTIMIZED_PLAYER_SAVING
1082                switch(index)
1083                {
1084                case UNIT_FIELD_LEVEL:
1085                case PLAYER_XP:
1086                        static_cast< Player* >( this )->save_LevelXP();
1087                        break;
1088
1089                case PLAYER_FIELD_COINAGE:
1090                        static_cast< Player* >( this )->save_Gold();
1091                        break;
1092                }
1093#endif
1094
1095                switch (index)
1096                {
1097                        case UNIT_FIELD_POWER1:
1098                        case UNIT_FIELD_POWER2:
1099                        case UNIT_FIELD_POWER4:
1100                        case UNIT_FIELD_POWER7:
1101                                static_cast< Unit* >( this )->SendPowerUpdate(true);
1102                                break;
1103                        default:
1104                                break;
1105                }
1106        }
1107        else if(m_objectTypeId == TYPEID_UNIT)
1108        {
1109                switch(index)
1110                {
1111                        case UNIT_FIELD_POWER1:
1112                        case UNIT_FIELD_POWER2:
1113                        case UNIT_FIELD_POWER3:
1114                        case UNIT_FIELD_POWER4:
1115                        case UNIT_FIELD_POWER7:
1116                                static_cast< Unit* >( this )->SendPowerUpdate(false);
1117                                break;
1118                        default:
1119                                break;
1120                }
1121        }
1122}
1123
1124void Object::ModSignedInt32Value(uint32 index, int32 value )
1125{
1126        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
1127        if(value == 0)
1128                return;
1129
1130        m_uint32Values[ index ] += value;
1131        if(IsInWorld())
1132        {
1133                m_updateMask.SetBit( index );
1134
1135                if(!m_objectUpdated)
1136                {
1137                        m_mapMgr->ObjectUpdated(this);
1138                        m_objectUpdated = true;
1139                }
1140        }
1141
1142        if(m_objectTypeId == TYPEID_PLAYER)
1143        {
1144#ifdef OPTIMIZED_PLAYER_SAVING
1145                switch(index)
1146                {
1147                case UNIT_FIELD_LEVEL:
1148                case PLAYER_XP:
1149                        static_cast< Player* >( this )->save_LevelXP();
1150                        break;
1151
1152                case PLAYER_FIELD_COINAGE:
1153                        static_cast< Player* >( this )->save_Gold();
1154                        break;
1155                }
1156#endif
1157        }
1158}
1159
1160void Object::ModFloatValue(const uint32 index, const float value )
1161{
1162        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
1163        m_floatValues[ index ] += value;
1164
1165        if(IsInWorld())
1166        {
1167                m_updateMask.SetBit( index );
1168
1169                if(!m_objectUpdated)
1170                {
1171                        m_mapMgr->ObjectUpdated(this);
1172                        m_objectUpdated = true;
1173                }
1174        }
1175}
1176void Object::ModFloatValueByPCT( const uint32 index, int32 byPct )
1177{
1178        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
1179        if( byPct > 0 )
1180                m_floatValues[ index ] *= 1.0f + float( byPct ) / 100.0f;
1181        else
1182                m_floatValues[ index ] /= 1.0f + float( -byPct ) / 100.0f;
1183
1184
1185        if( IsInWorld() )
1186        {
1187                m_updateMask.SetBit( index );
1188
1189                if( !m_objectUpdated )
1190                {
1191                        m_mapMgr->ObjectUpdated( this );
1192                        m_objectUpdated = true;
1193                }
1194        }
1195}
1196
1197//! Set uint64 property
1198void Object::SetUInt64Value( const uint32 index, const uint64 value )
1199{
1200        Arcemu::Util::ARCEMU_ASSERT(    index + 1 < m_valuesCount );
1201
1202    uint64 *p = reinterpret_cast< uint64* >( &m_uint32Values[ index ] );
1203
1204    if( *p == value )
1205        return;
1206    else
1207        *p = value;
1208
1209        if(IsInWorld())
1210        {
1211                m_updateMask.SetBit( index );
1212                m_updateMask.SetBit( index + 1 );
1213
1214                if(!m_objectUpdated)
1215                {
1216                        m_mapMgr->ObjectUpdated( this );
1217                        m_objectUpdated = true;
1218                }
1219        }
1220}
1221
1222//! Set float property
1223void Object::SetFloatValue( const uint32 index, const float value )
1224{
1225        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
1226        if(m_floatValues[index] == value)
1227                return;
1228
1229        m_floatValues[ index ] = value;
1230
1231        if(IsInWorld())
1232        {
1233                m_updateMask.SetBit( index );
1234
1235                if(!m_objectUpdated)
1236                {
1237                        m_mapMgr->ObjectUpdated(this);
1238                        m_objectUpdated = true;
1239                }
1240        }
1241}
1242
1243
1244void Object::SetFlag( const uint32 index, uint32 newFlag )
1245{
1246        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
1247
1248        //no change -> no update
1249        if((m_uint32Values[ index ] & newFlag)==newFlag)
1250                return;
1251
1252        m_uint32Values[ index ] |= newFlag;
1253
1254        if(IsInWorld())
1255        {
1256                m_updateMask.SetBit( index );
1257
1258                if(!m_objectUpdated)
1259                {
1260                        m_mapMgr->ObjectUpdated(this);
1261                        m_objectUpdated = true;
1262                }
1263        }
1264}
1265
1266
1267void Object::RemoveFlag( const uint32 index, uint32 oldFlag )
1268{
1269        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
1270
1271        //no change -> no update
1272        if((m_uint32Values[ index ] & oldFlag)== 0)
1273                return;
1274
1275        m_uint32Values[ index ] &= ~oldFlag;
1276
1277        if(IsInWorld())
1278        {
1279                m_updateMask.SetBit( index );
1280
1281                if(!m_objectUpdated)
1282                {
1283                        m_mapMgr->ObjectUpdated(this);
1284                        m_objectUpdated = true;
1285                }
1286        }
1287}
1288
1289////////////////////////////////////////////////////////////
1290
1291float Object::CalcDistance(Object *Ob)
1292{
1293        Arcemu::Util::ARCEMU_ASSERT(   Ob != NULL);
1294        return CalcDistance(this->GetPositionX(), this->GetPositionY(), this->GetPositionZ(), Ob->GetPositionX(), Ob->GetPositionY(), Ob->GetPositionZ());
1295}
1296float Object::CalcDistance(float ObX, float ObY, float ObZ)
1297{
1298        return CalcDistance(this->GetPositionX(), this->GetPositionY(), this->GetPositionZ(), ObX, ObY, ObZ);
1299}
1300float Object::CalcDistance(Object *Oa, Object *Ob)
1301{
1302        Arcemu::Util::ARCEMU_ASSERT(   Oa != NULL);
1303        Arcemu::Util::ARCEMU_ASSERT(   Ob != NULL);
1304        return CalcDistance(Oa->GetPositionX(), Oa->GetPositionY(), Oa->GetPositionZ(), Ob->GetPositionX(), Ob->GetPositionY(), Ob->GetPositionZ());
1305}
1306float Object::CalcDistance(Object *Oa, float ObX, float ObY, float ObZ)
1307{
1308        Arcemu::Util::ARCEMU_ASSERT(   Oa != NULL);
1309        return CalcDistance(Oa->GetPositionX(), Oa->GetPositionY(), Oa->GetPositionZ(), ObX, ObY, ObZ);
1310}
1311
1312float Object::CalcDistance(float OaX, float OaY, float OaZ, float ObX, float ObY, float ObZ)
1313{
1314        float xdest = OaX - ObX;
1315        float ydest = OaY - ObY;
1316        float zdest = OaZ - ObZ;
1317        return sqrtf(zdest*zdest + ydest*ydest + xdest*xdest);
1318}
1319
1320bool Object::IsWithinDistInMap(Object* obj, const float dist2compare) const
1321{
1322        Arcemu::Util::ARCEMU_ASSERT(   obj != NULL);
1323        float xdest = this->GetPositionX() - obj->GetPositionX();
1324        float ydest = this->GetPositionY() - obj->GetPositionY();
1325        float zdest = this->GetPositionZ() - obj->GetPositionZ();
1326        return sqrtf(zdest*zdest + ydest*ydest + xdest*xdest) <= dist2compare;
1327}
1328
1329bool Object::IsWithinLOSInMap(Object* obj)
1330{
1331        Arcemu::Util::ARCEMU_ASSERT(   obj != NULL);
1332    if (!IsInMap(obj)) return false;
1333        LocationVector location;
1334    location = obj->GetPosition();
1335    return IsWithinLOS(location );
1336}
1337
1338bool Object::IsWithinLOS( LocationVector location )
1339{
1340    LocationVector location2;
1341    location2 = GetPosition();
1342
1343        if (sWorld.Collision) {
1344                return CollideInterface.CheckLOS(GetMapId(), location2.x, location2.y, location2.z+2.0f, location.x, location.y, location.z+2.0f);
1345        } else {
1346                return true;
1347        }
1348}
1349
1350
1351float Object::calcAngle( float Position1X, float Position1Y, float Position2X, float Position2Y )
1352{
1353        float dx = Position2X-Position1X;
1354        float dy = Position2Y-Position1Y;
1355        double angle= 0.0f;
1356
1357        // Calculate angle
1358        if (dx == 0.0)
1359        {
1360                if (dy == 0.0)
1361                        angle = 0.0;
1362                else if (dy > 0.0)
1363                        angle = M_PI * 0.5 /* / 2 */;
1364                else
1365                        angle = M_PI * 3.0 * 0.5/* / 2 */;
1366        }
1367        else if (dy == 0.0)
1368        {
1369                if (dx > 0.0)
1370                        angle = 0.0;
1371                else
1372                        angle = M_PI;
1373        }
1374        else
1375        {
1376                if (dx < 0.0)
1377                        angle = atanf(dy/dx) + M_PI;
1378                else if (dy < 0.0)
1379                        angle = atanf(dy/dx) + (2*M_PI);
1380                else
1381                        angle = atanf(dy/dx);
1382        }
1383
1384        // Convert to degrees
1385        angle = angle * float(180 / M_PI);
1386
1387        // Return
1388        return float(angle);
1389}
1390
1391float Object::calcRadAngle( float Position1X, float Position1Y, float Position2X, float Position2Y )
1392{
1393        double dx = double(Position2X-Position1X);
1394        double dy = double(Position2Y-Position1Y);
1395        double angle= 0.0;
1396
1397        // Calculate angle
1398        if (dx == 0.0)
1399        {
1400                if (dy == 0.0)
1401                        angle = 0.0;
1402                else if (dy > 0.0)
1403                        angle = M_PI * 0.5/*/ 2.0*/;
1404                else
1405                        angle = M_PI * 3.0 * 0.5/*/ 2.0*/;
1406        }
1407        else if (dy == 0.0)
1408        {
1409                if (dx > 0.0)
1410                        angle = 0.0;
1411                else
1412                        angle = M_PI;
1413        }
1414        else
1415        {
1416                if (dx < 0.0)
1417                        angle = atan(dy/dx) + M_PI;
1418                else if (dy < 0.0)
1419                        angle = atan(dy/dx) + (2*M_PI);
1420                else
1421                        angle = atan(dy/dx);
1422        }
1423
1424        // Return
1425        return float(angle);
1426}
1427
1428float Object::getEasyAngle( float angle )
1429{
1430        while ( angle < 0 ) {
1431                angle = angle + 360;
1432        }
1433        while ( angle >= 360 ) {
1434                angle = angle - 360;
1435        }
1436        return angle;
1437}
1438
1439bool Object::inArc(float Position1X, float Position1Y, float FOV, float Orientation, float Position2X, float Position2Y )
1440{
1441        float angle = calcAngle( Position1X, Position1Y, Position2X, Position2Y );
1442        float lborder = getEasyAngle( ( Orientation - (FOV*0.5f/*/2*/) ) );
1443        float rborder = getEasyAngle( ( Orientation + (FOV*0.5f/*/2*/) ) );
1444        //sLog.outDebug("Orientation: %f Angle: %f LeftBorder: %f RightBorder %f",Orientation,angle,lborder,rborder);
1445        if(((angle >= lborder) && (angle <= rborder)) || ((lborder > rborder) && ((angle < rborder) || (angle > lborder))))
1446        {
1447                return true;
1448        }
1449        else
1450        {
1451                return false;
1452        }
1453}
1454
1455bool Object::isInFront(Object* target)
1456{
1457        // check if we facing something ( is the object within a 180 degree slice of our positive y axis )
1458
1459    double x = target->GetPositionX() - m_position.x;
1460    double y = target->GetPositionY() - m_position.y;
1461
1462    double angle = atan2( y, x );
1463    angle = ( angle >= 0.0 ) ? angle : 2.0 * M_PI + angle;
1464        angle -= m_position.o;
1465
1466    while( angle > M_PI)
1467        angle -= 2.0 * M_PI;
1468
1469    while(angle < -M_PI)
1470        angle += 2.0 * M_PI;
1471
1472        // replace M_PI in the two lines below to reduce or increase angle
1473
1474    double left = -1.0 * ( M_PI / 2.0 );
1475    double right = ( M_PI / 2.0 );
1476
1477    return( ( angle >= left ) && ( angle <= right ) );
1478}
1479
1480bool Object::isInBack(Object* target)
1481{
1482        // check if we are behind something ( is the object within a 180 degree slice of our negative y axis )
1483
1484    double x = m_position.x - target->GetPositionX();
1485    double y = m_position.y - target->GetPositionY();
1486
1487    double angle = atan2( y, x );
1488    angle = ( angle >= 0.0 ) ? angle : 2.0 * M_PI + angle;
1489
1490        // if we are a unit and have a UNIT_FIELD_TARGET then we are always facing them
1491        if( m_objectTypeId == TYPEID_UNIT && TO_UNIT(this)->GetTargetGUID() != 0 && TO_UNIT(this)->GetAIInterface()->GetNextTarget() )
1492        {
1493                Unit* pTarget = TO_UNIT(this)->GetAIInterface()->GetNextTarget();
1494                angle -= double( Object::calcRadAngle( target->m_position.x, target->m_position.y, pTarget->m_position.x, pTarget->m_position.y ) );
1495        }
1496        else
1497                angle -= target->GetOrientation();
1498
1499    while( angle > M_PI)
1500        angle -= 2.0 * M_PI;
1501
1502    while(angle < -M_PI)
1503        angle += 2.0 * M_PI;
1504
1505        // replace M_H_PI in the two lines below to reduce or increase angle
1506
1507    double left = -1.0 * ( M_H_PI / 2.0 );
1508    double right = ( M_H_PI / 2.0 );
1509
1510    return( ( angle <= left ) && ( angle >= right ) );
1511}
1512bool Object::isInArc(Object* target , float angle) // angle in degrees
1513{
1514    return inArc( GetPositionX() , GetPositionY() , angle , GetOrientation() , target->GetPositionX() , target->GetPositionY() );
1515}
1516
1517bool Object::HasInArc( float degrees, Object* target )
1518{
1519        return isInArc(target, degrees);
1520}
1521
1522bool Object::isInRange(Object* target, float range)
1523{
1524  if ( !this->IsInWorld() || !target ) return false;
1525        float dist = CalcDistance( target );
1526        return( dist <= range );
1527}
1528
1529bool Object::IsPet()
1530{
1531    if ( GetTypeId() != TYPEID_UNIT || !m_uint32Values || !IsCreature())
1532                return false;
1533
1534    if (TO_UNIT(this)->GetCreatedByGUID() == 0 || TO_UNIT(this)->GetSummonedByGUID() == 0)
1535        return false;
1536    if (static_cast< Creature * >(this)->IsPet())
1537        return true;
1538
1539        return false;
1540}
1541
1542void Object::_setFaction()
1543{
1544        FactionTemplateDBC* factT = NULL;
1545
1546        if(GetTypeId() == TYPEID_UNIT || GetTypeId() == TYPEID_PLAYER)
1547        {
1548                factT = dbcFactionTemplate.LookupEntryForced(TO_UNIT(this)->GetFaction());
1549                if( !factT )
1550                        sLog.outDetail("Unit does not have a valid faction. It will make him act stupid in world. Don't blame us, blame yourself for not checking :P, faction %u set to entry %u",TO_UNIT(this)->GetFaction(),GetEntry() );
1551        }
1552        else
1553        if(GetTypeId() == TYPEID_GAMEOBJECT)
1554        {
1555                factT = dbcFactionTemplate.LookupEntryForced(static_cast<GameObject*>(this)->GetFaction());
1556                if( !factT )
1557                        sLog.outDetail("Game Object does not have a valid faction. It will make him act stupid in world. Don't blame us, blame yourself for not checking :P, faction %u set to entry %u",static_cast<GameObject*>(this)->GetFaction(),GetEntry() );
1558        }
1559
1560        if(!factT)
1561        {
1562                factT = dbcFactionTemplate.LookupRow( 0 );
1563                //this is causing a lot of crashes cause people have shitty dbs
1564//              return;
1565        }
1566        m_faction = factT;
1567        m_factionDBC = dbcFaction.LookupEntryForced(factT->Faction);
1568        if( !m_factionDBC )
1569                m_factionDBC = dbcFaction.LookupRow( 0 );
1570}
1571
1572void Object::UpdateOppFactionSet()
1573{
1574        m_oppFactsInRange.clear();
1575       
1576    for( std::set< Object* >::iterator itr = m_objectsInRange.begin(); itr != m_objectsInRange.end(); ++itr)
1577        {
1578        Object *i = *itr;
1579
1580        if( ( i->IsUnit() ) || ( i->GetTypeId() == TYPEID_GAMEOBJECT ) )
1581                {
1582                        if(isHostile( this, i) )
1583                        {
1584                                if(!i->IsInRangeOppFactSet( this ) )
1585                                        i->m_oppFactsInRange.insert( this );
1586                                if (!IsInRangeOppFactSet( i ) )
1587                                        m_oppFactsInRange.insert( i );
1588
1589                        }
1590                        else
1591                        {
1592                                if( i->IsInRangeOppFactSet( this ) )
1593                                        i->m_oppFactsInRange.erase( this );
1594                                if( IsInRangeOppFactSet( i ) )
1595                                        m_oppFactsInRange.erase( i );
1596                        }
1597                }
1598        }
1599}
1600
1601void Object::UpdateSameFactionSet()
1602{
1603        m_sameFactsInRange.clear();
1604
1605
1606    for( std::set< Object* >::iterator itr = m_objectsInRange.begin(); itr != m_objectsInRange.end(); ++itr)
1607        {
1608        Object *i = *itr;
1609
1610        if( ( i->IsUnit() ) || ( i->GetTypeId() == TYPEID_GAMEOBJECT) )
1611                {
1612                        if( isFriendly( this, i ) )
1613                        {
1614                                if(!i->IsInRangeSameFactSet( this ) )
1615                                        i->m_sameFactsInRange.insert( this );
1616                               
1617                if (!IsInRangeOppFactSet( i ) )
1618                                        m_sameFactsInRange.insert( i );
1619
1620                        }
1621                        else
1622                        {
1623                                if( i->IsInRangeSameFactSet( this ) )
1624                                        i->m_sameFactsInRange.erase( this );
1625                               
1626                if( IsInRangeSameFactSet( i ) )
1627                                        m_sameFactsInRange.erase( i );
1628                        }
1629                }
1630        }
1631}
1632
1633void Object::EventSetUInt32Value(uint32 index, uint32 value)
1634{
1635        SetUInt32Value(index,value);
1636}
1637
1638void Object::DealDamage(Unit *pVictim, uint32 damage, uint32 targetEvent, uint32 unitEvent, uint32 spellId, bool no_remove_auras)
1639{
1640        Player* plr = NULL;
1641
1642        if( !pVictim || !pVictim->isAlive() || !pVictim->IsInWorld() || !IsInWorld() )
1643                return;
1644        if( pVictim->GetTypeId() == TYPEID_PLAYER && static_cast< Player* >( pVictim )->GodModeCheat == true )
1645                return;
1646        if( pVictim->bInvincible )
1647                return;
1648        if( pVictim->IsSpiritHealer() )
1649                return;
1650        if (this->IsPlayer())
1651                plr = static_cast<Player* >(this);
1652
1653        if( damage > 14000 && this != pVictim && IsPlayer() && !static_cast< Player* >(this)->GetSession()->HasPermissions() && sWorld.m_limits.enable )
1654        {
1655                if(spellId && sWorld.m_limits.spellDamageCap > 0)
1656                {
1657                        if((damage > sWorld.m_limits.spellDamageCap) && this!=pVictim && this->IsPlayer() && !((Player*)this)->GetSession()->HasPermissions())
1658                        {
1659                                SpellEntry* spellInfo = dbcSpell.LookupEntryForced(spellId);
1660                                char dmglog[256];
1661                                snprintf(dmglog, 256, "Dealt %u damage with spell %u ( %s )", damage, spellId, (spellInfo != NULL) ? spellInfo->Name : "ERROR (NULL SPELL)");
1662                                sCheatLog.writefromsession(((Player*)this)->GetSession(),dmglog);
1663                                if(sWorld.m_limits.broadcast) // send info to online GM
1664                                {
1665                                        string gm_ann = MSG_COLOR_GREEN;
1666                                        gm_ann += "|Hplayer:";
1667                                        gm_ann += ((Player*)this)->GetName();
1668                                        gm_ann += "|h[";
1669                                        gm_ann += ((Player*)this)->GetName();
1670                                        gm_ann += "]|h: ";
1671                                        gm_ann += MSG_COLOR_YELLOW;
1672                                        gm_ann += dmglog;
1673                                        sWorld.SendGMWorldText(gm_ann.c_str());
1674                                }
1675                                if(sWorld.m_limits.disconnect)
1676                                {
1677                                        ((Player*)this)->GetSession()->Disconnect();
1678                                }
1679                                else // no disconnect, we'll just set it to the cap. it's been logged and gms have been notified (if configured)
1680                                {
1681                                        damage = sWorld.m_limits.spellDamageCap;
1682                                }
1683                        }
1684                }
1685                else // !spellId
1686                {
1687                        if((sWorld.m_limits.autoattackDamageCap > 0) && (damage > sWorld.m_limits.autoattackDamageCap) && (this!=pVictim) && (this->IsPlayer()) && !((Player*)this)->GetSession()->HasPermissions())
1688                        {
1689                                char dmglog[64];
1690                                snprintf(dmglog, 64, "Dealt %u damage with Auto Attack", damage);
1691                                sCheatLog.writefromsession(((Player*)this)->GetSession(),dmglog);
1692                                if(sWorld.m_limits.broadcast) // send info to GM
1693                                {
1694                                        string gm_ann = MSG_COLOR_GREEN;
1695                                        gm_ann += "|Hplayer:";
1696                                        gm_ann += ((Player*)this)->GetName();
1697                                        gm_ann += "|h[";
1698                                        gm_ann += ((Player*)this)->GetName();
1699                                        gm_ann += "]|h: ";
1700                                        gm_ann += MSG_COLOR_YELLOW;
1701                                        gm_ann += dmglog;
1702                                        sWorld.SendGMWorldText(gm_ann.c_str());
1703                                }
1704                                if(sWorld.m_limits.disconnect)
1705                                {
1706                                        ((Player*)this)->GetSession()->Disconnect();
1707                                }
1708                                else // no disconnect, we'll just set it to the cap. it's been logged and gms have been notified (if configured)
1709                                {
1710                                        damage = sWorld.m_limits.autoattackDamageCap;
1711                                }
1712                        }
1713                }
1714        }
1715        if( IsUnit() && pVictim->IsUnit() && pVictim != this )
1716        {
1717                // Set our attack target to the victim.
1718                static_cast< Unit* >( this )->CombatStatus.OnDamageDealt( pVictim );
1719        }
1720
1721        if( pVictim->GetStandState() )//not standing-> standup
1722        {
1723                pVictim->SetStandState( STANDSTATE_STAND );//probably mobs also must standup
1724        }
1725
1726/////////////////////////////////////////////////////// PvP flagging on attack ///////////////////////////////////////////////
1727{
1728    // Player we are attacking, or the owner of totem/pet/etc
1729    Player *pOwner = GetPlayerOwner( static_cast< Object* >( pVictim ) );
1730
1731    // This is the player or the player controlling the totem/pet/summon
1732    Player *pAttacker = GetPlayerOwner( this );
1733
1734    // We identified both the attacker and the victim as possible PvP combatants, if we are not dueling we will flag the attacker
1735    if( pOwner != NULL && pAttacker != NULL && pOwner != pAttacker && pOwner != pAttacker->DuelingWith ){
1736        if( !pAttacker->IsPvPFlagged() ){
1737            pAttacker->PvPToggle();
1738        }
1739        pAttacker->AggroPvPGuards();
1740    }
1741
1742    // PvP NPCs will flag the player when attacking them
1743    if( pVictim->IsCreature() && pVictim->IsPvPFlagged() && pAttacker != NULL ){
1744        if( !pAttacker->IsPvPFlagged() ){
1745            pAttacker->PvPToggle();
1746        }
1747        pAttacker->AggroPvPGuards();
1748    }
1749
1750}
1751///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1752        if(!no_remove_auras)
1753        {
1754                //zack 2007 04 24 : root should not remove self (and also other unknown spells)
1755                if(spellId)
1756                {
1757                        pVictim->RemoveAurasByInterruptFlagButSkip(AURA_INTERRUPT_ON_ANY_DAMAGE_TAKEN,spellId);
1758                        if(Rand(35.0f))
1759                                pVictim->RemoveAurasByInterruptFlagButSkip(AURA_INTERRUPT_ON_UNUSED2,spellId);
1760                }
1761                else
1762                {
1763                        pVictim->RemoveAurasByInterruptFlag(AURA_INTERRUPT_ON_ANY_DAMAGE_TAKEN);
1764                        if(Rand(35.0f))
1765                                pVictim->RemoveAurasByInterruptFlag(AURA_INTERRUPT_ON_UNUSED2);
1766                }
1767        }
1768
1769        if( IsUnit() )
1770        {
1771                if( pVictim->CombatStatus.IsInCombat() && pVictim->IsPlayer() )
1772                        sHookInterface.OnEnterCombat( static_cast< Player* >( pVictim ), static_cast< Unit* >( this ) );
1773
1774                if( IsPlayer() && static_cast< Player* >( this )->CombatStatus.IsInCombat() == true )
1775                        sHookInterface.OnEnterCombat( static_cast< Player* >( this ), static_cast< Player* >( this ) );
1776
1777                //the black sheep , no actually it is paladin : Ardent Defender
1778                if( static_cast< Unit* >( this )->DamageTakenPctModOnHP35 && HasFlag( UNIT_FIELD_AURASTATE , AURASTATE_FLAG_HEALTH35 ) )
1779                        damage = damage - float2int32( damage * static_cast< Unit* >( this )->DamageTakenPctModOnHP35 ) / 100 ;
1780
1781                //Mage: Fiery Payback
1782                if(pVictim->IsPlayer() && static_cast< Player* >(pVictim)->FieryPaybackModHP35 == 1)
1783                {
1784                        if(pVictim->GetHealthPct() <= 35)
1785                        {
1786                                if(!pVictim->HasAura(44441))
1787                                        pVictim->CastSpell(pVictim->GetGUID(), 44441, true);
1788                        }
1789                        else
1790                                pVictim->RemoveAllAuraById( 44441 );
1791                }
1792               
1793                plr = NULL;
1794                if(IsPet())
1795                        plr = static_cast<Pet*>(this)->GetPetOwner();
1796                else if(IsPlayer())
1797                        plr = static_cast< Player* >( this );
1798
1799                if(pVictim->GetTypeId()==TYPEID_UNIT && plr && plr->GetTypeId() == TYPEID_PLAYER) // Units can't tag..
1800                {
1801                        // Tagging
1802                        Creature *victim = static_cast<Creature*>(pVictim);
1803                        bool taggable;
1804                        if( ( victim->GetCreatureInfo() && victim->GetCreatureInfo()->Type == UNIT_TYPE_CRITTER ) || victim->IsPet())
1805                                taggable = false;
1806                        else taggable = true;
1807
1808                        if(!victim->Tagged && taggable)
1809                        {
1810                                victim->Tagged = true;
1811                                victim->TaggerGuid = plr->GetGUID();
1812
1813                                /* set loot method */
1814                                if( plr->GetGroup() != NULL )
1815                                        victim->m_lootMethod = plr->GetGroup()->GetMethod();
1816
1817                                // For new players who get a create object
1818                                uint32 Flags = pVictim->m_uint32Values[UNIT_DYNAMIC_FLAGS];
1819                                Flags |= U_DYN_FLAG_TAPPED_BY_PLAYER;
1820
1821                                pVictim->m_uint32Values[UNIT_DYNAMIC_FLAGS] |= U_DYN_FLAG_TAGGED_BY_OTHER;
1822
1823                                // Update existing players.
1824                                ByteBuffer buf(500);
1825                                ByteBuffer buf1(500);
1826
1827                                pVictim->BuildFieldUpdatePacket(&buf1, UNIT_DYNAMIC_FLAGS, Flags);
1828                                pVictim->BuildFieldUpdatePacket(&buf, UNIT_DYNAMIC_FLAGS, pVictim->m_uint32Values[UNIT_DYNAMIC_FLAGS]);
1829
1830                                // Loop inrange set, append to their update data.
1831                                for( std::set< Object* >::iterator itr = m_inRangePlayers.begin(); itr != m_inRangePlayers.end(); ++itr)
1832                                {
1833
1834                    Player *p = static_cast< Player* >( *itr );
1835
1836                                        if ( plr->InGroup())
1837                                        {
1838                                                if ( p->GetGroup() && plr->GetGroup()->GetID() == p->GetGroup()->GetID())
1839                                                {
1840                                                        p->PushUpdateData(&buf1, 1);
1841                                                }
1842                                                else
1843                                                {
1844                                                        p->PushUpdateData(&buf, 1);
1845                                                }
1846
1847                                        }
1848                                        else
1849                                        {
1850                                                p->PushUpdateData(&buf, 1);
1851                                        }
1852                                }
1853
1854                                // Update ourselves
1855                                plr->PushUpdateData(&buf1, 1);
1856
1857                        }
1858                }
1859        }
1860
1861        ///Rage
1862
1863                if( pVictim->GetPowerType() == POWER_TYPE_RAGE
1864                        && pVictim != this
1865                        && pVictim->IsPlayer())
1866                {
1867                        float val;
1868                        float level = (float)pVictim->getLevel();
1869                        float c = 0.0091107836f * level * level + 3.225598133f * level + 4.2652911f;
1870                        val = 2.5f * damage / c;
1871            uint32 rage = pVictim->GetPower( POWER_TYPE_RAGE );
1872                        if( rage + float2int32( val ) > 1000 )
1873                                  val = 1000.0f - (float)pVictim->GetPower( POWER_TYPE_RAGE );
1874                        val *= 10.0;
1875            pVictim->ModPower( POWER_TYPE_RAGE, (int32)val);
1876        }
1877
1878        if( pVictim->IsPlayer() )
1879        {
1880                Player *pThis = static_cast< Player* >(pVictim);
1881                if(pThis->cannibalize)
1882                {
1883                        sEventMgr.RemoveEvents(pVictim, EVENT_CANNIBALIZE);
1884                        pThis->SetEmoteState(0);
1885                        pThis->cannibalize = false;
1886                }
1887        }
1888
1889        //* BATTLEGROUND DAMAGE COUNTER *//
1890        if( pVictim != this )
1891        {
1892                if( IsPlayer() )
1893                {
1894                        plr = static_cast< Player* >( this );
1895                }
1896                else if( IsPet() )
1897                {
1898                        plr = static_cast< Pet* >( this )->GetPetOwner();
1899                        if (plr)
1900                                if( plr != NULL && plr->GetMapMgr() == GetMapMgr() )
1901                                        plr = NULL;
1902                }
1903
1904                if( plr != NULL && plr->m_bg != NULL && plr->GetMapMgr() == GetMapMgr() )
1905                {
1906                        plr->m_bgScore.DamageDone += damage;
1907                        plr->m_bg->UpdatePvPData();
1908                }
1909        }
1910
1911        uint32 health = pVictim->GetUInt32Value(UNIT_FIELD_HEALTH );
1912
1913        /*------------------------------------ DUEL HANDLERS --------------------------*/
1914        if((pVictim->IsPlayer()) && ( IsPlayer() ) && static_cast< Player* >(pVictim)->DuelingWith == static_cast< Player* >( this ) ) //Both Players
1915        {
1916                if((health <= damage) && static_cast< Player* >( this )->DuelingWith != NULL)
1917                {
1918                        //Player in Duel and Player Victim has lost
1919                        uint32 NewHP = pVictim->GetMaxHealth()/100;
1920
1921                        if(NewHP < 5)
1922                                NewHP = 5;
1923
1924                        //Set their health to 1% or 5 if 1% is lower then 5
1925                        pVictim->SetHealth( NewHP);
1926                        //End Duel
1927                        static_cast< Player* >( this )->EndDuel(DUEL_WINNER_KNOCKOUT);
1928
1929                        // surrender emote
1930                        pVictim->Emote(EMOTE_ONESHOT_BEG);                      // Animation
1931
1932                        return;
1933                }
1934        }
1935
1936        if((pVictim->IsPlayer()) && (IsPet()))
1937        {
1938                if((health <= damage) && static_cast< Player* >(pVictim)->DuelingWith == static_cast<Pet*>(this)->GetPetOwner())
1939                {
1940                        Player *petOwner = static_cast<Pet*>(this)->GetPetOwner();
1941                        if(petOwner)
1942                        {
1943                                //Player in Duel and Player Victim has lost
1944                                uint32 NewHP = pVictim->GetMaxHealth()/100;
1945                                if(NewHP < 5) NewHP = 5;
1946
1947                                //Set their health to 1% or 5 if 1% is lower then 5
1948                                pVictim->SetHealth( NewHP);
1949                                //End Duel
1950                                petOwner->EndDuel(DUEL_WINNER_KNOCKOUT);
1951                                return;
1952                        }
1953                }
1954        }
1955        /*------------------------------------ DUEL HANDLERS END--------------------------*/
1956
1957        bool isCritter = false;
1958        uint32 highGUID = 0;
1959        uint32 lowGUID = 0;
1960        if(pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->GetCreatureInfo())
1961        {
1962                if(((Creature*)pVictim)->GetCreatureInfo()->Type == UNIT_TYPE_CRITTER)
1963                {
1964                        isCritter = true;
1965                }
1966        }
1967        /* -------------------------- HIT THAT CAUSES VICTIM TO DIE ---------------------------*/
1968        if ( health <= damage )
1969        {
1970                // If it's a training dummy then we simply set the HP to 1 instead of killing the unit
1971                if(pVictim->IsCreature() &&  (static_cast<Creature*>(pVictim))->GetProto() != NULL && (static_cast<Creature*>(pVictim))->GetProto()->isTrainingDummy ){
1972                        pVictim->SetHealth(1 );
1973                        return;
1974                }
1975
1976        // We've just killed a totem
1977        if( pVictim->IsCreature() && static_cast< Creature* >( pVictim )->IsTotem() )
1978                {
1979            Creature *pTotem = static_cast< Creature*>( pVictim );
1980           
1981            // If we have summons then let's remove them first
1982                        pTotem->RemoveAllGuardians();
1983
1984                        //we delete the summon later since its reference is used outside of this loop, like AIInterface::_UpdateCombat().
1985                        //this fixes totems not properly disappearing from the clients.
1986                        //on a side note, it would be better to modify AIInterface::_UpdateCombat() instead of this.
1987                        sEventMgr.AddEvent( pTotem, &Creature::TotemExpire, EVENT_UNK, 1, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT );
1988
1989            return;
1990        }
1991
1992        // We've killed some kind of summon
1993        if( pVictim->GetCreatedByGUID() != 0 )
1994                {
1995            Unit *pSummoner = pVictim->GetMapMgr()->GetUnit( pVictim->GetCreatedByGUID() );
1996
1997            if( pSummoner && pSummoner->IsInWorld() && pSummoner->IsCreature() )
1998                        {
1999                Creature *pSummonerC = static_cast< Creature* >( pSummoner );
2000           
2001                // We've killed a summon summoned by a totem
2002                if( pSummonerC->IsTotem() )
2003                                        sEventMgr.AddEvent( pSummonerC, &Creature::TotemExpire, EVENT_UNK, 1, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT );
2004            }
2005        }
2006               
2007#ifdef ENABLE_ACHIEVEMENTS
2008                // A Player has died
2009                if( pVictim->IsPlayer() )
2010                {
2011                        ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH, 1, 0, 0);
2012                        ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP, pVictim->GetMapId(), 1, 0);
2013                        // A Player killed a Player
2014                        if( this->IsPlayer() )
2015                        {
2016                                ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, 0, 0);
2017                        }
2018                        // A Creature killed a Player
2019                        else if( this->IsCreature() )
2020                        {
2021                                ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, 1, 0, 0);
2022                        }
2023                }
2024                // Player delivered a killing blow
2025                if( pVictim->IsUnit() && this->IsPlayer() )
2026                {
2027                        ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLING_BLOW, GetMapId(), 0, 0);
2028                }
2029#endif
2030                //general hook for die
2031                sHookInterface.OnPreUnitDie( static_cast< Unit* >( this ), pVictim);
2032                //warlock - seed of corruption
2033                if( IsUnit() )
2034                {
2035                        SpellEntry *killerspell;
2036                        if( spellId )
2037                                killerspell = dbcSpell.LookupEntry( spellId );
2038                        else killerspell = NULL;
2039                        pVictim->HandleProc( PROC_ON_DIE, static_cast< Unit* >( this ), killerspell );
2040                        pVictim->m_procCounter = 0;
2041                        static_cast< Unit* >( this )->HandleProc( PROC_ON_TARGET_DIE, pVictim, killerspell );
2042                        static_cast< Unit* >( this )->m_procCounter = 0;
2043                }
2044                // check if pets owner is combat participant
2045                bool owner_participe = false;
2046                if( IsPet() )
2047                {
2048                        Player* owner = static_cast<Pet*>( this )->GetPetOwner();
2049                        if( owner != NULL && pVictim->GetAIInterface()->getThreatByPtr( owner ) > 0 )
2050                                owner_participe = true;
2051                }
2052
2053                /* -------------------------------- HONOR + BATTLEGROUND CHECKS ------------------------ */
2054                //Zack : this event should occur before setting death state !
2055                plr = NULL;
2056                if( IsPlayer() )
2057                        plr = static_cast< Player* >( this );
2058                else if(IsPet())
2059                        plr = static_cast< Pet* >( this )->GetPetOwner();
2060
2061                if( plr != NULL)
2062                {
2063                        if( plr->m_bg != NULL )
2064                                plr->m_bg->HookOnUnitKill( plr, pVictim );
2065
2066                        if( pVictim->IsPlayer() )
2067                        {
2068                                if( plr->m_bg != NULL )
2069                                        plr->m_bg->HookOnPlayerKill( plr, static_cast< Player* >( pVictim ) );
2070
2071                                sHookInterface.OnKillPlayer( plr, static_cast< Player* >( pVictim ) );
2072                                bool setAurastateFlag = false;
2073                                if( plr->getLevel() >= (pVictim->getLevel() - 8) && (plr->GetGUID() != pVictim->GetGUID()) )
2074                                {
2075#ifdef ENABLE_ACHIEVEMENTS
2076                                        plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, plr->GetAreaID(), 1, 0);
2077                                        plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL, 1, 0, 0);
2078#endif                         
2079                                        HonorHandler::OnPlayerKilledUnit(plr, pVictim);
2080                                        setAurastateFlag = true;
2081                                }
2082
2083                                if (setAurastateFlag)
2084                                {
2085                                        this->SetFlag(UNIT_FIELD_AURASTATE,AURASTATE_FLAG_LASTKILLWITHHONOR);
2086                                        if(!sEventMgr.HasEvent(this,EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE))
2087                                                sEventMgr.AddEvent((Unit*)this,&Unit::EventAurastateExpire,(uint32)AURASTATE_FLAG_LASTKILLWITHHONOR,EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE,20000,1,0);
2088                                        else sEventMgr.ModifyEventTimeLeft(this,EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE,20000);
2089                                }
2090                        }
2091                        else
2092                        {
2093                                if (!isCritter) // REPUTATION
2094                                {
2095                                        plr->Reputation_OnKilledUnit( pVictim, false );
2096                                }
2097                        }
2098                }
2099                /* -------------------------------- HONOR + BATTLEGROUND CHECKS END------------------------ */
2100
2101                /* victim died! */
2102                if( pVictim->IsPlayer() )
2103                        static_cast< Player* >( pVictim )->KillPlayer();
2104                else
2105                {
2106                        pVictim->setDeathState( JUST_DIED );
2107                        pVictim->GetAIInterface()->HandleEvent( EVENT_LEAVECOMBAT, pVictim, 0);
2108                }
2109
2110                if( pVictim->IsPlayer() && !IsPlayer())
2111                {
2112                        static_cast< Player* >( pVictim )->DeathDurabilityLoss(0.10);
2113                }
2114
2115                /* Zone Under Attack */
2116        MapInfo * pMapInfo = WorldMapInfoStorage.LookupEntry(GetMapId());
2117        if( pMapInfo && pMapInfo->type == INSTANCE_NULL && !pVictim->IsPlayer() && !pVictim->IsPet() && ( IsPlayer() || IsPet() ) )
2118                {
2119                        // Only NPCs that bear the PvP flag can be truly representing their faction.
2120                        if( ((Creature*)pVictim)->HasFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_PVP ) )
2121                        {
2122                                Player * pAttacker = NULL;
2123                                if( IsPet() )
2124                                        pAttacker = static_cast< Pet* >( this )->GetPetOwner();
2125                                else if(IsPlayer())
2126                                        pAttacker = static_cast< Player* >( this );
2127
2128                                if( pAttacker != NULL)
2129                {
2130                                    uint8 teamId = (uint8)pAttacker->GetTeam();
2131                                    if(teamId == 0) // Swap it.
2132                                            teamId = 1;
2133                                    else
2134                                            teamId = 0;
2135                                    uint32 AreaID = pVictim->GetMapMgr()->GetAreaID(pVictim->GetPositionX(), pVictim->GetPositionY());
2136                                    if(!AreaID)
2137                                            AreaID = pAttacker->GetZoneId(); // Failsafe for a shitty TerrainMgr
2138
2139                                    if(AreaID)
2140                                    {
2141                        sWorld.SendZoneUnderAttackMsg( AreaID, teamId );
2142                                    }
2143                }
2144                        }
2145                }
2146
2147        if(pVictim->GetChannelSpellTargetGUID() != 0)
2148                {
2149                        Spell *spl = pVictim->GetCurrentSpell();
2150                        if(spl != NULL)
2151                        {
2152                                for(int i = 0; i < 3; i++)
2153                                {
2154                                        if(spl->GetProto()->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
2155                                        {
2156                        uint64 guid = pVictim->GetChannelSpellTargetGUID();
2157
2158                        DynamicObject *dObj = GetMapMgr()->GetDynamicObject( Arcemu::Util::GUID_LOPART( guid ) );
2159                                                if(!dObj)
2160                                                        return;
2161                                                WorldPacket data(SMSG_GAMEOBJECT_DESPAWN_ANIM, 8);
2162                                                data << dObj->GetGUID();
2163                                                dObj->SendMessageToSet(&data, false);
2164                                                dObj->Remove();
2165                                        }
2166                                }
2167                                if(spl->GetProto()->ChannelInterruptFlags == 48140) spl->cancel();
2168                        }
2169                }
2170
2171
2172                /* Stop players from casting */
2173                std::set< Object* >::iterator itr;
2174
2175                for( itr = pVictim->GetInRangePlayerSetBegin() ; itr != pVictim->GetInRangePlayerSetEnd() ; itr ++ )
2176                {
2177
2178            Player *p = static_cast< Player* >( *itr );
2179
2180                        if( p->GetCurrentSpell() != NULL)
2181                        {
2182                                if ( p->GetCurrentSpell()->m_targets.m_unitTarget == pVictim->GetGUID())
2183                                        p->GetCurrentSpell()->cancel();
2184                        }
2185                }
2186                /* Stop victim from attacking */
2187                if( this->IsUnit() )
2188                        pVictim->smsg_AttackStop( static_cast< Unit* >( this ) );
2189
2190                if( pVictim->GetTypeId() == TYPEID_PLAYER )
2191                        static_cast< Player* >( pVictim )->EventAttackStop();
2192
2193                /* Set victim health to 0 */
2194                pVictim->SetHealth( 0);
2195                CALL_INSTANCE_SCRIPT_EVENT( m_mapMgr, OnPlayerDeath )( TO_PLAYER( pVictim ), TO_UNIT(this) );
2196
2197                if(pVictim->IsPlayer())
2198                {
2199                        uint32 self_res_spell = 0;
2200                        if (static_cast< Player* >( pVictim )->m_bg == NULL || (static_cast< Player* >( pVictim )->m_bg != NULL && static_cast< Player* >( pVictim )->m_bg->GetType() != BATTLEGROUND_ARENA_5V5 && static_cast< Player* >( pVictim )->m_bg->GetType() != BATTLEGROUND_ARENA_3V3 && static_cast< Player* >( pVictim )->m_bg->GetType() != BATTLEGROUND_ARENA_2V2))
2201                        {
2202                                self_res_spell = static_cast< Player* >( pVictim )->SoulStone;
2203                                static_cast< Player* >( pVictim )->SoulStone = static_cast< Player* >( pVictim )->SoulStoneReceiver = 0;
2204
2205                                if( !self_res_spell && static_cast< Player* >( pVictim )->bReincarnation )
2206                                {
2207                                        SpellEntry* m_reincarnSpellInfo = dbcSpell.LookupEntry( 20608 );
2208                                        if( static_cast< Player* >( pVictim )->Cooldown_CanCast( m_reincarnSpellInfo ) )
2209                                        {
2210                                                uint32 ankh_count = static_cast< Player* >( pVictim )->GetItemInterface()->GetItemCount( 17030 );
2211                                                if( ankh_count )
2212                                                        self_res_spell = 21169;
2213                                        }
2214                                }
2215                        }
2216                        pVictim->SetUInt32Value( PLAYER_SELF_RES_SPELL, self_res_spell );
2217                        pVictim->SetUInt32Value( UNIT_FIELD_MOUNTDISPLAYID , 0 );
2218                        //pVictim->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNTED_TAXI);
2219                }
2220
2221                // Wipe our attacker set on death
2222                pVictim->CombatStatus.Vanished();
2223
2224                //               sent to set. don't send it to the party, because if they're out of
2225                //               range they won't know this guid exists -> possible 132.
2226
2227                /*if (this->IsPlayer())
2228                        if( static_cast< Player* >( this )->InGroup() )
2229                                static_cast< Player* >( this )->GetGroup()->SendPartyKillLog( this, pVictim );*/
2230
2231                /* Stop Unit from attacking */
2232                if( this->IsPlayer() && (((Player*)this)->GetSelection() == pVictim->GetGUID()) )
2233                        static_cast< Player* >( this )->EventAttackStop();
2234
2235                if( this->IsUnit() )
2236                {
2237                        if( !pVictim->IsPlayer() && !pVictim->IsPet() )
2238                                pVictim->RemoveAllNonPersistentAuras();
2239
2240            CALL_SCRIPT_EVENT( this, OnTargetDied )( pVictim );
2241                        static_cast< Unit* >( this )->smsg_AttackStop( pVictim );
2242
2243                        /* Tell Unit that it's target has Died */
2244                        static_cast< Unit* >( this )->addStateFlag( UF_TARGET_DIED );
2245
2246                        // We will no longer be attacking this target, as it's dead.
2247                        //static_cast<Unit*>(this)->setAttackTarget(NULL);
2248                }
2249                //so now we are completely dead
2250                //lets see if we have spirit of redemption
2251                if( pVictim->IsPlayer() )
2252                {
2253                        if( static_cast< Player* >( pVictim)->HasSpell( 20711 ) ) //check for spirit of Redemption
2254                        {
2255                                SpellEntry* sorInfo = dbcSpell.LookupEntryForced(27827);
2256                                if( sorInfo != NULL )
2257                                {
2258                                        Spell *sor = new Spell(pVictim, sorInfo, true, NULL);
2259                                        SpellCastTargets targets;
2260                                        targets.m_unitTarget = pVictim->GetGUID();
2261                                        sor->prepare(&targets);
2262                                }
2263                        }
2264                }
2265                uint64 victimGuid = pVictim->GetGUID();
2266                lowGUID = victimGuid & 0x00000000ffffffff;
2267                highGUID = victimGuid >> 32;
2268
2269                if(pVictim->GetTypeId() == TYPEID_UNIT)
2270                {
2271                        pVictim->GetAIInterface()->OnDeath(this);
2272
2273                        /* Tell Unit that it's target has Died */
2274                        static_cast< Unit* >( pVictim )->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_DEAD );
2275
2276                        if(GetTypeId() == TYPEID_PLAYER)
2277                        {
2278                                WorldPacket data(SMSG_PARTYKILLLOG, 16);
2279                                data << GetGUID() << pVictim->GetGUID();
2280                                SendMessageToSet(&data, true);
2281                        }
2282
2283                        // it Seems that pets some how don't get a name and cause a crash here
2284                        //bool isCritter = (pVictim->GetCreatureInfo() != NULL)? pVictim->GetCreatureInfo()->Type : 0;
2285
2286                        //-----------------------------------LOOOT--------------------------------------------
2287            if ((!pVictim->IsPet())&& ( !isCritter ) && pVictim->GetCreatedByGUID() == 0)
2288                        {
2289                                Creature * victim = static_cast<Creature*>(pVictim);
2290
2291                Player *owner = 0;
2292                                if(victim->TaggerGuid)
2293                                        owner = GetMapMgr()->GetPlayer( (uint32)victim->TaggerGuid );
2294
2295                if(owner == 0 || victim->IsTotem() )  // no owner, or a totem
2296                                {
2297                    // dunno why this would happen, but anyway.. anyone can loot ;p
2298                                        // no owner no loot
2299                                        //victim->SetFlag(UNIT_DYNAMIC_FLAGS, U_DYN_FLAG_LOOTABLE);
2300                                }
2301                                else
2302                                {
2303                    // fill loot vector.
2304                                    victim->generateLoot();
2305
2306                                        // Build the actual update.
2307                                        ByteBuffer buf( 500 );
2308
2309                                        uint32 Flags = victim->m_uint32Values[ UNIT_DYNAMIC_FLAGS ];
2310                                        Flags |= U_DYN_FLAG_LOOTABLE;
2311                                        Flags |= U_DYN_FLAG_TAPPED_BY_PLAYER;
2312
2313                                        victim->BuildFieldUpdatePacket( &buf, UNIT_DYNAMIC_FLAGS, Flags );
2314
2315                                        // Check for owner's group.
2316                                        Group * pGroup = owner->GetGroup();
2317                                        if( pGroup != NULL )
2318                                        {
2319                                                // Owner was in a party.
2320                                                // Check loot method.
2321                                                victim->m_lootMethod = pGroup->GetMethod();
2322                                                switch( victim->m_lootMethod )
2323                                                {
2324                                                case PARTY_LOOT_RR:
2325/*                                              //this commented code is not used because it was never tested and finished !
2326                                                {
2327                                                                //get new tagger for creature
2328                                                                Player *tp = pGroup->GetnextRRlooter();
2329                                                                if(tp)
2330                                                                {
2331                                                                        //we force on creature a new tagger
2332                                                                        victim->TaggerGuid = tp->GetGUID();
2333                                                                        victim->Tagged = true;
2334                                                                        if(tp->IsVisible(victim))  // Save updates for non-existent creatures
2335                                                                                tp->PushUpdateData(&buf, 1);
2336                                                                }
2337                                                        }break;*/
2338                                                case PARTY_LOOT_FFA:
2339                                                case PARTY_LOOT_GROUP:
2340                                                case PARTY_LOOT_NBG:
2341                                                        {
2342                                                                // Loop party players and push update data.
2343                                                                GroupMembersSet::iterator itr;
2344                                                                SubGroup * sGrp;
2345                                                                pGroup->Lock();
2346                                                                for( uint32 Index = 0; Index < pGroup->GetSubGroupCount(); ++Index )
2347                                                                {
2348                                                                        sGrp = pGroup->GetSubGroup( Index );
2349                                                                        itr = sGrp->GetGroupMembersBegin();
2350                                                                        for( ; itr != sGrp->GetGroupMembersEnd(); ++itr )
2351                                                                        {
2352                                                                                if( (*itr)->m_loggedInPlayer && (*itr)->m_loggedInPlayer->IsVisible( victim ) )    // Save updates for non-existent creatures
2353                                                                                        (*itr)->m_loggedInPlayer->PushUpdateData( &buf, 1 );
2354                                                                        }
2355                                                                }
2356                                                                pGroup->Unlock();
2357                                                        }break;
2358                                                case PARTY_LOOT_MASTER:
2359                                                        {
2360                                                                GroupMembersSet::iterator itr;
2361                                                                SubGroup * sGrp;
2362                                                                pGroup->Lock();
2363                                                                for( uint32 Index = 0; Index < pGroup->GetSubGroupCount(); ++Index )
2364                                                                {
2365                                                                        sGrp = pGroup->GetSubGroup( Index );
2366                                                                        itr = sGrp->GetGroupMembersBegin();
2367                                                                        for( ; itr != sGrp->GetGroupMembersEnd(); ++itr )
2368                                                                        {
2369                                                                                if( (*itr)->m_loggedInPlayer && (*itr)->m_loggedInPlayer->IsVisible( victim ) )    // Save updates for non-existent creatures
2370                                                                                        (*itr)->m_loggedInPlayer->PushUpdateData( &buf, 1 );
2371                                                                        }
2372                                                                }
2373                                                                pGroup->Unlock();
2374
2375                                                                Player * pLooter = pGroup->GetLooter() ? pGroup->GetLooter()->m_loggedInPlayer : NULL;
2376                                                                if( pLooter == NULL )
2377                                                                        pLooter = pGroup->GetLeader()->m_loggedInPlayer;
2378
2379                                                                if( pLooter->IsVisible( victim ) )  // Save updates for non-existent creatures
2380                                                                        pLooter->PushUpdateData( &buf, 1 );
2381                                                        }break;
2382                                                }
2383                                        }
2384                                        else
2385                                        {
2386                                                // Owner killed the mob solo.
2387                                                if( owner->IsVisible( victim ) )
2388                                                        owner->PushUpdateData( &buf, 1 );
2389                                        }
2390                                }
2391                        }
2392                        //---------------------------------looot-----------------------------------------
2393
2394           
2395
2396
2397                        // ----------------------------- XP --------------
2398                        if ( pVictim->GetCreatedByGUID() == 0 &&
2399                                pVictim->GetUInt64Value( OBJECT_FIELD_CREATED_BY ) == 0 &&
2400                                !pVictim->IsPet() && TO_CREATURE(pVictim)->Tagged)
2401                        {
2402                                Unit *uTagger = pVictim->GetMapMgr()->GetUnit(static_cast<Creature*>(pVictim)->TaggerGuid);
2403                                if (uTagger != NULL)
2404                                {
2405                                        if (uTagger->IsPlayer())
2406                                        {
2407                                                Player *pTagger = TO_PLAYER(uTagger);
2408                                                if (pTagger)
2409                                                {
2410                                                        if (pTagger->InGroup())
2411                                                        {
2412                                                                pTagger->GiveGroupXP( pVictim, pTagger);
2413                                                        }
2414                                                        else if( IsUnit() )
2415                                                        {
2416                                                                uint32 xp = CalculateXpToGive( pVictim, uTagger );
2417                                                                if( xp > 0 )
2418                                                                {
2419                                                                        pTagger->GiveXP( xp, victimGuid, true );
2420
2421                                                                        this->SetFlag(UNIT_FIELD_AURASTATE,AURASTATE_FLAG_LASTKILLWITHHONOR);
2422                                                                        if(!sEventMgr.HasEvent(this,EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE))
2423                                                                        {
2424                                                                                sEventMgr.AddEvent((Unit*)this,&Unit::EventAurastateExpire,(uint32)AURASTATE_FLAG_LASTKILLWITHHONOR,EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE,20000,1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
2425                                                                        }
2426                                                                        else
2427                                                                        {
2428                                                                                sEventMgr.ModifyEventTimeLeft(this,EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE,20000);
2429                                                                        }
2430
2431                                                                        if( pTagger->GetSummon() && pTagger->GetSummon()->CanGainXP() )
2432                                                                        {
2433                                                                                xp = CalculateXpToGive( pVictim, pTagger->GetSummon() );
2434                                                                                if( xp > 0 )
2435                                                                                        pTagger->GetSummon()->GiveXP( xp );
2436                                                                        }
2437                                                                }
2438                                                        }
2439                                                        if( !pVictim->IsPlayer() )
2440                                                        {
2441                                                                sQuestMgr.OnPlayerKill( pTagger, TO_CREATURE( pVictim ), true );
2442                                                                if(pVictim->IsCreature())
2443                                                                {
2444                                                                        // code stolen from Unit::GiveGroupXP()
2445                                                                        if(pTagger->InGroup())
2446                                                                        {
2447                                                                                Group *pGroup = pTagger->GetGroup();
2448                                                                                //since group is small we can afford to do this rather then recheck again the whole active player set
2449                                                                                Player *active_player_list[MAX_GROUP_SIZE_RAID];
2450                                                                                Player *pGroupGuy = NULL;
2451                                                                                int active_player_count= 0;
2452                                                                                GroupMembersSet::iterator itr;
2453                                                                                pGroup->Lock();
2454                                                                                for(uint32 i = 0; i < pGroup->GetSubGroupCount(); ++i) {
2455                                                                                        for(itr = pGroup->GetSubGroup(i)->GetGroupMembersBegin(); itr != pGroup->GetSubGroup(i)->GetGroupMembersEnd(); ++itr)
2456                                                                                        {
2457                                                                                                pGroupGuy = (*itr)->m_loggedInPlayer;
2458                                                                                                if( pGroupGuy &&
2459                                                                                                        pGroupGuy->isAlive() &&
2460                                                                                                        pVictim->GetMapMgr() == pGroupGuy->GetMapMgr() &&
2461                                                                                                        pGroupGuy->GetDistanceSq(pVictim)<100*100
2462                                                                                                )
2463                                                                                                {
2464                                                                                                        active_player_list[active_player_count] = pGroupGuy;
2465                                                                                                        active_player_count++;
2466                                                                                                }
2467                                                                                        }
2468                                                                                }
2469                                                                                pGroup->Unlock();
2470                                                                                if(active_player_count<1) //killer is always close to the victim. This should never execute
2471                                                                                {
2472                                                                                        active_player_list[0] = pTagger;
2473                                                                                        active_player_count=1;
2474                                                                                }
2475                                                                                for(int i = 0; i < active_player_count; ++i)
2476                                                                                {
2477                                                                                        Player * plr = active_player_list[i];
2478#ifdef ENABLE_ACHIEVEMENTS
2479                                                                                        plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, pVictim->GetEntry(), 1, 0);
2480                                                                                        plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, highGUID, lowGUID, 0);
2481#endif
2482                                                                                }
2483                                                                        }
2484                                                                        else // not in group, just update for pTagger
2485                                                                        {
2486#ifdef ENABLE_ACHIEVEMENTS
2487                                                                                pTagger->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, pVictim->GetEntry(), 1, 0);
2488                                                                                pTagger->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, highGUID, lowGUID, 0);
2489#endif
2490                                                                        }
2491                                                                }
2492                                                        }
2493                                                }
2494                                        }
2495                                        else if (uTagger->IsPet())
2496                                        {
2497                                                Pet* petTagger = TO_PET(uTagger);
2498                                                if (petTagger != NULL)
2499                                                {
2500                                                        Player* petOwner = petTagger->GetPetOwner();
2501                                                        if( petOwner != NULL)
2502                                                        {
2503                                                                if( petOwner->InGroup() )
2504                                                                {
2505                                                                        //Calc Group XP
2506                                                                        petOwner->GiveGroupXP( pVictim, petOwner );
2507                                                                }
2508                                                                else if( IsUnit() )
2509                                                                {
2510                                                                        uint32 xp = CalculateXpToGive( pVictim, petOwner );
2511                                                                        if( xp > 0 )
2512                                                                        {
2513                                                                                petOwner->GiveXP( xp, victimGuid, true );
2514
2515                                                                                this->SetFlag(UNIT_FIELD_AURASTATE,AURASTATE_FLAG_LASTKILLWITHHONOR);
2516                                                                                if(!sEventMgr.HasEvent(this,EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE))
2517                                                                                {
2518                                                                                        sEventMgr.AddEvent((Unit*)this,&Unit::EventAurastateExpire,(uint32)AURASTATE_FLAG_LASTKILLWITHHONOR,EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE,20000,1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
2519                                                                                }
2520                                                                                else
2521                                                                                {
2522                                                                                        sEventMgr.ModifyEventTimeLeft(this,EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE,20000);
2523                                                                                }
2524
2525                                                                                if( petTagger->CanGainXP() )
2526                                                                                {
2527                                                                                        xp = CalculateXpToGive( pVictim, petTagger );
2528                                                                                        if( xp > 0 )
2529                                                                                                petTagger->GiveXP( xp );
2530                                                                                }
2531                                                                        }
2532                                                                }
2533                                                                if(pVictim->GetTypeId() != TYPEID_PLAYER)
2534                                                                {
2535                                                                        sQuestMgr.OnPlayerKill( petOwner, TO_CREATURE( pVictim ), true );
2536                                                                        if(pVictim->IsCreature())
2537                                                                        {
2538                                                                                if(petOwner->InGroup())
2539                                                                                {
2540                                                                                        Group *pGroup = petOwner->GetGroup();
2541                                                                                        // since group is small we can afford to do this rather then recheck again the whole active player set
2542                                                                                        // This needs to be looked at..
2543                                                                                        Player *active_player_list[MAX_GROUP_SIZE_RAID];
2544                                                                                        Player *pGroupGuy = NULL;
2545                                                                                        int active_player_count = 0;
2546                                                                                        GroupMembersSet::iterator itr;
2547                                                                                        pGroup->Lock();
2548                                                                                        for(uint32 i = 0; i < pGroup->GetSubGroupCount(); ++i) {
2549                                                                                                for(itr = pGroup->GetSubGroup(i)->GetGroupMembersBegin(); itr != pGroup->GetSubGroup(i)->GetGroupMembersEnd(); ++itr)
2550                                                                                                {
2551                                                                                                        pGroupGuy = (*itr)->m_loggedInPlayer;
2552                                                                                                        if( pGroupGuy &&
2553                                                                                                                pGroupGuy->isAlive() &&
2554                                                                                                                //
2555                                                                                                                pVictim->GetMapMgr() == pGroupGuy->GetMapMgr() &&
2556                                                                                                                pGroupGuy->GetDistanceSq(pVictim)<100*100
2557                                                                                                        )
2558                                                                                                        {
2559                                                                                                                active_player_list[active_player_count] = pGroupGuy;
2560                                                                                                                active_player_count++;
2561                                                                                                        }
2562                                                                                                }
2563                                                                                        }
2564                                                                                        pGroup->Unlock();
2565                                                                                        //killer is always close to the victim. This should never execute
2566                                                                                        if(active_player_count < 1) 
2567                                                                                        {
2568                                                                                                active_player_list[0] = petOwner;
2569                                                                                                active_player_count=1;
2570                                                                                        }
2571                                                                                        for(int i = 0; i < active_player_count; ++i)
2572                                                                                        {
2573                                                                                                Player * plr = active_player_list[i];
2574#ifdef ENABLE_ACHIEVEMENTS
2575                                                                                                plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, pVictim->GetEntry(), 1, 0);
2576                                                                                                plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, highGUID, lowGUID, 0);
2577#endif
2578                                                                                        }
2579                                                                                }
2580                                                                                else // not in group, just update for petOwner
2581                                                                                {
2582#ifdef ENABLE_ACHIEVEMENTS
2583                                                                                        petOwner->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, pVictim->GetEntry(), 1, 0);
2584                                                                                        petOwner->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, highGUID, lowGUID, 0);
2585#endif                                                                 
2586                                                                                }
2587                                                                        }
2588                                                                }
2589                                                        }
2590                                                }
2591                                        }
2592                                }
2593                                // ----------------------------- XP --------------
2594
2595               
2596
2597                        /* ----------------------------- PET XP HANDLING END-------------- */
2598
2599                        /* ----------------------------- PET DEATH HANDLING -------------- */
2600                                if( pVictim->IsPet() )
2601                                {
2602                                        Pet* pPet = TO_PET(pVictim );
2603
2604                                        // dying pet looses 1 happiness level (not in BG)
2605                                        if( !pPet->IsSummon() && !pPet->IsInBg() )
2606                                        {
2607                                                uint32 hap = pPet->GetPower( POWER_TYPE_HAPPINESS );
2608                                                hap = hap - PET_HAPPINESS_UPDATE_VALUE > 0 ? hap - PET_HAPPINESS_UPDATE_VALUE : 0;
2609                                                pPet->SetPower( POWER_TYPE_HAPPINESS, hap );
2610                                        }
2611
2612                                        pPet->DelayedRemove( false, true );
2613                                }
2614                                /* ----------------------------- PET DEATH HANDLING END -------------- */
2615                                else if( pVictim->GetCharmedByGUID() )
2616                                {
2617                                        //remove owner warlock soul link from caster
2618                                        Unit *owner=pVictim->GetMapMgr()->GetUnit( pVictim->GetCharmedByGUID() );
2619                                        if( owner != NULL && owner->IsPlayer())
2620                                                TO_PLAYER( owner )->EventDismissPet();
2621                                }
2622                        }
2623            // Clear owner, except pets
2624            if( !pVictim->IsPet() && pVictim->GetCreatedByGUID() != 0 )
2625                pVictim->SetCreatedByGUID( 0 );
2626            // Same as the above
2627            if( pVictim->IsCreature() )
2628                        {
2629                Creature *pCreature = TO_CREATURE( pVictim );
2630                if( pCreature->GetOwner() != NULL )
2631                                {
2632                    pCreature->GetOwner()->RemoveGuardianRef( pCreature );
2633                                        pCreature->SetOwner( NULL );
2634                                }
2635            }
2636
2637#ifdef ENABLE_ACHIEVEMENTS
2638                        if(isCritter)
2639                        {
2640                                if(IsPlayer()) // Player killed a critter
2641                                {
2642                                        ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, pVictim->GetEntry(), 1, 0);
2643                                        ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, highGUID, lowGUID, 0);
2644                                }
2645                                else if(IsPet()) // Player's pet killed a critter
2646                                {
2647                                        ((Pet*)this)->GetPetOwner()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, pVictim->GetEntry(), 1, 0);
2648                                        ((Pet*)this)->GetPetOwner()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, highGUID, lowGUID, 0);
2649                                }
2650                        }
2651#endif
2652                }
2653                else if( pVictim->GetTypeId() == TYPEID_PLAYER )
2654                {
2655
2656                        /* -------------------- RESET BREATH STATE ON DEATH -------------- */
2657                        static_cast< Player* >( pVictim )->m_UnderwaterTime = 0;
2658                        static_cast< Player* >( pVictim )->m_UnderwaterState = 0;
2659                        static_cast< Player* >( pVictim )->m_BreathDamageTimer = 0;
2660                        static_cast< Player* >( pVictim )->m_SwimmingTime = 0;
2661
2662                        /* -------------------- KILL PET / GUARDIANS WHEN PLAYER DIES ---------------*/
2663                        static_cast< Player* >( pVictim )->DismissActivePets();
2664                        pVictim->RemoveAllGuardians();
2665                }
2666                else sLog.outError("DealDamage for Unknown Object.");
2667        }
2668        else /* ---------- NOT DEAD YET --------- */
2669        {
2670                if(pVictim != this /* && updateskill */)
2671                {
2672                        // Send AI Reaction UNIT vs UNIT
2673                        /* Weird: why should WE react on OUR damage?
2674                        If meaning of this is to get reaction of victim, then its already handled few rows below...
2675                        if( GetTypeId() ==TYPEID_UNIT )
2676                        {
2677                                static_cast< Unit* >( this )->GetAIInterface()->AttackReaction( pVictim, damage, spellId );
2678                        }*/
2679
2680                        // Send AI Victim Reaction
2681                        if( this->IsPlayer() || this->IsCreature() )
2682                        {
2683                                if( !pVictim->IsPlayer() )
2684                                {
2685                                        static_cast< Creature* >( pVictim )->GetAIInterface()->AttackReaction( static_cast< Unit* >( this ), damage, spellId );
2686                                }
2687                                else
2688                                {
2689                                        // Defensive pet
2690                                        std::list<Pet*> summons = static_cast< Player* >( pVictim )->GetSummons();
2691                                        for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
2692                                        {
2693                                                Pet* pPet = *itr;
2694                                                if( pPet->GetPetState() != PET_STATE_PASSIVE )
2695                                                {
2696                                                        pPet->GetAIInterface()->AttackReaction( static_cast< Unit* >( this ), 1, 0 );
2697                                                        pPet->HandleAutoCastEvent( AUTOCAST_EVENT_OWNER_ATTACKED );
2698                                                }
2699                                        }
2700                                }
2701                        }
2702                }
2703
2704                // TODO: Mark victim as a HK
2705                /*if( static_cast< Player* >( pVictim )->GetCurrentBattleground() != NULL && static_cast< Player* >( this )->GetCurrentBattleground() != NULL)
2706                {
2707
2708                }*/
2709
2710                pVictim->ModHealth(-(int32)damage);
2711        }
2712}
2713
2714void Object::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool allowProc, bool static_damage, bool no_remove_auras)
2715{
2716//==========================================================================================
2717//==============================Unacceptable Cases Processing===============================
2718//==========================================================================================
2719        if(!pVictim || !pVictim->isAlive())
2720                return;
2721
2722        SpellEntry *spellInfo = dbcSpell.LookupEntryForced( spellID );
2723        if(!spellInfo)
2724        return;
2725
2726        if (this->IsPlayer() && !static_cast< Player* >( this )->canCast(spellInfo))
2727                return;
2728//==========================================================================================
2729//==============================Variables Initialization====================================
2730//==========================================================================================
2731        uint32 school = spellInfo->School;
2732        float res = float(damage);
2733        uint32 aproc = PROC_ON_ANY_HOSTILE_ACTION; /*| PROC_ON_SPELL_HIT;*/
2734        uint32 vproc = PROC_ON_ANY_HOSTILE_ACTION | PROC_ON_ANY_DAMAGE_VICTIM; /*| PROC_ON_SPELL_HIT_VICTIM;*/
2735
2736        //A school damage is not necessarily magic
2737        switch( spellInfo->Spell_Dmg_Type )
2738        {
2739        case SPELL_DMG_TYPE_RANGED:     {
2740                        aproc |= PROC_ON_RANGED_ATTACK;
2741                        vproc |= PROC_ON_RANGED_ATTACK_VICTIM;
2742                }break;
2743
2744        case SPELL_DMG_TYPE_MELEE:{
2745                        aproc |= PROC_ON_MELEE_ATTACK;
2746                        vproc |= PROC_ON_MELEE_ATTACK_VICTIM;
2747                }break;
2748
2749        case SPELL_DMG_TYPE_MAGIC:{
2750                        aproc |= PROC_ON_SPELL_HIT;
2751                        vproc |= PROC_ON_SPELL_HIT_VICTIM;
2752                }break;
2753        }
2754
2755        bool critical = false;
2756//==========================================================================================
2757//==============================+Spell Damage Bonus Calculations============================
2758//==========================================================================================
2759//------------------------------by stats----------------------------------------------------
2760        if( IsUnit() && !static_damage )
2761        {
2762                Unit* caster = static_cast< Unit* >( this );
2763                caster->RemoveAurasByInterruptFlag( AURA_INTERRUPT_ON_START_ATTACK );
2764
2765                int32 spelldmgbonus = caster->GetSpellDmgBonus( pVictim, spellInfo, ( int )res, false );
2766
2767                res += spelldmgbonus;
2768
2769//==========================================================================================
2770//==============================Post +SpellDamage Bonus Modifications=======================
2771//==========================================================================================
2772                if( res < 0 )
2773                        res = 0;
2774                else if( spellInfo->spell_can_crit == true )
2775                {
2776//------------------------------critical strike chance--------------------------------------
2777                        // lol ranged spells were using spell crit chance
2778                        float CritChance= 0.0f;
2779                        if( spellInfo->is_ranged_spell )
2780                        {
2781
2782                                if( IsPlayer() )
2783                                {
2784                                        CritChance = GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE );
2785                                        if( pVictim->IsPlayer() )
2786                                                CritChance += static_cast< Player* >(pVictim)->res_R_crit_get();
2787
2788                                        CritChance += (float)(pVictim->AttackerCritChanceMod[spellInfo->School]);
2789                                }
2790                                else
2791                                {
2792                                        CritChance = 5.0f; // static value for mobs.. not blizzlike, but an unfinished formula is not fatal :)
2793                                }
2794                                if( pVictim->IsPlayer() )
2795                                        CritChance -= static_cast< Player* >(pVictim)->CalcRating( PLAYER_RATING_MODIFIER_RANGED_CRIT_RESILIENCE );
2796                        }
2797                        else if( spellInfo->is_melee_spell )
2798                        {
2799                                // Same shit with the melee spells, such as Judgement/Seal of Command
2800                                if( IsPlayer() )
2801                                {
2802                                        CritChance = GetFloatValue(PLAYER_CRIT_PERCENTAGE);
2803                                }
2804                                if( pVictim->IsPlayer() )
2805                                {
2806                                        CritChance += static_cast< Player* >(pVictim)->res_R_crit_get(); //this could be ability but in that case we overwrite the value
2807                                }
2808                                // Resilience
2809                                CritChance -= pVictim->IsPlayer() ? static_cast< Player* >(pVictim)->CalcRating( PLAYER_RATING_MODIFIER_MELEE_CRIT_RESILIENCE ) : 0.0f;
2810                                // Victim's (!) crit chance mod for physical attacks?
2811                                CritChance += (float)(pVictim->AttackerCritChanceMod[0]);
2812
2813                        }
2814                        else
2815                        {
2816                                CritChance = caster->spellcritperc + caster->SpellCritChanceSchool[school] + pVictim->AttackerCritChanceMod[school];
2817                                if( caster->IsPlayer() && ( pVictim->m_rooted - pVictim->m_stunned ) )
2818                                        CritChance += static_cast< Player* >( caster )->m_RootedCritChanceBonus;
2819
2820                                if( spellInfo->SpellGroupType )
2821                                {
2822                                        SM_FFValue(caster->SM_CriticalChance, &CritChance, spellInfo->SpellGroupType);
2823                                }
2824
2825                                if( pVictim->IsPlayer() )
2826                                CritChance -= static_cast< Player* >(pVictim)->CalcRating( PLAYER_RATING_MODIFIER_SPELL_CRIT_RESILIENCE );
2827                        }
2828                        if( CritChance < 0 ) CritChance = 0;
2829                        if( CritChance > 95 ) CritChance = 95;
2830                        critical = Rand(CritChance);
2831                        //sLog.outString( "SpellNonMeleeDamageLog: Crit Chance %f%%, WasCrit = %s" , CritChance , critical ? "Yes" : "No" );
2832
2833                        Aura *fs = NULL;
2834                        if(spellInfo->NameHash == SPELL_HASH_LAVA_BURST && (fs = pVictim->FindAuraByNameHash(SPELL_HASH_FLAME_SHOCK)) != NULL)
2835                        {
2836                                critical = true;
2837                                if( !caster->HasAura(55447) )   // Glyph of Flame Shock
2838                                                fs->Remove();
2839                        }
2840
2841//==========================================================================================
2842//==============================Spell Critical Hit==========================================
2843//==========================================================================================
2844                        if (critical)
2845                        {
2846                                int32 critical_bonus = 100;
2847                                if( spellInfo->SpellGroupType )
2848                                        SM_FIValue( caster->SM_PCriticalDamage, &critical_bonus, spellInfo->SpellGroupType );
2849
2850                                if( critical_bonus > 0 )
2851                                {
2852                                        // the bonuses are halved by 50% (funky blizzard math :S)
2853                                        float b;
2854                                        if( spellInfo->School == 0 || spellInfo->is_melee_spell || spellInfo->is_ranged_spell )         // physical || hackfix SoCommand/JoCommand
2855                                                b = ( ( float(critical_bonus) ) / 100.0f ) + 1.0f;
2856                                        else
2857                                                b = ( ( float(critical_bonus) / 2.0f ) / 100.0f ) + 1.0f;
2858
2859                                        res *= b;
2860                                }
2861
2862                                if( pVictim->IsPlayer() )
2863                                {
2864                                        //res = res*(1.0f-2.0f*static_cast< Player* >(pVictim)->CalcRating(PLAYER_RATING_MODIFIER_MELEE_CRIT_RESISTANCE));
2865                                        //Resilience is a special new rating which was created to reduce the effects of critical hits against your character.
2866                                        //It has two components; it reduces the chance you will be critically hit by x%,
2867                                        //and it reduces the damage dealt to you by critical hits by 2x%. x is the percentage resilience granted by a given resilience rating.
2868                                        //It is believed that resilience also functions against spell crits,
2869                                        //though it's worth noting that NPC mobs cannot get critical hits with spells.
2870                                        float dmg_reduction_pct = 2 * static_cast< Player* >(pVictim)->CalcRating( PLAYER_RATING_MODIFIER_MELEE_CRIT_RESILIENCE ) / 100.0f;
2871                                        if( dmg_reduction_pct > 1.0f )
2872                                                dmg_reduction_pct = 1.0f; //we cannot resist more then he is criticalling us, there is no point of the critical then :P
2873                                        res = res - res * dmg_reduction_pct;
2874                                }
2875
2876                                if (pVictim->GetTypeId() == TYPEID_UNIT && static_cast<Creature*>(pVictim)->GetCreatureInfo() && static_cast<Creature*>(pVictim)->GetCreatureInfo()->Rank != ELITE_WORLDBOSS)
2877                                        pVictim->Emote( EMOTE_ONESHOT_WOUNDCRITICAL );
2878                                /*aproc |= PROC_ON_SPELL_CRIT_HIT;
2879                                vproc |= PROC_ON_SPELL_CRIT_HIT_VICTIM;*/
2880
2881                                switch( spellInfo->Spell_Dmg_Type )
2882                                {
2883                                case SPELL_DMG_TYPE_RANGED:     {
2884                                                aproc |= PROC_ON_RANGED_CRIT_ATTACK;
2885                                                vproc |= PROC_ON_RANGED_CRIT_ATTACK_VICTIM;
2886                                        }break;
2887
2888                                case SPELL_DMG_TYPE_MELEE:{
2889                                                aproc |= PROC_ON_CRIT_ATTACK;
2890                                                vproc |= PROC_ON_CRIT_HIT_VICTIM;
2891                                        }break;
2892
2893                                case SPELL_DMG_TYPE_MAGIC:{
2894                                                aproc |= PROC_ON_SPELL_CRIT_HIT;
2895                                                vproc |= PROC_ON_SPELL_CRIT_HIT_VICTIM;
2896                                        }break;
2897                                }
2898                        }
2899                }
2900        }
2901//==========================================================================================
2902//==============================Post Roll Calculations======================================
2903//==========================================================================================
2904
2905//------------------------------absorption--------------------------------------------------
2906        uint32 ress=(uint32)res;
2907        uint32 abs_dmg = pVictim->AbsorbDamage(school, &ress);
2908        uint32 ms_abs_dmg= pVictim->ManaShieldAbsorb(ress);
2909        if (ms_abs_dmg)
2910        {
2911                if(ms_abs_dmg > ress)
2912                        ress = 0;
2913                else
2914                        ress-=ms_abs_dmg;
2915
2916                abs_dmg += ms_abs_dmg;
2917        }
2918
2919        if(abs_dmg)
2920                vproc |= PROC_ON_ABSORB;
2921
2922        // Incanter's Absorption
2923        if( pVictim->IsPlayer() && pVictim->HasAurasWithNameHash( SPELL_HASH_INCANTER_S_ABSORPTION ) )
2924        {
2925                float pctmod = 0.0f;
2926                Player* pl = static_cast< Player* >( pVictim );
2927                if( pl->HasAura( 44394 ) )
2928                        pctmod = 0.05f;
2929                else if( pl->HasAura( 44395 ) )
2930                        pctmod = 0.10f;
2931                else if( pl->HasAura( 44396 ) )
2932                        pctmod = 0.15f;
2933
2934                uint32 hp = static_cast<uint32>( 0.05f * pl->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) );
2935                uint32 spellpower = static_cast<uint32>( pctmod * pl->GetPosDamageDoneMod(SCHOOL_NORMAL) );
2936
2937                if( spellpower > hp )
2938                        spellpower = hp;
2939
2940                SpellEntry * entry = dbcSpell.LookupEntryForced( 44413 );
2941                if( !entry ) 
2942                        return;
2943
2944                Spell * sp = new Spell( pl, entry, true, NULL );
2945                sp->GetProto()->EffectBasePoints[0] = spellpower;
2946                SpellCastTargets targets;
2947                targets.m_unitTarget = pl->GetGUID();
2948                sp->prepare(&targets);
2949        }
2950
2951        if(ress < 0) ress = 0;
2952
2953        res=(float)ress;
2954        dealdamage dmg;
2955        dmg.school_type = school;
2956        dmg.full_damage = ress;
2957        dmg.resisted_damage = 0;
2958
2959        if(res <= 0)
2960                dmg.resisted_damage = dmg.full_damage;
2961
2962        //------------------------------resistance reducing-----------------------------------------
2963        if(res > 0 && this->IsUnit())
2964        {
2965                static_cast<Unit*>(this)->CalculateResistanceReduction( pVictim, &dmg, spellInfo, 0 );
2966                if( (int32)dmg.resisted_damage > dmg.full_damage )
2967                        res = 0;
2968                else
2969                        res = float( dmg.full_damage - dmg.resisted_damage );
2970        }
2971        //------------------------------special states----------------------------------------------
2972        if(pVictim->GetTypeId() == TYPEID_PLAYER && static_cast< Player* >(pVictim)->GodModeCheat == true)
2973        {
2974                res = float(dmg.full_damage);
2975                dmg.resisted_damage = dmg.full_damage;
2976        }
2977
2978        // Paladin: Blessing of Sacrifice, and Warlock: Soul Link
2979        if( pVictim->m_damageSplitTarget)
2980        {
2981                res = (float)pVictim->DoDamageSplitTarget((uint32)res, school, false);
2982        }
2983
2984//==========================================================================================
2985//==============================Data Sending ProcHandling===================================
2986//==========================================================================================
2987        SendSpellNonMeleeDamageLog(this, pVictim, spellID, float2int32(res), static_cast<uint8>( school ), abs_dmg, dmg.resisted_damage, false, 0, critical, IsPlayer());
2988        DealDamage( pVictim, float2int32( res ), 2, 0, spellID );
2989
2990        if( IsUnit() && allowProc && spellInfo->Id != 25501 && spellInfo->noproc == false )
2991        {
2992                int32 dmg = float2int32(res);
2993
2994                pVictim->HandleProc( vproc, static_cast< Unit* >( this ), spellInfo, dmg, abs_dmg);
2995                pVictim->m_procCounter = 0;
2996                static_cast< Unit* >( this )->HandleProc( aproc, pVictim, spellInfo, dmg, abs_dmg);
2997                static_cast< Unit* >( this )->m_procCounter = 0;
2998        }
2999        if( this->IsPlayer() )
3000        {
3001                        static_cast< Player* >( this )->m_casted_amount[school] = ( uint32 )res;
3002        }
3003
3004        if( !(dmg.full_damage == 0 && abs_dmg) )
3005        {
3006                //Only pushback the victim current spell if it's not fully absorbed
3007                if( pVictim->GetCurrentSpell() )
3008                        pVictim->GetCurrentSpell()->AddTime( school );
3009        }
3010
3011//==========================================================================================
3012//==============================Post Damage Processing======================================
3013//==========================================================================================
3014        if( (int32)dmg.resisted_damage == dmg.full_damage && !abs_dmg )
3015        {
3016                //Magic Absorption
3017                if( pVictim->IsPlayer() )
3018                {
3019                        if( static_cast< Player* >( pVictim )->m_RegenManaOnSpellResist )
3020                        {
3021                                Player* pl = static_cast< Player* >( pVictim );
3022
3023                                uint32 maxmana = pl->GetMaxPower( POWER_TYPE_MANA );
3024                                uint32 amount = uint32( maxmana * pl->m_RegenManaOnSpellResist );
3025
3026                                pVictim->Energize( pVictim, 29442, amount, POWER_TYPE_MANA );
3027                        }
3028                        // we still stay in combat dude
3029                        static_cast< Player* >(pVictim)->CombatStatusHandler_ResetPvPTimeout();
3030                }
3031                if( IsPlayer() )
3032                        static_cast< Player* >(this)->CombatStatusHandler_ResetPvPTimeout();
3033        }
3034        if( school == SHADOW_DAMAGE )
3035        {
3036                if( IsPlayer() && ((Unit*)this)->isAlive() && ((Player*)this)->getClass() == PRIEST )
3037                        ((Player*)this)->VampiricSpell(float2int32(res), pVictim);
3038
3039                if( pVictim->isAlive() && this->IsUnit() )
3040                {
3041                        //Shadow Word:Death
3042                        if( spellID == 32379 || spellID == 32996 || spellID == 48157 || spellID == 48158 ) 
3043                        {
3044                                uint32 damage = uint32( res + abs_dmg );
3045                                uint32 absorbed = static_cast< Unit* >( this )->AbsorbDamage( school, &damage );
3046                                DealDamage( static_cast< Unit* >( this ), damage, 2, 0, spellID );
3047                                SendSpellNonMeleeDamageLog( this, this, spellID, damage, static_cast<uint8>( school ), absorbed, 0, false, 0, false, IsPlayer() );
3048                        }
3049                }
3050        }
3051}
3052
3053//*****************************************************************************************
3054//* SpellLog packets just to keep the code cleaner and better to read
3055//*****************************************************************************************
3056
3057void Object::SendSpellLog(Object *Caster, Object *Target,uint32 Ability, uint8 SpellLogType)
3058{
3059        if( Caster == NULL || Target == NULL || Ability == 0 ) 
3060                return;
3061
3062
3063        WorldPacket data( SMSG_SPELLLOGMISS, 26 );
3064       
3065    data << uint32( Ability );                                  // spellid
3066        data << Caster->GetGUID();                                      // caster / player
3067        data << uint8( 1 );                                                     // unknown but I think they are const
3068        data << uint32( 1 );                                            // unknown but I think they are const
3069        data << Target->GetGUID();                                      // target
3070        data << uint8( SpellLogType );                          // spelllogtype
3071       
3072    Caster->SendMessageToSet( &data, true );
3073}
3074
3075
3076void Object::SendSpellNonMeleeDamageLog( Object* Caster, Object* Target, uint32 SpellID, uint32 Damage, uint8 School, uint32 AbsorbedDamage, uint32 ResistedDamage, bool PhysicalDamage, uint32 BlockedDamage, bool CriticalHit, bool bToset )
3077{
3078        if( !Caster || !Target || !SpellID )
3079                return;
3080       
3081        uint32 Overkill = 0;
3082       
3083    if( Damage > Target->GetUInt32Value( UNIT_FIELD_HEALTH ) )
3084                Overkill = Damage - Target->GetUInt32Value( UNIT_FIELD_HEALTH );
3085
3086        WorldPacket data( SMSG_SPELLNONMELEEDAMAGELOG, 48 );
3087
3088        data << Target->GetNewGUID();
3089        data << Caster->GetNewGUID();
3090        data << uint32( SpellID );                    // SpellID / AbilityID
3091        data << uint32( Damage );                     // All Damage
3092        data << uint32( Overkill );                                     // Overkill
3093        data << uint8( g_spellSchoolConversionTable[School] );   // School
3094        data << uint32( AbsorbedDamage );             // Absorbed Damage
3095        data << uint32( ResistedDamage );             // Resisted Damage
3096        data << uint8( PhysicalDamage );      // Physical Damage (true/false)
3097        data << uint8( 0 );                   // unknown or it binds with Physical Damage
3098    data << uint32( BlockedDamage );                 // Physical Damage (true/false)
3099
3100    // unknown const
3101    if( CriticalHit )
3102        data << uint8( 7 );
3103    else
3104        data << uint8( 5 );
3105
3106    data << uint32( 0 );
3107
3108        Caster->SendMessageToSet( &data, bToset );
3109}
3110
3111void Object::SendAttackerStateUpdate( Object* Caster, Object* Target, dealdamage *Dmg, uint32 Damage, uint32 Abs, uint32 BlockedDamage, uint32 HitStatus, uint32 VState )
3112{
3113        if (!Caster || !Target || !Dmg)
3114                return;
3115
3116        WorldPacket data( SMSG_ATTACKERSTATEUPDATE, 70 );
3117
3118        uint32 Overkill = 0;
3119
3120        if( Damage > Target->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) )
3121                Overkill = Damage - Target->GetUInt32Value( UNIT_FIELD_HEALTH );
3122 
3123        data << uint32( HitStatus );
3124        data << Caster->GetNewGUID();
3125        data << Target->GetNewGUID();
3126
3127        data << uint32( Damage );                                               // Realdamage
3128        data << uint32( Overkill );                                     // Overkill
3129        data << uint8( 1 );                                     // Damage type counter / swing type
3130
3131        data << uint32( g_spellSchoolConversionTable[Dmg->school_type] );                                 // Damage school
3132        data << float( Dmg->full_damage );      // Damage float
3133        data << uint32( Dmg->full_damage );     // Damage amount
3134
3135    if( HitStatus & HITSTATUS_ABSORBED) {
3136                data << uint32( Abs );                          // Damage absorbed
3137        }
3138
3139    if( HitStatus & HITSTATUS_RESIST ){
3140                data << uint32( Dmg->resisted_damage ); // Damage resisted
3141        }
3142
3143    data << uint8( VState );
3144        data << uint32( 0 );                            // can be 0,1000 or -1
3145        data << uint32( 0 );
3146       
3147    if( HitStatus & HITSTATUS_BLOCK ){
3148                data << uint32( BlockedDamage );                // Damage amount blocked
3149        }
3150       
3151    if ( HitStatus & 0x00800000 ){
3152                data << uint32( 0 );                            // unknown
3153        }
3154
3155        if( HitStatus & HITSTATUS_unk )
3156        {
3157                data << uint32( 0 );
3158                data << float( 0 );
3159                data << float( 0 );
3160                data << float( 0 );
3161                data << float( 0 );
3162                data << float( 0 );
3163                data << float( 0 );
3164                data << float( 0 );
3165                data << float( 0 );
3166                for(uint8 i = 0; i < 5; ++i)
3167                {
3168                        data << float( 0 );
3169                        data << float( 0 );
3170                }
3171                data << uint32( 0 );
3172        }
3173
3174        SendMessageToSet(&data, Caster->IsPlayer());
3175}
3176
3177int32 Object::event_GetInstanceID()
3178{
3179        // return -1 for non-inworld.. so we get our shit moved to the right thread
3180        if(!IsInWorld())
3181                return -1;
3182        else
3183                return m_instanceId;
3184}
3185
3186void Object::EventSpellDamage(uint64 Victim, uint32 SpellID, uint32 Damage)
3187{
3188        if( !IsInWorld() )
3189                return;
3190
3191        Unit * pUnit = GetMapMgr()->GetUnit( Victim );
3192        if( pUnit == NULL )
3193                return;
3194
3195        SpellNonMeleeDamageLog( pUnit, SpellID, Damage, true );
3196}
3197
3198//! Object has an active state
3199bool Object::CanActivate()
3200{
3201        switch(m_objectTypeId)
3202        {
3203        case TYPEID_UNIT:
3204                {
3205                        if ( !IsPet() )
3206                                return true;
3207                }break;
3208
3209        case TYPEID_GAMEOBJECT:
3210                {
3211                        if(static_cast<GameObject*>(this)->HasAI() && GetByte(GAMEOBJECT_BYTES_1, 1) != GAMEOBJECT_TYPE_TRAP)
3212                                return true;
3213                }break;
3214        }
3215
3216        return false;
3217}
3218
3219void Object::Activate(MapMgr * mgr)
3220{
3221        switch ( m_objectTypeId )
3222        {
3223        case TYPEID_UNIT:
3224                mgr->activeCreatures.insert( ( Creature* )this );
3225                break;
3226
3227        case TYPEID_GAMEOBJECT:
3228                mgr->activeGameObjects.insert( ( GameObject* )this );
3229                break;
3230        }
3231        // Objects are active so set to true.
3232        Active = true;
3233}
3234
3235void Object::Deactivate(MapMgr * mgr)
3236{
3237        if ( mgr == NULL )
3238                return;
3239
3240        switch(m_objectTypeId)
3241        {
3242        case TYPEID_UNIT:
3243                // check iterator
3244                if(mgr->creature_iterator != mgr->activeCreatures.end() && (*mgr->creature_iterator) == TO_CREATURE(this))
3245                        ++mgr->creature_iterator;
3246                mgr->activeCreatures.erase((Creature*)this);
3247                break;
3248
3249        case TYPEID_GAMEOBJECT:
3250                mgr->activeGameObjects.erase((GameObject*)this);
3251                break;
3252        }
3253        Active = false;
3254}
3255
3256void Object::SetByte(uint32 index, uint32 index1,uint8 value)
3257{
3258        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
3259        // save updating when val isn't changing.
3260
3261    uint8 * v =&((uint8*)m_uint32Values)[index*4+index1];
3262
3263        if(*v == value)
3264                return;
3265
3266        *v = value;
3267
3268        if(IsInWorld())
3269        {
3270                m_updateMask.SetBit( index );
3271
3272                if(!m_objectUpdated)
3273                {
3274                        m_mapMgr->ObjectUpdated(this);
3275                        m_objectUpdated = true;
3276                }
3277        }
3278
3279}
3280
3281void Object::SetByteFlag( uint16 index, uint8 offset, uint8 newFlag )
3282{
3283    Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
3284        Arcemu::Util::ARCEMU_ASSERT(    offset < 4 );
3285       
3286        offset <<= 3;
3287
3288    if( !( uint8( m_uint32Values[ index ] >> offset ) & newFlag ) )
3289    {
3290        m_uint32Values[ index ] |= uint32( uint32( newFlag ) << offset );
3291
3292        if(IsInWorld())
3293        {
3294                        m_updateMask.SetBit( index );
3295
3296            if(!m_objectUpdated)
3297            {
3298                m_mapMgr->ObjectUpdated(this);
3299                m_objectUpdated = true;
3300            }
3301        }
3302    }
3303}
3304
3305void Object::RemoveByteFlag( uint16 index, uint8 offset, uint8 oldFlag )
3306{
3307        Arcemu::Util::ARCEMU_ASSERT(    index < m_valuesCount );
3308        Arcemu::Util::ARCEMU_ASSERT(    offset < 4 );
3309       
3310        offset <<= 3;
3311
3312    if( uint8( m_uint32Values[ index ] >> offset ) & oldFlag )
3313    {
3314        m_uint32Values[ index ] &= ~uint32( uint32( oldFlag ) << offset );
3315
3316        if(IsInWorld())
3317        {
3318                        m_updateMask.SetBit( index );
3319
3320            if(!m_objectUpdated)
3321            {
3322                m_mapMgr->ObjectUpdated(this);
3323                m_objectUpdated = true;
3324            }
3325        }
3326    }
3327}
3328
3329void Object::SetZoneId(uint32 newZone)
3330{
3331        m_zoneId = newZone;
3332
3333        if( m_objectTypeId == TYPEID_PLAYER && static_cast< Player* >( this )->GetGroup() )
3334                static_cast< Player* >( this )->GetGroup()->HandlePartialChange( PARTY_UPDATE_FLAG_ZONEID, static_cast< Player* >( this ) );
3335}
3336
3337void Object::PlaySoundToSet(uint32 sound_entry)
3338{
3339        WorldPacket data(SMSG_PLAY_SOUND, 4);
3340        data << sound_entry;
3341       
3342    SendMessageToSet(&data, true);
3343}
3344
3345void Object::_SetExtension(const string& name, void* ptr)
3346{
3347        if( m_extensions == NULL )
3348                m_extensions = new ExtensionSet;
3349
3350        m_extensions->insert( make_pair( name, ptr ) );
3351}
3352
3353bool Object::IsInBg()
3354{
3355        MapInfo *pMapinfo = WorldMapInfoStorage.LookupEntry( GetMapId() );
3356       
3357    if( pMapinfo != NULL )
3358        {
3359                return ( pMapinfo->type == INSTANCE_BATTLEGROUND );
3360        }
3361
3362        return false;
3363}
3364
3365uint32 Object::GetTeam()
3366{
3367        if (IsPlayer())
3368        {
3369                return static_cast< Player* >( this )->GetTeam();
3370        }
3371        if (IsPet())
3372        {
3373                if (static_cast< Pet* >( this )->GetPetOwner() != NULL)
3374                {
3375                        return static_cast< Pet* >( this )->GetPetOwner()->GetTeam();
3376                }
3377        }
3378        if (IsUnit() && !IsPlayer() && static_cast< Creature* >( this )->IsTotem() )
3379        {
3380                if (static_cast< Creature* >( this )->GetTotemOwner() != NULL)
3381                {
3382                        return static_cast< Creature* >( this )->GetTotemOwner()->GetTeam();
3383                }
3384        }
3385
3386        return static_cast<uint32>(-1);
3387}
3388
3389//Manipulates the phase value, see "enum PHASECOMMANDS" in Object.h for a longer explanation!
3390void Object::Phase(uint8 command, uint32 newphase)
3391{
3392        switch( command )
3393        {
3394        case PHASE_SET:
3395                m_phase = newphase;
3396                break;
3397        case PHASE_ADD:
3398                m_phase |= newphase;
3399                break;
3400        case PHASE_DEL:
3401                m_phase &= ~newphase;
3402                break;
3403        case PHASE_RESET:
3404                m_phase = 1;
3405                break;
3406        default:
3407                return;
3408        }
3409
3410        if ( IsPlayer() ) 
3411        {
3412                Player * p_player=static_cast< Player* >( this );
3413                std::list<Pet*> summons = p_player->GetSummons();
3414                for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
3415                {
3416                        (*itr)->Phase(command, newphase);
3417                }
3418                //We should phase other, non-combat "pets" too...
3419        }
3420
3421        for( std::set<Object*>::iterator itr=m_objectsInRange.begin(); itr!=m_objectsInRange.end(); ++itr )
3422        {
3423                if ( (*itr)->IsUnit() )
3424                        static_cast< Unit* >( *itr )->UpdateVisibility();
3425        }
3426
3427        if ( IsUnit() )
3428                static_cast< Unit* >( this )->UpdateVisibility();
3429
3430        return;
3431}
3432
3433void Object::AddInRangeObject(Object *pObj){
3434
3435    Arcemu::Util::ARCEMU_ASSERT(    pObj != NULL );
3436
3437        if( pObj == this )
3438        sLog.outError( "We are in range of ourselves!" );
3439
3440    if( pObj->IsPlayer() )
3441        m_inRangePlayers.insert( pObj ); 
3442
3443    m_objectsInRange.insert( pObj );
3444}
3445
3446void Object::OutPacketToSet(uint16 Opcode, uint16 Len, const void * Data, bool self)
3447{
3448        if( !IsInWorld() )
3449                return;
3450
3451    // We are on Object level, which means we can't send it to ourselves so we only send to Players inrange
3452        for( std::set< Object* >::iterator itr = m_inRangePlayers.begin(); itr != m_inRangePlayers.end(); ++itr )
3453        {
3454        Object *o = *itr;
3455
3456        o->OutPacket( Opcode, Len, Data );
3457        }
3458}
3459
3460void Object::SendMessageToSet(WorldPacket *data, bool bToSelf,bool myteam_only)
3461{
3462    if(!IsInWorld())
3463        return;
3464
3465    for( std::set< Object* >::iterator itr = m_inRangePlayers.begin(); itr != m_inRangePlayers.end(); ++itr ){
3466        Object *o = *itr;
3467
3468        o->SendPacket( data );
3469    }
3470}
3471
3472void Object::RemoveInRangeObject( Object *pObj ){
3473    Arcemu::Util::ARCEMU_ASSERT(    pObj != NULL );   
3474 
3475    if( pObj->IsPlayer() ){
3476        Arcemu::Util::ARCEMU_ASSERT(    m_inRangePlayers.erase( pObj ) == 1 );
3477    }
3478   
3479    Arcemu::Util::ARCEMU_ASSERT(    m_objectsInRange.erase( pObj ) == 1 );
3480
3481    OnRemoveInRangeObject( pObj );
3482}
3483
3484void Object::RemoveSelfFromInrangeSets(){
3485    std::set< Object* >::iterator itr;
3486
3487    for( itr = m_objectsInRange.begin(); itr != m_objectsInRange.end(); ++itr ){
3488        Object *o = *itr;
3489
3490        Arcemu::Util::ARCEMU_ASSERT(    o != NULL );
3491       
3492        o->RemoveInRangeObject( this );
3493       
3494    }
3495
3496}
3497
3498
3499void Object::OnRemoveInRangeObject( Object *pObj ){
3500    /* This method will remain empty for now, don't remove it!
3501    -dfighter
3502    */
3503}
Note: See TracBrowser for help on using the browser.