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

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

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

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