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
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
31 FleeingMovementGenerator
<T
>::_setTargetLocation(T
&owner
)
36 // ignore in case other no reaction state
37 if (owner
.hasUnitState(UNIT_STAT_CAN_NOT_REACT
& ~UNIT_STAT_FLEEING
))
40 if(!_setMoveData(owner
))
44 if(!_getPoint(owner
, x
, y
, z
))
47 owner
.addUnitState(UNIT_STAT_FLEEING_MOVE
);
48 Traveller
<T
> traveller(owner
);
49 i_destinationHolder
.SetDestination(traveller
, x
, y
, z
);
54 FleeingMovementGenerator
<T
>::_getPoint(T
&owner
, float &x
, float &y
, float &z
)
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)
71 float distance
= 5.0f
;
87 angle
= i_cur_angle
+ M_PI_F
/4.0f
;
90 angle
= i_cur_angle
- M_PI_F
/4.0f
;
93 angle
= i_cur_angle
+ M_PI_F
/4.0f
;
97 angle
= i_cur_angle
- M_PI_F
/4.0f
;
101 angle
= i_cur_angle
+ M_PI_F
/2.0f
;
104 angle
= i_cur_angle
- M_PI_F
/2.0f
;
107 angle
= i_cur_angle
+ M_PI_F
/2.0f
;
111 angle
= i_cur_angle
- M_PI_F
/2.0f
;
115 angle
= i_cur_angle
+ M_PI_F
/4.0f
;
119 angle
= i_cur_angle
- M_PI_F
/4.0f
;
123 angle
= i_cur_angle
+ M_PI_F
/2.0f
;
127 angle
= i_cur_angle
- M_PI_F
/2.0f
;
131 angle
= i_cur_angle
+ M_PI_F
*3/4.0f
;
135 angle
= i_cur_angle
- M_PI_F
*3/4.0f
;
139 angle
= i_cur_angle
+ M_PI_F
;
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
))
157 float new_z
= _map
->GetHeight(temp_x
,temp_y
,z
,true);
159 if(new_z
<= INVALID_HEIGHT
)
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
))
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
)
181 i_to_distance_from_caster
= 0.0f
;
182 i_nextCheckTime
.Reset( urand(500,1000) );
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) );
211 // now we are running, continue
212 i_last_distance_from_caster
= cur_dist_xyz
;
218 float angle_to_caster
;
220 Unit
* fright
= ObjectAccessor::GetUnit(owner
, i_frightGUID
);
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
);
234 cur_dist
= cur_dist_xyz
;
235 angle_to_caster
= owner
.GetAngle(i_caster_x
, i_caster_y
) + M_PI_F
;
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
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
);
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
;
276 i_last_distance_from_caster
= cur_dist
;
283 FleeingMovementGenerator
<T
>::Initialize(T
&owner
)
285 owner
.addUnitState(UNIT_STAT_FLEEING
|UNIT_STAT_FLEEING_MOVE
);
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();
297 i_caster_x
= owner
.GetPositionX();
298 i_caster_y
= owner
.GetPositionY();
299 i_caster_z
= owner
.GetPositionZ();
302 i_only_forward
= true;
304 i_last_distance_from_caster
= 0.0f
;
305 i_to_distance_from_caster
= 0.0f
;
306 _setTargetLocation(owner
);
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();
321 FleeingMovementGenerator
<Player
>::_Init(Player
&)
328 void FleeingMovementGenerator
<Player
>::Finalize(Player
&owner
)
330 owner
.clearUnitState(UNIT_STAT_FLEEING
|UNIT_STAT_FLEEING_MOVE
);
334 void FleeingMovementGenerator
<Creature
>::Finalize(Creature
&owner
)
336 owner
.AddSplineFlag(SPLINEFLAG_WALKMODE
);
337 owner
.clearUnitState(UNIT_STAT_FLEEING
|UNIT_STAT_FLEEING_MOVE
);
341 void FleeingMovementGenerator
<T
>::Interrupt(T
&owner
)
343 // flee state still applied while movegen disabled
344 owner
.clearUnitState(UNIT_STAT_FLEEING_MOVE
);
348 void FleeingMovementGenerator
<T
>::Reset(T
&owner
)
354 bool FleeingMovementGenerator
<T
>::Update(T
&owner
, const uint32
& time_diff
)
356 if( !&owner
|| !owner
.isAlive() )
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
);
366 Traveller
<T
> traveller(owner
);
368 i_nextCheckTime
.Update(time_diff
);
370 if( (owner
.IsStopped() && !i_destinationHolder
.HasArrived()) || !i_destinationHolder
.HasDestination() )
372 _setTargetLocation(owner
);
376 if (i_destinationHolder
.UpdateTraveller(traveller
, time_diff
, false))
378 i_destinationHolder
.ResetUpdate(50);
379 if(i_nextCheckTime
.Passed() && i_destinationHolder
.HasArrived())
381 _setTargetLocation(owner
);
388 template void FleeingMovementGenerator
<Player
>::Initialize(Player
&);
389 template void FleeingMovementGenerator
<Creature
>::Initialize(Creature
&);
390 template bool FleeingMovementGenerator
<Player
>::_setMoveData(Player
&);
391 template bool FleeingMovementGenerator
<Creature
>::_setMoveData(Creature
&);
392 template bool FleeingMovementGenerator
<Player
>::_getPoint(Player
&, float &, float &, float &);
393 template bool FleeingMovementGenerator
<Creature
>::_getPoint(Creature
&, float &, float &, float &);
394 template void FleeingMovementGenerator
<Player
>::_setTargetLocation(Player
&);
395 template void FleeingMovementGenerator
<Creature
>::_setTargetLocation(Creature
&);
396 template void FleeingMovementGenerator
<Player
>::Interrupt(Player
&);
397 template void FleeingMovementGenerator
<Creature
>::Interrupt(Creature
&);
398 template void FleeingMovementGenerator
<Player
>::Reset(Player
&);
399 template void FleeingMovementGenerator
<Creature
>::Reset(Creature
&);
400 template bool FleeingMovementGenerator
<Player
>::Update(Player
&, const uint32
&);
401 template bool FleeingMovementGenerator
<Creature
>::Update(Creature
&, const uint32
&);
403 void TimedFleeingMovementGenerator::Finalize(Unit
&owner
)
405 owner
.clearUnitState(UNIT_STAT_FLEEING
|UNIT_STAT_FLEEING_MOVE
);
406 if (Unit
* victim
= owner
.getVictim())
410 owner
.AttackStop(true);
411 ((Creature
*)&owner
)->AI()->AttackStart(victim
);
416 bool TimedFleeingMovementGenerator::Update(Unit
& owner
, const uint32
& time_diff
)
418 if( !owner
.isAlive() )
421 // ignore in case other no reaction state
422 if (owner
.hasUnitState(UNIT_STAT_CAN_NOT_REACT
& ~UNIT_STAT_FLEEING
))
424 owner
.clearUnitState(UNIT_STAT_FLEEING_MOVE
);
428 i_totalFleeTime
.Update(time_diff
);
429 if (i_totalFleeTime
.Passed())
432 // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const uint32 &) version
433 // This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly
434 return MovementGeneratorMedium
< Creature
, FleeingMovementGenerator
<Creature
> >::Update(owner
, time_diff
);