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

Revision 102, 11.8 kB (checked in by yumileroy, 17 years ago)

[svn] Fixed copyright notices to comply with GPL.

Original author: w12x
Date: 2008-10-23 03:29:52-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 "Creature.h"
22#include "MapManager.h"
23#include "FleeingMovementGenerator.h"
24#include "DestinationHolderImp.h"
25#include "ObjectAccessor.h"
26
27#define MIN_QUIET_DISTANCE 28.0f
28#define MAX_QUIET_DISTANCE 43.0f
29
30template<class T>
31void
32FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
33{
34    if( !&owner )
35        return;
36
37    if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
38        return;
39
40    if(!_setMoveData(owner))
41        return;
42
43    float x, y, z;
44    if(!_getPoint(owner, x, y, z))
45        return;
46
47    owner.addUnitState(UNIT_STAT_FLEEING);
48    Traveller<T> traveller(owner);
49    i_destinationHolder.SetDestination(traveller, x, y, z);
50}
51
52template<class T>
53bool
54FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
55{
56    if(!&owner)
57        return false;
58
59    x = owner.GetPositionX();
60    y = owner.GetPositionY();
61    z = owner.GetPositionZ();
62
63    float temp_x, temp_y, angle;
64    const Map * _map = MapManager::Instance().GetBaseMap(owner.GetMapId());
65    //primitive path-finding
66    for(uint8 i = 0; i < 18; i++)
67    {
68        if(i_only_forward && i > 2)
69            break;
70
71        float distance = 5.0f;
72
73        switch(i)
74        {
75            case 0:
76                angle = i_cur_angle;
77                break;
78            case 1:
79                angle = i_cur_angle;
80                distance /= 2;
81                break;
82            case 2:
83                angle = i_cur_angle;
84                distance /= 4;
85                break;
86            case 3:
87                angle = i_cur_angle + M_PI/4.0f;
88                break;
89            case 4:
90                angle = i_cur_angle - M_PI/4.0f;
91                break;
92            case 5:
93                angle = i_cur_angle + M_PI/4.0f;
94                distance /= 2;
95                break;
96            case 6:
97                angle = i_cur_angle - M_PI/4.0f;
98                distance /= 2;
99                break;
100            case 7:
101                angle = i_cur_angle + M_PI/2.0f;
102                break;
103            case 8:
104                angle = i_cur_angle - M_PI/2.0f;
105                break;
106            case 9:
107                angle = i_cur_angle + M_PI/2.0f;
108                distance /= 2;
109                break;
110            case 10:
111                angle = i_cur_angle - M_PI/2.0f;
112                distance /= 2;
113                break;
114            case 11:
115                angle = i_cur_angle + M_PI/4.0f;
116                distance /= 4;
117                break;
118            case 12:
119                angle = i_cur_angle - M_PI/4.0f;
120                distance /= 4;
121                break;
122            case 13:
123                angle = i_cur_angle + M_PI/2.0f;
124                distance /= 4;
125                break;
126            case 14:
127                angle = i_cur_angle - M_PI/2.0f;
128                distance /= 4;
129                break;
130            case 15:
131                angle = i_cur_angle + M_PI*3/4.0f;
132                distance /= 2;
133                break;
134            case 16:
135                angle = i_cur_angle - M_PI*3/4.0f;
136                distance /= 2;
137                break;
138            case 17:
139                angle = i_cur_angle + M_PI;
140                distance /= 2;
141                break;
142        }
143        temp_x = x + distance * cos(angle);
144        temp_y = y + distance * sin(angle);
145        Trinity::NormalizeMapCoord(temp_x);
146        Trinity::NormalizeMapCoord(temp_y);
147        if( owner.IsWithinLOS(temp_x,temp_y,z))
148        {
149            bool is_water_now = _map->IsInWater(x,y,z);
150
151            if(is_water_now && _map->IsInWater(temp_x,temp_y,z))
152            {
153                x = temp_x;
154                y = temp_y;
155                return true;
156            }
157            float new_z = _map->GetHeight(temp_x,temp_y,z,true);
158
159            if(new_z <= INVALID_HEIGHT)
160                continue;
161
162            bool is_water_next = _map->IsInWater(temp_x,temp_y,new_z);
163
164            if((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
165                continue;
166
167            if( !(new_z - z) || distance / fabs(new_z - z) > 1.0f)
168            {
169                float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+M_PI/2),temp_y + 1.0f*sin(angle+M_PI/2),z,true);
170                float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-M_PI/2),temp_y + 1.0f*sin(angle-M_PI/2),z,true);
171                if(fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
172                {
173                    x = temp_x;
174                    y = temp_y;
175                    z = new_z;
176                    return true;
177                }
178            }
179        }
180    }
181    i_to_distance_from_caster = 0.0f;
182    i_nextCheckTime.Reset( urand(500,1000) );
183    return false;
184}
185
186template<class T>
187bool
188FleeingMovementGenerator<T>::_setMoveData(T &owner)
189{
190    float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);
191
192    if(i_to_distance_from_caster > 0.0f)
193    {
194        if((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster)   ||
195                                                            // if we reach lower distance
196           (i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) ||
197                                                            // if we can't be close
198           (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster)   ||
199                                                            // if we reach bigger distance
200           (cur_dist_xyz > MAX_QUIET_DISTANCE) ||           // if we are too far
201           (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE) )
202                                                            // if we leave 'quiet zone'
203        {
204            // we are very far or too close, stopping
205            i_to_distance_from_caster = 0.0f;
206            i_nextCheckTime.Reset( urand(500,1000) );
207            return false;
208        }
209        else
210        {
211            // now we are running, continue
212            i_last_distance_from_caster = cur_dist_xyz;
213            return true;
214        }
215    }
216
217    float cur_dist;
218    float angle_to_caster;
219
220    Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
221
222    if(fright)
223    {
224        cur_dist = fright->GetDistance(&owner);
225        if(cur_dist < cur_dist_xyz)
226        {
227            i_caster_x = fright->GetPositionX();
228            i_caster_y = fright->GetPositionY();
229            i_caster_z = fright->GetPositionZ();
230            angle_to_caster = fright->GetAngle(&owner);
231        }
232        else
233        {
234            cur_dist = cur_dist_xyz;
235            angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
236        }
237    }
238    else
239    {
240        cur_dist = cur_dist_xyz;
241        angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
242    }
243
244    // if we too close may use 'path-finding' else just stop
245    i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3;
246
247    //get angle and 'distance from caster' to run
248    float angle;
249
250    if(i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
251    {
252        angle = rand_norm()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * M_PI/3 + rand_norm()*M_PI*2/3;
253        i_to_distance_from_caster = MIN_QUIET_DISTANCE;
254        i_only_forward = true;
255    }
256    else if(cur_dist < MIN_QUIET_DISTANCE)
257    {
258        angle = M_PI/6 + rand_norm()*M_PI*2/3;
259        i_to_distance_from_caster = cur_dist*2/3 + rand_norm()*(MIN_QUIET_DISTANCE - cur_dist*2/3);
260    }
261    else if(cur_dist > MAX_QUIET_DISTANCE)
262    {
263        angle = rand_norm()*M_PI/3 + M_PI*2/3;
264        i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
265    }
266    else
267    {
268        angle = rand_norm()*M_PI;
269        i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
270    }
271
272    int8 sign = rand_norm() > 0.5f ? 1 : -1;
273    i_cur_angle = sign*angle + angle_to_caster;
274
275    // current distance
276    i_last_distance_from_caster = cur_dist;
277
278    return true;
279}
280
281template<class T>
282void
283FleeingMovementGenerator<T>::Initialize(T &owner)
284{
285    if(!&owner)
286        return;
287
288    Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
289    if(!fright)
290        return;
291
292    _Init(owner);
293    owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
294    i_caster_x = fright->GetPositionX();
295    i_caster_y = fright->GetPositionY();
296    i_caster_z = fright->GetPositionZ();
297    i_only_forward = true;
298    i_cur_angle = 0.0f;
299    i_last_distance_from_caster = 0.0f;
300    i_to_distance_from_caster = 0.0f;
301    _setTargetLocation(owner);
302}
303
304template<>
305void
306FleeingMovementGenerator<Creature>::_Init(Creature &owner)
307{
308    if(!&owner)
309        return;
310    owner.SetUInt64Value(UNIT_FIELD_TARGET, 0);
311    is_water_ok = owner.canSwim();
312    is_land_ok  = owner.canWalk();
313}
314
315template<>
316void
317FleeingMovementGenerator<Player>::_Init(Player &)
318{
319    is_water_ok = true;
320    is_land_ok  = true;
321}
322
323template<class T>
324void
325FleeingMovementGenerator<T>::Finalize(T &owner)
326{
327    owner.clearUnitState(UNIT_STAT_FLEEING);
328}
329
330template<class T>
331void
332FleeingMovementGenerator<T>::Reset(T &owner)
333{
334    Initialize(owner);
335}
336
337template<class T>
338bool
339FleeingMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
340{
341    if( !&owner || !owner.isAlive() )
342        return false;
343    if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
344        return true;
345
346    Traveller<T> traveller(owner);
347
348    i_nextCheckTime.Update(time_diff);
349
350    if( (owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination() )
351    {
352        _setTargetLocation(owner);
353        return true;
354    }
355
356    if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
357    {
358        i_destinationHolder.ResetUpdate(50);
359        if(i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
360        {
361            _setTargetLocation(owner);
362            return true;
363        }
364    }
365    return true;
366}
367
368template void FleeingMovementGenerator<Player>::Initialize(Player &);
369template void FleeingMovementGenerator<Creature>::Initialize(Creature &);
370template bool FleeingMovementGenerator<Player>::_setMoveData(Player &);
371template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature &);
372template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, float &, float &);
373template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
374template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
375template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &);
376template void FleeingMovementGenerator<Player>::Finalize(Player &);
377template void FleeingMovementGenerator<Creature>::Finalize(Creature &);
378template void FleeingMovementGenerator<Player>::Reset(Player &);
379template void FleeingMovementGenerator<Creature>::Reset(Creature &);
380template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32 &);
381template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32 &);
Note: See TracBrowser for help on using the browser.