root/trunk/src/arcemu-world/AIInterface.cpp @ 2950

Revision 2950, 124.6 kB (checked in by Dfighter, 11 months ago)

Merging the Untested branch back to Trunk.
Trunk is now 3.2.2 compatible.

  • 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-2009 <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
23#ifndef UNIX
24#include <cmath>
25#endif
26
27
28#ifdef WIN32
29#define HACKY_CRASH_FIXES 1             // SEH stuff
30#endif
31
32AIInterface::AIInterface()
33:
34m_waypoints(NULL),
35m_canMove(true),
36m_destinationX(0),
37m_destinationY(0),
38m_destinationZ(0),
39m_nextPosX(0),
40m_nextPosY(0),
41m_nextPosZ(0),
42UnitToFollow(NULL),
43FollowDistance(0.0f),
44m_fallowAngle(float(M_PI/2)),
45m_timeToMove(0),
46m_timeMoved(0),
47m_moveTimer(0),
48m_WayPointsShowing(false),
49m_WayPointsShowBackwards(false),
50m_currentWaypoint(0),
51m_moveBackward(false),
52m_moveType(0),
53m_moveRun(false),
54m_moveSprint(false),
55m_moveFly(false),
56m_creatureState(STOPPED),
57m_canCallForHelp(false),
58m_hasCalledForHelp(false),
59m_fleeTimer(0),
60m_FleeDuration(0),
61m_canFlee(false),
62m_hasFleed(false),
63m_canRangedAttack(false),
64m_FleeHealth(0.0f),
65m_CallForHelpHealth(0.0f),
66m_AIState(STATE_IDLE),
67
68m_updateAssist(false),
69m_updateTargets(false),
70m_updateAssistTimer(1),
71m_updateTargetsTimer(TARGET_UPDATE_INTERVAL_ON_PLAYER),
72m_updateTargetsTimer2(0),
73
74m_nextSpell(NULL),
75m_nextTarget(0),
76totemspell(NULL),
77m_Unit(NULL),
78m_PetOwner(NULL),
79m_aiCurrentAgent(AGENT_NULL),
80m_runSpeed(0.0f),
81m_flySpeed(0.0f),
82UnitToFear(NULL),
83m_outOfCombatRange(2500), // Where did u get this value?
84
85tauntedBy(NULL),
86isTaunted(false),
87soullinkedWith(NULL),
88isSoulLinked(false),
89m_AllowedToEnterCombat(true),
90m_totalMoveTime(0),
91m_lastFollowX(0),
92m_lastFollowY(0),
93m_FearTimer(0),
94m_WanderTimer(0),
95m_totemspelltime(0),
96m_totemspelltimer(0),
97m_formationFollowAngle(0.0f),
98m_formationFollowDistance(0.0f),
99m_formationLinkTarget(0),
100m_formationLinkSqlId(0),
101m_currentHighestThreat(0),
102
103disable_combat(false),
104
105disable_melee(false),
106disable_ranged(false),
107disable_spell(false),
108
109disable_targeting(false),
110
111next_spell_time(0),
112waiting_for_cooldown(false),
113UnitToFollow_backup(NULL),
114m_isGuard(false),
115m_isNeutralGuard(false),
116m_is_in_instance(false),
117skip_reset_hp(false),
118timed_emotes(NULL),
119timed_emote_expire(0xFFFFFFFF),
120m_MovementState(MOVEMENTSTATE_STOP)
121
122#ifdef HACKY_SERVER_CLIENT_POS_SYNC
123,
124moved_for_attack(false)
125#endif
126{
127        m_aiTargets.clear();
128        m_assistTargets.clear();
129        m_spells.clear();
130}
131
132void AIInterface::EventAiInterfaceParamsetFinish()
133{
134        if( timed_emotes && timed_emotes->begin() != timed_emotes->end() )
135        {
136                next_timed_emote = timed_emotes->begin();
137                timed_emote_expire = (*next_timed_emote)->expire_after;
138        }
139}
140
141void AIInterface::Init(Unit *un, AIType at, MovementType mt)
142{
143        ASSERT(at != AITYPE_PET);
144
145        m_AIType = at;
146        m_MovementType = mt;
147
148        m_AIState = STATE_IDLE;
149        m_MovementState = MOVEMENTSTATE_STOP;
150
151        m_Unit = un;
152
153        m_walkSpeed = m_Unit->m_walkSpeed*0.001f;//move distance per ms time
154        m_runSpeed = m_Unit->m_runSpeed*0.001f;//move distance per ms time
155        m_flySpeed = m_Unit->m_flySpeed * 0.001f;
156        /*if(!m_DefaultMeleeSpell)
157        {
158                m_DefaultMeleeSpell = new AI_Spell;
159                m_DefaultMeleeSpell->entryId = 0;
160                m_DefaultMeleeSpell->spellType = 0;
161                m_DefaultMeleeSpell->agent = AGENT_MELEE;
162                m_DefaultSpell = m_DefaultMeleeSpell;
163        }*/
164        m_sourceX = un->GetPositionX();
165        m_sourceY = un->GetPositionY();
166        m_sourceZ = un->GetPositionZ();
167        m_guardTimer = getMSTime();
168}
169
170AIInterface::~AIInterface()
171{
172        for(list<AI_Spell*>::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
173                        delete (*itr);
174        m_spells.clear();
175}
176
177void AIInterface::Init(Unit *un, AIType at, MovementType mt, Unit *owner)
178{
179        ASSERT(at == AITYPE_PET || at == AITYPE_TOTEM);
180
181        m_AIType = at;
182        m_MovementType = mt;
183
184        m_AIState = STATE_IDLE;
185        m_MovementState = MOVEMENTSTATE_STOP;
186
187        m_Unit = un;
188        m_PetOwner = owner;
189
190        m_walkSpeed = m_Unit->m_walkSpeed*0.001f;//move distance per ms time
191        m_runSpeed = m_Unit->m_runSpeed*0.001f;//move/ms
192        m_flySpeed = m_Unit->m_flySpeed*0.001f;
193        m_sourceX = un->GetPositionX();
194        m_sourceY = un->GetPositionY();
195        m_sourceZ = un->GetPositionZ();
196}
197
198void AIInterface::HandleEvent(uint32 event, Unit* pUnit, uint32 misc1)
199{
200        if( m_Unit == NULL ) return;
201
202        if(m_AIState != STATE_EVADE)
203        {
204                switch(event)
205                {
206                case EVENT_ENTERCOMBAT:
207                        {
208                                if( pUnit == NULL || pUnit->IsDead() || m_Unit->IsDead() ) return;
209
210                                // set the target first
211                                if(pUnit && pUnit->GetInstanceID() == m_Unit->GetInstanceID())
212                                {
213                                        m_Unit->SetUInt64Value(UNIT_FIELD_TARGET, pUnit->GetGUID());
214                                }
215                                /* send the message */
216                                if( m_Unit->GetTypeId() == TYPEID_UNIT )
217                                {
218                                        if( static_cast< Creature* >( m_Unit )->has_combat_text )
219                                                objmgr.HandleMonsterSayEvent( static_cast< Creature* >( m_Unit ), MONSTER_SAY_EVENT_ENTER_COMBAT );
220
221                                        CALL_SCRIPT_EVENT(m_Unit, OnCombatStart)(pUnit);
222
223                                        if( static_cast< Creature* >( m_Unit )->m_spawn && ( static_cast< Creature* >( m_Unit )->m_spawn->channel_target_go || static_cast< Creature* >( m_Unit )->m_spawn->channel_target_creature))
224                                        {
225                                                m_Unit->SetUInt32Value(UNIT_CHANNEL_SPELL, 0);
226                                                m_Unit->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, 0);
227                                        }
228                                }
229
230                                // Stop the emote - change to fight emote
231                                m_Unit->SetUInt32Value( UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H );
232                                m_returnX = m_Unit->GetPositionX();
233                                m_returnY = m_Unit->GetPositionY();
234                                m_returnZ = m_Unit->GetPositionZ();
235
236                                m_moveRun = true; //run to the target
237
238                                // dismount if mounted
239                                m_Unit->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
240
241                                if(m_AIState != STATE_ATTACKING)
242                                        StopMovement(0);
243
244                                m_AIState = STATE_ATTACKING;
245                                if(m_Unit->GetMapMgr() && m_Unit->GetMapMgr()->GetMapInfo() && m_Unit->GetMapMgr()->GetMapInfo()->type == INSTANCE_RAID)
246                                {
247                                        if(m_Unit->GetTypeId() == TYPEID_UNIT)
248                                        {
249                                                if(static_cast<Creature*>(m_Unit)->GetCreatureInfo() && static_cast<Creature*>(m_Unit)->GetCreatureInfo()->Rank == 3)
250                                                {
251                                                         m_Unit->GetMapMgr()->AddCombatInProgress(m_Unit->GetGUID());
252                                                }
253                                        }
254                                }
255                                if (pUnit->IsPlayer() && static_cast<Player*>(pUnit)->InGroup())
256                                {
257                                        m_Unit->GetAIInterface()->modThreatByPtr(pUnit, 1);
258                                        Group *pGroup = static_cast<Player*>(pUnit)->GetGroup();
259
260                                        Player *pGroupGuy;
261                                        GroupMembersSet::iterator itr;
262                                        pGroup->Lock();
263                                        for(uint32 i = 0; i < pGroup->GetSubGroupCount(); i++) {
264                                                for(itr = pGroup->GetSubGroup(i)->GetGroupMembersBegin(); itr != pGroup->GetSubGroup(i)->GetGroupMembersEnd(); ++itr)
265                                                {
266                                                        pGroupGuy = (*itr)->m_loggedInPlayer;
267                                                        if( pGroupGuy && pGroupGuy->isAlive() && m_Unit->GetMapMgr() == pGroupGuy->GetMapMgr() && pGroupGuy->GetDistanceSq(pUnit) <= 40*40) //50 yards for now. lets see if it works
268                                                        {
269                                                                m_Unit->GetAIInterface()->AttackReaction(pGroupGuy, 1, 0);
270                                                        }
271                                                }
272                                        }
273                                        pGroup->Unlock();
274                                }
275                                //Zack : Put mob into combat animation. Take out weapons and start to look serious :P
276                                m_Unit->smsg_AttackStart( pUnit );
277                        }break;
278                case EVENT_LEAVECOMBAT:
279                        {
280                                if( pUnit == NULL ) return;     
281                               
282                                if( pUnit->IsCreature() )
283                                {
284                                        if( pUnit->IsDead() )
285                                                pUnit->RemoveAllAuras();
286                                        else
287                                                pUnit->RemoveNegativeAuras();
288                                }
289
290                                Unit* target = NULL;
291                                if (m_Unit->GetMapMgr() && m_Unit->GetMapMgr()->GetMapInfo())
292                                {
293                                        switch (m_Unit->GetMapMgr()->GetMapInfo()->type)
294                                        {
295                                        case INSTANCE_NULL:
296                                        case INSTANCE_BATTLEGROUND:
297                                                if (m_outOfCombatRange && _CalcDistanceFromHome() < m_outOfCombatRange)
298                                                        target = FindTarget();
299                                                break;
300
301                                        case INSTANCE_RAID:
302                                        case INSTANCE_NONRAID:
303                                        case INSTANCE_ARENA:
304                                                target = FindTarget();
305                                                break;
306                                        }
307
308                                        if(target != NULL)
309                                        {
310                                                AttackReaction(target, 1, 0);
311                                                return;
312                                        }
313                                }
314
315                                //cancel spells that we are casting. Should remove bug where creatures cast a spell after they died
316//                              CancelSpellCast();
317                                // restart emote
318                                if(m_Unit->GetTypeId() == TYPEID_UNIT)
319                                {
320                                        if( static_cast< Creature* >( m_Unit )->has_combat_text )
321                                                objmgr.HandleMonsterSayEvent( static_cast< Creature* >( m_Unit ), MONSTER_SAY_EVENT_ON_COMBAT_STOP );
322
323                                        if( static_cast< Creature* >( m_Unit )->original_emotestate )
324                                                m_Unit->SetUInt32Value( UNIT_NPC_EMOTESTATE, static_cast< Creature* >( m_Unit )->original_emotestate );
325                                        else
326                                                m_Unit->SetUInt32Value( UNIT_NPC_EMOTESTATE, 0 );
327
328                                        if(static_cast<Creature*>(m_Unit)->m_spawn && (static_cast< Creature* >( m_Unit )->m_spawn->channel_target_go || static_cast< Creature* >( m_Unit )->m_spawn->channel_target_creature ) )
329                                        {
330                                                if(static_cast<Creature*>(m_Unit)->m_spawn->channel_target_go)
331                                                        sEventMgr.AddEvent( static_cast< Creature* >( m_Unit ), &Creature::ChannelLinkUpGO, static_cast< Creature* >( m_Unit )->m_spawn->channel_target_go, EVENT_CREATURE_CHANNEL_LINKUP, 1000, 5, 0 );
332
333                                                if(static_cast<Creature*>(m_Unit)->m_spawn->channel_target_creature)
334                                                        sEventMgr.AddEvent( static_cast< Creature* >( m_Unit ), &Creature::ChannelLinkUpCreature, static_cast< Creature* >( m_Unit )->m_spawn->channel_target_creature, EVENT_CREATURE_CHANNEL_LINKUP, 1000, 5, 0 );
335                                        }
336                                }
337
338                                //reset ProcCount
339                                //ResetProcCounts();
340                                m_moveSprint = true;
341                                LockAITargets(true);
342                                m_aiTargets.clear();
343                                LockAITargets(false);
344                                m_fleeTimer = 0;
345                                m_hasFleed = false;
346                                m_hasCalledForHelp = false;
347                                m_nextSpell = NULL;
348                                SetNextTarget( (Unit*)NULL );
349                                m_Unit->CombatStatus.Vanished();
350
351                                if(m_AIType == AITYPE_PET)
352                                {
353                                        m_AIState = STATE_FOLLOWING;
354                                        UnitToFollow = m_PetOwner;
355                                        FollowDistance = 3.0f;
356                                        m_lastFollowX = m_lastFollowY = 0;
357                                        if( m_Unit->IsPet() )
358                                        {
359                                                static_cast< Pet* >( m_Unit )->SetPetAction( PET_ACTION_FOLLOW );
360                                                if( m_Unit->isAlive() && m_Unit->IsInWorld() )
361                                                {
362                                                        static_cast< Pet* >( m_Unit )->HandleAutoCastEvent( AUTOCAST_EVENT_LEAVE_COMBAT );
363                                                }
364                                        }
365                                        HandleEvent(EVENT_FOLLOWOWNER, 0, 0);
366                                }
367                                else
368                                {
369                                        m_AIState = STATE_EVADE;
370
371                                        Unit* SavedFollow = UnitToFollow;
372                                        UnitToFollow = NULL;
373                                        FollowDistance = 0.0f;
374                                        m_lastFollowX = m_lastFollowY = 0;
375
376                                        if(m_Unit->isAlive())
377                                        {
378                                                if(m_returnX != 0.0f && m_returnY != 0.0f && m_returnZ != 0.0f)
379                                                        MoveTo(m_returnX,m_returnY,m_returnZ,m_Unit->GetSpawnO());
380                                                else
381                                                {
382                                                        MoveTo(m_Unit->GetSpawnX(),m_Unit->GetSpawnY(),m_Unit->GetSpawnZ(),m_Unit->GetSpawnO());
383                                                        m_returnX=m_Unit->GetSpawnX();
384                                                        m_returnY=m_Unit->GetSpawnY();
385                                                        m_returnZ=m_Unit->GetSpawnZ();
386                                                }
387
388                                                Creature *aiowner = static_cast<Creature*>(m_Unit);
389                                                //clear tagger.
390                                                aiowner->Tagged = false;
391                                                aiowner->TaggerGuid = 0;
392                                                aiowner->SetUInt32Value(UNIT_DYNAMIC_FLAGS,aiowner->GetUInt32Value(UNIT_DYNAMIC_FLAGS) & ~(U_DYN_FLAG_TAGGED_BY_OTHER |U_DYN_FLAG_LOOTABLE));
393                                                aiowner->m_lootMethod = -1;
394                                        }
395                                        CALL_SCRIPT_EVENT(m_Unit, OnCombatStop)(SavedFollow);
396                                }
397
398                                if(m_Unit->GetMapMgr() && m_Unit->GetMapMgr()->GetMapInfo() && m_Unit->GetMapMgr()->GetMapInfo()->type == INSTANCE_RAID)
399                                {
400                                        if(m_Unit->GetTypeId() == TYPEID_UNIT)
401                                        {
402                                                if(static_cast<Creature*>(m_Unit)->GetCreatureInfo() && static_cast<Creature*>(m_Unit)->GetCreatureInfo()->Rank == 3)
403                                                {
404                                                          m_Unit->GetMapMgr()->RemoveCombatInProgress(m_Unit->GetGUID());
405                                                }
406                                        }
407                                }
408
409                                // Remount if mounted
410                                if(m_Unit->GetTypeId() == TYPEID_UNIT)
411                                {
412                                        Creature *creature = static_cast< Creature* >( m_Unit );
413                                        if( creature->GetProto() && creature->m_spawn )
414                                                m_Unit->SetUInt32Value( UNIT_FIELD_MOUNTDISPLAYID, creature->m_spawn->MountedDisplayID );
415                                                //m_Unit->SetUInt32Value( UNIT_FIELD_MOUNTDISPLAYID, static_cast< Creature* >( m_Unit )->GetSpawnO->MountedDisplayID );
416                                }
417                                //Zack : not sure we need to send this. Did not see it in the dumps since mob died eventually but it seems logical to make this
418                                m_Unit->smsg_AttackStop( pUnit );
419                        }break;
420                case EVENT_DAMAGETAKEN:
421                        {
422                                if( pUnit == NULL ) return;
423
424                                if( static_cast< Creature* >( m_Unit )->has_combat_text )
425                                        objmgr.HandleMonsterSayEvent( static_cast< Creature* >( m_Unit ), MONSTER_SAY_EVENT_ON_DAMAGE_TAKEN );
426
427                                if( pUnit->HasAura(24575) )
428                                        pUnit->RemoveAura(24575);
429
430                                CALL_SCRIPT_EVENT(m_Unit, OnDamageTaken)(pUnit, float(misc1));
431                                if(!modThreatByPtr(pUnit, misc1))
432                                {
433                                        m_aiTargets.insert(TargetMap::value_type(pUnit->GetGUID(), misc1));
434                                }
435                                pUnit->CombatStatus.OnDamageDealt( m_Unit );
436                        }break;
437                case EVENT_FOLLOWOWNER:
438                        {
439                                m_AIState = STATE_FOLLOWING;
440                                if(m_Unit->IsPet())
441                                        ((Pet*)m_Unit)->SetPetAction(PET_ACTION_FOLLOW);
442                                UnitToFollow = m_PetOwner;
443                                m_lastFollowX = m_lastFollowY = 0;
444                                FollowDistance = 4.0f;
445
446                                LockAITargets(true);
447                                m_aiTargets.clear();
448                                LockAITargets(false);
449                                m_fleeTimer = 0;
450                                m_hasFleed = false;
451                                m_hasCalledForHelp = false;
452                                m_nextSpell = NULL;
453                                SetNextTarget( (Unit*)NULL );
454                                m_moveRun = true;
455                        }break;
456
457                case EVENT_FEAR:
458                        {
459                                if( pUnit == NULL ) return;
460
461                                m_FearTimer = 0;
462                                SetUnitToFear(pUnit);
463
464                                CALL_SCRIPT_EVENT(m_Unit, OnFear)(pUnit, 0);
465                                m_AIState = STATE_FEAR;
466                                StopMovement(1);
467
468                                UnitToFollow_backup = UnitToFollow;
469                                UnitToFollow = NULL;
470                                m_lastFollowX = m_lastFollowY = 0;
471                                FollowDistance_backup = FollowDistance;
472                                FollowDistance = 0.0f;
473
474                                LockAITargets(true);
475                                m_aiTargets.clear(); // we'll get a new target after we are unfeared
476                                LockAITargets(false);
477                                m_fleeTimer = 0;
478                                m_hasFleed = false;
479                                m_hasCalledForHelp = false;
480
481                                // update speed
482                                m_moveRun = true;
483                                getMoveFlags();
484
485                                SetNextSpell( NULL );
486                                SetNextTarget( (Unit*)NULL);
487                        }break;
488
489                case EVENT_UNFEAR:
490                        {
491                                UnitToFollow = UnitToFollow_backup;
492                                FollowDistance = FollowDistance_backup;
493                                m_AIState = STATE_IDLE; // we need this to prevent permanent fear, wander, and other problems
494
495                                SetUnitToFear(NULL);
496                                StopMovement(1);
497                        }break;
498
499                case EVENT_WANDER:
500                        {
501                                if( pUnit == NULL ) return;
502
503                                m_WanderTimer = 0;
504
505                                //CALL_SCRIPT_EVENT(m_Unit, OnWander)(pUnit, 0); FIX ME
506                                m_AIState = STATE_WANDER;
507                                StopMovement(1);
508
509                                UnitToFollow_backup = UnitToFollow;
510                                UnitToFollow = NULL;
511                                m_lastFollowX = m_lastFollowY = 0;
512                                FollowDistance_backup = FollowDistance;
513                                FollowDistance = 0.0f;
514
515                                LockAITargets(true);
516                                m_aiTargets.clear(); // we'll get a new target after we are unwandered
517                                LockAITargets(false);
518                                m_fleeTimer = 0;
519                                m_hasFleed = false;
520                                m_hasCalledForHelp = false;
521
522                                // update speed
523                                m_moveRun = true;
524                                getMoveFlags();
525
526                                SetNextSpell(NULL);
527                                SetNextTarget( (Unit*)NULL );
528                        }break;
529
530                case EVENT_UNWANDER:
531                        {
532                                UnitToFollow = UnitToFollow_backup;
533                                FollowDistance = FollowDistance_backup;
534                                m_AIState = STATE_IDLE; // we need this to prevent permanent fear, wander, and other problems
535
536                                StopMovement(1);
537                        }break;
538
539                default:
540                        {
541                        }break;
542                }
543        }
544
545        //Should be able to do this stuff even when evading
546        switch(event)
547        {
548                case EVENT_UNITDIED:
549                {
550                        if( pUnit == NULL ) return;
551
552                        if( static_cast< Creature* >( m_Unit )->has_combat_text )
553                                objmgr.HandleMonsterSayEvent( static_cast< Creature* >( m_Unit ), MONSTER_SAY_EVENT_ON_DIED );
554
555                        CALL_SCRIPT_EVENT(m_Unit, OnDied)(pUnit);
556                        if ( m_Unit->IsCreature() )
557                                CALL_INSTANCE_SCRIPT_EVENT( m_Unit->GetMapMgr(), OnCreatureDeath )( TO_CREATURE( m_Unit ), pUnit );
558
559                        m_AIState = STATE_IDLE;
560
561                        StopMovement(0);
562                        LockAITargets(true);
563                        m_aiTargets.clear();
564                        LockAITargets(false);
565                        UnitToFollow = NULL;
566                        m_lastFollowX = m_lastFollowY = 0;
567                        UnitToFear = NULL;
568                        FollowDistance = 0.0f;
569                        m_fleeTimer = 0;
570                        m_hasFleed = false;
571                        m_hasCalledForHelp = false;
572                        m_nextSpell = NULL;
573
574                        SetNextTarget( (Unit*)NULL );
575                        //reset ProcCount
576                        //ResetProcCounts();
577               
578                        //reset waypoint to 0
579                        m_currentWaypoint = 0;
580                       
581                        // There isn't any need to do any attacker checks here, as
582                        // they should all be taken care of in DealDamage
583
584                        //removed by Zack : why do we need to go to our master if we just died ? On next spawn we will be spawned near him after all
585/*                      if(m_AIType == AITYPE_PET)
586                        {
587                                SetUnitToFollow(m_PetOwner);
588                                SetFollowDistance(3.0f);
589                                HandleEvent(EVENT_FOLLOWOWNER, m_Unit, 0);
590                        }*/
591
592                        Instance *pInstance = NULL;
593                        if( m_Unit->GetMapMgr() )
594                                pInstance = m_Unit->GetMapMgr()->pInstance;
595
596                        if(m_Unit->GetMapMgr()
597                                && m_Unit->GetTypeId() == TYPEID_UNIT
598                                && !m_Unit->IsPet() 
599                                && pInstance
600                                && (pInstance->m_mapInfo->type == INSTANCE_RAID
601                                || pInstance->m_mapInfo->type == INSTANCE_NONRAID
602                                || pInstance->m_mapInfo->type == INSTANCE_ARENA ))
603                        {
604                                InstanceBossInfoMap *bossInfoMap = objmgr.m_InstanceBossInfoMap[m_Unit->GetMapMgr()->GetMapId()];
605                                Creature *pCreature = static_cast< Creature* >( m_Unit );
606                                bool found = false;
607
608                                if(IS_PERSISTENT_INSTANCE(pInstance) && bossInfoMap != NULL && pCreature->GetProto())
609                                {
610                                        uint32 npcGuid = pCreature->GetProto()->Id;
611                                        InstanceBossInfoMap::const_iterator bossInfo = bossInfoMap->find(npcGuid);
612                                        if(bossInfo != bossInfoMap->end())
613                                        {
614                                                found = true;
615                                                m_Unit->GetMapMgr()->pInstance->m_killedNpcs.insert( npcGuid );
616                                                m_Unit->GetMapMgr()->pInstance->SaveToDB();
617                                                for(InstanceBossTrashList::iterator trash = bossInfo->second->trash.begin(); trash != bossInfo->second->trash.end(); ++trash)
618                                                {
619                                                        Creature *c = m_Unit->GetMapMgr()->GetSqlIdCreature((*trash));
620                                                        if(c != NULL)
621                                                                c->m_noRespawn = true;
622                                                }
623                                                if(!pInstance->m_persistent)
624                                                {
625                                                        pInstance->m_persistent = true;
626                                                        pInstance->SaveToDB();
627                                                        for(PlayerStorageMap::iterator itr = m_Unit->GetMapMgr()->m_PlayerStorage.begin(); itr != m_Unit->GetMapMgr()->m_PlayerStorage.end(); ++itr)
628                                                        {
629                                                                (*itr).second->SetPersistentInstanceId(pInstance);
630                                                        }
631                                                }
632                                        }
633                                }
634
635                                if (found == false) {
636                                        // No instance boss information ... so fallback ...
637                                        uint32 npcGuid = pCreature->GetSQL_id();
638                                        m_Unit->GetMapMgr()->pInstance->m_killedNpcs.insert( npcGuid );
639                                        m_Unit->GetMapMgr()->pInstance->SaveToDB();
640                                }
641                        }
642                        if(m_Unit->GetMapMgr() && m_Unit->GetMapMgr()->GetMapInfo() && m_Unit->GetMapMgr()->GetMapInfo()->type == INSTANCE_RAID)
643                        {
644                                if(m_Unit->GetTypeId() == TYPEID_UNIT)
645                                {
646                                        if(static_cast<Creature*>(m_Unit)->GetCreatureInfo() && static_cast<Creature*>(m_Unit)->GetCreatureInfo()->Rank == 3)
647                                        {
648                                                m_Unit->GetMapMgr()->RemoveCombatInProgress(m_Unit->GetGUID());
649                                        }
650                                }
651                        }
652
653
654                        //remove negative auras
655                        //if( m_Unit->IsCreature() )
656                        //      m_Unit->RemoveNegativeAuras();
657
658                }break;
659        }
660}
661
662void AIInterface::Update(uint32 p_time)
663{
664        float tdist;
665        if(m_AIType == AITYPE_TOTEM)
666        {
667                assert(totemspell != 0);
668                if(p_time >= m_totemspelltimer)
669                {
670                        Spell *pSpell = new Spell(m_Unit, totemspell, true, 0);
671                        if (!pSpell)
672                                return;
673                        SpellCastTargets targets(0);
674                        if(!GetNextTarget() ||
675                                (GetNextTarget() && 
676                                        (!m_Unit->GetMapMgr()->GetUnit(GetNextTarget()->GetGUID()) || 
677                                        !GetNextTarget()->isAlive() ||
678                                        !IsInrange(m_Unit,GetNextTarget(),pSpell->GetProto()->base_range_or_radius_sqr) ||
679                                        !isAttackable(m_Unit, GetNextTarget(),!(pSpell->GetProto()->c_is_flags & SPELL_FLAG_IS_TARGETINGSTEALTHED))
680                                        )
681                                )
682                                )
683                        {
684                                //we set no target and see if we managed to fid a new one
685                                SetNextTarget( (Unit*)NULL );
686                                //something happened to our target, pick another one
687                                pSpell->GenerateTargets(&targets);
688                                if(targets.m_targetMask & TARGET_FLAG_UNIT)
689                                        SetNextTarget( targets.m_unitTarget );
690                        }
691                        if(GetNextTarget())
692                        {
693                                SpellCastTargets targets(GetNextTarget()->GetGUID());
694                                pSpell->prepare(&targets);
695                                // need proper cooldown time!
696                                m_totemspelltimer = m_totemspelltime;
697                        }
698                        else
699                        {
700                                delete pSpell;
701                                pSpell = NULL;
702                        }
703                        // these will *almost always* be AoE, so no need to find a target here.
704//                      SpellCastTargets targets(m_Unit->GetGUID());
705//                      Spell * pSpell = new Spell(m_Unit, totemspell, true, 0);
706//                      pSpell->prepare(&targets);
707                        // need proper cooldown time!
708//                      m_totemspelltimer = m_totemspelltime;
709                }
710                else
711                {
712                        m_totemspelltimer -= p_time;
713                }
714                return;
715        }
716
717        _UpdateTimer(p_time);
718        _UpdateTargets();
719        if(m_Unit->isAlive() && m_AIState != STATE_IDLE
720                && m_AIState != STATE_FOLLOWING && m_AIState != STATE_FEAR
721                && m_AIState != STATE_WANDER && m_AIState != STATE_SCRIPTMOVE)
722        {
723                if(m_AIType == AITYPE_PET )
724                {
725                        if(!m_Unit->bInvincible && m_Unit->IsPet()) 
726                        {
727                                Pet * pPet = static_cast<Pet*>(m_Unit);
728       
729                                if(pPet->GetPetAction() == PET_ACTION_ATTACK || pPet->GetPetState() != PET_STATE_PASSIVE)
730                                {
731                                        _UpdateCombat(p_time);
732                                }
733                        }
734                        //we just use any creature as a pet guardian
735                        else if(!m_Unit->IsPet())
736                        {
737                                _UpdateCombat(p_time);
738                        }
739                }
740                else
741                {
742                        _UpdateCombat(p_time);
743                }
744        }
745
746        _UpdateMovement(p_time);
747        if(m_AIState==STATE_EVADE)
748        {
749                tdist = m_Unit->GetDistanceSq(m_returnX,m_returnY,m_returnZ);
750                if(tdist <= 4.0f/*2.0*/)
751                {
752                        m_AIState = STATE_IDLE;
753                        m_returnX = m_returnY = m_returnZ = 0.0f;
754                        m_moveRun = false;
755                        //removed by zack : in scripted events if we keep reducing this it will bug the world out !
756                        //On Blizz it will return to previous wp but we can accept the fact that it will move on to next one
757                        /*
758                        if(hasWaypoints())
759                        {
760                                if(m_moveBackward)
761                                {
762                                        if(m_currentWaypoint != GetWayPointsCount()-1)
763                                                m_currentWaypoint++;
764                                }
765                                else
766                                {
767                                        if(m_currentWaypoint != 0)
768                                                m_currentWaypoint--;
769                                }
770                        }
771                        */
772                        // Set health to full if they at there last location before attacking
773                        if(m_AIType != AITYPE_PET&&!skip_reset_hp)
774                                m_Unit->SetUInt32Value(UNIT_FIELD_HEALTH,m_Unit->GetUInt32Value(UNIT_FIELD_MAXHEALTH));
775                }
776                else
777                {
778                        if( m_creatureState == STOPPED )
779                        {
780                                // return to the home
781                                if( m_returnX == 0.0f && m_returnY == 0.0f )
782                                {
783                                        m_returnX = m_Unit->GetSpawnX();
784                                        m_returnY = m_Unit->GetSpawnY();
785                                        m_returnZ = m_Unit->GetSpawnZ();
786                                }
787
788                                MoveTo(m_returnX, m_returnY, m_returnZ, m_Unit->GetSpawnO());
789                        }
790                }
791        }
792
793        if(m_fleeTimer)
794        {
795                if(m_fleeTimer > p_time)
796                {
797                        m_fleeTimer -= p_time;
798                        _CalcDestinationAndMove(GetNextTarget(), 5.0f);
799                }
800                else
801                {
802                        m_fleeTimer = 0;
803                        SetNextTarget(FindTargetForSpell(m_nextSpell));
804                }
805        }
806
807        //Pet Dismiss after a certain distance away
808        /*if(m_AIType == AITYPE_PET && m_PetOwner != NULL)
809        {
810                float dist = (m_Unit->GetInstanceID() == m_PetOwner->GetInstanceID()) ?
811                        m_Unit->GetDistanceSq(m_PetOwner) : 99999.0f;
812
813                if(dist > 8100.0f) //90 yard away we Dismissed
814                {
815                        DismissPet();
816                        return;
817                }
818        }*/
819
820        if ( !GetNextTarget() && !m_fleeTimer && m_creatureState == STOPPED && m_AIState == STATE_IDLE && m_Unit->isAlive() )
821        {
822                if ( timed_emote_expire <= p_time ) // note that creature might go idle and p_time might get big next time ...We do not skip emotes because of lost time
823                {
824                        if ( (*next_timed_emote)->type == 1) //standstate
825                        {
826                                m_Unit->SetStandState( static_cast<uint8>( (*next_timed_emote)->value  ));
827                                m_Unit->SetUInt32Value ( UNIT_NPC_EMOTESTATE, 0 );
828                        }
829                        else if ( (*next_timed_emote)->type == 2) //emotestate
830                        {
831                                m_Unit->SetUInt32Value ( UNIT_NPC_EMOTESTATE, (*next_timed_emote)->value );
832                                m_Unit->SetStandState( 0 );
833                        }
834                        else if ( (*next_timed_emote)->type == 3) //oneshot emote
835                        {
836                                m_Unit->SetUInt32Value ( UNIT_NPC_EMOTESTATE, 0 );
837                                m_Unit->SetStandState( 0 );
838                                m_Unit->Emote( (EmoteType)(*next_timed_emote)->value );         // Animation
839                        }
840                        if ( (*next_timed_emote)->msg )
841                                m_Unit->SendChatMessage((*next_timed_emote)->msg_type, (*next_timed_emote)->msg_lang, (*next_timed_emote)->msg);
842
843                        timed_emote_expire = (*next_timed_emote)->expire_after; //should we keep lost time ? I think not
844                        next_timed_emote++;
845                        if ( next_timed_emote == timed_emotes->end() )
846                                next_timed_emote = timed_emotes->begin();
847                }
848                else 
849                        timed_emote_expire -= p_time;
850        }
851}
852
853void AIInterface::_UpdateTimer(uint32 p_time)
854{
855        if(m_updateAssistTimer > p_time)
856        {
857                m_updateAssistTimer -= p_time;
858        }else
859        {
860                m_updateAssist = true;
861                m_updateAssistTimer = TARGET_UPDATE_INTERVAL_ON_PLAYER * 2 - m_updateAssistTimer - p_time;
862        }
863
864        if(m_updateTargetsTimer > p_time)
865        {
866                m_updateTargetsTimer -= p_time;
867        }else
868        {
869                m_updateTargets = true;
870                m_updateTargetsTimer = TARGET_UPDATE_INTERVAL_ON_PLAYER * 2 - m_updateTargetsTimer - p_time;
871        }
872}
873
874void AIInterface::_UpdateTargets()
875{
876        if( m_Unit->IsPlayer() || (m_AIType != AITYPE_PET && disable_targeting ))
877                return;
878        if( ( ( Creature* )m_Unit )->GetCreatureInfo() && ( ( Creature* )m_Unit )->GetCreatureInfo()->Type == UNIT_TYPE_CRITTER )
879                return;
880
881        if(  m_Unit->GetMapMgr() == NULL )
882                return; 
883
884    AssistTargetSet::iterator i, i2;
885        TargetMap::iterator itr, it2;
886
887        // Find new Assist Targets and remove old ones
888        if(m_AIState == STATE_FLEEING)
889        {
890                FindFriends(100.0f/*10.0*/);
891        }
892        else if(m_AIState != STATE_IDLE && m_AIState != STATE_SCRIPTIDLE)
893        {
894                FindFriends(64.0f/*8.0f*/);
895        }
896
897        if( m_updateAssist )
898        {
899                m_updateAssist = false;
900        /*      deque<Unit*> tokill;
901
902                //modified for vs2005 compatibility
903                for(i = m_assistTargets.begin(); i != m_assistTargets.end(); ++i)
904                {
905                        if(m_Unit->GetDistanceSq((*i)) > 2500.0f|| !(*i)->isAlive() || !(*i)->CombatStatus.IsInCombat())
906                        {
907                                tokill.push_back(*i);
908                        }
909                }
910
911                for(deque<Unit*>::iterator i2 = tokill.begin(); i2 != tokill.end(); ++i2)
912                        m_assistTargets.erase(*i2);*/
913
914                for(i = m_assistTargets.begin(); i != m_assistTargets.end();)
915                {
916                        i2 = i++;
917                        if((*i2) == NULL || (*i2)->event_GetCurrentInstanceId() != m_Unit->event_GetCurrentInstanceId() ||
918                                !(*i2)->isAlive() || m_Unit->GetDistanceSq((*i2)) >= 2500.0f || !(*i2)->CombatStatus.IsInCombat() || !((*i2)->m_phase & m_Unit->m_phase) )
919                        {
920                                m_assistTargets.erase( i2 );
921                        }
922                }
923        }
924
925        if( m_updateTargets )
926        {
927                m_updateTargets = false;
928                /*deque<Unit*> tokill;
929
930                //modified for vs2005 compatibility
931                for(itr = m_aiTargets.begin(); itr != m_aiTargets.end();++itr)
932                {
933                        if(!itr->first->isAlive() || m_Unit->GetDistanceSq(itr->first) >= 6400.0f)
934                        {
935                                tokill.push_back(itr->first);
936                        }
937                }
938                for(deque<Unit*>::iterator itr = tokill.begin(); itr != tokill.end(); ++itr)
939                        m_aiTargets.erase((*itr));
940                tokill.clear();*/
941
942                LockAITargets(true);
943
944                for(itr = m_aiTargets.begin(); itr != m_aiTargets.end();)
945                {
946                        it2 = itr++;
947
948                        Unit *ai_t = m_Unit->GetMapMgr()->GetUnit( it2->first );
949                        if (ai_t == NULL) {
950                                m_aiTargets.erase( it2 );
951                        } else {
952                                bool instance = false;
953                                if (m_Unit->GetMapMgr() && m_Unit->GetMapMgr()->GetMapInfo())
954                                {
955                                        switch (m_Unit->GetMapMgr()->GetMapInfo()->type)
956                                        {
957                                        case INSTANCE_RAID:
958                                        case INSTANCE_NONRAID:
959                                        case INSTANCE_ARENA:
960                                                instance = true;
961                                                break;
962                                        }
963                                }
964
965                                if( ai_t->event_GetCurrentInstanceId() != m_Unit->event_GetCurrentInstanceId() || !ai_t->isAlive() || (!instance && m_Unit->GetDistanceSq(ai_t) >= 6400.0f || !(ai_t->m_phase & m_Unit->m_phase))) {
966                                        m_aiTargets.erase( it2 );
967                                }
968                        }
969                }
970
971                LockAITargets(false);
972               
973                if(m_aiTargets.size() == 0 
974                        && m_AIState != STATE_IDLE && m_AIState != STATE_FOLLOWING
975                        && m_AIState != STATE_EVADE && m_AIState != STATE_FEAR
976                        && m_AIState != STATE_WANDER && m_AIState != STATE_SCRIPTIDLE)
977                {
978                        if (m_Unit->GetMapMgr() && m_Unit->GetMapMgr()->GetMapInfo())
979                        {
980                                Unit* target = NULL;
981                                switch (m_Unit->GetMapMgr()->GetMapInfo()->type)
982                                {
983                                case INSTANCE_RAID:
984                                case INSTANCE_NONRAID:
985                                case INSTANCE_ARENA:
986                                        target = FindTarget();
987                                        break;
988
989                                default:
990                                        if (m_outOfCombatRange && _CalcDistanceFromHome() < m_outOfCombatRange)
991                                                target = FindTarget();
992                                        break;
993                                }
994
995                                if(target != NULL)
996                                        AttackReaction(target, 1, 0);
997                        }
998                }
999                else if( m_aiTargets.size() == 0 && (m_AIType == AITYPE_PET && (m_Unit->IsPet() && static_cast<Pet*>(m_Unit)->GetPetState() == PET_STATE_AGGRESSIVE) || (!m_Unit->IsPet() && disable_melee == false ) ) )
1000                {
1001                         Unit* target = FindTarget();
1002                         if( target )
1003                         {
1004                                 AttackReaction(target, 1, 0);
1005                         }
1006                }
1007        }
1008        // Find new Targets when we are ooc
1009        if((m_AIState == STATE_IDLE || m_AIState == STATE_SCRIPTIDLE) && m_assistTargets.size() == 0)
1010        {
1011                Unit* target = FindTarget();
1012                if(target)
1013                {
1014                        AttackReaction(target, 1, 0);
1015                }
1016        }
1017}
1018
1019///====================================================================
1020///  Desc: Updates Combat Status of m_Unit
1021///====================================================================
1022void AIInterface::_UpdateCombat(uint32 p_time)
1023{
1024        if( m_AIType != AITYPE_PET && disable_combat )
1025                return;
1026
1027        //just make sure we are not hitting self.
1028        // This was reported as an exploit.Should never occur anyway
1029        if( GetNextTarget() == m_Unit )
1030                SetNextTarget( GetMostHated() );
1031
1032        uint16 agent = static_cast<uint16>( m_aiCurrentAgent );
1033
1034        // If creature is very far from spawn point return to spawnpoint
1035        // If at instance don't return -- this is wrong ... instance creatures always returns to spawnpoint, dunno how do you got this idea.
1036        // If at instance returns to spawnpoint after empty agrolist
1037        if(     m_AIType != AITYPE_PET
1038                && m_AIState != STATE_EVADE
1039                && m_AIState != STATE_SCRIPTMOVE
1040                && !m_is_in_instance
1041                && (m_outOfCombatRange && m_Unit->GetDistanceSq(m_returnX,m_returnY,m_returnZ) > m_outOfCombatRange)  )
1042        {
1043                HandleEvent( EVENT_LEAVECOMBAT, m_Unit, 0 );
1044        }
1045        else if( GetNextTarget() == NULL && m_AIState != STATE_FOLLOWING && m_AIState != STATE_SCRIPTMOVE )
1046        {
1047//              SetNextTarget(FindTargetForSpell(m_nextSpell));
1048                if( m_is_in_instance )
1049                        SetNextTarget( FindTarget() );
1050                else 
1051                        SetNextTarget( GetMostHated() );
1052
1053                if( GetNextTarget() == NULL )
1054                {
1055                        HandleEvent( EVENT_LEAVECOMBAT, m_Unit, 0 );
1056                }
1057        } else if( GetNextTarget() && !(GetNextTarget()->m_phase & m_Unit->m_phase) ) // the target or we changed phase, stop attacking
1058        {
1059                if( m_is_in_instance )
1060                        SetNextTarget( FindTarget() );
1061                else 
1062                        SetNextTarget( GetMostHated() );
1063                if( GetNextTarget() == NULL )
1064                {
1065                        HandleEvent( EVENT_LEAVECOMBAT, m_Unit, 0 );
1066                }
1067        }
1068
1069#ifdef HACKY_SERVER_CLIENT_POS_SYNC
1070        if( moved_for_attack && GetNextTarget() && m_creatureState != MOVING )
1071        {
1072                //make sure we reached the exact desired location.
1073                // due to combat updates creature might interrupt moving and start attacking and does not get to destination making us get out of range errors
1074                if(     m_destinationX )
1075                {
1076                        m_Unit->m_position.x = m_destinationX;
1077                        m_Unit->m_position.y = m_destinationY;
1078                }
1079                //send a forced update position to client
1080                StopMovement(0); 
1081                //no need to update position until mob moves to nev target
1082                moved_for_attack = false;
1083        }
1084#endif
1085
1086        if (sWorld.Collision) {
1087               
1088                if ( m_Unit->GetMapMgr() != NULL && GetNextTarget() != NULL )
1089                {
1090                        if (!m_moveFly)
1091                        {
1092                                float target_land_z = CollideInterface.GetHeight(m_Unit->GetMapId(), GetNextTarget()->GetPositionX(), GetNextTarget()->GetPositionY(), GetNextTarget()->GetPositionZ() + 2.0f);
1093                                if ( target_land_z == NO_WMO_HEIGHT )
1094                                        target_land_z = m_Unit->GetMapMgr()->GetLandHeight(GetNextTarget()->GetPositionX(), GetNextTarget()->GetPositionY());
1095
1096                                if (fabs(GetNextTarget()->GetPositionZ() - target_land_z) > _CalcCombatRange(GetNextTarget(), false))
1097                                {
1098                                        if ( GetNextTarget()->GetTypeId() != TYPEID_PLAYER )
1099                                        {
1100                                                if ( target_land_z > m_Unit->GetMapMgr()->GetWaterHeight(GetNextTarget()->GetPositionX(), GetNextTarget()->GetPositionY()) )
1101                                                        HandleEvent( EVENT_LEAVECOMBAT, m_Unit, 0); //bugged npcs, probably db fault
1102                                        }
1103                                        else if (static_cast<Player*>(GetNextTarget())->GetSession() != NULL)
1104                                        {
1105                                                MovementInfo* mi=static_cast<Player*>(GetNextTarget())->GetSession()->GetMovementInfo();
1106
1107                                                if ( mi != NULL && !(mi->flags & MOVEFLAG_FALLING) && !(mi->flags & MOVEFLAG_SWIMMING) && !(mi->flags & MOVEFLAG_LEVITATE))
1108                                                        HandleEvent( EVENT_LEAVECOMBAT, m_Unit, 0);
1109                                        }
1110                                }
1111                        }
1112                }
1113        }
1114
1115        if ( GetNextTarget() != NULL && GetNextTarget()->GetTypeId() == TYPEID_UNIT && m_AIState == STATE_EVADE)
1116                HandleEvent( EVENT_LEAVECOMBAT, m_Unit, 0);
1117#ifdef HACKY_CRASH_FIXES
1118        bool cansee = (GetNextTarget() != NULL) ? CheckCurrentTarget() : NULL;
1119
1120#else
1121        bool cansee;
1122        if(GetNextTarget() && GetNextTarget()->event_GetCurrentInstanceId() == m_Unit->event_GetCurrentInstanceId())
1123        {
1124                if( m_Unit->GetTypeId() == TYPEID_UNIT )
1125                        cansee = static_cast< Creature* >( m_Unit )->CanSee( GetNextTarget() );
1126                else
1127                        cansee = static_cast< Player* >( m_Unit )->CanSee( GetNextTarget() );
1128        }
1129        else 
1130        {
1131                if( GetNextTarget() )
1132                        SetNextTarget( (Unit*)NULL );                   // corrupt pointer
1133
1134                cansee = false;
1135        }
1136#endif
1137        if( cansee && GetNextTarget() && GetNextTarget()->isAlive() && m_AIState != STATE_EVADE && !m_Unit->IsCasting() )
1138        {
1139                if( agent == AGENT_NULL || ( m_AIType == AITYPE_PET && !m_nextSpell ) ) // allow pets autocast
1140                {
1141                        if( !m_nextSpell )
1142                                m_nextSpell = this->getSpell();
1143
1144                        /*
1145                        if(!m_nextSpell && waiting_for_cooldown)
1146                        {
1147                                // don't start running to the target for melee if we're waiting for a cooldown.
1148                                return;
1149                        }
1150                        */
1151
1152                        if(m_canFlee && !m_hasFleed
1153                                && ((m_Unit->GetUInt32Value(UNIT_FIELD_HEALTH) / m_Unit->GetUInt32Value(UNIT_FIELD_MAXHEALTH)) < m_FleeHealth ))
1154                                agent = AGENT_FLEE;
1155                        else if(m_canCallForHelp
1156                                && !m_hasCalledForHelp
1157                                /*&& (m_CallForHelpHealth > (m_Unit->GetUInt32Value(UNIT_FIELD_HEALTH) / (m_Unit->GetUInt32Value(UNIT_FIELD_MAXHEALTH) > 0 ? m_Unit->GetUInt32Value(UNIT_FIELD_MAXHEALTH) : 1)))*/)
1158                                agent = AGENT_CALLFORHELP;
1159                        else if(m_nextSpell)
1160                        {
1161                                if(m_nextSpell->agent != AGENT_NULL)
1162                                {
1163                                        agent = m_nextSpell->agent;
1164                                }
1165                                else
1166                                {
1167                                        agent = AGENT_MELEE;
1168                                }
1169                        }
1170                        else
1171                        {
1172                                agent = AGENT_MELEE;
1173                        }
1174                }
1175                if(agent == AGENT_RANGED || agent == AGENT_MELEE)
1176                {
1177                        if(m_canRangedAttack)
1178                        {
1179                                agent = AGENT_MELEE;
1180                                if(GetNextTarget()->GetTypeId() == TYPEID_PLAYER)
1181                                {
1182                                        float dist = m_Unit->GetDistanceSq(GetNextTarget());
1183                                        if( static_cast< Player* >( GetNextTarget() )->m_currentMovement == MOVE_ROOT || dist >= 64.0f )
1184                                        {
1185                                                agent =  AGENT_RANGED;
1186                                        }
1187                                }
1188                                else if( GetNextTarget()->m_canMove == false || m_Unit->GetDistanceSq(GetNextTarget()) >= 64.0f )
1189                                {
1190                                   agent = AGENT_RANGED;
1191                                }
1192                        }
1193                        else
1194                        {
1195                                agent = AGENT_MELEE;
1196                        }
1197                }
1198
1199                if(this->disable_melee && agent == AGENT_MELEE)
1200                        agent = AGENT_NULL;
1201                 
1202                if(this->disable_ranged && agent == AGENT_RANGED)
1203                        agent = AGENT_NULL;
1204
1205                if(this->disable_spell && agent == AGENT_SPELL)
1206                        agent = AGENT_NULL;
1207
1208                switch(agent)
1209                {
1210                case AGENT_MELEE:
1211                        {
1212                                float combatReach[2]; // Calculate Combat Reach
1213                                float distance = m_Unit->CalcDistance(GetNextTarget());
1214
1215                                combatReach[0] = GetNextTarget()->GetModelHalfSize();
1216                                combatReach[1] = _CalcCombatRange(GetNextTarget(), false);
1217
1218                                if(     (
1219//                                      distance >= combatReach[0] &&  //removed by Zack. You can create an exploit with this that creature will never attack
1220                                        distance <= combatReach[1] + DISTANCE_TO_SMALL_TO_WALK ) 
1221//                                      || gracefull_hit_on_target == GetNextTarget()
1222                                        ) // Target is in Range -> Attack
1223                                {
1224//                                      gracefull_hit_on_target = NULL;
1225                                        if(UnitToFollow != NULL)
1226                                        {
1227                                                UnitToFollow = NULL; //we shouldn't be following any one
1228                                                m_lastFollowX = m_lastFollowY = 0;
1229                                                //m_Unit->setAttackTarget(NULL);  // remove ourselves from any target that might have been followed
1230                                        }
1231                                       
1232                                        FollowDistance = 0.0f;
1233//                                      m_moveRun = false;
1234                                        //FIX ME: offhand shit
1235                                        if(m_Unit->isAttackReady(false) && !m_fleeTimer)
1236                                        {
1237                                                m_creatureState = ATTACKING;
1238                                                bool infront = m_Unit->isInFront(GetNextTarget());
1239
1240                                                if(!infront) // set InFront
1241                                                {
1242                                                        //prevent mob from rotating while stunned
1243                                                        if(!m_Unit->IsStunned ())
1244                                                        {
1245                                                                setInFront(GetNextTarget());
1246                                                                infront = true;
1247                                                        }                                                       
1248                                                }
1249                                                if(infront)
1250                                                {
1251                                                        m_Unit->setAttackTimer(0, false);
1252#ifdef ENABLE_CREATURE_DAZE
1253                                                        //we require to know if strike was successful. If there was no dmg then target cannot be dazed by it
1254                                                        Unit *t_unit = GetNextTarget();
1255                                                        if( !t_unit )
1256                                                                return; //omg lol, in seconds we lost target. This might be possible due to the Eventrelocated
1257                                                        uint32 health_before_strike = t_unit->GetUInt32Value(UNIT_FIELD_HEALTH);
1258#endif
1259                                                        m_Unit->Strike( GetNextTarget(), ( agent == AGENT_MELEE ? MELEE : RANGED ), NULL, 0, 0, 0, false, false );
1260#ifdef ENABLE_CREATURE_DAZE
1261                                                        //now if the target is facing his back to us then we could just cast dazed on him :P
1262                                                        //as far as i know dazed is casted by most of the creatures but feel free to remove this code if you think otherwise
1263                                                        if(GetNextTarget() && m_Unit->m_factionDBC &&
1264                                                                !(m_Unit->m_factionDBC->RepListId == -1 && m_Unit->m_faction->FriendlyMask==0 && m_Unit->m_faction->HostileMask==0) /* neutral creature */
1265                                                                && GetNextTarget()->IsPlayer() && !m_Unit->IsPet() && health_before_strike>GetNextTarget()->GetUInt32Value(UNIT_FIELD_HEALTH)
1266                                                                && Rand(m_Unit->get_chance_to_daze(GetNextTarget())))
1267                                                        {
1268                                                                float our_facing=m_Unit->calcRadAngle(m_Unit->GetPositionX(),m_Unit->GetPositionY(),GetNextTarget()->GetPositionX(),GetNextTarget()->GetPositionY());
1269                                                                float his_facing=GetNextTarget()->GetOrientation();
1270                                                                if(fabs(our_facing-his_facing)<CREATURE_DAZE_TRIGGER_ANGLE && !GetNextTarget()->HasAura(CREATURE_SPELL_TO_DAZE))
1271                                                                {
1272                                                                        SpellEntry *info = dbcSpell.LookupEntry(CREATURE_SPELL_TO_DAZE);
1273                                                                        Spell *sp = new Spell(m_Unit, info, false, NULL);
1274                                                                        if (!sp)
1275                                                                                return;
1276                                                                        SpellCastTargets targets;
1277                                                                        targets.m_unitTarget = GetNextTarget()->GetGUID();
1278                                                                        sp->prepare(&targets);
1279                                                                }
1280                                                        }
1281#endif
1282                                                }
1283                                        }
1284                                }
1285                                else // Target out of Range -> Run to it
1286                                {
1287                                        //calculate next move
1288//                                      float dist = combatReach[1]; //this is theoretically right but annoying formula in game
1289//                                      float dist = combatReach[1] - m_Unit->GetFloatValue( UNIT_FIELD_COMBATREACH ); //ignore our combat reach, make sure target (player) can reach us first.
1290
1291                                        //practical tests show that we really should try to jump on target to get good results :S
1292                                        //simply ignore combat reach and move as close as visually not annoying
1293                                        float dist;
1294                                        if( m_Unit->GetModelHalfSize() > GetNextTarget()->GetModelHalfSize() )
1295                                                dist = m_Unit->GetModelHalfSize(); 
1296                                        else 
1297                                                dist = GetNextTarget()->GetModelHalfSize();
1298
1299                                        //removed by Zack. You can create an exploit with this that creature will never attack
1300//                                      if (distance<combatReach[0]) //if we are inside one each other
1301//                                              dist = -(combatReach[1] - distance);
1302//                                      gracefull_hit_on_target = GetNextTarget(); // this is an exploit where you manage to move the exact speed that mob will reposition itself all the time
1303
1304                                        m_moveRun = true;
1305                                        _CalcDestinationAndMove(GetNextTarget(), dist);
1306                                }
1307                        }break;
1308                case AGENT_RANGED:
1309                        {
1310                                float combatReach[2]; // Calculate Combat Reach
1311                                float distance = m_Unit->CalcDistance(GetNextTarget());
1312
1313                                combatReach[0] = 8.0f;
1314                                combatReach[1] = 30.0f;
1315
1316                                if(distance >= combatReach[0] && distance <= combatReach[1]) // Target is in Range -> Attack
1317                                {
1318                                        if(UnitToFollow != NULL)
1319                                        {
1320                                                UnitToFollow = NULL; //we shouldn't be following any one
1321                                                m_lastFollowX = m_lastFollowY = 0;
1322                                                //m_Unit->setAttackTarget(NULL);  // remove ourselves from any target that might have been followed
1323                                        }
1324                                       
1325                                        FollowDistance = 0.0f;
1326//                                      m_moveRun = false;
1327                                        //FIX ME: offhand shit
1328                                        if(m_Unit->isAttackReady(false) && !m_fleeTimer)
1329                                        {
1330                                                m_creatureState = ATTACKING;
1331                                                bool infront = m_Unit->isInFront(GetNextTarget());
1332
1333                                                if(!infront) // set InFront
1334                                                {
1335                                                        //prevent mob from rotating while stunned
1336                                                        if(!m_Unit->IsStunned ())
1337                                                        {
1338                                                                setInFront(GetNextTarget());
1339                                                                infront = true;
1340                                                        }                                                       
1341                                                }
1342
1343                                                if(infront)
1344                                                {
1345                                                        m_Unit->setAttackTimer(0, false);
1346                                                        SpellEntry *info = dbcSpell.LookupEntry(SPELL_RANGED_GENERAL);
1347                                                        if(info)
1348                                                        {
1349                                                                Spell *sp = new Spell(m_Unit, info, false, NULL);
1350                                                                if (!sp)
1351                                                                        return;
1352                                                                SpellCastTargets targets;
1353                                                                targets.m_unitTarget = GetNextTarget()->GetGUID();
1354                                                                sp->prepare(&targets);
1355                                                                //Lets make spell handle this
1356                                                                //m_Unit->Strike( GetNextTarget(), ( agent == AGENT_MELEE ? MELEE : RANGED ), NULL, 0, 0, 0 );
1357                                                        }
1358                                                }
1359                                        }
1360                                }
1361                                else // Target out of Range -> Run to it
1362                                {
1363                                        //calculate next move
1364                                        float dist;
1365
1366                                        if(distance < combatReach[0])// Target is too near
1367                                                dist = 9.0f;
1368                                        else
1369                                                dist = 20.0f;
1370
1371                                        m_moveRun = true;
1372                                        _CalcDestinationAndMove(GetNextTarget(), dist);
1373                                }
1374                        }break;
1375                case AGENT_SPELL:
1376                        {
1377                                if(!m_nextSpell || !GetNextTarget())
1378                                        return;  // this shouldn't happen
1379
1380                                SpellCastTime *sd = dbcSpellCastTime.LookupEntry(m_nextSpell->spell->CastingTimeIndex);
1381
1382                                float distance = m_Unit->CalcDistance(GetNextTarget());
1383                                bool los = true;
1384
1385                                if (sWorld.Collision) {
1386                                        los = CollideInterface.CheckLOS(m_Unit->GetMapId(), m_Unit->GetPositionNC(),GetNextTarget()->GetPositionNC());
1387                                }
1388                                if(los
1389                                        && ( ( distance <= m_nextSpell->maxrange + m_Unit->GetModelHalfSize() 
1390//                                      && distance >= m_nextSpell->minrange
1391                                        ) 
1392                                                        || m_nextSpell->maxrange == 0) ) // Target is in Range -> Attack
1393                                {
1394                                        SpellEntry* spellInfo = m_nextSpell->spell;
1395
1396                                        /* if in range stop moving so we don't interrupt the spell */
1397                                        //do not stop for instant spells
1398                                        if(sd && GetCastTime(sd) != 0)
1399                                                StopMovement(0);
1400
1401/*                                      if(m_nextSpell->procCount)
1402                                                m_nextSpell->procCount--;*/
1403
1404                                        SpellCastTargets targets = setSpellTargets(spellInfo, GetNextTarget());
1405                                        uint32 targettype = m_nextSpell->spelltargetType;
1406                                        switch(targettype)
1407                                        {
1408                                        case TTYPE_CASTER:
1409                                        case TTYPE_SINGLETARGET:
1410                                                {
1411                                                        CastSpell(m_Unit, spellInfo, targets);
1412                                                        break;
1413                                                }
1414                                        case TTYPE_SOURCE:
1415                                                {
1416                                                        m_Unit->CastSpellAoF(targets.m_srcX,targets.m_srcY,targets.m_srcZ, spellInfo, true);
1417                                                        break;
1418                                                }
1419                                        case TTYPE_DESTINATION:
1420                                                {
1421                                                        m_Unit->CastSpellAoF(targets.m_destX,targets.m_destY,targets.m_destZ, spellInfo, true);
1422                                                        break;
1423                                                }
1424                                        default:
1425                                                sLog.outError("AI Agents: Targettype of AI agent spell %u for creature %u not set", spellInfo->Id, static_cast< Creature* >( m_Unit )->GetCreatureInfo()->Id );
1426                                        }
1427                                        // CastSpell(m_Unit, spellInfo, targets);
1428                                        if(m_nextSpell&&m_nextSpell->cooldown)
1429                                                m_nextSpell->cooldowntime = getMSTime() + m_nextSpell->cooldown;
1430
1431                                        next_spell_time = (uint32)UNIXTIME + MOB_SPELLCAST_GLOBAL_COOLDOWN;
1432
1433                                        m_nextSpell = NULL;
1434                                }
1435                                else // Target out of Range -> Run to it
1436                                {
1437                                        //calculate next move
1438                                        m_moveRun = true;
1439                                        float close_to_enemy = 0.0f;
1440                                        if( distance > m_nextSpell->maxrange )
1441                                                close_to_enemy = m_nextSpell->maxrange - DISTANCE_TO_SMALL_TO_WALK ;
1442                                        else if( distance < m_nextSpell->minrange )
1443                                                close_to_enemy = m_nextSpell->minrange + DISTANCE_TO_SMALL_TO_WALK ;
1444
1445                                        if( close_to_enemy < 0 )
1446                                                close_to_enemy = 0;
1447                                               
1448                                        _CalcDestinationAndMove(GetNextTarget(), close_to_enemy ); //if we make exact movement we will never position perfectly
1449                                        /*Destination* dst = _CalcDestination(GetNextTarget(), dist);
1450                                        MoveTo(dst->x, dst->y, dst->z,0);
1451                                        delete dst;*/
1452                                }
1453                        }break;
1454                case AGENT_FLEE:
1455                        {
1456                                //float dist = 5.0f;
1457
1458                                m_moveRun = false;
1459                                if(m_fleeTimer == 0)
1460                                        m_fleeTimer = m_FleeDuration;
1461
1462                                /*Destination* dst = _CalcDestination(GetNextTarget(), dist);
1463                                MoveTo(dst->x, dst->y, dst->z,0);
1464                                delete dst;*/
1465                                _CalcDestinationAndMove(GetNextTarget(), 5.0f);
1466                                if(!m_hasFleed)
1467                                        CALL_SCRIPT_EVENT(m_Unit, OnFlee)(GetNextTarget());
1468
1469                                m_AIState = STATE_FLEEING;
1470                                //removed by Zack : somehow creature starts to attack self. Just making sure it is not this one
1471//                              m_nextTarget = m_Unit;
1472//                              m_Unit->SetUInt64Value(UNIT_FIELD_TARGET, 0);
1473                                SetNextTarget( (Unit*)NULL );
1474
1475                                WorldPacket data( SMSG_MESSAGECHAT, 100 );
1476                                string msg = "%s attempts to run away in fear!";
1477                                data << (uint8)CHAT_MSG_CHANNEL;
1478                                data << (uint32)LANG_UNIVERSAL;
1479                                data << (uint32)( strlen( static_cast< Creature* >( m_Unit )->GetCreatureInfo()->Name ) + 1 );
1480                                data << static_cast< Creature* >( m_Unit )->GetCreatureInfo()->Name;
1481                                data << (uint64)0;
1482                                data << (uint32)(msg.size() + 1);
1483                                data << msg;
1484                                data << uint8(0);
1485
1486                                m_Unit->SendMessageToSet(&data, false);
1487
1488                                //m_Unit->SendChatMessage(CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, msg);
1489                                //sChatHandler.FillMessageData(&data, CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, msg, m_Unit->GetGUID());                     
1490                           
1491                                m_hasFleed = true;
1492                        }break;
1493                case AGENT_CALLFORHELP:
1494                        {
1495                                FindFriends( 64.0f /*8.0f*/ );
1496                                m_hasCalledForHelp = true; // We only want to call for Help once in a Fight.
1497                                if( m_Unit->GetTypeId() == TYPEID_UNIT )
1498                                                objmgr.HandleMonsterSayEvent( static_cast< Creature* >( m_Unit ), MONSTER_SAY_EVENT_CALL_HELP );
1499                                CALL_SCRIPT_EVENT( m_Unit, OnCallForHelp )();
1500                        }break;
1501                }
1502        }
1503        else if( !GetNextTarget() || GetNextTarget()->GetInstanceID() != m_Unit->GetInstanceID() || !GetNextTarget()->isAlive() || !cansee )
1504        {
1505                SetNextTarget( (Unit*)NULL );
1506                // no more target
1507                //m_Unit->setAttackTarget(NULL);
1508        }
1509}
1510
1511void AIInterface::DismissPet()
1512{
1513        /*
1514        if(m_AIType != AITYPE_PET)
1515                return;
1516
1517        if(!m_PetOwner)
1518                return;
1519       
1520        if(m_PetOwner->GetTypeId() != TYPEID_PLAYER)
1521                return;
1522
1523        if(m_Unit->GetUInt32Value(UNIT_CREATED_BY_SPELL) == 0)
1524                static_cast< Player* >( m_PetOwner )->SetFreePetNo(false, (int)m_Unit->GetUInt32Value(UNIT_FIELD_PETNUMBER));
1525        static_cast< Player* >( m_PetOwner )->SetPet(NULL);
1526        static_cast< Player* >( m_PetOwner )->SetPetName("");
1527       
1528        //FIXME:Check hunter pet or not
1529        //FIXME:Check enslaved creature
1530        m_PetOwner->SetUInt64Value(UNIT_FIELD_SUMMON, 0);
1531       
1532        WorldPacket data;
1533        data.Initialize(SMSG_PET_SPELLS);
1534        data << (uint64)0;
1535        static_cast< Player* >( m_PetOwner )->GetSession()->SendPacket(&data);
1536       
1537        sEventMgr.RemoveEvents(((Creature*)m_Unit));
1538        if(m_Unit->IsInWorld())
1539        {
1540                m_Unit->RemoveFromWorld();
1541        }
1542        //setup an event to delete the Creature
1543        sEventMgr.AddEvent(((Creature*)this->m_Unit), &Creature::DeleteMe, EVENT_DELETE_TIMER, 1, 1);*/
1544}
1545
1546void AIInterface::AttackReaction(Unit* pUnit, uint32 damage_dealt, uint32 spellId)
1547{
1548        if( m_AIState == STATE_EVADE || !pUnit || !pUnit->isAlive() || m_Unit->IsDead() || m_Unit == pUnit )
1549                return;
1550
1551        if( sWorld.Collision && pUnit->IsPlayer() )
1552        {
1553                if ( m_Unit->GetMapMgr() != NULL )
1554                {
1555                        if (!m_moveFly)
1556                        {
1557                                float target_land_z = CollideInterface.GetHeight(m_Unit->GetMapId(), pUnit->GetPositionX(), pUnit->GetPositionY(), pUnit->GetPositionZ() + 2.0f);
1558                                if ( target_land_z == NO_WMO_HEIGHT )
1559                                        target_land_z = m_Unit->GetMapMgr()->GetLandHeight(pUnit->GetPositionX(), pUnit->GetPositionY());
1560
1561                                if (fabs(pUnit->GetPositionZ() - target_land_z) > _CalcCombatRange(pUnit, false) )
1562                                {
1563                                        if ( pUnit->GetTypeId()!=TYPEID_PLAYER && target_land_z > m_Unit->GetMapMgr()->GetWaterHeight(pUnit->GetPositionX(), pUnit->GetPositionY()) )
1564                                                return;
1565                                        else if( static_cast<Player*>(pUnit)->GetSession() != NULL )
1566                                        {
1567                                                MovementInfo* mi=static_cast<Player*>(pUnit)->GetSession()->GetMovementInfo();
1568
1569                                                if ( mi != NULL && !(mi->flags & MOVEFLAG_FALLING) && !(mi->flags & MOVEFLAG_SWIMMING) && !(mi->flags & MOVEFLAG_LEVITATE))
1570                                                        return;
1571                                        }
1572                                }
1573                        }
1574                }
1575        }
1576
1577        if (pUnit->GetTypeId() == TYPEID_PLAYER && static_cast<Player *>(pUnit)->GetMisdirectionTarget() != 0)
1578        {
1579                Unit *mTarget = m_Unit->GetMapMgr()->GetUnit(static_cast<Player *>(pUnit)->GetMisdirectionTarget());
1580                if (mTarget != NULL && mTarget->isAlive())
1581                        pUnit = mTarget;
1582        }
1583
1584        if( (m_AIState == STATE_IDLE || m_AIState == STATE_FOLLOWING) && m_Unit->GetAIInterface()->GetAllowedToEnterCombat())
1585        {
1586                WipeTargetList();
1587               
1588                HandleEvent(EVENT_ENTERCOMBAT, pUnit, 0);
1589        }
1590
1591        HandleEvent(EVENT_DAMAGETAKEN, pUnit, _CalcThreat(damage_dealt, spellId ? dbcSpell.LookupEntryForced(spellId) : NULL, pUnit));
1592}
1593
1594void AIInterface::HealReaction(Unit* caster, Unit* victim, SpellEntry* sp, uint32 amount)
1595{
1596        if(!caster || !victim)
1597                return;
1598
1599        bool casterInList = false, victimInList = false;
1600
1601        if(m_aiTargets.find(caster->GetGUID()) != m_aiTargets.end())
1602                casterInList = true;
1603
1604        if(m_aiTargets.find(victim->GetGUID()) != m_aiTargets.end())
1605                victimInList = true;
1606
1607        if(!victimInList && !casterInList) // none of the Casters is in the Creatures Threat list
1608                return;
1609
1610        int32 threat = int32(amount / 2);
1611        if (caster->getClass() == PALADIN)
1612                threat = threat / 2; //Paladins only get 50% threat per heal than other classes
1613
1614        if (sp != NULL)
1615                threat += (threat * caster->GetGeneratedThreatModifyer(sp->School) / 100);
1616
1617        if (threat < 1)
1618                threat = 1;
1619
1620        if(!casterInList && victimInList) // caster is not yet in Combat but victim is
1621        {
1622                // get caster into combat if he's hostile
1623                if(isHostile(m_Unit, caster))
1624                        m_aiTargets.insert(TargetMap::value_type(caster->GetGUID(), threat));
1625        }
1626        else if(casterInList && victimInList) // both are in combat already
1627                modThreatByPtr(caster, threat);
1628
1629        else // caster is in Combat already but victim is not
1630        {
1631                modThreatByPtr(caster, threat);
1632                // both are players so they might be in the same group
1633                if( caster->GetTypeId() == TYPEID_PLAYER && victim->GetTypeId() == TYPEID_PLAYER )
1634                {
1635                        if( static_cast< Player* >( caster )->GetGroup() == static_cast< Player* >( victim )->GetGroup() )
1636                        {
1637                                // get victim into combat since they are both
1638                                // in the same party
1639                                if( isHostile( m_Unit, victim ) )
1640                                        m_aiTargets.insert( TargetMap::value_type( victim->GetGUID(), 1 ) );
1641                        }
1642                }
1643        }
1644}
1645
1646void AIInterface::OnDeath(Object* pKiller)
1647{
1648        if(pKiller->GetTypeId() == TYPEID_PLAYER || pKiller->GetTypeId() == TYPEID_UNIT)
1649                HandleEvent(EVENT_UNITDIED, static_cast<Unit*>(pKiller), 0);
1650        else
1651                HandleEvent(EVENT_UNITDIED, m_Unit, 0);
1652}
1653
1654//function is designed to make a quick check on target to decide if we can attack it
1655bool AIInterface::UnsafeCanOwnerAttackUnit(Unit *pUnit)
1656{
1657        if( !isHostile(m_Unit,pUnit ) )
1658                return false;
1659
1660        if( !pUnit->isAlive() )
1661                return false;
1662
1663        if( !(pUnit->m_phase & m_Unit->m_phase) ) //Not in the same phase
1664                return false;
1665
1666        //do not agro units that are faking death. Should this be based on chance ?
1667        if( pUnit->HasFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_FEIGN_DEATH ) )
1668                return false;
1669
1670        //don't attack owner
1671        if( m_Unit->GetUInt64Value(UNIT_FIELD_CREATEDBY) == pUnit->GetGUID() )
1672                return false; 
1673
1674        //don't agro neutrals
1675        if( ( pUnit->IsPlayer() || pUnit->IsPet() )
1676                && m_Unit->m_factionDBC
1677                && m_Unit->m_factionDBC->RepListId == -1 
1678                && m_Unit->m_faction->HostileMask == 0 
1679                && m_Unit->m_faction->FriendlyMask == 0
1680                )
1681                        return false;
1682        else if( ( m_Unit->IsPlayer() || m_Unit->IsPet() )
1683                        && pUnit->m_factionDBC
1684                        && pUnit->m_factionDBC->RepListId == -1 
1685                        && pUnit->m_faction->HostileMask == 0 
1686                        && pUnit->m_faction->FriendlyMask == 0
1687                        )
1688                        return false;
1689
1690        //make sure we do not agro flying stuff
1691        if( abs( pUnit->GetPositionZ() - m_Unit->GetPositionZ() ) > _CalcCombatRange( pUnit, false ) )
1692                return false; //blizz has this set to 250 but uses pathfinding
1693
1694        return true;
1695}
1696
1697//this function might be slow but so it should not be spammed
1698//!!!this function has been reported the biggest bottleneck on emu in 2008 07 04
1699Unit* AIInterface::FindTarget()
1700{// find nearest hostile Target to attack
1701        if( !m_AllowedToEnterCombat ) 
1702                return NULL;
1703
1704        if(  m_Unit->GetMapMgr() == NULL )
1705                return NULL; 
1706
1707        Unit* target = NULL;
1708        Unit* critterTarget = NULL;
1709        float distance = 999999.0f; // that should do it.. :p
1710//      float crange;
1711//      float z_diff;
1712
1713        std::set<Object*>::iterator itr, itr2;
1714        std::set<Player *>::iterator pitr, pitr2;
1715//      Object *pObj;
1716        Unit *pUnit;
1717        float dist;
1718
1719    // Don't remove this please! - dfighter
1720    /*
1721    if( m_AIType == AITYPE_PET ){
1722        printf("I'm a pet and I'm looking for targets, RAWR!\n");
1723    }
1724    */
1725
1726   
1727       
1728        /* Commented due to no use
1729        bool pvp=true;
1730        if(m_Unit->GetTypeId()==TYPEID_UNIT&&((Creature*)m_Unit)->GetCreatureInfo()&&((Creature*)m_Unit)->GetCreatureInfo()->Civilian)
1731                pvp=false;*/
1732
1733        //target is immune to all form of attacks, cant attack either.
1734        // not attackable creatures sometimes fight enemies in scripted fights though
1735        if(m_Unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NOT_ATTACKABLE_2))
1736        {
1737                return 0;
1738        }
1739
1740    // Start of neutralguard snippet
1741        if (m_isNeutralGuard)
1742        {
1743                Player *tmpPlr;
1744                for (std::set<Player*>::iterator itrPlr = m_Unit->GetInRangePlayerSetBegin(); itrPlr != m_Unit->GetInRangePlayerSetEnd(); ++itrPlr)
1745                {
1746                        tmpPlr = (*itrPlr);
1747                        if (tmpPlr == NULL)
1748                                continue;
1749                        if (tmpPlr->IsDead())
1750                                continue;
1751                        if (tmpPlr->GetTaxiState())
1752                                continue;
1753                        if (tmpPlr->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FEIGN_DEATH))
1754                                continue;
1755                        if (tmpPlr->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9))
1756                                continue;
1757                        if (tmpPlr->m_invisible)
1758                                continue;
1759                        if( !tmpPlr->HasFlag( PLAYER_FLAGS, PLAYER_FLAG_UNKNOWN2 ) )//PvP Guard Attackable.
1760                                continue;
1761                        if( !(tmpPlr->m_phase & m_Unit->m_phase) ) //Not in the same phase, skip this target
1762                                continue;
1763
1764                        dist = m_Unit->GetDistanceSq(tmpPlr);
1765
1766                        if (dist > 2500.0f)
1767                                continue;
1768                        if (distance > dist)
1769                        {
1770                                if (sWorld.Collision) {
1771                                        if( CollideInterface.CheckLOS( m_Unit->GetMapId(), m_Unit->GetPositionNC(), tmpPlr->GetPositionNC() ) )
1772                                        {
1773                                                distance = dist;
1774                                                target = static_cast<Unit*>(tmpPlr);
1775                                        }
1776                                } else {
1777                                        distance = dist;
1778                                        target = static_cast<Unit*>(tmpPlr);
1779                                }
1780                        }
1781                }
1782                if (target)
1783                {
1784                        m_Unit->m_runSpeed = m_Unit->m_base_runSpeed * 2.0f;
1785                        AttackReaction(target, 1, 0);
1786
1787                        WorldPacket data(SMSG_AI_REACTION, 12);
1788                        data << m_Unit->GetGUID() << uint32(2);         // Aggro sound
1789                        static_cast< Player* >( target )->GetSession()->SendPacket( &data );
1790
1791                        return target;
1792                }
1793                distance = 999999.0f; //Reset Distance for normal check
1794        }
1795    // End of neutralguard snippet
1796
1797        //we have a high chance that we will agro a player
1798        //this is slower then oppfaction list BUT it has a lower chance that contains invalid pointers
1799        for( pitr2 = m_Unit->GetInRangePlayerSetBegin(); pitr2 != m_Unit->GetInRangePlayerSetEnd(); )
1800        {
1801                pitr = pitr2;
1802                ++pitr2;
1803
1804                pUnit = *pitr;
1805       
1806        if( UnsafeCanOwnerAttackUnit( pUnit ) == false )
1807                        continue;
1808
1809                //on blizz there is no Z limit check
1810                dist = m_Unit->GetDistance2dSq(pUnit);
1811
1812                if(dist > distance)      // we want to find the CLOSEST target
1813                        continue;
1814
1815                if(dist <= _CalcAggroRange(pUnit) )
1816                {
1817                        if (sWorld.Collision) {
1818                                if( CollideInterface.CheckLOS( m_Unit->GetMapId( ), m_Unit->GetPositionNC( ), pUnit->GetPositionNC( ) ) )
1819                                {
1820                                        distance = dist;
1821                                        target = pUnit;
1822                                }
1823                        } else {
1824                                distance = dist;
1825                                target = pUnit;
1826                        }
1827                }
1828        }
1829
1830        //a lot less times are check inter faction mob wars :)
1831        if( m_updateTargetsTimer2 < getMSTime() )
1832        {
1833                m_updateTargetsTimer2 = getMSTime() + TARGET_UPDATE_INTERVAL;
1834                m_Unit->AquireInrangeLock(); //make sure to release lock before exit function !
1835                for( itr2 = m_Unit->GetInRangeSetBegin(); itr2 != m_Unit->GetInRangeSetEnd(); )
1836                {
1837                        itr = itr2;
1838                        ++itr2;
1839
1840                        if( !(*itr)->IsUnit() )
1841                                continue;
1842
1843            // We checked for player targets before, so this shouldn't happen
1844            // [14:45] <+burlex> but andy
1845            // [14:45] <+burlex> dey have dead pointerz
1846            if( (*itr)->IsPlayer() )
1847                continue;
1848
1849                        pUnit = static_cast< Unit* >( (*itr) );
1850
1851                        if( UnsafeCanOwnerAttackUnit( pUnit ) == false )
1852                                continue;
1853
1854                        //on blizz there is no Z limit check
1855                        dist = m_Unit->GetDistance2dSq(pUnit);
1856
1857                        if(pUnit->m_faction && pUnit->m_faction->Faction == 28)// only Attack a critter if there is no other Enemy in range
1858                        {
1859                                if(dist < 225.0f)       // was 10
1860                                        critterTarget = pUnit;
1861                                continue;
1862                        }
1863
1864                        if(dist > distance)      // we want to find the CLOSEST target
1865                                continue;
1866       
1867                        if(dist <= _CalcAggroRange(pUnit) )
1868                        {
1869                                if (sWorld.Collision) {
1870                                        if( CollideInterface.CheckLOS( m_Unit->GetMapId( ), m_Unit->GetPositionNC( ), pUnit->GetPositionNC( ) ) )
1871                                        {
1872                                                distance = dist;
1873                                                target = pUnit;
1874                                        }
1875                                } else {
1876                                        distance = dist;
1877                                        target = pUnit;
1878                                }
1879                        }
1880                }
1881                m_Unit->ReleaseInrangeLock();
1882        }
1883
1884        if( !target )
1885        {
1886                target = critterTarget;
1887        }
1888
1889        if( target )
1890        {
1891/*              if(m_isGuard)
1892                {
1893                        m_Unit->m_runSpeed = m_Unit->m_base_runSpeed * 2.0f;
1894                        m_fastMove = true;
1895                }*/
1896
1897                AttackReaction(target, 1, 0);
1898                if(target->IsPlayer())
1899                {
1900                        WorldPacket data(SMSG_AI_REACTION, 12);
1901                        data << m_Unit->GetGUID() << uint32(2);         // Aggro sound
1902                        static_cast< Player* >( target )->GetSession()->SendPacket( &data );
1903                }
1904                if(target->GetUInt32Value(UNIT_FIELD_CREATEDBY) != 0)
1905                {
1906                        Unit* target2 = m_Unit->GetMapMgr()->GetPlayer(target->GetUInt32Value(UNIT_FIELD_CREATEDBY));
1907                        /*if(!target2)
1908                        {
1909                                target2 = sObjHolder.GetObject<Player>(target->GetUInt32Value(UNIT_FIELD_CREATEDBY));
1910                        }*/
1911                        if(target2)
1912                        {
1913                                AttackReaction(target2, 1, 0);
1914                        }
1915                }
1916        }
1917        return target;
1918}
1919
1920Unit* AIInterface::FindTargetForSpell(AI_Spell *sp)
1921{
1922        /*if(!m_Unit) return NULL;*/
1923
1924        /*if(!sp)
1925        {
1926                m_Unit->SetUInt64Value(UNIT_FIELD_TARGET, 0);
1927                return NULL;
1928        }*/
1929
1930        TargetMap::iterator itr, itr2;
1931
1932        if(sp)
1933        {
1934                if(sp->spellType == STYPE_HEAL)
1935                {
1936                        uint32 cur = m_Unit->GetUInt32Value(UNIT_FIELD_HEALTH) + 1;
1937                        uint32 max = m_Unit->GetUInt32Value(UNIT_FIELD_MAXHEALTH) + 1;
1938                        float healthPercent = float(cur) / float(max);
1939                        if(healthPercent <= sp->floatMisc1) // Heal ourselves cause we got too low HP
1940                        {
1941                                m_Unit->SetUInt64Value(UNIT_FIELD_TARGET, 0);
1942                                return m_Unit;
1943                        }
1944                        for(AssistTargetSet::iterator i = m_assistTargets.begin(); i != m_assistTargets.end(); i++)
1945                        {
1946                                if(!(*i)->isAlive())
1947                                {
1948                                        continue;
1949                                }
1950                                cur = (*i)->GetUInt32Value(UNIT_FIELD_HEALTH);
1951                                max = (*i)->GetUInt32Value(UNIT_FIELD_MAXHEALTH);
1952                                healthPercent = float(cur) / float(max);
1953                                if(healthPercent <= sp->floatMisc1) // Heal ourselves cause we got too low HP
1954                                {
1955                                        m_Unit->SetUInt64Value(UNIT_FIELD_TARGET, (*i)->GetGUID());
1956                                        return (*i); // heal Assist Target which has low HP
1957                                }
1958                        }
1959                }
1960                if(sp->spellType == STYPE_BUFF)
1961                {
1962                        m_Unit->SetUInt64Value(UNIT_FIELD_TARGET, 0);
1963                        return m_Unit;
1964                }
1965        }
1966
1967        return GetMostHated();
1968}
1969
1970bool AIInterface::FindFriends(float dist)
1971{
1972
1973        if(  m_Unit->GetMapMgr() == NULL )
1974                return false; 
1975
1976        bool result = false;
1977        TargetMap::iterator it;
1978
1979        std::set<Object*>::iterator itr;
1980        Unit *pUnit;
1981
1982        m_Unit->AquireInrangeLock(); //make sure to release lock before exit function !
1983        for( itr = m_Unit->GetInRangeSetBegin(); itr != m_Unit->GetInRangeSetEnd(); itr++ )
1984        {
1985                if(!(*itr) || (*itr)->GetTypeId() != TYPEID_UNIT)
1986                        continue;
1987
1988                pUnit = static_cast<Unit*>((*itr));
1989                if(!pUnit->isAlive())
1990                        continue;
1991
1992                if(pUnit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
1993                {
1994                        continue;
1995                }
1996                if(pUnit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9))
1997                {
1998                        continue;
1999                }
2000
2001                if( !(pUnit->m_phase & m_Unit->m_phase) ) //We can't help a friendly unit if it is not in our phase
2002                        continue;
2003
2004                if( isCombatSupport( m_Unit, pUnit ) && ( pUnit->GetAIInterface()->getAIState() == STATE_IDLE || pUnit->GetAIInterface()->getAIState() == STATE_SCRIPTIDLE ) )//Not sure
2005                {
2006                        if( m_Unit->GetDistanceSq(pUnit) < dist)
2007                        {
2008                                if( m_assistTargets.count( pUnit ) == 0 )
2009                                {
2010                                        result = true;
2011                                        m_assistTargets.insert(pUnit);
2012                                }
2013
2014                                LockAITargets(true);
2015
2016                                for(it = m_aiTargets.begin(); it != m_aiTargets.end(); ++it)
2017                                {
2018                                        Unit *ai_t = m_Unit->GetMapMgr()->GetUnit( it->first );
2019                                        if( ai_t && pUnit->GetAIInterface() && isHostile((Object*)ai_t,(Object*)pUnit) )
2020                                                pUnit->GetAIInterface()->AttackReaction( ai_t, 1, 0 );
2021                                }
2022
2023                                LockAITargets(false);
2024                        }
2025                }
2026        }
2027        m_Unit->ReleaseInrangeLock();
2028
2029        // check if we're a civilian, in which case summon guards on a despawn timer
2030        uint8 civilian = (((Creature*)m_Unit)->GetCreatureInfo()) ? (((Creature*)m_Unit)->GetCreatureInfo()->Civilian) : 0;
2031        uint32 family = (((Creature*)m_Unit)->GetCreatureInfo()) ? (((Creature*)m_Unit)->GetCreatureInfo()->Type) : 0;
2032        if(family == UNIT_TYPE_HUMANOID && civilian && getMSTime() > m_guardTimer && !IS_INSTANCE(m_Unit->GetMapId()))
2033        {
2034                m_guardTimer = getMSTime() + 15000;
2035                uint16 AreaId = m_Unit->GetMapMgr()->GetAreaID(m_Unit->GetPositionX(),m_Unit->GetPositionY());
2036                AreaTable * at = dbcArea.LookupEntry(AreaId);
2037                if(!at)
2038                        return result;
2039
2040                ZoneGuardEntry * zoneSpawn = ZoneGuardStorage.LookupEntry(at->ZoneId);
2041                if(!zoneSpawn) return result;
2042
2043                uint32 team = 1; // horde default
2044                if(isAlliance(m_Unit))
2045                        team = 0;
2046
2047                uint32 guardid = zoneSpawn->AllianceEntry;
2048                if(team == 1) guardid = zoneSpawn->HordeEntry;
2049                if(!guardid) return result;
2050
2051                CreatureInfo * ci = CreatureNameStorage.LookupEntry(guardid);
2052                if(!ci)
2053                        return result;
2054
2055                float x = m_Unit->GetPositionX() + (float)( (float)(rand() % 150 + 100) / 1000.0f );
2056                float y = m_Unit->GetPositionY() + (float)( (float)(rand() % 150 + 100) / 1000.0f );
2057                float z;
2058
2059                if (sWorld.Collision) {
2060                        z = CollideInterface.GetHeight(m_Unit->GetMapId(), x, y, m_Unit->GetPositionZ() + 2.0f);
2061                        if( z == NO_WMO_HEIGHT )
2062                                z = m_Unit->GetMapMgr()->GetLandHeight(x, y);
2063
2064                        if( fabs( z - m_Unit->GetPositionZ() ) > 10.0f )
2065                                z = m_Unit->GetPositionZ();
2066                } else {
2067                        z = m_Unit->GetPositionZ();
2068                        float adt_z = m_Unit->GetMapMgr()->GetLandHeight(x, y);
2069                        if(fabs(z - adt_z) < 3)
2070                                z = adt_z;
2071                }
2072
2073                CreatureProto * cp = CreatureProtoStorage.LookupEntry(guardid);
2074                if(!cp) return result;
2075
2076                uint8 spawned = 0;
2077       
2078                std::set<Player*>::iterator hostileItr = m_Unit->GetInRangePlayerSetBegin();
2079                for(; hostileItr != m_Unit->GetInRangePlayerSetEnd(); hostileItr++)
2080                {
2081                        if(spawned >= 3)
2082                                break;
2083
2084                        if(!isHostile(*hostileItr, m_Unit))
2085                                continue;
2086
2087                        if (spawned == 0)
2088                        {
2089                                uint32 languageid = (team == 0) ? LANG_COMMON : LANG_ORCISH;
2090                                m_Unit->SendChatMessage(CHAT_MSG_MONSTER_SAY, languageid, "Guards!");
2091                        }
2092
2093                        Creature * guard = m_Unit->GetMapMgr()->CreateCreature(guardid);
2094                        guard->Load(cp, x, y, z);
2095                        guard->SetInstanceID(m_Unit->GetInstanceID());
2096                        guard->SetZoneId(m_Unit->GetZoneId());
2097                        guard->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); /* shitty DBs */
2098                        guard->m_noRespawn=true;
2099               
2100                        if(guard->CanAddToWorld())
2101                        {
2102                                uint32 t = RandomUInt(8)*1000;
2103                                if(t==0)
2104                                        guard->PushToWorld(m_Unit->GetMapMgr());
2105                                else
2106                                        sEventMgr.AddEvent(guard,&Creature::AddToWorld, m_Unit->GetMapMgr(), EVENT_UNK, t, 1, 0);
2107                        }
2108                        else
2109                        {
2110                                guard->SafeDelete();
2111                                return result;
2112                        }
2113                       
2114                        sEventMgr.AddEvent(guard, &Creature::SetGuardWaypoints, EVENT_UNK, 10000, 1,0);
2115                        sEventMgr.AddEvent(guard, &Creature::SafeDelete, EVENT_CREATURE_SAFE_DELETE, 60*5*1000, 1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
2116                        spawned++;
2117                }
2118        }
2119
2120        return result;
2121}
2122
2123float AIInterface::_CalcAggroRange(Unit* target)
2124{
2125        //float baseAR = 15.0f; // Base Aggro Range
2126        //                    -8     -7     -6      -5    -4      -3     -2     -1     0      +1     +2     +3    +4     +5     +6     +7    +8
2127        //float baseAR[17] = {29.0f, 27.5f, 26.0f, 24.5f, 23.0f, 21.5f, 20.0f, 18.5f, 17.0f, 15.5f, 14.0f, 12.5f, 11.0f,  9.5f,  8.0f,  6.5f, 5.0f};
2128        float baseAR[17] = {19.0f, 18.5f, 18.0f, 17.5f, 17.0f, 16.5f, 16.0f, 15.5f, 15.0f, 14.5f, 12.0f, 10.5f, 8.5f,  7.5f,  6.5f,  6.5f, 5.0f};
2129        // Lvl Diff -8 -7 -6 -5 -4 -3 -2 -1 +0 +1 +2  +3  +4  +5  +6  +7  +8
2130        // Arr Pos   0  1  2  3  4  5  6  7  8  9 10  11  12  13  14  15  16
2131        int8 lvlDiff = static_cast<int8>(target->getLevel() - m_Unit->getLevel());
2132        uint8 realLvlDiff = lvlDiff;
2133        if (lvlDiff > 8)
2134        {
2135                lvlDiff = 8;
2136        }
2137        if (lvlDiff < -8)
2138        {
2139                lvlDiff = -8;
2140        }
2141        if (!((Creature*)m_Unit)->CanSee(target))
2142                return 0;
2143
2144        // Retrieve aggrorange from table
2145        float AggroRange = baseAR[lvlDiff + 8];
2146
2147        // Check to see if the target is a player mining a node
2148        bool isMining = false;
2149        if (target->IsPlayer())
2150        {
2151                if (target->IsCasting())
2152                {
2153                        // If nearby miners weren't spotted already we'll give them a little surprise.
2154                        Spell * sp = target->GetCurrentSpell();
2155                        if (sp->GetProto()->Effect[0] == SPELL_EFFECT_OPEN_LOCK && sp->GetProto()->EffectMiscValue[0] == LOCKTYPE_MINING)
2156                        {
2157                                isMining = true;
2158                        }
2159                }
2160        }
2161
2162        // If the target is of a much higher level the aggro range must be scaled down, unless the target is mining a nearby resource node
2163        if (realLvlDiff > 8 && !isMining)
2164        {
2165                AggroRange += AggroRange * ((lvlDiff - 8) * 5 / 100);
2166        }
2167
2168        // Multiply by elite value
2169        if (m_Unit->IsCreature() && ((Creature*)m_Unit)->GetCreatureInfo() && ((Creature*)m_Unit)->GetCreatureInfo()->Rank > 0)
2170        {
2171                AggroRange *= (((Creature*)m_Unit)->GetCreatureInfo()->Rank) * 1.50f;
2172        }
2173
2174        // Cap Aggro range at 40.0f
2175        if (AggroRange > 40.0f)
2176        {
2177                AggroRange = 40.0f;
2178        }
2179
2180/*  //printf("aggro range: %f , stealthlvl: %d , detectlvl: %d\n",AggroRange,target->GetStealthLevel(),m_Unit->m_stealthDetectBonus);
2181        if(! ((Creature*)m_Unit)->CanSee(target))
2182        {
2183                AggroRange =0;
2184        //      AggroRange *= ( 100.0f - (target->m_stealthLevel - m_Unit->m_stealthDetectBonus)* 20.0f ) / 100.0f;
2185        }
2186*/
2187
2188        // SPELL_AURA_MOD_DETECT_RANGE
2189        int32 modDetectRange = target->getDetectRangeMod(m_Unit->GetGUID());
2190        AggroRange += modDetectRange;
2191        if (target->IsPlayer())
2192        {
2193                AggroRange += static_cast< Player* >(target)->DetectedRange;
2194        }
2195
2196        // Re-check if aggro range exceeds Minimum/Maximum caps
2197        if (AggroRange < 3.0f)
2198        {
2199                AggroRange = 3.0f;
2200        }
2201        if (AggroRange > 40.0f)
2202        {
2203                AggroRange = 40.0f;
2204        }
2205
2206        return (AggroRange * AggroRange);
2207}
2208
2209void AIInterface::_CalcDestinationAndMove(Unit *target, float dist)
2210{
2211        if(!m_canMove || m_Unit->IsStunned())
2212        {
2213                StopMovement(0); //Just Stop
2214                return;
2215        }
2216       
2217        if( target && ( target->GetTypeId() == TYPEID_UNIT || target->GetTypeId() == TYPEID_PLAYER) )
2218        {
2219#ifdef HACKY_SERVER_CLIENT_POS_SYNC
2220                moved_for_attack = true;
2221#endif
2222                float ResX = target->GetPositionX();
2223                float ResY = target->GetPositionY();
2224
2225                //avoid eating bandwidth with useless movement packets when target did not move since last position
2226                //this will work since it turned into a common myth that when you pull mob you should not move :D
2227                if( abs(m_last_target_x - ResX) < DISTANCE_TO_SMALL_TO_WALK
2228                        && abs(m_last_target_y - ResY) < DISTANCE_TO_SMALL_TO_WALK && m_creatureState == MOVING)
2229                        return;
2230                m_last_target_x = ResX;
2231                m_last_target_y = ResY;
2232
2233                float ResZ = target->GetPositionZ();
2234
2235                float angle = m_Unit->calcAngle(m_Unit->GetPositionX(), m_Unit->GetPositionY(), ResX, ResY) * float(M_PI) / 180.0f;
2236                float x = dist * cosf(angle);
2237                float y = dist * sinf(angle);
2238
2239                if(target->GetTypeId() == TYPEID_PLAYER && static_cast< Player* >( target )->m_isMoving )
2240                {
2241                        // cater for moving player vector based on orientation
2242                        x -= cosf(target->GetOrientation());
2243                        y -= sinf(target->GetOrientation());
2244                }
2245
2246                m_nextPosX = ResX - x;
2247                m_nextPosY = ResY - y;
2248                m_nextPosZ = ResZ;
2249        }
2250        else
2251        {
2252                target = NULL;
2253                m_nextPosX = m_Unit->GetPositionX();
2254                m_nextPosY = m_Unit->GetPositionY();
2255                m_nextPosZ = m_Unit->GetPositionZ();
2256        }
2257
2258/*
2259        if (sWorld.Collision) {
2260                float target_land_z=0.0f;
2261                if( m_Unit->GetMapMgr() != NULL )
2262                {
2263                        if(m_moveFly != true)
2264                        {
2265                                target_land_z = CollideInterface.GetHeight(m_Unit->GetMapId(), m_nextPosX, m_nextPosY, m_nextPosZ + 2.0f);
2266                                if( target_land_z == NO_WMO_HEIGHT )
2267                                        target_land_z = m_Unit->GetMapMgr()->GetLandHeight(m_nextPosX, m_nextPosY);
2268                        }
2269                }
2270
2271                if (m_nextPosZ > m_Unit->GetMapMgr()->GetWaterHeight(m_nextPosX, m_nextPosY) && target_land_z != 0.0f)
2272                        m_nextPosZ=target_land_z;
2273        }
2274*/
2275
2276        float dx = m_nextPosX - m_Unit->GetPositionX();
2277        float dy = m_nextPosY - m_Unit->GetPositionY();
2278        if(dy != 0.0f)
2279        {
2280                float angle = atan2(dx, dy);
2281                m_Unit->SetOrientation(angle);
2282        }
2283
2284        if(m_creatureState != MOVING)
2285                UpdateMove();
2286}
2287
2288float AIInterface::_CalcCombatRange(Unit* target, bool ranged)
2289{
2290        if(!target)
2291        {
2292                return 0;
2293        }
2294        float range = 0.0f;
2295        float rang = 0.0f;
2296        if(ranged)
2297        {
2298                rang = 5.0f;
2299        }
2300
2301        float selfreach = m_Unit->GetFloatValue(UNIT_FIELD_COMBATREACH);
2302        float targetradius;
2303//      targetradius = target->GetFloatValue(UNIT_FIELD_BOUNDINGRADIUS); //this is plain wrong. Represents i have no idea what :)
2304        targetradius = target->GetModelHalfSize();
2305        float selfradius;
2306//      selfradius = m_Unit->GetFloatValue(UNIT_FIELD_BOUNDINGRADIUS); //this is plain wrong. Represents i have no idea what :)
2307        selfradius = m_Unit->GetModelHalfSize();
2308//      float targetscale = target->GetFloatValue(OBJECT_FIELD_SCALE_X);
2309//      float selfscale = m_Unit->GetFloatValue(OBJECT_FIELD_SCALE_X);
2310
2311//      range = ((((targetradius*targetradius)*targetscale) + selfreach) + ((selfradius*selfscale) + rang));
2312        range = targetradius + selfreach + selfradius + rang;
2313//      if(range > 28.29f) range = 28.29f;
2314        return range;
2315}
2316
2317float AIInterface::_CalcDistanceFromHome()
2318{
2319        if (m_AIType == AITYPE_PET)
2320        {
2321                return m_Unit->GetDistanceSq(m_PetOwner);
2322        }
2323        else if(m_Unit->GetTypeId() == TYPEID_UNIT)
2324        {
2325
2326                if(m_returnX !=0.0f && m_returnY != 0.0f)
2327                {
2328                        return m_Unit->GetDistanceSq(m_returnX,m_returnY,m_returnZ);
2329                }
2330        }
2331
2332        return 0.0f;
2333}
2334
2335/************************************************************************************************************
2336SendMoveToPacket:
2337Comments: Some comments on the SMSG_MONSTER_MOVE packet:
2338        the uint8 field:
2339                0: Default                                                                                                                      known
2340                1: Don't move                                                                                                           known
2341                2: there is an extra 3 floats, also known as a vector                           unknown
2342                3: there is an extra uint64 most likely a guid.                                         unknown
2343                4: there is an extra float that causes the orientation to be set.       known
2344               
2345                note:   when this field is 1.
2346                        there is no need to send  the next 3 uint32's as they aren't used by the client
2347       
2348        the MoveFlags:
2349                0x00000000 - Walk
2350                0x00000100 - Teleport
2351                0x00001000 - Run
2352                0x00000200 - Fly - OLD FLAG, IS THIS STILL VALID?
2353                0x00003000 - Fly
2354                some comments on that 0x00000300 - Fly = 0x00000100 | 0x00000200
2355
2356        waypoint's:
2357                TODO.... as they somehow seemed to be changed long time ago..
2358               
2359*************************************************************************************************************/
2360
2361void AIInterface::SendMoveToPacket(float toX, float toY, float toZ, float toO, uint32 time, uint32 MoveFlags)
2362{
2363        //this should NEVER be called directly !!!!!!
2364        //use MoveTo()
2365
2366#ifndef USING_BIG_ENDIAN
2367        StackWorldPacket<100> data(SMSG_MONSTER_MOVE);
2368#else
2369        WorldPacket data(SMSG_MONSTER_MOVE, 100);
2370#endif
2371        data << m_Unit->GetNewGUID();
2372        data << uint8(0); //VLack: for 3.1.x support; I've discovered this in Mangos code while doing research on how to fix invisible mobs on 3.0.9
2373        data << m_Unit->GetPositionX() << m_Unit->GetPositionY() << m_Unit->GetPositionZ();
2374        data << getMSTime();
2375       
2376        // Check if we have an orientation
2377        if(toO != 0.0f)
2378        {
2379                data << uint8(4);
2380                data << toO;
2381        } else {
2382                data << uint8(0);
2383        }
2384        data << MoveFlags;
2385/*      if(MoveFlags & 0x200000) //VLack: Aspire code for 3.1.x support - I don't know these flags, as the ones I knew are the 3 well known shown in the above comment and their combinations
2386        {
2387                data << uint8(0);
2388                data << uint32(0);
2389        }
2390        if(MoveFlags & 0x800) //VLack: Aspire code for 3.1.x support
2391        {
2392                data << float(0);
2393                data << uint32(0);
2394        }*/
2395        data << time;
2396        data << uint32(1);        // 1 waypoint
2397        data << toX << toY << toZ;
2398
2399#ifndef ENABLE_COMPRESSED_MOVEMENT_FOR_CREATURES
2400        bool self = m_Unit->GetTypeId() == TYPEID_PLAYER;
2401        m_Unit->SendMessageToSet( &data, self );
2402#else
2403        if( m_Unit->GetTypeId() == TYPEID_PLAYER )
2404                static_cast<Player*>(m_Unit)->GetSession()->SendPacket(&data);
2405
2406        for(set<Player*>::iterator itr = m_Unit->GetInRangePlayerSetBegin(); itr != m_Unit->GetInRangePlayerSetEnd(); ++itr)
2407        {
2408                if( (*itr)->GetPositionNC().Distance2DSq( m_Unit->GetPosition() ) >= World::m_movementCompressThresholdCreatures )
2409                        (*itr)->AppendMovementData( SMSG_MONSTER_MOVE, data.GetSize(), (const uint8*)data.GetBufferPointer() );
2410                else
2411                        (*itr)->GetSession()->SendPacket(&data);
2412        }
2413#endif
2414}
2415
2416/*
2417void AIInterface::SendMoveToSplinesPacket(std::list<Waypoint> wp, bool run)
2418{
2419        if(!m_canMove)
2420        {
2421                return;
2422        }
2423
2424        WorldPacket data;
2425
2426        uint8 DontMove = 0;
2427        uint32 travelTime = 0;
2428        for(std::list<Waypoint>::iterator i = wp.begin(); i != wp.end(); i++)
2429        {
2430                travelTime += i->time;
2431        }
2432
2433        data.Initialize( SMSG_MONSTER_MOVE );
2434        data << m_Unit->GetNewGUID();
2435        data << m_Unit->GetPositionX() << m_Unit->GetPositionY() << m_Unit->GetPositionZ();
2436        data << getMSTime();
2437        data << uint8(DontMove);
2438        data << uint32(run ? 0x00000100 : 0x00000000);
2439        data << travelTime;
2440        data << (uint32)wp.size();
2441        for(std::list<Waypoint>::iterator i = wp.begin(); i != wp.end(); i++)
2442        {
2443                data << i->x;
2444                data << i->y;
2445                data << i->z;
2446        }
2447
2448        m_Unit->SendMessageToSet( &data, false );
2449}
2450*/
2451bool AIInterface::StopMovement(uint32 time)
2452{
2453        m_moveTimer = time; //set pause after stopping
2454        m_creatureState = STOPPED;
2455
2456        m_destinationX = m_destinationY = m_destinationZ = 0;
2457        m_nextPosX = m_nextPosY = m_nextPosZ = 0;
2458        m_timeMoved = 0;
2459        m_timeToMove = 0;
2460
2461        WorldPacket data(27);
2462        data.SetOpcode(SMSG_MONSTER_MOVE);
2463        data << m_Unit->GetNewGUID();
2464        data << uint8(0); //VLack: 3.1 SMSG_MONSTER_MOVE change...
2465        data << m_Unit->GetPositionX() << m_Unit->GetPositionY() << m_Unit->GetPositionZ();
2466        data << getMSTime();
2467        data << uint8(1);   // "DontMove = 1"
2468
2469        m_Unit->SendMessageToSet( &data, false );
2470        return true;
2471}
2472
2473void AIInterface::MoveTo(float x, float y, float z, float o)
2474{
2475        m_sourceX = m_Unit->GetPositionX();
2476        m_sourceY = m_Unit->GetPositionY();
2477        m_sourceZ = m_Unit->GetPositionZ();
2478
2479        if(!m_canMove || m_Unit->IsStunned())
2480        {
2481                StopMovement(0); //Just Stop
2482                return;
2483        }
2484
2485
2486        m_nextPosX = x;
2487        m_nextPosY = y;
2488        m_nextPosZ = z;
2489
2490/*      //Andy
2491#ifdef COLLISION
2492        float target_land_z=0.0f;
2493        if( m_Unit->GetMapMgr() != NULL )
2494        {
2495                if(m_moveFly != true)
2496                {
2497                        target_land_z = CollideInterface.GetHeight(m_Unit->GetMapId(), m_nextPosX, m_nextPosY, m_nextPosZ + 2.0f);
2498                        if( target_land_z == NO_WMO_HEIGHT )
2499                                target_land_z = m_Unit->GetMapMgr()->GetLandHeight(m_nextPosX, m_nextPosY);
2500                }
2501        }
2502
2503        if (m_nextPosZ > m_Unit->GetMapMgr()->GetWaterHeight(m_nextPosX, m_nextPosY) && target_land_z != 0.0f)
2504                m_nextPosZ=target_land_z;
2505#endif*/
2506
2507        if ( m_creatureState != MOVING )
2508                UpdateMove();
2509}
2510
2511bool AIInterface::IsFlying()
2512{
2513        if(m_moveFly)
2514                return true;
2515       
2516        /*float z = m_Unit->GetMapMgr()->GetLandHeight(m_Unit->GetPositionX(), m_Unit->GetPositionY());
2517        if(z)
2518        {
2519                if(m_Unit->GetPositionZ() >= (z + 1.0f)) //not on ground? Oo
2520                {
2521                        return true;
2522                }
2523        }
2524        return false;*/
2525        if( m_Unit->GetTypeId() == TYPEID_PLAYER )
2526                return static_cast< Player* >( m_Unit )->FlyCheat;
2527
2528        return false;
2529}
2530
2531uint32 AIInterface::getMoveFlags()
2532{
2533        uint32 MoveFlags = 0;
2534        if(m_moveFly == true) //Fly
2535        {
2536                m_flySpeed = m_Unit->m_flySpeed*0.001f;
2537//              MoveFlags = 0x300;
2538                MoveFlags = 0x3000; //VLack: flight flag changed on 3.1.1
2539        }
2540        else if(m_moveSprint == true) //Sprint
2541        {
2542                m_runSpeed = (m_Unit->m_runSpeed+5.0f)*0.001f;
2543//              MoveFlags = 0x100;
2544                MoveFlags = 0x1000; //VLack: on 3.1.1 0x100 would teleport the NPC, and this is not what we want here!
2545        }
2546        else if(m_moveRun == true) //Run
2547        {
2548                m_runSpeed = m_Unit->m_runSpeed*0.001f;
2549//              MoveFlags = 0x100;
2550                MoveFlags = 0x1000; //VLack: on 3.1.1 0x100 would teleport the NPC, and this is not what we want here!
2551        }
2552/*      else //Walk
2553        {
2554                m_runSpeed = m_Unit->m_walkSpeed*0.001f;
2555                MoveFlags = 0x000;
2556        }*/
2557        m_walkSpeed = m_Unit->m_walkSpeed*0.001f;//move distance per ms time
2558        return MoveFlags;
2559}
2560
2561void AIInterface::UpdateMove()
2562{
2563        //this should NEVER be called directly !!!!!!
2564        //use MoveTo()
2565        float distance = m_Unit->CalcDistance(m_nextPosX,m_nextPosY,m_nextPosZ);
2566       
2567        if(distance < DISTANCE_TO_SMALL_TO_WALK) 
2568                return; //we don't want little movements here and there
2569
2570        m_destinationX = m_nextPosX;
2571        m_destinationY = m_nextPosY;
2572        m_destinationZ = m_nextPosZ;
2573       
2574        /*if(m_moveFly != true)
2575        {
2576                if(m_Unit->GetMapMgr())
2577                {
2578                        float adt_Z = m_Unit->GetMapMgr()->GetLandHeight(m_destinationX, m_destinationY);
2579                        if(fabsf(adt_Z - m_destinationZ) < 3.0f)
2580                                m_destinationZ = adt_Z;
2581                }
2582        }*/
2583
2584        //this prevents updatemovement working on this function
2585        //m_nextPosX = m_nextPosY = m_nextPosZ = 0;
2586
2587        uint32 moveTime;
2588        /* #ifdef INHERIT_FOLLOWED_UNIT_SPEED vojta - this is pointless and we don't need it anymore
2589        if( UnitToFollow )
2590        {
2591//              moveTime = (uint32) (distance * 1000 / UnitToFollow->m_runSpeed ); //I wonder if run peed can ever drop to 0
2592//life sucks, due to calculations the pet will move slower with correct formulas. We add some catch-up speed
2593                moveTime = (uint32) (distance * 1000 / ( UnitToFollow->m_runSpeed * sqrt( distance ) ) ); //I wonder if run peed can ever drop to 0
2594        }
2595#endif */
2596        if(m_moveFly)
2597                moveTime = (uint32) (distance / m_flySpeed);
2598        else if(m_moveRun)
2599                moveTime = (uint32) (distance / m_runSpeed);
2600        else moveTime = (uint32) (distance / m_walkSpeed);
2601
2602        m_totalMoveTime = moveTime;
2603
2604        if(m_Unit->GetTypeId() == TYPEID_UNIT)
2605        {
2606                Creature *creature = static_cast<Creature*>(m_Unit);
2607                // check if we're returning to our respawn location. if so, reset back to default
2608                // orientation
2609                if(creature->GetSpawnX() == m_destinationX &&
2610                        creature->GetSpawnY() == m_destinationY)
2611                {
2612                        float o = creature->GetSpawnO();
2613                        creature->SetOrientation(o);
2614                } else {
2615                        // Calculate the angle to our next position
2616
2617                        float dx = (float)m_destinationX - m_Unit->GetPositionX();
2618                        float dy = (float)m_destinationY - m_Unit->GetPositionY();
2619                        if(dy != 0.0f)
2620                        {
2621                                float angle = atan2(dy, dx);
2622                                m_Unit->SetOrientation(angle);
2623                        }
2624                }
2625        }
2626
2627        if (m_Unit->GetCurrentSpell() == NULL)
2628                SendMoveToPacket(m_destinationX, m_destinationY, m_destinationZ, m_Unit->GetOrientation(), moveTime, getMoveFlags());
2629
2630        m_timeToMove = moveTime;
2631        m_timeMoved = 0;
2632        if(m_moveTimer == 0)
2633        {
2634                m_moveTimer =  UNIT_MOVEMENT_INTERPOLATE_INTERVAL; // update every few msecs
2635        }
2636
2637        m_creatureState = MOVING;
2638}
2639
2640void AIInterface::SendCurrentMove(Player* plyr/*uint64 guid*/)
2641{
2642        if(m_destinationX == 0.0f && m_destinationY == 0.0f && m_destinationZ == 0.0f) return; //invalid move
2643        ByteBuffer *splineBuf = new ByteBuffer(20*4);
2644        *splineBuf << uint32(0); // spline flags
2645        *splineBuf << uint32((m_totalMoveTime - m_timeToMove)+m_moveTimer); //Time Passed (start Position) //should be generated/save
2646        *splineBuf << uint32(m_totalMoveTime); //Total Time //should be generated/save
2647        *splineBuf << uint32(0); //Unknown
2648        *splineBuf << uint32(4); //Spline Count // lets try this
2649
2650        *splineBuf << m_sourceX << m_sourceY << m_sourceZ;
2651        *splineBuf << m_Unit->GetPositionX() << m_Unit->GetPositionY() << m_Unit->GetPositionZ();
2652        *splineBuf << m_destinationX << m_destinationY << m_destinationZ + 0.1f;
2653        *splineBuf << m_destinationX << m_destinationY << m_destinationZ + 0.2f;
2654        *splineBuf << uint8(0);
2655        *splineBuf << m_destinationX << m_destinationY << m_destinationZ;
2656       
2657        plyr->AddSplinePacket(m_Unit->GetGUID(), splineBuf);
2658
2659        //This should only be called by Players AddInRangeObject() ONLY
2660        //using guid cuz when I attempted to use pointer the player was deleted when this event was called some times
2661        //Player* plyr = World::GetPlayer(guid);
2662        //if(!plyr) return;
2663
2664        /*if(m_destinationX == 0.0f && m_destinationY == 0.0f && m_destinationZ == 0.0f) return; //invalid move
2665        uint32 moveTime = m_timeToMove-m_timeMoved;
2666        //uint32 moveTime = (m_timeToMove-m_timeMoved)+m_moveTimer;
2667        WorldPacket data(50);
2668        data.SetOpcode( SMSG_MONSTER_MOVE );
2669        data << m_Unit->GetNewGUID();
2670        data << m_Unit->GetPositionX() << m_Unit->GetPositionY() << m_Unit->GetPositionZ();
2671        data << getMSTime();
2672        data << uint8(0);
2673        data << getMoveFlags();
2674
2675        //float distance = m_Unit->CalcDistance(m_destinationX, m_destinationY, m_destinationZ);
2676        //uint32 moveTime = (uint32) (distance / m_runSpeed);
2677
2678        data << moveTime;
2679        data << uint32(1); //Number of Waypoints
2680        data << m_destinationX << m_destinationY << m_destinationZ;
2681        plyr->GetSession()->SendPacket(&data);*/
2682
2683}
2684
2685bool AIInterface::setInFront(Unit* target) // not the best way to do it, though
2686{
2687        //angle the object has to face
2688        float angle = m_Unit->calcAngle(m_Unit->GetPositionX(), m_Unit->GetPositionY(), target->GetPositionX(), target->GetPositionY() ); 
2689        //Change angle slowly 2000ms to turn 180 deg around
2690        if(angle > 180) angle += 90;
2691        else angle -= 90; //angle < 180
2692        m_Unit->getEasyAngle(angle);
2693        //Convert from degrees to radians (180 deg = PI rad)
2694        float orientation = angle / float(180 / M_PI);
2695        //Update Orientation Server Side
2696        m_Unit->SetPosition(m_Unit->GetPositionX(), m_Unit->GetPositionY(), m_Unit->GetPositionZ(), orientation);
2697       
2698        return m_Unit->isInFront(target);
2699}
2700
2701bool AIInterface::addWayPoint(WayPoint* wp)
2702{
2703        if(!m_waypoints)
2704                m_waypoints = new WayPointMap ;
2705        if(!wp) 
2706                return false;
2707        if(wp->id <= 0)
2708                return false; //not valid id
2709
2710        if(m_waypoints->size() <= wp->id)
2711                m_waypoints->resize(wp->id+1);
2712
2713        if((*m_waypoints)[wp->id] == NULL)
2714        {
2715                (*m_waypoints)[wp->id] = wp;
2716                return true;
2717        }
2718        return false;
2719}
2720
2721void AIInterface::changeWayPointID(uint32 oldwpid, uint32 newwpid)
2722{
2723        if(!m_waypoints)return;
2724        if(newwpid <= 0) 
2725                return; //not valid id
2726        if(newwpid > m_waypoints->size()) 
2727                return; //not valid id
2728        if(oldwpid > m_waypoints->size())
2729                return;
2730
2731        if(newwpid == oldwpid) 
2732                return; //same spot
2733
2734        //already wp with that id ?
2735        WayPoint* originalwp = getWayPoint(newwpid);
2736        if(!originalwp) 
2737                return;
2738        WayPoint* oldwp = getWayPoint(oldwpid);
2739        if(!oldwp) 
2740                return;
2741
2742        oldwp->id = newwpid;
2743        originalwp->id = oldwpid;
2744        (*m_waypoints)[oldwp->id] = oldwp;
2745        (*m_waypoints)[originalwp->id] = originalwp;
2746
2747        //SaveAll to db
2748        saveWayPoints();
2749}
2750
2751void AIInterface::deleteWayPoint(uint32 wpid)
2752{
2753        if(!m_waypoints)return;
2754        if(wpid <= 0) 
2755                return; //not valid id
2756        if(wpid > m_waypoints->size()) 
2757                return; //not valid id
2758
2759        WayPointMap new_waypoints;
2760        uint32 newpid = 1;
2761        for(WayPointMap::iterator itr = m_waypoints->begin(); itr != m_waypoints->end(); ++itr)
2762        {
2763                if((*itr) == NULL || (*itr)->id == wpid)
2764                {
2765                        if((*itr) != NULL)
2766                                delete (*itr);
2767
2768                        continue;
2769                }
2770
2771                new_waypoints.push_back(*itr);
2772        }
2773
2774        m_waypoints->clear();
2775        m_waypoints->push_back((WayPoint*)NULL);                // waypoint 0
2776        for(WayPointMap::iterator itr = new_waypoints.begin(); itr != new_waypoints.end(); ++itr)
2777        {
2778                (*itr)->id = newpid++;
2779                m_waypoints->push_back(*itr);
2780        }
2781
2782        saveWayPoints();
2783}
2784
2785bool AIInterface::showWayPoints(Player* pPlayer, bool Backwards)
2786{
2787        if(!m_waypoints)
2788                return false;
2789
2790        //wpid of 0 == all
2791        WayPointMap::const_iterator itr;
2792        if(m_WayPointsShowing == true) 
2793                return false;
2794
2795        m_WayPointsShowing = true;
2796
2797        WayPoint* wp = NULL;
2798        for (itr = m_waypoints->begin(); itr != m_waypoints->end(); itr++)
2799        {
2800                if( (*itr) != NULL )
2801                {
2802                        wp = *itr;
2803
2804                        //Create
2805                        Creature* pWayPoint = new Creature((uint64)HIGHGUID_TYPE_WAYPOINT << 32 | wp->id);
2806                        pWayPoint->CreateWayPoint(wp->id,pPlayer->GetMapId(),wp->x,wp->y,wp->z,0);
2807                        pWayPoint->SetUInt32Value(OBJECT_FIELD_ENTRY, 300000);
2808                        pWayPoint->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5f);
2809                        if(Backwards)
2810                        {
2811                                uint32 DisplayID = (wp->backwardskinid == 0)? GetUnit()->GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID) : wp->backwardskinid;
2812                                pWayPoint->SetUInt32Value(UNIT_FIELD_DISPLAYID, DisplayID);
2813                                pWayPoint->SetUInt32Value(UNIT_NPC_EMOTESTATE, wp->backwardemoteid);
2814                        }
2815                        else
2816                        {
2817                                uint32 DisplayID = (wp->forwardskinid == 0)? GetUnit()->GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID) : wp->forwardskinid;
2818                                pWayPoint->SetUInt32Value(UNIT_FIELD_DISPLAYID, DisplayID);
2819                                pWayPoint->SetUInt32Value(UNIT_NPC_EMOTESTATE, wp->forwardemoteid);
2820                        }
2821                        pWayPoint->SetUInt32Value(UNIT_FIELD_LEVEL, wp->id);
2822                        pWayPoint->SetUInt32Value(UNIT_NPC_FLAGS, 0);
2823                        pWayPoint->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE , pPlayer->GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE));
2824                        pWayPoint->SetUInt32Value(UNIT_FIELD_HEALTH, 1);
2825                        pWayPoint->SetUInt32Value(UNIT_FIELD_MAXHEALTH, 1);
2826                        pWayPoint->SetUInt32Value(UNIT_FIELD_STAT0, wp->flags);
2827
2828                        //Create on client
2829                        ByteBuffer buf(3000);
2830                        uint32 count = pWayPoint->BuildCreateUpdateBlockForPlayer(&buf, pPlayer);
2831                        pPlayer->PushCreationData(&buf, count);
2832
2833                        //root the object
2834                        WorldPacket data1;
2835                        data1.Initialize(SMSG_FORCE_MOVE_ROOT);
2836                        data1 << pWayPoint->GetNewGUID();
2837                        pPlayer->GetSession()->SendPacket( &data1 );
2838
2839                        //Cleanup
2840                        delete pWayPoint;
2841                }
2842        }
2843        return true;
2844}
2845
2846bool AIInterface::hideWayPoints(Player* pPlayer)
2847{
2848        if(!m_waypoints)
2849                return false;
2850
2851        //wpid of 0 == all
2852        if(m_WayPointsShowing != true) return false;
2853        m_WayPointsShowing = false;
2854        WayPointMap::const_iterator itr;
2855
2856        // slightly better way to do this
2857        uint64 guid;
2858
2859        for (itr = m_waypoints->begin(); itr != m_waypoints->end(); itr++)
2860        {
2861                if( (*itr) != NULL )
2862                {
2863                        // avoid C4293
2864                        guid = ((uint64)HIGHGUID_TYPE_WAYPOINT << 32) | (*itr)->id;
2865                        WoWGuid wowguid(guid);
2866                        pPlayer->PushOutOfRange(wowguid);
2867                }
2868        }
2869        return true;
2870}
2871
2872bool AIInterface::saveWayPoints()
2873{
2874        if(!m_waypoints)return false;
2875
2876        if(!GetUnit()) return false;
2877        if(GetUnit()->GetTypeId() != TYPEID_UNIT) return false;
2878
2879        WorldDatabase.Execute("DELETE FROM creature_waypoints WHERE spawnid = %u", ((Creature*)GetUnit())->GetSQL_id());
2880        WayPointMap::const_iterator itr;
2881        WayPoint* wp = NULL;
2882        std::stringstream ss;
2883
2884        for (itr = m_waypoints->begin(); itr != m_waypoints->end(); itr++)
2885        {
2886                if((*itr) == NULL) 
2887                        continue;
2888
2889                wp = (*itr);
2890
2891                //Save
2892                ss.str("");
2893                ss << "REPLACE INTO creature_waypoints ";
2894                ss << "(spawnid,waypointid,position_x,position_y,position_z,waittime,flags,forwardemoteoneshot,forwardemoteid,backwardemoteoneshot,backwardemoteid,forwardskinid,backwardskinid) VALUES (";
2895                ss << ((Creature*)GetUnit())->GetSQL_id() << ", ";
2896                ss << wp->id << ", ";
2897                ss << wp->x << ", ";
2898                ss << wp->y << ", ";
2899                ss << wp->z << ", ";
2900                ss << wp->waittime << ", ";
2901                ss << wp->flags << ", ";
2902                ss << wp->forwardemoteoneshot << ", ";
2903                ss << wp->forwardemoteid << ", ";
2904                ss << wp->backwardemoteoneshot << ", ";
2905                ss << wp->backwardemoteid << ", ";
2906                ss << wp->forwardskinid << ", ";
2907                ss << wp->backwardskinid << ")\0";
2908                WorldDatabase.Query( ss.str().c_str() );
2909        }
2910        return true;
2911}
2912
2913void AIInterface::deleteWaypoints()
2914{
2915        if(!m_waypoints)
2916                return;
2917
2918        for(WayPointMap::iterator itr = m_waypoints->begin(); itr != m_waypoints->end(); ++itr)
2919        {
2920                if((*itr) != NULL)
2921                        delete (*itr);
2922        }
2923        m_waypoints->clear();
2924}
2925
2926WayPoint* AIInterface::getWayPoint(uint32 wpid)
2927{
2928        if(!m_waypoints)return NULL;
2929        if(wpid >= m_waypoints->size()) 
2930                return NULL; //not valid id
2931
2932        /*WayPointMap::const_iterator itr = m_waypoints->find( wpid );
2933        if( itr != m_waypoints->end( ) )
2934                return itr->second;*/
2935        return m_waypoints->at(wpid);
2936}
2937
2938void AIInterface::_UpdateMovement(uint32 p_time)
2939{
2940        if(!m_Unit->isAlive())
2941        {
2942                StopMovement(0);
2943                return;
2944        }
2945
2946        //move after finishing our current spell
2947        if ( m_Unit->GetCurrentSpell() != NULL )
2948                return;
2949
2950        uint32 timediff = 0;
2951
2952        if(m_moveTimer > 0)
2953        {
2954                if(p_time >= m_moveTimer)
2955                {
2956                        timediff = p_time - m_moveTimer;
2957                        m_moveTimer = 0;
2958                }
2959                else
2960                        m_moveTimer -= p_time;
2961        }
2962
2963        if(m_timeToMove > 0)
2964        {
2965                m_timeMoved = m_timeToMove <= p_time + m_timeMoved ? m_timeToMove : p_time + m_timeMoved;
2966        }
2967
2968        if(m_creatureState == MOVING)
2969        {
2970                if(!m_moveTimer)
2971                {
2972                        if(m_timeMoved == m_timeToMove) //reached destination
2973                        {
2974/*                              if(m_fastMove)
2975                                {
2976                                        m_Unit->UpdateSpeed();
2977                                        m_fastMove = false;
2978                                }*/
2979
2980                                if(m_moveType == MOVEMENTTYPE_WANTEDWP)//We reached wanted wp stop now
2981                                        m_moveType = MOVEMENTTYPE_DONTMOVEWP;
2982
2983                                float wayO = 0.0f;
2984
2985                                if((GetWayPointsCount() != 0) && (m_AIState == STATE_IDLE || m_AIState == STATE_SCRIPTMOVE)) //if we attacking don't use wps
2986                                {
2987                                        WayPoint* wp = getWayPoint(getCurrentWaypoint());
2988                                        if(wp)
2989                                        {
2990                                                CALL_SCRIPT_EVENT(m_Unit, OnReachWP)(wp->id, !m_moveBackward);
2991                                                if(((Creature*)m_Unit)->has_waypoint_text)
2992                                                        objmgr.HandleMonsterSayEvent(((Creature*)m_Unit), MONSTER_SAY_EVENT_RANDOM_WAYPOINT);
2993
2994                                                //Lets face to correct orientation
2995                                                wayO = wp->o;
2996                                                m_moveTimer = wp->waittime; //wait before next move
2997                                                if(!m_moveBackward)
2998                                                {
2999                                                        if(wp->forwardemoteoneshot)
3000                                                        {
3001                                                                GetUnit()->Emote(EmoteType(wp->forwardemoteid));
3002                                                        }
3003                                                        else
3004                                                        {
3005                                                                if(GetUnit()->GetUInt32Value(UNIT_NPC_EMOTESTATE) != wp->forwardemoteid)
3006                                                                {
3007                                                                        GetUnit()->SetUInt32Value(UNIT_NPC_EMOTESTATE, wp->forwardemoteid);
3008                                                                }
3009                                                        }
3010                                                }
3011                                                else
3012                                                {
3013                                                        if(wp->backwardemoteoneshot)
3014                                                        {
3015                                                                GetUnit()->Emote(EmoteType(wp->backwardemoteid));
3016                                                        }
3017                                                        else
3018                                                        {
3019                                                                if(GetUnit()->GetUInt32Value(UNIT_NPC_EMOTESTATE) != wp->backwardemoteid)
3020                                                                {
3021                                                                        GetUnit()->SetUInt32Value(UNIT_NPC_EMOTESTATE, wp->backwardemoteid);
3022                                                                }
3023                                                        }
3024                                                }
3025                                        }
3026                                        else
3027                                                m_moveTimer = RandomUInt(m_moveRun ? 5000 : 10000); // wait before next move
3028                                }
3029
3030                                m_creatureState = STOPPED;
3031                                m_moveSprint = false;
3032
3033                                if(m_MovementType == MOVEMENTTYPE_DONTMOVEWP)
3034                                        m_Unit->SetPosition(m_destinationX, m_destinationY, m_destinationZ, wayO, true);
3035                                else
3036                                        m_Unit->SetPosition(m_destinationX, m_destinationY, m_destinationZ, m_Unit->GetOrientation(), true);
3037
3038                                m_destinationX = m_destinationY = m_destinationZ = 0;
3039                                m_timeMoved = 0;
3040                                m_timeToMove = 0;
3041                        }
3042                        else
3043                        {
3044                                //Move Server Side Update
3045                                float q = (float)m_timeMoved / (float)m_timeToMove;
3046                                float x = m_Unit->GetPositionX() + (m_destinationX - m_Unit->GetPositionX()) * q;
3047                                float y = m_Unit->GetPositionY() + (m_destinationY - m_Unit->GetPositionY()) * q;
3048                                float z = m_Unit->GetPositionZ() + (m_destinationZ - m_Unit->GetPositionZ()) * q;
3049
3050                                //Andy
3051                                if (sWorld.Collision) {
3052                                        float target_land_z=0.0f;
3053                                        if( m_Unit->GetMapMgr() != NULL )
3054                                        {
3055                                                if(m_moveFly != true)
3056                                                {
3057                                                        target_land_z = CollideInterface.GetHeight(m_Unit->GetMapId(), x, y, z + 2.0f);
3058                                                        if ( target_land_z == NO_WMO_HEIGHT )
3059                                                        {
3060                                                                target_land_z = m_Unit->GetMapMgr()->GetLandHeight(x, y);
3061                                                                if ( target_land_z == 999999.0f )
3062                                                                        target_land_z = z;
3063                                                        }
3064                                                }
3065
3066                                                if ( z > m_Unit->GetMapMgr()->GetWaterHeight( m_nextPosX, m_nextPosY ) && target_land_z != 0.0f )
3067                                                        z = target_land_z;
3068                                        }
3069                                }
3070
3071                                m_Unit->SetPosition(x, y, z, m_Unit->GetOrientation());
3072                               
3073                                m_timeToMove -= m_timeMoved;
3074                                m_timeMoved = 0;
3075                                m_moveTimer = (UNIT_MOVEMENT_INTERPOLATE_INTERVAL < m_timeToMove) ? UNIT_MOVEMENT_INTERPOLATE_INTERVAL : m_timeToMove;
3076                        }
3077                        //**** Movement related stuff that should be done after a move update (Keeps Client and Server Synced) ****//
3078                        //**** Process the Pending Move ****//
3079                        if(m_nextPosX != 0.0f && m_nextPosY != 0.0f)
3080                        {
3081                                UpdateMove();
3082                        }
3083                }
3084        }
3085        else if(m_creatureState == STOPPED && (m_AIState == STATE_IDLE || m_AIState == STATE_SCRIPTMOVE) && !m_moveTimer && !m_timeToMove && UnitToFollow == NULL) //creature is stopped and out of Combat
3086        {
3087                if(sWorld.getAllowMovement() == false) //is creature movement enabled?
3088                        return;
3089
3090                if(m_Unit->GetUInt32Value(UNIT_FIELD_DISPLAYID) == 5233) //if Spirit Healer don't move
3091                        return;
3092
3093                // do we have a formation?
3094                if(m_formationLinkSqlId != 0)
3095                {
3096                        if(!m_formationLinkTarget)
3097                        {
3098                                // haven't found our target yet
3099                                Creature * c = static_cast<Creature*>(m_Unit);
3100                                if(!c->haslinkupevent)
3101                                {
3102                                        // register linkup event
3103                                        c->haslinkupevent = true;
3104                                        sEventMgr.AddEvent(c, &Creature::FormationLinkUp, m_formationLinkSqlId, 
3105                                                EVENT_CREATURE_FORMATION_LINKUP, 1000, 0,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
3106                                }
3107                        }
3108                        else
3109                        {
3110                                // we've got a formation target, set unittofollow to this
3111                                UnitToFollow = m_formationLinkTarget;
3112                                FollowDistance = m_formationFollowDistance;
3113                                m_fallowAngle = m_formationFollowAngle;
3114                        }
3115                }
3116                if(UnitToFollow == 0)
3117                {
3118                        // no formation, use waypoints
3119                        int destpoint = -1;
3120
3121                        // If creature has no waypoints just wander aimlessly around spawnpoint
3122                        if(GetWayPointsCount()==0) //no waypoints
3123                        {
3124                                /*      if(m_moveRandom)
3125                                {
3126                                if((rand()%10)==0)                                                                                                                                                                                                                                                                     
3127                                {                                                                                                                                                                                                                                                                                                                                 
3128                                float wanderDistance = rand()%4 + 2;
3129                                float wanderX = ((wanderDistance*rand()) / RAND_MAX) - wanderDistance / 2;                                                                                                                                                                                                                         
3130                                float wanderY = ((wanderDistance*rand()) / RAND_MAX) - wanderDistance / 2;                                                                                                                                                                                                                         
3131                                float wanderZ = 0; // FIX ME ( I don't know how to get appropriate Z coord, maybe use client height map data)                                                                                                                                                                                                                   
3132
3133                                if(m_Unit->CalcDistance(m_Unit->GetPositionX(), m_Unit->GetPositionY(), m_Unit->GetPositionZ(), ((Creature*)m_Unit)->respawn_cord[0], ((Creature*)m_Unit)->respawn_cord[1], ((Creature*)m_Unit)->respawn_cord[2])>15)                                                                                                                                             
3134                                {   
3135                                //return home                                                                                                                                                                                                                                                                                           
3136                                MoveTo(((Creature*)m_Unit)->respawn_cord[0],((Creature*)m_Unit)->respawn_cord[1],((Creature*)m_Unit)->respawn_cord[2],false);
3137                                }   
3138                                else
3139                                {
3140                                MoveTo(m_Unit->GetPositionX() + wanderX, m_Unit->GetPositionY() + wanderY, m_Unit->GetPositionZ() + wanderZ,false);
3141                                }       
3142                                }       
3143                                }
3144                                */     
3145                                return;                                                                                                                                                                                                                                                                                           
3146                        }                                                                                                                                                                                                                                                                                                                 
3147                        else //we do have waypoints
3148                        {
3149                                if(m_moveType == MOVEMENTTYPE_RANDOMWP) //is random move on if so move to a random waypoint
3150                                {
3151                                        if(GetWayPointsCount() > 1)
3152                                                destpoint = RandomUInt((uint32)GetWayPointsCount());
3153                                }
3154                                else if (m_moveType == MOVEMENTTYPE_CIRCLEWP) //random move is not on lets follow the path in circles
3155                                {
3156                                        // 1 -> 10 then 1 -> 10
3157                                        m_currentWaypoint++;
3158                                        if (m_currentWaypoint > GetWayPointsCount()) m_currentWaypoint = 1; //Happens when you delete last wp seems to continue ticking
3159                                        destpoint = m_currentWaypoint;
3160                                        m_moveBackward = false;
3161                                }
3162                                else if(m_moveType == MOVEMENTTYPE_WANTEDWP)//Move to wanted wp
3163                                {
3164                                        if(m_currentWaypoint)
3165                                        {
3166                                                if(GetWayPointsCount() > 0)
3167                                                {
3168                                                        destpoint = m_currentWaypoint;
3169                                                }
3170                                                else
3171                                                        destpoint = -1;
3172                                        }
3173                                }
3174                                else if(m_moveType == MOVEMENTTYPE_FORWARDTHANSTOP)// move to end, then stop
3175                                {
3176                                        ++m_currentWaypoint;
3177                                        if(m_currentWaypoint > GetWayPointsCount())
3178                                        {
3179                                                //hmm maybe we should stop being path walker since we are waiting here anyway
3180                                                destpoint = -1;
3181                                        }
3182                                        else
3183                                                destpoint = m_currentWaypoint;
3184                                }
3185                                else if(m_moveType != MOVEMENTTYPE_QUEST && m_moveType != MOVEMENTTYPE_DONTMOVEWP)//4 Unused
3186                                {
3187                                        // 1 -> 10 then 10 -> 1
3188                                        if (m_currentWaypoint > GetWayPointsCount()) m_currentWaypoint = 1; //Happens when you delete last wp seems to continue ticking
3189                                        if (m_currentWaypoint == GetWayPointsCount()) // Are we on the last waypoint? if so walk back
3190                                                m_moveBackward = true;
3191                                        if (m_currentWaypoint == 1) // Are we on the first waypoint? if so lets goto the second waypoint
3192                                                m_moveBackward = false;
3193                                        if (!m_moveBackward) // going 1..n
3194                                                destpoint = ++m_currentWaypoint;
3195                                        else                            // going n..1
3196                                                destpoint = --m_currentWaypoint;
3197                                }
3198
3199                                if(destpoint != -1)
3200                                {
3201                                        WayPoint* wp = getWayPoint(destpoint);
3202                                        if(wp)
3203                                        {
3204                                                if(!m_moveBackward)
3205                                                {
3206                                                        if((wp->forwardskinid != 0) && (GetUnit()->GetUInt32Value(UNIT_FIELD_DISPLAYID) != wp->forwardskinid))
3207                                                        {
3208                                                                GetUnit()->SetUInt32Value(UNIT_FIELD_DISPLAYID, wp->forwardskinid);
3209                                                                GetUnit()->EventModelChange();
3210                                                        }
3211                                                }
3212                                                else
3213                                                {
3214                                                        if((wp->backwardskinid != 0) && (GetUnit()->GetUInt32Value(UNIT_FIELD_DISPLAYID) != wp->backwardskinid))
3215                                                        {
3216                                                                GetUnit()->SetUInt32Value(UNIT_FIELD_DISPLAYID, wp->backwardskinid);
3217                                                                GetUnit()->EventModelChange();
3218                                                        }
3219                                                }
3220                                                m_moveFly = (wp->flags == 768) ? 1 : 0;
3221                                                m_moveRun = (wp->flags == 256) ? 1 : 0;
3222                                                MoveTo(wp->x, wp->y, wp->z, 0);
3223                                        }
3224                                }
3225                        }
3226                }
3227        }
3228
3229        //Fear Code
3230        if(m_AIState == STATE_FEAR && UnitToFear != NULL && m_creatureState == STOPPED)
3231        {
3232                if(getMSTime() > m_FearTimer)   // Wait at point for x ms ;)
3233                {
3234                        float Fx;
3235                        float Fy;
3236                        float Fz;
3237
3238                        if( sWorld.DisableFearMovement )
3239                        {
3240                                if( m_Unit->GetMapId() == 529|| m_Unit->GetMapId() == 566 || m_Unit->GetMapId() == 489 || m_Unit->GetMapId() == 572 || m_Unit->GetMapId() == 562 || m_Unit->GetMapId() == 559 )
3241                                {
3242                                        return; 
3243                                }
3244                        }
3245                        // Calculate new angle to target.
3246                        float Fo = m_Unit->calcRadAngle(UnitToFear->GetPositionX(), UnitToFear->GetPositionY(), m_Unit->GetPositionX(), m_Unit->GetPositionY());
3247                        double fAngleAdd = RandomDouble(((M_PI/2) * 2)) - (M_PI/2);
3248                        Fo += (float)fAngleAdd;
3249                       
3250                        float dist = m_Unit->CalcDistance(UnitToFear);
3251                        if(dist > 30.0f || (Rand(25) && dist > 10.0f))  // not too far or too close
3252                        {
3253                                        if( m_Unit->GetMapId() == 572 || m_Unit->GetMapId() == 562 || m_Unit->GetMapId() == 559 ) //GET MAP ID
3254                                        {
3255                                                Fx = m_Unit->GetPositionX();
3256                                                Fy = m_Unit->GetPositionY();
3257                                        }
3258                                        else 
3259                                        {
3260                                                Fx = m_Unit->GetPositionX() - (RandomFloat(15.f)+5.0f)*cosf(Fo);
3261                                                Fy = m_Unit->GetPositionY() - (RandomFloat(15.f)+5.0f)*sinf(Fo);
3262                                        }
3263                        }
3264                        else
3265                        {
3266                                Fx = m_Unit->GetPositionX() + (RandomFloat(20.f)+5.0f)*cosf(Fo);
3267                                Fy = m_Unit->GetPositionY() + (RandomFloat(20.f)+5.0f)*sinf(Fo);
3268                        }
3269                        // Check if this point is in water.
3270                        float wl = m_Unit->GetMapMgr()->GetWaterHeight(Fx, Fy);
3271//                      uint8 wt = m_Unit->GetMapMgr()->GetWaterType(Fx, Fy);
3272
3273                        if (sWorld.Collision) {
3274                                Fz = CollideInterface.GetHeight(m_Unit->GetMapId(), Fx, Fy, m_Unit->GetPositionZ() + 2.0f);
3275                                if( Fz == NO_WMO_HEIGHT )
3276                        Fz = m_Unit->GetMapMgr()->GetLandHeight(Fx, Fy);
3277                                else
3278                                {
3279                                        if( CollideInterface.GetFirstPoint(m_Unit->GetMapId(), m_Unit->GetPositionX(), m_Unit->GetPositionY(), m_Unit->GetPositionZ() + 2.0f,
3280                                                Fx, Fy, Fz + 2.0f, Fx, Fy, Fz, -1.0f) )
3281                                        {
3282                                                //Fz = CollideInterface.GetHeight(m_Unit->GetMapId(), Fx, Fy, m_Unit->GetPositionZ() + 2.0f);
3283                                        }
3284                                }
3285
3286                                if( fabs( m_Unit->GetPositionZ() - Fz ) > 10.0f || 
3287                                        ( wl != 0.0f && Fz < wl ) )             // in water
3288                                {
3289                                        m_FearTimer=getMSTime() + 500;
3290                                }
3291                                else if( CollideInterface.CheckLOS(m_Unit->GetMapId(), m_Unit->GetPositionX(), m_Unit->GetPositionY(), m_Unit->GetPositionZ() + 2.0f, Fx, Fy, Fz) )
3292                                {
3293                                        MoveTo(Fx, Fy, Fz, Fo);
3294                                        m_FearTimer = m_totalMoveTime + getMSTime() + 400;
3295                                }
3296                                else
3297                                {
3298                                        StopMovement(0);
3299                                }
3300                        } else {
3301                                Fz = m_Unit->GetMapMgr()->GetLandHeight(Fx, Fy);
3302                                if(fabs(m_Unit->GetPositionZ()-Fz) > 4 || (Fz != 0.0f && Fz < (wl-2.0f)))
3303                                        m_FearTimer=getMSTime()+100;
3304                                else
3305                                {
3306                                        MoveTo(Fx, Fy, Fz, Fo);
3307                                        m_FearTimer = m_totalMoveTime + getMSTime() + 200;
3308                                }
3309                        }
3310                }
3311        }
3312
3313        // Wander AI movement code
3314        if(m_AIState == STATE_WANDER && m_creatureState == STOPPED)
3315        {
3316                if(getMSTime() < m_WanderTimer) // is it time to move again?
3317                        return;
3318
3319                // calculate a random distance and angle to move
3320                float wanderD = RandomFloat(2.0f) + 2.0f;
3321                float wanderO = RandomFloat(6.283f);
3322                float wanderX = m_Unit->GetPositionX() + wanderD * cosf(wanderO);
3323                float wanderY = m_Unit->GetPositionY() + wanderD * sinf(wanderO);
3324
3325                if (sWorld.Collision) {
3326                        float wanderZ = CollideInterface.GetHeight(m_Unit->GetMapId(), wanderX, wanderY, m_Unit->GetPositionZ() + 2.0f);
3327                        float wanderZ2 = wanderZ;
3328                        if( wanderZ == NO_WMO_HEIGHT )
3329                                wanderZ = m_Unit->GetMapMgr()->GetLandHeight(wanderX, wanderY);
3330                        else
3331                        {
3332                                if( CollideInterface.GetFirstPoint(m_Unit->GetMapId(), m_Unit->GetPositionX(), m_Unit->GetPositionY(), m_Unit->GetPositionZ() + 2.0f,
3333                                        wanderX, wanderY, wanderZ + 2.0f, wanderX, wanderY, wanderZ, -1.0f) )
3334                                {
3335                                        //wanderZ = CollideInterface.GetHeight(m_Unit->GetMapId(), wanderX, wanderY, m_Unit->GetPositionZ() + 2.0f);
3336                                }
3337                                else
3338                                        wanderZ = wanderZ2;
3339                        }
3340
3341                        if( fabs( m_Unit->GetPositionZ() - wanderZ ) > 10.0f )
3342                        {
3343                                m_WanderTimer=getMSTime() + 1000;
3344                        }
3345                        else if(CollideInterface.CheckLOS(m_Unit->GetMapId(), m_Unit->GetPositionX(), m_Unit->GetPositionY(), m_Unit->GetPositionZ() + 2.0f, wanderX, wanderY, wanderZ))
3346                        {
3347                                m_Unit->SetOrientation(wanderO);
3348                                MoveTo(wanderX, wanderY, wanderZ, wanderO);
3349                                m_WanderTimer = getMSTime() + m_totalMoveTime + 300; // time till next move (+ pause)
3350                        }
3351                        else
3352                        {
3353                                StopMovement(0);
3354                        }
3355                } else {
3356                        float wanderZ = m_Unit->GetMapMgr()->GetLandHeight(wanderX, wanderY);
3357
3358                        // without these next checks we could fall through the "ground" (WMO) and get stuck
3359                        // wander won't work correctly in cities until we get some way to fix this and remove these checks
3360                        float currentZ = m_Unit->GetPositionZ();
3361                        float landZ = m_Unit->GetMapMgr()->GetLandHeight(m_Unit->GetPositionX(), m_Unit->GetPositionY());
3362
3363                        if( currentZ > landZ + 1.0f // are we more than 1yd above ground? (possible WMO)
3364                         || wanderZ < currentZ - 5.0f // is our destination land height too low? (possible WMO)
3365                         || wanderZ > currentZ + wanderD) // is our destination too high to climb?
3366                        {
3367                                m_WanderTimer = getMSTime() + 1000; // wait 1 second before we try again
3368                                return;
3369                        }
3370
3371                        m_Unit->SetOrientation(wanderO);
3372                        MoveTo(wanderX, wanderY, wanderZ, wanderO);
3373                        m_WanderTimer = getMSTime() + m_totalMoveTime + 300; // time till next move (+ pause)
3374                }
3375        }
3376
3377        //Unit Follow Code
3378        if(UnitToFollow != NULL)
3379        {
3380#if !defined(WIN32) && !defined(HACKY_CRASH_FIXES)
3381                if( UnitToFollow->event_GetCurrentInstanceId() != m_Unit->event_GetCurrentInstanceId() || !UnitToFollow->IsInWorld() )
3382                        UnitToFollow = NULL;
3383                else
3384                {
3385#else
3386                __try
3387                {
3388                        if( UnitToFollow->event_GetCurrentInstanceId() != m_Unit->event_GetCurrentInstanceId() || !UnitToFollow->IsInWorld() )
3389                                UnitToFollow = NULL;
3390                        else
3391                        {
3392#endif
3393                                if(m_AIState == STATE_IDLE || m_AIState == STATE_FOLLOWING)
3394                                {
3395                                        float dist = m_Unit->GetDistanceSq(UnitToFollow);
3396
3397                                        // re-calculate orientation based on target's movement
3398                                        if(m_lastFollowX != UnitToFollow->GetPositionX() ||
3399                                                m_lastFollowY != UnitToFollow->GetPositionY())
3400                                        {
3401                                                float dx = UnitToFollow->GetPositionX() - m_Unit->GetPositionX();
3402                                                float dy = UnitToFollow->GetPositionY() - m_Unit->GetPositionY();
3403                                                if(dy != 0.0f)
3404                                                {
3405                                                        float angle = atan2(dx,dy);
3406                                                        m_Unit->SetOrientation(angle);
3407                                                }
3408                                                m_lastFollowX = UnitToFollow->GetPositionX();
3409                                                m_lastFollowY = UnitToFollow->GetPositionY();
3410                                        }
3411
3412                                        if (dist > (FollowDistance*FollowDistance)) //if out of range
3413                                        {
3414                                                m_AIState = STATE_FOLLOWING;
3415                                               
3416                                                if(dist > 25.0f) //25 yard away lets run else we will loose the them
3417                                                        m_moveRun = true;
3418                                                else 
3419                                                        m_moveRun = false;
3420
3421                                                if(m_AIType == AITYPE_PET || UnitToFollow == m_formationLinkTarget) //Unit is Pet/formation
3422                                                {
3423                                                        if(dist > 900.0f/*30*/)
3424                                                                m_moveSprint = true;
3425
3426                                                        float delta_x = UnitToFollow->GetPositionX();
3427                                                        float delta_y = UnitToFollow->GetPositionY();
3428                                                        float d = 3;
3429                                                        if(m_formationLinkTarget)
3430                                                                d = m_formationFollowDistance;
3431
3432                                                        MoveTo(delta_x+(d*(cosf(m_fallowAngle+UnitToFollow->GetOrientation()))),
3433                                                                delta_y+(d*(sinf(m_fallowAngle+UnitToFollow->GetOrientation()))),
3434                                                                UnitToFollow->GetPositionZ(),UnitToFollow->GetOrientation());                           
3435                                                }
3436                                                else
3437                                                {
3438                                                        _CalcDestinationAndMove(UnitToFollow, FollowDistance);
3439                                                }
3440                                        }
3441                                }
3442                        }
3443#if defined(WIN32) && defined(HACKY_CRASH_FIXES)
3444                }
3445                __except(EXCEPTION_EXECUTE_HANDLER)
3446                {
3447                        UnitToFollow = NULL;
3448                }
3449#endif
3450        }
3451}
3452
3453void AIInterface::CastSpell(Unit* caster, SpellEntry *spellInfo, SpellCastTargets targets)
3454{
3455        if( m_AIType != AITYPE_PET && disable_spell )
3456                return;
3457
3458        // Stop movement while casting.
3459        m_AIState = STATE_CASTING;
3460#ifdef _AI_DEBUG
3461        sLog.outString("AI DEBUG: Unit %u casting spell %s on target "I64FMT, caster->GetEntry(), 
3462                sSpellStore.LookupString(spellInfo->Name), targets.m_unitTarget);
3463#endif
3464
3465        //i wonder if this will lead to a memory leak :S
3466        Spell *nspell = new Spell(caster, spellInfo, false, NULL);
3467        if (!nspell)
3468                return;
3469        nspell->prepare(&targets);
3470}
3471
3472SpellEntry *AIInterface::getSpellEntry(uint32 spellId)
3473{
3474        SpellEntry *spellInfo = dbcSpell.LookupEntry(spellId );
3475
3476        if(!spellInfo)
3477        {
3478                sLog.outError("WORLD: unknown spell id %i\n", spellId);
3479                return NULL;
3480        }
3481
3482        return spellInfo;
3483}
3484
3485SpellCastTargets AIInterface::setSpellTargets(SpellEntry *spellInfo, Unit* target)
3486{
3487        SpellCastTargets targets;
3488        targets.m_unitTarget = target ? target->GetGUID() : 0;
3489        targets.m_itemTarget = 0;
3490        targets.m_srcX = targets.m_destX = m_Unit->GetPositionX();
3491        targets.m_srcY = targets.m_destY = m_Unit->GetPositionY();
3492        targets.m_srcZ = targets.m_destZ = m_Unit->GetPositionZ();
3493
3494        if(m_nextSpell->spelltargetType == TTYPE_SINGLETARGET)
3495        {
3496                targets.m_targetMask = 2;
3497        }
3498        else if(m_nextSpell->spelltargetType == TTYPE_SOURCE)
3499        {
3500                targets.m_targetMask = 32;
3501//              targets.m_srcX = m_Unit->GetPositionX();
3502//              targets.m_srcY = m_Unit->GetPositionY();
3503//              targets.m_srcZ = m_Unit->GetPositionZ();
3504        }
3505        else if(m_nextSpell->spelltargetType == TTYPE_DESTINATION)
3506        {
3507                targets.m_targetMask = 64;
3508                if( target != NULL )
3509                {
3510                        targets.m_destX = target->GetPositionX();
3511                        targets.m_destY = target->GetPositionY();
3512                        targets.m_destZ = target->GetPositionZ();
3513                }
3514                else
3515                {
3516                        targets.m_destX = m_Unit->GetPositionX();
3517                        targets.m_destY = m_Unit->GetPositionY();
3518                        targets.m_destZ = m_Unit->GetPositionZ();
3519                }
3520        }
3521        else if(m_nextSpell->spelltargetType == TTYPE_CASTER)
3522        {
3523                targets.m_targetMask = 2;
3524                targets.m_unitTarget = m_Unit->GetGUID();
3525        }
3526
3527        return targets;
3528}
3529
3530AI_Spell *AIInterface::getSpell()
3531{
3532        if(next_spell_time > (uint32)UNIXTIME)
3533                return NULL;
3534
3535        waiting_for_cooldown = false;
3536
3537        // look at our spells
3538        AI_Spell *  sp = NULL;
3539        AI_Spell *  def_spell = NULL;
3540        uint32 cool_time=0;
3541        uint32 cool_time2;
3542        uint32 nowtime = getMSTime();
3543
3544        if(m_Unit->IsPet())
3545        {
3546                sp = def_spell = ((Pet*)m_Unit)->HandleAutoCastEvent();
3547        }
3548        else
3549        {
3550                for(list<AI_Spell*>::iterator itr = m_spells.begin(); itr != m_spells.end();)
3551                {
3552                        sp = *itr;
3553                        ++itr;
3554                        if(     
3555//                              sp->cooldowntime && //Zack : no need for this double check here
3556                                nowtime < sp->cooldowntime
3557//                              && sp->procChance >= 100 //Zack: why was this put here ? It makes mobs spam spells like no tomorrow
3558                                )
3559                        {
3560                                cool_time2=sp->cooldowntime-nowtime;
3561                                if(!cool_time || cool_time2<cool_time)
3562                                        cool_time=cool_time2;
3563
3564                                waiting_for_cooldown = true;
3565                                continue;
3566                        }
3567
3568                        if(sp->procCount && sp->procCounter >= sp->procCount)
3569                                continue;
3570
3571                        if(sp->agent == AGENT_SPELL)
3572                        {
3573                                if (sp->spellType == STYPE_BUFF)
3574                                {
3575                                        // cast the buff at requested percent only if we don't have it already
3576                                        if(sp->procChance >= 100 || Rand(sp->procChance))
3577                                        {
3578                                                if(!m_Unit->HasBuff(sp->spell->Id))
3579                                                {
3580                                                        return sp;
3581                                                }
3582                                        }
3583                                }
3584                                else
3585                                {
3586                                        if(def_spell!=0)
3587                                                continue;
3588
3589                                        // cast the spell at requested percent.
3590                                        if(sp->procChance >= 100 || Rand(sp->procChance))
3591                                        {
3592                                                //focus/mana requirement
3593                                                switch(sp->spell->powerType)
3594                                                {
3595                                                case POWER_TYPE_MANA:
3596                                                        if(m_Unit->GetUInt32Value(UNIT_FIELD_POWER1) < sp->spell->manaCost)
3597                                                                continue;
3598                                                        break;
3599
3600                                                case POWER_TYPE_FOCUS:
3601                                                        if(m_Unit->GetUInt32Value(UNIT_FIELD_POWER3) < sp->spell->manaCost)
3602                                                                continue;
3603                                                        break;
3604                                                }
3605                                                def_spell = sp;
3606                                                //we got a selected spell, we can exit loop now
3607                                                break;
3608                                        }
3609                                        else //we failed casting it due to given chance, we activate false cooldown on it to not spam searching this list
3610                                        {
3611//                                              sp->cooldowntime = nowtime + sp->cooldown / ( sp->procChance + 1 );
3612                                                cool_time2 = 2000;
3613                                                sp->cooldowntime = nowtime + cool_time2; 
3614                                                if( !cool_time || cool_time2 < cool_time )
3615                                                        cool_time = cool_time2;
3616                                        }
3617                                }
3618                        }
3619                }
3620        }
3621
3622        if(def_spell)
3623        {
3624                // set cooldown
3625                if(def_spell->procCount)
3626                        def_spell->procCounter++;
3627
3628                if(def_spell->cooldown)
3629                        def_spell->cooldowntime = nowtime + def_spell->cooldown;
3630
3631                waiting_for_cooldown = false;
3632                return def_spell;
3633        }
3634
3635        // save some loops if waiting for cooldownz
3636        if(cool_time)
3637        {
3638                cool_time2 = cool_time / 1000;
3639                if(cool_time2)
3640                        next_spell_time = (uint32)UNIXTIME + cool_time2;
3641        }
3642        else
3643        {
3644                next_spell_time = (uint32)UNIXTIME + MOB_SPELLCAST_REFRESH_COOLDOWN_INTERVAL;
3645                waiting_for_cooldown = false;
3646        }
3647
3648#ifdef _AI_DEBUG
3649        sLog.outString("AI DEBUG: Returning no spell for unit %u", m_Unit->GetEntry());
3650#endif
3651        return 0;
3652}
3653
3654void AIInterface::addSpellToList(AI_Spell *sp)
3655{
3656        if(!sp || !sp->spell)
3657                return;
3658
3659        AI_Spell * sp2 = new AI_Spell;
3660        memcpy(sp2, sp, sizeof(AI_Spell));
3661        m_spells.push_back(sp2);
3662}
3663
3664uint32 AIInterface::getThreatByGUID(uint64 guid)
3665{
3666
3667        if(  m_Unit->GetMapMgr() == NULL )
3668                return 0; 
3669
3670        Unit *obj = m_Unit->GetMapMgr()->GetUnit(guid);
3671        if(obj)
3672                return getThreatByPtr(obj);
3673
3674        return 0;
3675}
3676
3677uint32 AIInterface::getThreatByPtr(Unit* obj)
3678{
3679        if( !obj  || m_Unit->GetMapMgr() == NULL)
3680                return 0;
3681        TargetMap::iterator it = m_aiTargets.find(obj->GetGUID());
3682        if(it != m_aiTargets.end())
3683        {
3684                Unit *tempUnit = m_Unit->GetMapMgr()->GetUnit(it->first);
3685                if (tempUnit)
3686                        return it->second + tempUnit->GetThreatModifyer();
3687                else
3688                        return it->second;
3689
3690        }
3691        return 0;
3692}
3693
3694/*
3695#if defined(WIN32) && defined(HACKY_CRASH_FIXES)
3696__declspec(noinline) bool ___CheckTarget(Unit * ptr, Unit * him)
3697{
3698        __try
3699        {
3700                if( him->GetInstanceID() != ptr->GetInstanceID() || !him->isAlive() || !isAttackable( ptr, him ) )
3701                {
3702                        return false;
3703                }
3704        }
3705        __except(EXCEPTION_EXECUTE_HANDLER)
3706        {
3707                return false;
3708        }
3709        return true;
3710}
3711#endif
3712*/
3713
3714//should return a valid target
3715Unit *AIInterface::GetMostHated()
3716{
3717        if( m_Unit->GetMapMgr() == NULL )
3718                return NULL; 
3719
3720        Unit *ResultUnit= NULL;
3721
3722        //override mosthated with taunted target. Basic combat checks are made for it.
3723        //What happens if we can't see tauntedby unit ?
3724        ResultUnit = getTauntedBy();
3725        if( ResultUnit != NULL )
3726                return ResultUnit;
3727
3728        pair<Unit*, int32> currentTarget;
3729        currentTarget.first = 0;
3730        currentTarget.second = -1;
3731
3732        LockAITargets(true);
3733
3734        TargetMap::iterator it2 = m_aiTargets.begin();
3735        TargetMap::iterator itr;
3736        for(; it2 != m_aiTargets.end();)
3737        {
3738                itr = it2;
3739                ++it2;
3740
3741                /* check the target is valid */
3742/*
3743#if defined(WIN32) && defined(HACKY_CRASH_FIXES)
3744                if(!___CheckTarget( m_Unit, itr->first ) )
3745                {
3746                        if( m_nextTarget == itr->first )
3747                                m_nextTarget = NULL;
3748
3749                        m_aiTargets.erase(itr);
3750                        continue;
3751                }
3752#else
3753                if(itr->first->event_GetCurrentInstanceId() != m_Unit->event_GetCurrentInstanceId() || !itr->first->isAlive() || !isAttackable(m_Unit, itr->first))
3754                {
3755                        m_aiTargets.erase(itr);
3756                        continue;
3757                }
3758#endif
3759*/
3760                // this is a much slower version then the previous one but it causes a lot of crashes and that is above speed right now.
3761                Unit *ai_t = m_Unit->GetMapMgr()->GetUnit( itr->first );
3762
3763                if( !ai_t || ai_t->GetInstanceID() != m_Unit->GetInstanceID() || !ai_t->isAlive() || !isAttackable( m_Unit, ai_t ) )
3764                {
3765                        if( GetNextTarget() == ai_t )
3766                                SetNextTarget( (Unit*)NULL );
3767
3768                        m_aiTargets.erase(itr);
3769                        continue;
3770                }
3771
3772                if((itr->second + ai_t->GetThreatModifyer()) > currentTarget.second)
3773                {
3774                        /* new target */
3775                        currentTarget.first = ai_t;
3776                        currentTarget.second = itr->second + ai_t->GetThreatModifyer();
3777                        m_currentHighestThreat = currentTarget.second;
3778                }
3779
3780                /* there are no more checks needed here... the needed checks are done by CheckTarget() */
3781        }
3782
3783        LockAITargets(false);
3784
3785        return currentTarget.first;
3786}
3787Unit *AIInterface::GetSecondHated()
3788{
3789        if(  m_Unit->GetMapMgr() == NULL )
3790                return NULL; 
3791
3792        Unit *ResultUnit=GetMostHated();
3793
3794        pair<Unit*, int32> currentTarget;
3795        currentTarget.first = 0;
3796        currentTarget.second = -1;
3797
3798        LockAITargets(true);
3799
3800        TargetMap::iterator it2 = m_aiTargets.begin();
3801        TargetMap::iterator itr;
3802        for(; it2 != m_aiTargets.end();)
3803        {
3804                itr = it2;
3805                ++it2;
3806
3807                /* check the target is valid */
3808                Unit *ai_t = m_Unit->GetMapMgr()->GetUnit( itr->first );
3809                if(!ai_t || ai_t->GetInstanceID() != m_Unit->GetInstanceID() || !ai_t->isAlive() || !isAttackable(m_Unit, ai_t))
3810                {
3811                        m_aiTargets.erase(itr);
3812                        continue;
3813                }
3814
3815                if((itr->second + ai_t->GetThreatModifyer()) > currentTarget.second &&
3816                        ai_t != ResultUnit)
3817                {
3818                        /* new target */
3819                        currentTarget.first = ai_t;
3820                        currentTarget.second = itr->second + ai_t->GetThreatModifyer();
3821                        m_currentHighestThreat = currentTarget.second;
3822                }
3823        }
3824
3825        LockAITargets(false);
3826
3827        return currentTarget.first;
3828}
3829bool AIInterface::modThreatByGUID(uint64 guid, int32 mod)
3830{
3831        if (!m_aiTargets.size())
3832                return false;
3833
3834        if(  m_Unit->GetMapMgr() == NULL )
3835                return false; 
3836
3837        Unit *obj = m_Unit->GetMapMgr()->GetUnit(guid);
3838        if(obj)
3839                return modThreatByPtr(obj, mod);
3840
3841        return false;
3842}
3843
3844bool AIInterface::modThreatByPtr(Unit* obj, int32 mod)
3845{
3846        if(!obj)
3847                return false;
3848
3849        LockAITargets(true);
3850
3851        int32 tempthreat;
3852        TargetMap::iterator it = m_aiTargets.find(obj->GetGUID());
3853        if(it != m_aiTargets.end())
3854        {
3855                it->second += mod;
3856                if (it->second < 1)
3857                        it->second = 1;
3858
3859                tempthreat = it->second + obj->GetThreatModifyer();
3860                if (tempthreat < 1)
3861                        tempthreat = 1;
3862                if(tempthreat > m_currentHighestThreat)
3863                {
3864                        // new target!
3865                        if(!isTaunted)
3866                        {
3867                                m_currentHighestThreat = tempthreat;
3868                                SetNextTarget(obj);
3869                        }
3870                }
3871        }
3872        else
3873        {
3874                m_aiTargets.insert( make_pair( obj->GetGUID(), mod ) );
3875
3876                tempthreat = mod + obj->GetThreatModifyer();
3877                if (tempthreat < 1)
3878                        tempthreat = 1;
3879                if(tempthreat > m_currentHighestThreat)
3880                {
3881                        if(!isTaunted)
3882                        {
3883                                m_currentHighestThreat = tempthreat;
3884                                SetNextTarget(obj);
3885                        }
3886                }
3887        }
3888
3889        LockAITargets(false);
3890
3891        if(obj == GetNextTarget())
3892        {
3893                // check for a possible decrease in threat.
3894                if(mod < 0)
3895                {
3896                        SetNextTarget(GetMostHated());
3897                        //if there is no more new targets then we can walk back home ?
3898                        if(!GetNextTarget())
3899                                HandleEvent(EVENT_LEAVECOMBAT, m_Unit, 0);
3900                }
3901        }
3902        return true;
3903}
3904
3905void AIInterface::RemoveThreatByGUID(uint64 guid)
3906{
3907        if (!m_aiTargets.size())
3908                return;
3909
3910        if(  m_Unit->GetMapMgr() == NULL )
3911                return; 
3912
3913        Unit *obj = m_Unit->GetMapMgr()->GetUnit(guid);
3914        if(obj)
3915                RemoveThreatByPtr(obj);
3916}
3917
3918void AIInterface::RemoveThreatByPtr(Unit* obj)
3919{
3920        if(!obj)
3921                return;
3922
3923        LockAITargets(true);
3924
3925        TargetMap::iterator it = m_aiTargets.find(obj->GetGUID());
3926        if(it != m_aiTargets.end())
3927        {
3928                m_aiTargets.erase(it);
3929                //check if we are in combat and need a new target
3930                if(obj==GetNextTarget())
3931                {
3932                        SetNextTarget(GetMostHated());
3933                        //if there is no more new targets then we can walk back home ?
3934                        if(!GetNextTarget())
3935                                HandleEvent(EVENT_LEAVECOMBAT, m_Unit, 0);
3936                }
3937        }
3938
3939        LockAITargets(false);
3940}
3941
3942void AIInterface::addAssistTargets(Unit* Friend)
3943{
3944        // stop adding stuff that gives errors on linux!
3945        m_assistTargets.insert(Friend);
3946}
3947
3948void AIInterface::WipeHateList()
3949{
3950        for(TargetMap::iterator itr = m_aiTargets.begin(); itr != m_aiTargets.end(); ++itr)
3951                itr->second = 0;
3952        m_currentHighestThreat = 0;
3953}
3954void AIInterface::ClearHateList() //without leaving combat
3955{
3956        for(TargetMap::iterator itr = m_aiTargets.begin(); itr != m_aiTargets.end(); ++itr)
3957                itr->second = 1;
3958        m_currentHighestThreat = 1;
3959}
3960
3961void AIInterface::WipeTargetList()
3962{
3963        SetNextTarget( (Unit*)NULL );
3964
3965        m_nextSpell = NULL;
3966        m_currentHighestThreat = 0;
3967        LockAITargets( true );
3968        m_aiTargets.clear();
3969        LockAITargets( false );
3970        m_Unit->CombatStatus.Vanished();
3971}
3972
3973bool AIInterface::taunt(Unit* caster, bool apply)
3974{
3975        if(apply)
3976        {
3977                //wowwiki says that we cannot override this spell
3978                if(GetIsTaunted())
3979                        return false;
3980
3981                if(!caster)
3982                {
3983                        isTaunted = false;
3984                        return false;
3985                }
3986
3987                //check if we can attack taunter. Maybe it's a hack or a bug if we fail this test
3988                if(isHostile(m_Unit, caster))
3989                {
3990                        //check if we have to add him to our agro list
3991                        //GetMostHated(); //update our most hated list/ Note that at this point we do not have a taunter yet. If we would have then this funtion will not give real mosthated
3992                        int32 oldthreat = getThreatByPtr(caster);
3993                        //make sure we rush the target anyway. Since we are not taunted yet, this will also set our target
3994                        modThreatByPtr(caster,abs(m_currentHighestThreat-oldthreat)+1); //we need to be the most hated at this moment
3995//                      SetNextTarget(caster);
3996                }
3997                isTaunted = true;
3998                tauntedBy = caster;
3999        }
4000        else
4001        {
4002                isTaunted = false;
4003                tauntedBy = NULL;
4004                //taunt is over, we should get a new target based on most hated list
4005                SetNextTarget(GetMostHated());
4006        }
4007
4008        return true;
4009}
4010
4011Unit* AIInterface::getTauntedBy()
4012{
4013        if(GetIsTaunted())
4014        {
4015                return tauntedBy;
4016        }
4017        else
4018        {
4019                return NULL;
4020        }
4021}
4022
4023bool AIInterface::GetIsTaunted()
4024{
4025        if(isTaunted)
4026        {
4027                if(!tauntedBy || !tauntedBy->isAlive())
4028                {
4029                        isTaunted = false;
4030                        tauntedBy = NULL;
4031                }
4032        }
4033        return isTaunted;
4034}
4035
4036void AIInterface::SetSoulLinkedWith(Unit* target)
4037{
4038        if (!target)
4039                return;
4040        soullinkedWith = target;
4041        isSoulLinked = true;
4042}
4043
4044Unit* AIInterface::getSoullinkedWith()
4045{
4046        if(GetIsTaunted())
4047        {
4048                return soullinkedWith;
4049        }
4050        else
4051        {
4052                return NULL;
4053        }
4054}
4055
4056bool AIInterface::GetIsSoulLinked()
4057{
4058        if(isSoulLinked)
4059        {
4060                if(!soullinkedWith || !soullinkedWith->isAlive())
4061                {
4062                        isSoulLinked = false;
4063                        soullinkedWith = NULL;
4064                }
4065        }
4066        return isSoulLinked;
4067}
4068
4069void AIInterface::CheckTarget(Unit* target)
4070{
4071        if( target == NULL )
4072                return;
4073
4074        if( target == UnitToFollow )              // fix for crash here
4075        {
4076                UnitToFollow = NULL;
4077                m_lastFollowX = m_lastFollowY = 0;
4078                FollowDistance = 0;
4079        }
4080
4081        if( target == UnitToFollow_backup )
4082        {
4083                UnitToFollow_backup = NULL;
4084        }
4085
4086        AssistTargetSet::iterator  itr = m_assistTargets.find(target);
4087        if(itr != m_assistTargets.end())
4088                m_assistTargets.erase(itr);
4089
4090
4091        LockAITargets(true);
4092
4093        TargetMap::iterator it2 = m_aiTargets.find( target->GetGUID() );
4094        if( it2 != m_aiTargets.end() || target == GetNextTarget() )
4095        {
4096                target->CombatStatus.RemoveAttacker( m_Unit, m_Unit->GetGUID() );
4097                m_Unit->CombatStatus.RemoveAttackTarget( target );
4098
4099                if(it2 != m_aiTargets.end())
4100                {
4101                        m_aiTargets.erase(it2);
4102                }
4103
4104                if (target == GetNextTarget())   // no need to cast on these.. mem addresses are still the same
4105                {
4106                        SetNextTarget( (Unit*)NULL );
4107                        m_nextSpell = NULL;
4108
4109                        // find the one with the next highest threat
4110                        GetMostHated();
4111                }
4112        }
4113
4114        LockAITargets(false);
4115
4116        if( target->GetTypeId() == TYPEID_UNIT )
4117        {
4118                it2 = target->GetAIInterface()->m_aiTargets.find( m_Unit->GetGUID() );
4119                if( it2 != target->GetAIInterface()->m_aiTargets.end() )
4120                {
4121                        target->GetAIInterface()->LockAITargets(true);
4122                        target->GetAIInterface()->m_aiTargets.erase( it2 );
4123                        target->GetAIInterface()->LockAITargets(false);
4124                }
4125       
4126                if( target->GetAIInterface()->GetNextTarget() == m_Unit )
4127                {
4128                        target->GetAIInterface()->SetNextTarget( (Unit*)NULL );
4129                        target->GetAIInterface()->m_nextSpell = NULL;
4130                        target->GetAIInterface()->GetMostHated();
4131                }
4132
4133                if( target->GetAIInterface()->UnitToFollow == m_Unit )
4134                        target->GetAIInterface()->UnitToFollow = NULL;
4135        }
4136
4137        if(target == UnitToFear)
4138                UnitToFear = NULL;
4139
4140        if(tauntedBy == target)
4141                tauntedBy = NULL;
4142}
4143
4144uint32 AIInterface::_CalcThreat(uint32 damage, SpellEntry * sp, Unit* Attacker)
4145{
4146        if(!Attacker)
4147                return 0; // No attacker means no threat and we prevent crashes this way
4148
4149        if(m_Unit->m_faction != NULL && Attacker->m_faction != NULL)
4150                if (isSameFaction(m_Unit,Attacker))
4151                        return 0;
4152       
4153        int32 mod = 0;
4154        if( sp != NULL && sp->ThreatForSpell != 0 )
4155        {
4156                mod = sp->ThreatForSpell;
4157        }
4158        if( sp != NULL && sp->ThreatForSpellCoef != 0.0f )
4159                mod += int32(damage * sp->ThreatForSpellCoef);
4160        else
4161                mod += damage;
4162
4163        if( sp != NULL && sp->SpellGroupType && Attacker)
4164        {
4165                SM_FIValue(Attacker->SM_FThreat,&mod,sp->SpellGroupType);
4166                SM_PIValue(Attacker->SM_PThreat,&mod,sp->SpellGroupType);
4167        }
4168
4169        if (Attacker->getClass() == ROGUE)
4170                mod = int32(mod * 0.71); // Rogues generate 0.71x threat per damage.
4171
4172        // modify threat by Buffs
4173        if (sp != NULL)
4174                mod += (mod * Attacker->GetGeneratedThreatModifyer(sp->School) / 100);
4175        else
4176                mod += (mod * Attacker->GetGeneratedThreatModifyer(0) / 100);
4177
4178        if (mod < 1)
4179                mod = 1;
4180
4181        return mod;
4182}
4183
4184void AIInterface::WipeReferences()
4185{
4186        m_nextSpell = 0;
4187        m_currentHighestThreat = 0;
4188        LockAITargets(true);
4189        m_aiTargets.clear();
4190        LockAITargets(false);
4191        SetNextTarget( (Unit*)NULL );
4192        UnitToFear = 0;
4193        UnitToFollow = 0;
4194        tauntedBy = 0;
4195        m_Unit->AquireInrangeLock(); //make sure to release lock before exit function !
4196        //Clear targettable
4197        for(set<Object*>::iterator itr = m_Unit->GetInRangeSetBegin(); itr != m_Unit->GetInRangeSetEnd(); ++itr)
4198                if( (*itr) && (*itr)->GetTypeId() == TYPEID_UNIT && static_cast<Unit*>(*itr)->GetAIInterface())
4199                        static_cast<Unit*>(*itr)->GetAIInterface()->RemoveThreatByPtr( m_Unit );
4200        m_Unit->ReleaseInrangeLock();
4201
4202}
4203
4204void AIInterface::ResetProcCounts()
4205{
4206        for(list<AI_Spell*>::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
4207                if((*itr)->procCount)
4208                        (*itr)->procCounter=0;
4209}
4210
4211//we only cast once a spell and we will set his health and resistances. Note that this can be made with db too !
4212void AIInterface::Event_Summon_EE_totem( uint32 summon_duration )
4213{
4214        //some say it should inherit the level of the caster
4215        Unit *caster = m_Unit->GetMapMgr()->GetUnit( m_Unit->GetUInt64Value( UNIT_FIELD_CREATEDBY ) );
4216        uint32 new_level = 0;
4217        if( caster )
4218                new_level = caster->getLevel( );
4219        //timer should not reach this value thus not cast this spell again
4220        m_totemspelltimer = 0xEFFFFFFF;
4221        //creatures do not support PETs and the spell uses that effect so we force a summon guardian thing
4222        Creature *ourslave = m_Unit->create_guardian( 15352, summon_duration, float(-M_PI * 2), new_level );
4223    if( ourslave == NULL )
4224                return;
4225
4226        m_Unit->AddGuardianRef( ourslave );
4227        ourslave->ResistanceModPct[ NATURE_DAMAGE ] = 100; //we should be immune to nature dmg. This can be also set in db
4228        ourslave->m_noRespawn = true;
4229        ourslave->SetOwner( caster );
4230        ourslave->SetUInt32Value( UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED | UNIT_FLAG_SELF_RES );
4231
4232    // we want the elemental to have the same pvp flag as the shaman who popped the totem
4233    if( caster->IsPvPFlagged() )
4234        ourslave->SetPvPFlag();
4235    else
4236        ourslave->RemovePvPFlag();
4237
4238    if( caster->IsFFAPvPFlagged() )
4239        ourslave->SetFFAPvPFlag();
4240    else
4241        ourslave->RemoveFFAPvPFlag();
4242}
4243
4244//we only cast once a spell and we will set his health and resistances. Note that this can be made with db too !
4245void AIInterface::Event_Summon_FE_totem( uint32 summon_duration )
4246{
4247        //some say it should inherit the level of the caster
4248        Unit *caster = m_Unit->GetMapMgr()->GetUnit( m_Unit->GetUInt64Value( UNIT_FIELD_CREATEDBY ) );
4249        uint32 new_level = 0;
4250        if( caster != NULL )
4251                new_level = caster->getLevel( );
4252        //timer should not reach this value thus not cast this spell again
4253        m_totemspelltimer = 0xEFFFFFFF;
4254        //creatures do not support PETs and the spell uses that effect so we force a summon guardian thing
4255        Creature *ourslave = m_Unit->create_guardian( 15438, summon_duration, float(-M_PI * 2), new_level );
4256    if( ourslave == NULL )
4257                return;
4258
4259        m_Unit->AddGuardianRef( ourslave );
4260        ourslave->ResistanceModPct[ FIRE_DAMAGE ] = 100; //we should be immune to nature dmg. This can be also set in db
4261        ourslave->m_noRespawn = true;
4262        ourslave->SetOwner( caster );
4263        ourslave->SetUInt32Value( UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED | UNIT_FLAG_SELF_RES );
4264
4265    // we want the elemental to have the same pvp flag as the shaman who popped the totem
4266    if( caster->IsPvPFlagged() )
4267        ourslave->SetPvPFlag();
4268    else
4269        ourslave->RemovePvPFlag();
4270
4271    if( caster->IsFFAPvPFlagged() )
4272        ourslave->SetFFAPvPFlag();
4273    else
4274        ourslave->RemoveFFAPvPFlag();
4275}
4276/*
4277void AIInterface::CancelSpellCast()
4278{
4279        //hmm unit spell casting is not the same as Ai spell casting ? Have to test this
4280        if(m_Unit->IsCasting())
4281                m_Unit->m_currentSpell->safe_cancel();
4282        //i can see this crashing already :P.
4283        m_AIState = STATE_IDLE;
4284}
4285*/
4286
4287void AIInterface::EventChangeFaction( Unit *ForceAttackersToHateThisInstead )
4288{
4289        m_nextSpell = 0;
4290        m_currentHighestThreat = 0;
4291        //we need a new hatred list
4292        LockAITargets(true);
4293        m_aiTargets.clear();
4294        LockAITargets(false);
4295        //we need a new assist list
4296        m_assistTargets.clear();
4297        //Clear targettable
4298        if( ForceAttackersToHateThisInstead == NULL )
4299        {
4300                m_Unit->AquireInrangeLock(); //make sure to release lock before exit function !
4301                for(set<Object*>::iterator itr = m_Unit->GetInRangeSetBegin(); itr != m_Unit->GetInRangeSetEnd(); ++itr)
4302                        if( (*itr) && (*itr)->GetTypeId() == TYPEID_UNIT && static_cast<Unit*>(*itr)->GetAIInterface() )
4303                                static_cast<Unit*>(*itr)->GetAIInterface()->RemoveThreatByPtr( m_Unit );
4304                m_Unit->ReleaseInrangeLock();
4305                SetNextTarget( (Unit*)NULL );
4306        }
4307        else
4308        {
4309                m_Unit->AquireInrangeLock(); //make sure to release lock before exit function !
4310                for(set<Object*>::iterator itr = m_Unit->GetInRangeSetBegin(); itr != m_Unit->GetInRangeSetEnd(); ++itr)
4311                        if( (*itr) && (*itr)->GetTypeId() == TYPEID_UNIT && static_cast<Unit*>(*itr)->GetAIInterface() 
4312                                && static_cast<Unit*>(*itr)->GetAIInterface()->getThreatByPtr( m_Unit ) )//this guy will join me in fight since I'm telling him "sorry i was controlled"
4313                        {
4314                                static_cast<Unit*>(*itr)->GetAIInterface()->modThreatByPtr( ForceAttackersToHateThisInstead, 10 ); //just aping to be bale to hate him in case we got nothing else
4315                                static_cast<Unit*>(*itr)->GetAIInterface()->RemoveThreatByPtr( m_Unit );
4316                        }
4317                m_Unit->ReleaseInrangeLock();
4318                modThreatByPtr( ForceAttackersToHateThisInstead, 1 );
4319                SetNextTarget( ForceAttackersToHateThisInstead );
4320        }
4321}
4322
4323void AIInterface::WipeCurrentTarget()
4324{
4325        if( GetNextTarget() )
4326        {
4327                LockAITargets( true );
4328                TargetMap::iterator itr = m_aiTargets.find( GetNextTarget()->GetGUID() );
4329                if( itr != m_aiTargets.end() )
4330                        m_aiTargets.erase( itr );
4331                LockAITargets( false );
4332        }
4333
4334        SetNextTarget( (Unit*)NULL );
4335
4336        if( GetNextTarget() == UnitToFollow )
4337                UnitToFollow = NULL;
4338
4339        if( GetNextTarget() == UnitToFollow_backup )
4340                UnitToFollow_backup = NULL;
4341}
4342
4343#ifdef HACKY_CRASH_FIXES
4344
4345bool AIInterface::CheckCurrentTarget()
4346{
4347        //in case target was removed from map since our last check on him
4348        if( GetNextTarget() == NULL )
4349        {
4350                WipeCurrentTarget();
4351                return false;
4352        }
4353       
4354        bool cansee = false;
4355        if( GetNextTarget()->GetInstanceID() == m_Unit->GetInstanceID())
4356        {
4357                if( m_Unit->GetTypeId() == TYPEID_UNIT )
4358                        cansee = static_cast< Creature* >( m_Unit )->CanSee( GetNextTarget() );
4359                else
4360                        cansee = static_cast< Player* >( m_Unit )->CanSee( GetNextTarget() );
4361        }
4362        else 
4363        {
4364                WipeCurrentTarget();
4365        }
4366
4367        return cansee;
4368}
4369
4370bool AIInterface::TargetUpdateCheck(Unit * ptr)
4371{
4372        __try
4373        {
4374                if( ptr->event_GetCurrentInstanceId() != m_Unit->event_GetCurrentInstanceId() ||
4375                        !ptr->isAlive() || m_Unit->GetDistanceSq(ptr) >= 6400.0f )
4376                {
4377                        return false;
4378                }
4379        }
4380        __except(EXCEPTION_EXECUTE_HANDLER)
4381        {
4382                return false;
4383        }
4384
4385        return true;
4386}
4387
4388#endif
4389Unit* AIInterface::GetNextTarget()
4390{
4391        if (m_nextTarget && m_Unit && m_Unit->GetMapMgr()) return m_Unit->GetMapMgr()->GetUnit(m_nextTarget);
4392        return NULL;
4393}
4394
4395void AIInterface::SetNextTarget (Unit *nextTarget) {
4396        if (nextTarget)
4397                SetNextTarget(nextTarget->GetGUID());
4398        else
4399                SetNextTarget((uint64)NULL);
4400}
4401
4402void AIInterface::SetNextTarget (uint64 nextTarget) 
4403{
4404        m_nextTarget = nextTarget; 
4405        m_Unit->SetUInt64Value(UNIT_FIELD_TARGET, m_nextTarget);
4406        if(nextTarget)
4407        {
4408#ifdef ENABLE_GRACEFULL_HIT
4409                have_graceful_hit=false;
4410#endif
4411        }
4412}
Note: See TracBrowser for help on using the browser.