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 | |
---|
28 | template<class T> |
---|
29 | void |
---|
30 | FleeingMovementGenerator<T>::_setTargetLocation(T &owner) |
---|
31 | { |
---|
32 | if( !&owner ) |
---|
33 | return; |
---|
34 | |
---|
35 | if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) ) |
---|
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 | |
---|
50 | template<class T> |
---|
51 | bool |
---|
52 | FleeingMovementGenerator<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 | |
---|
184 | template<class T> |
---|
185 | bool |
---|
186 | FleeingMovementGenerator<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 | |
---|
279 | template<class T> |
---|
280 | void |
---|
281 | FleeingMovementGenerator<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 | |
---|
302 | template<> |
---|
303 | void |
---|
304 | FleeingMovementGenerator<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 | |
---|
313 | template<> |
---|
314 | void |
---|
315 | FleeingMovementGenerator<Player>::_Init(Player &) |
---|
316 | { |
---|
317 | is_water_ok = true; |
---|
318 | is_land_ok = true; |
---|
319 | } |
---|
320 | |
---|
321 | template<class T> |
---|
322 | void |
---|
323 | FleeingMovementGenerator<T>::Finalize(T &owner) |
---|
324 | { |
---|
325 | owner.clearUnitState(UNIT_STAT_FLEEING); |
---|
326 | } |
---|
327 | |
---|
328 | template<class T> |
---|
329 | void |
---|
330 | FleeingMovementGenerator<T>::Reset(T &owner) |
---|
331 | { |
---|
332 | Initialize(owner); |
---|
333 | } |
---|
334 | |
---|
335 | template<class T> |
---|
336 | bool |
---|
337 | FleeingMovementGenerator<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_STUNNED) ) |
---|
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 | |
---|
366 | template void FleeingMovementGenerator<Player>::Initialize(Player &); |
---|
367 | template void FleeingMovementGenerator<Creature>::Initialize(Creature &); |
---|
368 | template bool FleeingMovementGenerator<Player>::_setMoveData(Player &); |
---|
369 | template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature &); |
---|
370 | template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, float &, float &); |
---|
371 | template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &); |
---|
372 | template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &); |
---|
373 | template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &); |
---|
374 | template void FleeingMovementGenerator<Player>::Finalize(Player &); |
---|
375 | template void FleeingMovementGenerator<Creature>::Finalize(Creature &); |
---|
376 | template void FleeingMovementGenerator<Player>::Reset(Player &); |
---|
377 | template void FleeingMovementGenerator<Creature>::Reset(Creature &); |
---|
378 | template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32 &); |
---|
379 | template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32 &); |
---|