root/trunk/src/game/TargetedMovementGenerator.cpp @ 123

Revision 118, 7.5 kB (checked in by yumileroy, 17 years ago)

[svn] Make mobs scatter around in melee attack. Patch provided by smellbee.
Fix Join Instance Can Enter while Encounter is in Progress. Patch provided by mknjc.

Original author: megamage
Date: 2008-10-27 08:00:33-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "ByteBuffer.h"
22#include "TargetedMovementGenerator.h"
23#include "Errors.h"
24#include "Creature.h"
25#include "MapManager.h"
26#include "DestinationHolderImp.h"
27#include "World.h"
28
29#define SMALL_ALPHA 0.05f
30
31#include <cmath>
32/*
33struct StackCleaner
34{
35    Creature &i_creature;
36    StackCleaner(Creature &creature) : i_creature(creature) {}
37    void Done(void) { i_creature.StopMoving(); }
38    ~StackCleaner()
39    {
40        i_creature->Clear();
41    }
42};
43*/
44
45template<class T>
46void
47TargetedMovementGenerator<T>::_setTargetLocation(T &owner)
48{
49    if( !i_target.isValid() || !&owner )
50        return;
51
52    if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) )
53        return;
54
55    // prevent redundant micro-movement for pets, other followers.
56    if(i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset))
57        return;
58
59    float x, y, z;
60    if(!i_offset)
61    {
62        // to nearest random contact position
63        i_target->GetRandomContactPoint( &owner, x, y, z,0.5f,4.5f );
64    }
65    else
66    {
67        // to at i_offset distance from target and i_angle from target facing
68        i_target->GetClosePoint(x,y,z,owner.GetObjectSize(),i_offset,i_angle);
69    }
70
71    /*
72        We MUST not check the distance difference and avoid setting the new location for smaller distances.
73        By that we risk having far too many GetContactPoint() calls freezing the whole system.
74        In TargetedMovementGenerator<T>::Update() we check the distance to the target and at
75        some range we calculate a new position. The calculation takes some processor cycles due to vmaps.
76        If the distance to the target it too large to ignore,
77        but the distance to the new contact point is short enough to be ignored,
78        we will calculate a new contact point each update loop, but will never move to it.
79        The system will freeze.
80        ralf
81
82        //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
83        float  bothObjectSize = i_target->GetObjectSize() + owner.GetObjectSize() + CONTACT_DISTANCE;
84        if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize )
85            return;
86    */
87    Traveller<T> traveller(owner);
88    i_destinationHolder.SetDestination(traveller, x, y, z);
89    owner.addUnitState(UNIT_STAT_CHASE);
90    if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
91        owner.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
92}
93
94template<class T>
95void
96TargetedMovementGenerator<T>::Initialize(T &owner)
97{
98    if(!&owner)
99        return;
100    owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
101
102    if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
103        owner.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
104   
105    _setTargetLocation(owner);
106}
107
108template<class T>
109void
110TargetedMovementGenerator<T>::Finalize(T &owner)
111{
112    owner.clearUnitState(UNIT_STAT_CHASE);
113}
114
115template<class T>
116void
117TargetedMovementGenerator<T>::Reset(T &owner)
118{
119    Initialize(owner);
120}
121
122template<class T>
123bool
124TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
125{
126    if(!i_target.isValid())
127        return false;
128
129    if( !&owner || !owner.isAlive())
130        return true;
131
132    if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED) )
133        return true;
134
135    // prevent movement while casting spells with cast time or channel time
136    if ( owner.IsNonMeleeSpellCasted(false, false,  true))
137    {
138        if (!owner.IsStopped())
139            owner.StopMoving();
140        return true;
141    }
142
143    // prevent crash after creature killed pet
144    if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget())
145        return true;
146
147    Traveller<T> traveller(owner);
148
149    if( !i_destinationHolder.HasDestination() )
150        _setTargetLocation(owner);
151    if( owner.IsStopped() && !i_destinationHolder.HasArrived() )
152    {
153        owner.addUnitState(UNIT_STAT_CHASE);
154        if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
155            owner.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
156
157        i_destinationHolder.StartTravel(traveller);
158        return true;
159    }
160
161    if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
162    {
163        // put targeted movement generators on a higher priority
164        if (owner.GetObjectSize())
165            i_destinationHolder.ResetUpdate(50);
166
167        float dist = i_target->GetObjectSize() + owner.GetObjectSize() + sWorld.getRate(RATE_TARGET_POS_RECALCULATION_RANGE);
168
169        //More distance let have better performance, less distance let have more sensitive reaction at target move.
170
171        // try to counter precision differences
172        if( i_destinationHolder.GetDistance2dFromDestSq(*i_target.getTarget()) >= dist * dist)
173        {
174            owner.SetInFront(i_target.getTarget());         // Set new Angle For Map::
175            _setTargetLocation(owner);                      //Calculate New Dest and Send data To Player
176        }
177        // Update the Angle of the target only for Map::, no need to send packet for player
178        else if ( !i_angle && !owner.HasInArc( 0.01f, i_target.getTarget() ) )
179            owner.SetInFront(i_target.getTarget());
180
181        if(( owner.IsStopped() && !i_destinationHolder.HasArrived() ) || i_recalculateTravel )
182        {
183            i_recalculateTravel = false;
184            //Angle update will take place into owner.StopMoving()
185            owner.SetInFront(i_target.getTarget());
186
187            owner.StopMoving();
188            if(owner.canReachWithAttack(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW))
189                owner.Attack(i_target.getTarget(),true);
190        }
191    }
192    return true;
193}
194
195template<class T>
196Unit*
197TargetedMovementGenerator<T>::GetTarget() const
198{
199    return i_target.getTarget();
200}
201
202template void TargetedMovementGenerator<Player>::_setTargetLocation(Player &);
203template void TargetedMovementGenerator<Creature>::_setTargetLocation(Creature &);
204template void TargetedMovementGenerator<Player>::Initialize(Player &);
205template void TargetedMovementGenerator<Creature>::Initialize(Creature &);
206template void TargetedMovementGenerator<Player>::Finalize(Player &);
207template void TargetedMovementGenerator<Creature>::Finalize(Creature &);
208template void TargetedMovementGenerator<Player>::Reset(Player &);
209template void TargetedMovementGenerator<Creature>::Reset(Creature &);
210template bool TargetedMovementGenerator<Player>::Update(Player &, const uint32 &);
211template bool TargetedMovementGenerator<Creature>::Update(Creature &, const uint32 &);
212template Unit* TargetedMovementGenerator<Player>::GetTarget() const;
213template Unit* TargetedMovementGenerator<Creature>::GetTarget() const;
Note: See TracBrowser for help on using the browser.