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
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 if( owner
.hasUnitState(UNIT_STAT_ROOT
| UNIT_STAT_STUNNED
) )
39 if(!_setMoveData(owner
))
43 if(!_getPoint(owner
, x
, y
, z
))
46 owner
.addUnitState(UNIT_STAT_FLEEING
);
47 Traveller
<T
> traveller(owner
);
48 i_destinationHolder
.SetDestination(traveller
, x
, y
, z
);
53 FleeingMovementGenerator
<T
>::_getPoint(T
&owner
, float &x
, float &y
, float &z
)
58 x
= owner
.GetPositionX();
59 y
= owner
.GetPositionY();
60 z
= owner
.GetPositionZ();
62 float temp_x
, temp_y
, angle
;
63 const Map
* _map
= MapManager::Instance().GetBaseMap(owner
.GetMapId());
64 //primitive path-finding
65 for(uint8 i
= 0; i
< 18; ++i
)
67 if(i_only_forward
&& i
> 2)
70 float distance
= 5.0f
;
86 angle
= i_cur_angle
+ M_PI
/4.0f
;
89 angle
= i_cur_angle
- M_PI
/4.0f
;
92 angle
= i_cur_angle
+ M_PI
/4.0f
;
96 angle
= i_cur_angle
- M_PI
/4.0f
;
100 angle
= i_cur_angle
+ M_PI
/2.0f
;
103 angle
= i_cur_angle
- M_PI
/2.0f
;
106 angle
= i_cur_angle
+ M_PI
/2.0f
;
110 angle
= i_cur_angle
- M_PI
/2.0f
;
114 angle
= i_cur_angle
+ M_PI
/4.0f
;
118 angle
= i_cur_angle
- M_PI
/4.0f
;
122 angle
= i_cur_angle
+ M_PI
/2.0f
;
126 angle
= i_cur_angle
- M_PI
/2.0f
;
130 angle
= i_cur_angle
+ M_PI
*3/4.0f
;
134 angle
= i_cur_angle
- M_PI
*3/4.0f
;
138 angle
= i_cur_angle
+ M_PI
;
142 temp_x
= x
+ distance
* cos(angle
);
143 temp_y
= y
+ distance
* sin(angle
);
144 MaNGOS::NormalizeMapCoord(temp_x
);
145 MaNGOS::NormalizeMapCoord(temp_y
);
146 if( owner
.IsWithinLOS(temp_x
,temp_y
,z
))
148 bool is_water_now
= _map
->IsInWater(x
,y
,z
);
150 if(is_water_now
&& _map
->IsInWater(temp_x
,temp_y
,z
))
156 float new_z
= _map
->GetHeight(temp_x
,temp_y
,z
,true);
158 if(new_z
<= INVALID_HEIGHT
)
161 bool is_water_next
= _map
->IsInWater(temp_x
,temp_y
,new_z
);
163 if((is_water_now
&& !is_water_next
&& !is_land_ok
) || (!is_water_now
&& is_water_next
&& !is_water_ok
))
166 if( !(new_z
- z
) || distance
/ fabs(new_z
- z
) > 1.0f
)
168 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);
169 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);
170 if(fabs(new_z_left
- new_z
) < 1.2f
&& fabs(new_z_right
- new_z
) < 1.2f
)
180 i_to_distance_from_caster
= 0.0f
;
181 i_nextCheckTime
.Reset( urand(500,1000) );
187 FleeingMovementGenerator
<T
>::_setMoveData(T
&owner
)
189 float cur_dist_xyz
= owner
.GetDistance(i_caster_x
, i_caster_y
, i_caster_z
);
191 if(i_to_distance_from_caster
> 0.0f
)
193 if((i_last_distance_from_caster
> i_to_distance_from_caster
&& cur_dist_xyz
< i_to_distance_from_caster
) ||
194 // if we reach lower distance
195 (i_last_distance_from_caster
> i_to_distance_from_caster
&& cur_dist_xyz
> i_last_distance_from_caster
) ||
196 // if we can't be close
197 (i_last_distance_from_caster
< i_to_distance_from_caster
&& cur_dist_xyz
> i_to_distance_from_caster
) ||
198 // if we reach bigger distance
199 (cur_dist_xyz
> MAX_QUIET_DISTANCE
) || // if we are too far
200 (i_last_distance_from_caster
> MIN_QUIET_DISTANCE
&& cur_dist_xyz
< MIN_QUIET_DISTANCE
) )
201 // if we leave 'quiet zone'
203 // we are very far or too close, stopping
204 i_to_distance_from_caster
= 0.0f
;
205 i_nextCheckTime
.Reset( urand(500,1000) );
210 // now we are running, continue
211 i_last_distance_from_caster
= cur_dist_xyz
;
217 float angle_to_caster
;
219 Unit
* fright
= ObjectAccessor::GetUnit(owner
, i_frightGUID
);
223 cur_dist
= fright
->GetDistance(&owner
);
224 if(cur_dist
< cur_dist_xyz
)
226 i_caster_x
= fright
->GetPositionX();
227 i_caster_y
= fright
->GetPositionY();
228 i_caster_z
= fright
->GetPositionZ();
229 angle_to_caster
= fright
->GetAngle(&owner
);
233 cur_dist
= cur_dist_xyz
;
234 angle_to_caster
= owner
.GetAngle(i_caster_x
, i_caster_y
) + M_PI
;
239 cur_dist
= cur_dist_xyz
;
240 angle_to_caster
= owner
.GetAngle(i_caster_x
, i_caster_y
) + M_PI
;
243 // if we too close may use 'path-finding' else just stop
244 i_only_forward
= cur_dist
>= MIN_QUIET_DISTANCE
/3;
246 //get angle and 'distance from caster' to run
249 if(i_cur_angle
== 0.0f
&& i_last_distance_from_caster
== 0.0f
) //just started, first time
251 angle
= rand_norm()*(1.0f
- cur_dist
/MIN_QUIET_DISTANCE
) * M_PI
/3 + rand_norm()*M_PI
*2/3;
252 i_to_distance_from_caster
= MIN_QUIET_DISTANCE
;
253 i_only_forward
= true;
255 else if(cur_dist
< MIN_QUIET_DISTANCE
)
257 angle
= M_PI
/6 + rand_norm()*M_PI
*2/3;
258 i_to_distance_from_caster
= cur_dist
*2/3 + rand_norm()*(MIN_QUIET_DISTANCE
- cur_dist
*2/3);
260 else if(cur_dist
> MAX_QUIET_DISTANCE
)
262 angle
= rand_norm()*M_PI
/3 + M_PI
*2/3;
263 i_to_distance_from_caster
= MIN_QUIET_DISTANCE
+ 2.5f
+ rand_norm()*(MAX_QUIET_DISTANCE
- MIN_QUIET_DISTANCE
- 2.5f
);
267 angle
= rand_norm()*M_PI
;
268 i_to_distance_from_caster
= MIN_QUIET_DISTANCE
+ 2.5f
+ rand_norm()*(MAX_QUIET_DISTANCE
- MIN_QUIET_DISTANCE
- 2.5f
);
271 int8 sign
= rand_norm() > 0.5f
? 1 : -1;
272 i_cur_angle
= sign
*angle
+ angle_to_caster
;
275 i_last_distance_from_caster
= cur_dist
;
282 FleeingMovementGenerator
<T
>::Initialize(T
&owner
)
288 owner
.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE
);
290 if(Unit
* fright
= ObjectAccessor::GetUnit(owner
, i_frightGUID
))
292 i_caster_x
= fright
->GetPositionX();
293 i_caster_y
= fright
->GetPositionY();
294 i_caster_z
= fright
->GetPositionZ();
298 i_caster_x
= owner
.GetPositionX();
299 i_caster_y
= owner
.GetPositionY();
300 i_caster_z
= owner
.GetPositionZ();
303 i_only_forward
= true;
305 i_last_distance_from_caster
= 0.0f
;
306 i_to_distance_from_caster
= 0.0f
;
307 _setTargetLocation(owner
);
312 FleeingMovementGenerator
<Creature
>::_Init(Creature
&owner
)
316 owner
.SetUInt64Value(UNIT_FIELD_TARGET
, 0);
317 is_water_ok
= owner
.canSwim();
318 is_land_ok
= owner
.canWalk();
323 FleeingMovementGenerator
<Player
>::_Init(Player
&)
331 FleeingMovementGenerator
<T
>::Finalize(T
&owner
)
333 owner
.clearUnitState(UNIT_STAT_FLEEING
);
338 FleeingMovementGenerator
<T
>::Reset(T
&owner
)
345 FleeingMovementGenerator
<T
>::Update(T
&owner
, const uint32
& time_diff
)
347 if( !&owner
|| !owner
.isAlive() )
349 if( owner
.hasUnitState(UNIT_STAT_ROOT
| UNIT_STAT_STUNNED
) )
352 Traveller
<T
> traveller(owner
);
354 i_nextCheckTime
.Update(time_diff
);
356 if( (owner
.IsStopped() && !i_destinationHolder
.HasArrived()) || !i_destinationHolder
.HasDestination() )
358 _setTargetLocation(owner
);
362 if (i_destinationHolder
.UpdateTraveller(traveller
, time_diff
, false))
364 i_destinationHolder
.ResetUpdate(50);
365 if(i_nextCheckTime
.Passed() && i_destinationHolder
.HasArrived())
367 _setTargetLocation(owner
);
374 template void FleeingMovementGenerator
<Player
>::Initialize(Player
&);
375 template void FleeingMovementGenerator
<Creature
>::Initialize(Creature
&);
376 template bool FleeingMovementGenerator
<Player
>::_setMoveData(Player
&);
377 template bool FleeingMovementGenerator
<Creature
>::_setMoveData(Creature
&);
378 template bool FleeingMovementGenerator
<Player
>::_getPoint(Player
&, float &, float &, float &);
379 template bool FleeingMovementGenerator
<Creature
>::_getPoint(Creature
&, float &, float &, float &);
380 template void FleeingMovementGenerator
<Player
>::_setTargetLocation(Player
&);
381 template void FleeingMovementGenerator
<Creature
>::_setTargetLocation(Creature
&);
382 template void FleeingMovementGenerator
<Player
>::Finalize(Player
&);
383 template void FleeingMovementGenerator
<Creature
>::Finalize(Creature
&);
384 template void FleeingMovementGenerator
<Player
>::Reset(Player
&);
385 template void FleeingMovementGenerator
<Creature
>::Reset(Creature
&);
386 template bool FleeingMovementGenerator
<Player
>::Update(Player
&, const uint32
&);
387 template bool FleeingMovementGenerator
<Creature
>::Update(Creature
&, const uint32
&);
389 void TimedFleeingMovementGenerator::Finalize(Unit
&owner
)
391 owner
.clearUnitState(UNIT_STAT_FLEEING
);
392 if (Unit
* victim
= owner
.getVictim())
396 owner
.AttackStop(true);
397 ((Creature
*)&owner
)->AI()->AttackStart(victim
);
402 bool TimedFleeingMovementGenerator::Update(Unit
& owner
, const uint32
& time_diff
)
404 if( !owner
.isAlive() )
407 if( owner
.hasUnitState(UNIT_STAT_ROOT
| UNIT_STAT_STUNNED
) )
410 i_totalFleeTime
.Update(time_diff
);
411 if (i_totalFleeTime
.Passed())
414 // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const uint32 &) version
415 // This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly
416 return MovementGeneratorMedium
< Creature
, FleeingMovementGenerator
<Creature
> >::Update(owner
, time_diff
);