[9581] Fixed apply damage reduction to melee/ranged damage.
[getmangos.git] / src / game / FleeingMovementGenerator.cpp
bloba686659cd770210dbce5068338804ed82f8a9b08
1 /*
2 * Copyright (C) 2005-2010 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 "CreatureAI.h"
21 #include "MapManager.h"
22 #include "FleeingMovementGenerator.h"
23 #include "DestinationHolderImp.h"
24 #include "ObjectAccessor.h"
26 #define MIN_QUIET_DISTANCE 28.0f
27 #define MAX_QUIET_DISTANCE 43.0f
29 template<class T>
30 void
31 FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
33 if( !&owner )
34 return;
36 // ignore in case other no reaction state
37 if (owner.hasUnitState(UNIT_STAT_CAN_NOT_REACT & ~UNIT_STAT_FLEEING))
38 return;
40 if(!_setMoveData(owner))
41 return;
43 float x, y, z;
44 if(!_getPoint(owner, x, y, z))
45 return;
47 owner.addUnitState(UNIT_STAT_FLEEING_MOVE);
48 Traveller<T> traveller(owner);
49 i_destinationHolder.SetDestination(traveller, x, y, z);
52 template<class T>
53 bool
54 FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
56 if(!&owner)
57 return false;
59 x = owner.GetPositionX();
60 y = owner.GetPositionY();
61 z = owner.GetPositionZ();
63 float temp_x, temp_y, angle;
64 const Map * _map = owner.GetBaseMap();
65 //primitive path-finding
66 for(uint8 i = 0; i < 18; ++i)
68 if(i_only_forward && i > 2)
69 break;
71 float distance = 5.0f;
73 switch(i)
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_F/4.0f;
88 break;
89 case 4:
90 angle = i_cur_angle - M_PI_F/4.0f;
91 break;
92 case 5:
93 angle = i_cur_angle + M_PI_F/4.0f;
94 distance /= 2;
95 break;
96 case 6:
97 angle = i_cur_angle - M_PI_F/4.0f;
98 distance /= 2;
99 break;
100 case 7:
101 angle = i_cur_angle + M_PI_F/2.0f;
102 break;
103 case 8:
104 angle = i_cur_angle - M_PI_F/2.0f;
105 break;
106 case 9:
107 angle = i_cur_angle + M_PI_F/2.0f;
108 distance /= 2;
109 break;
110 case 10:
111 angle = i_cur_angle - M_PI_F/2.0f;
112 distance /= 2;
113 break;
114 case 11:
115 angle = i_cur_angle + M_PI_F/4.0f;
116 distance /= 4;
117 break;
118 case 12:
119 angle = i_cur_angle - M_PI_F/4.0f;
120 distance /= 4;
121 break;
122 case 13:
123 angle = i_cur_angle + M_PI_F/2.0f;
124 distance /= 4;
125 break;
126 case 14:
127 angle = i_cur_angle - M_PI_F/2.0f;
128 distance /= 4;
129 break;
130 case 15:
131 angle = i_cur_angle + M_PI_F*3/4.0f;
132 distance /= 2;
133 break;
134 case 16:
135 angle = i_cur_angle - M_PI_F*3/4.0f;
136 distance /= 2;
137 break;
138 case 17:
139 angle = i_cur_angle + M_PI_F;
140 distance /= 2;
141 break;
143 temp_x = x + distance * cos(angle);
144 temp_y = y + distance * sin(angle);
145 MaNGOS::NormalizeMapCoord(temp_x);
146 MaNGOS::NormalizeMapCoord(temp_y);
147 if( owner.IsWithinLOS(temp_x,temp_y,z))
149 bool is_water_now = _map->IsInWater(x,y,z);
151 if(is_water_now && _map->IsInWater(temp_x,temp_y,z))
153 x = temp_x;
154 y = temp_y;
155 return true;
157 float new_z = _map->GetHeight(temp_x,temp_y,z,true);
159 if(new_z <= INVALID_HEIGHT)
160 continue;
162 bool is_water_next = _map->IsInWater(temp_x,temp_y,new_z);
164 if((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
165 continue;
167 if( !(new_z - z) || distance / fabs(new_z - z) > 1.0f)
169 float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+M_PI_F/2),temp_y + 1.0f*sin(angle+M_PI_F/2),z,true);
170 float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-M_PI_F/2),temp_y + 1.0f*sin(angle-M_PI_F/2),z,true);
171 if(fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
173 x = temp_x;
174 y = temp_y;
175 z = new_z;
176 return true;
181 i_to_distance_from_caster = 0.0f;
182 i_nextCheckTime.Reset( urand(500,1000) );
183 return false;
186 template<class T>
187 bool
188 FleeingMovementGenerator<T>::_setMoveData(T &owner)
190 float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);
192 if(i_to_distance_from_caster > 0.0f)
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'
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;
209 else
211 // now we are running, continue
212 i_last_distance_from_caster = cur_dist_xyz;
213 return true;
217 float cur_dist;
218 float angle_to_caster;
220 Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
222 if(fright)
224 cur_dist = fright->GetDistance(&owner);
225 if(cur_dist < cur_dist_xyz)
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);
232 else
234 cur_dist = cur_dist_xyz;
235 angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI_F;
238 else
240 cur_dist = cur_dist_xyz;
241 angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI_F;
244 // if we too close may use 'path-finding' else just stop
245 i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3;
247 //get angle and 'distance from caster' to run
248 float angle;
250 if(i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
252 angle = rand_norm_f()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * M_PI_F/3 + rand_norm_f()*M_PI_F*2/3;
253 i_to_distance_from_caster = MIN_QUIET_DISTANCE;
254 i_only_forward = true;
256 else if(cur_dist < MIN_QUIET_DISTANCE)
258 angle = M_PI_F/6 + rand_norm_f()*M_PI_F*2/3;
259 i_to_distance_from_caster = cur_dist*2/3 + rand_norm_f()*(MIN_QUIET_DISTANCE - cur_dist*2/3);
261 else if(cur_dist > MAX_QUIET_DISTANCE)
263 angle = rand_norm_f()*M_PI_F/3 + M_PI_F*2/3;
264 i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm_f()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
266 else
268 angle = rand_norm_f()*M_PI_F;
269 i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm_f()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
272 int8 sign = rand_norm_f() > 0.5f ? 1 : -1;
273 i_cur_angle = sign*angle + angle_to_caster;
275 // current distance
276 i_last_distance_from_caster = cur_dist;
278 return true;
281 template<class T>
282 void
283 FleeingMovementGenerator<T>::Initialize(T &owner)
285 owner.addUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
287 _Init(owner);
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 owner.RemoveSplineFlag(SPLINEFLAG_WALKMODE);
314 owner.SetTargetGUID(0);
315 is_water_ok = owner.canSwim();
316 is_land_ok = owner.canWalk();
319 template<>
320 void
321 FleeingMovementGenerator<Player>::_Init(Player &)
323 is_water_ok = true;
324 is_land_ok = true;
327 template<>
328 void FleeingMovementGenerator<Player>::Finalize(Player &owner)
330 owner.clearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
333 template<>
334 void FleeingMovementGenerator<Creature>::Finalize(Creature &owner)
336 owner.AddSplineFlag(SPLINEFLAG_WALKMODE);
337 owner.clearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
340 template<class T>
341 void FleeingMovementGenerator<T>::Interrupt(T &owner)
343 // flee state still applied while movegen disabled
344 owner.clearUnitState(UNIT_STAT_FLEEING_MOVE);
347 template<class T>
348 void FleeingMovementGenerator<T>::Reset(T &owner)
350 Initialize(owner);
353 template<class T>
354 bool FleeingMovementGenerator<T>::Update(T &owner, const uint32 & time_diff)
356 if( !&owner || !owner.isAlive() )
357 return false;
359 // ignore in case other no reaction state
360 if (owner.hasUnitState(UNIT_STAT_CAN_NOT_REACT & ~UNIT_STAT_FLEEING))
362 owner.clearUnitState(UNIT_STAT_FLEEING_MOVE);
363 return true;
366 Traveller<T> traveller(owner);
368 i_nextCheckTime.Update(time_diff);
370 if( (owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination() )
372 _setTargetLocation(owner);
373 return true;
376 if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
378 if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list)
379 return true; // not expire now, but already lost
381 i_destinationHolder.ResetUpdate(50);
382 if(i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
384 _setTargetLocation(owner);
385 return true;
388 return true;
391 template void FleeingMovementGenerator<Player>::Initialize(Player &);
392 template void FleeingMovementGenerator<Creature>::Initialize(Creature &);
393 template bool FleeingMovementGenerator<Player>::_setMoveData(Player &);
394 template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature &);
395 template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, float &, float &);
396 template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
397 template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
398 template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &);
399 template void FleeingMovementGenerator<Player>::Interrupt(Player &);
400 template void FleeingMovementGenerator<Creature>::Interrupt(Creature &);
401 template void FleeingMovementGenerator<Player>::Reset(Player &);
402 template void FleeingMovementGenerator<Creature>::Reset(Creature &);
403 template bool FleeingMovementGenerator<Player>::Update(Player &, const uint32 &);
404 template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint32 &);
406 void TimedFleeingMovementGenerator::Finalize(Unit &owner)
408 owner.clearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE);
409 if (Unit* victim = owner.getVictim())
411 if (owner.isAlive())
413 owner.AttackStop(true);
414 ((Creature*)&owner)->AI()->AttackStart(victim);
419 bool TimedFleeingMovementGenerator::Update(Unit & owner, const uint32 & time_diff)
421 if( !owner.isAlive() )
422 return false;
424 // ignore in case other no reaction state
425 if (owner.hasUnitState(UNIT_STAT_CAN_NOT_REACT & ~UNIT_STAT_FLEEING))
427 owner.clearUnitState(UNIT_STAT_FLEEING_MOVE);
428 return true;
431 i_totalFleeTime.Update(time_diff);
432 if (i_totalFleeTime.Passed())
433 return false;
435 // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const uint32 &) version
436 // This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly
437 return MovementGeneratorMedium< Creature, FleeingMovementGenerator<Creature> >::Update(owner, time_diff);