[7297] Fixed profession spells sorting in trainer spell list at client.
[getmangos.git] / src / game / FleeingMovementGenerator.cpp
blob073a95ade5e0d1e8d87601ad72a8ac9675b71cdb
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
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.
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.
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
19 #include "Creature.h"
20 #include "MapManager.h"
21 #include "FleeingMovementGenerator.h"
22 #include "DestinationHolderImp.h"
23 #include "ObjectAccessor.h"
25 #define MIN_QUIET_DISTANCE 28.0f
26 #define MAX_QUIET_DISTANCE 43.0f
28 template<class T>
29 void
30 FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
32 if( !&owner )
33 return;
35 if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
36 return;
38 if(!_setMoveData(owner))
39 return;
41 float x, y, z;
42 if(!_getPoint(owner, x, y, z))
43 return;
45 owner.addUnitState(UNIT_STAT_FLEEING);
46 Traveller<T> traveller(owner);
47 i_destinationHolder.SetDestination(traveller, x, y, z);
50 template<class T>
51 bool
52 FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
54 if(!&owner)
55 return false;
57 x = owner.GetPositionX();
58 y = owner.GetPositionY();
59 z = owner.GetPositionZ();
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++)
66 if(i_only_forward && i > 2)
67 break;
69 float distance = 5.0f;
71 switch(i)
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;
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))
147 bool is_water_now = _map->IsInWater(x,y,z);
149 if(is_water_now && _map->IsInWater(temp_x,temp_y,z))
151 x = temp_x;
152 y = temp_y;
153 return true;
155 float new_z = _map->GetHeight(temp_x,temp_y,z,true);
157 if(new_z <= INVALID_HEIGHT)
158 continue;
160 bool is_water_next = _map->IsInWater(temp_x,temp_y,new_z);
162 if((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
163 continue;
165 if( !(new_z - z) || distance / fabs(new_z - z) > 1.0f)
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)
171 x = temp_x;
172 y = temp_y;
173 z = new_z;
174 return true;
179 i_to_distance_from_caster = 0.0f;
180 i_nextCheckTime.Reset( urand(500,1000) );
181 return false;
184 template<class T>
185 bool
186 FleeingMovementGenerator<T>::_setMoveData(T &owner)
188 float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);
190 if(i_to_distance_from_caster > 0.0f)
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'
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;
207 else
209 // now we are running, continue
210 i_last_distance_from_caster = cur_dist_xyz;
211 return true;
215 float cur_dist;
216 float angle_to_caster;
218 Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
220 if(fright)
222 cur_dist = fright->GetDistance(&owner);
223 if(cur_dist < cur_dist_xyz)
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);
230 else
232 cur_dist = cur_dist_xyz;
233 angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
236 else
238 cur_dist = cur_dist_xyz;
239 angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
242 // if we too close may use 'path-finding' else just stop
243 i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3;
245 //get angle and 'distance from caster' to run
246 float angle;
248 if(i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
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;
254 else if(cur_dist < MIN_QUIET_DISTANCE)
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);
259 else if(cur_dist > MAX_QUIET_DISTANCE)
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);
264 else
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);
270 int8 sign = rand_norm() > 0.5f ? 1 : -1;
271 i_cur_angle = sign*angle + angle_to_caster;
273 // current distance
274 i_last_distance_from_caster = cur_dist;
276 return true;
279 template<class T>
280 void
281 FleeingMovementGenerator<T>::Initialize(T &owner)
283 if(!&owner)
284 return;
286 _Init(owner);
287 owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
289 if(Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
291 i_caster_x = fright->GetPositionX();
292 i_caster_y = fright->GetPositionY();
293 i_caster_z = fright->GetPositionZ();
295 else
297 i_caster_x = owner.GetPositionX();
298 i_caster_y = owner.GetPositionY();
299 i_caster_z = owner.GetPositionZ();
302 i_only_forward = true;
303 i_cur_angle = 0.0f;
304 i_last_distance_from_caster = 0.0f;
305 i_to_distance_from_caster = 0.0f;
306 _setTargetLocation(owner);
309 template<>
310 void
311 FleeingMovementGenerator<Creature>::_Init(Creature &owner)
313 if(!&owner)
314 return;
315 owner.SetUInt64Value(UNIT_FIELD_TARGET, 0);
316 is_water_ok = owner.canSwim();
317 is_land_ok = owner.canWalk();
320 template<>
321 void
322 FleeingMovementGenerator<Player>::_Init(Player &)
324 is_water_ok = true;
325 is_land_ok = true;
328 template<class T>
329 void
330 FleeingMovementGenerator<T>::Finalize(T &owner)
332 owner.clearUnitState(UNIT_STAT_FLEEING);
335 template<class T>
336 void
337 FleeingMovementGenerator<T>::Reset(T &owner)
339 Initialize(owner);
342 template<class T>
343 bool
344 FleeingMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
346 if( !&owner || !owner.isAlive() )
347 return false;
348 if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
349 return true;
351 Traveller<T> traveller(owner);
353 i_nextCheckTime.Update(time_diff);
355 if( (owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination() )
357 _setTargetLocation(owner);
358 return true;
361 if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
363 i_destinationHolder.ResetUpdate(50);
364 if(i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
366 _setTargetLocation(owner);
367 return true;
370 return true;
373 template void FleeingMovementGenerator<Player>::Initialize(Player &);
374 template void FleeingMovementGenerator<Creature>::Initialize(Creature &);
375 template bool FleeingMovementGenerator<Player>::_setMoveData(Player &);
376 template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature &);
377 template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, float &, float &);
378 template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
379 template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
380 template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &);
381 template void FleeingMovementGenerator<Player>::Finalize(Player &);
382 template void FleeingMovementGenerator<Creature>::Finalize(Creature &);
383 template void FleeingMovementGenerator<Player>::Reset(Player &);
384 template void FleeingMovementGenerator<Creature>::Reset(Creature &);
385 template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32 &);
386 template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32 &);