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 "MapManager.h"
21 #include "RandomMovementGenerator.h"
22 #include "DestinationHolderImp.h"
26 #define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV"
30 RandomMovementGenerator
<Creature
>::_setRandomLocation(Creature
&creature
)
32 float X
,Y
,Z
,z
,nx
,ny
,nz
,wander_distance
,ori
,dist
;
34 creature
.GetRespawnCoord(X
, Y
, Z
, &ori
, &wander_distance
);
36 z
= creature
.GetPositionZ();
37 Map
const* map
= creature
.GetBaseMap();
39 // For 2D/3D system selection
40 //bool is_land_ok = creature.canWalk(); // not used?
41 //bool is_water_ok = creature.canSwim(); // not used?
42 bool is_air_ok
= creature
.canFly();
44 const float angle
= rand_norm()*(M_PI
*2);
45 const float range
= rand_norm()*wander_distance
;
46 const float distanceX
= range
* cos(angle
);
47 const float distanceY
= range
* sin(angle
);
52 // prevent invalid coordinates generation
53 MaNGOS::NormalizeMapCoord(nx
);
54 MaNGOS::NormalizeMapCoord(ny
);
56 dist
= distanceX
*distanceX
+ distanceY
*distanceY
;
58 if (is_air_ok
) // 3D system above ground and above water (flying mode)
60 const float distanceZ
= rand_norm() * sqrtf(dist
)/2; // Limit height change
62 float tz
= map
->GetHeight(nx
, ny
, nz
-2.0f
, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
63 float wz
= map
->GetWaterLevel(nx
, ny
);
64 if (tz
>= nz
|| wz
>= nz
)
65 return; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
67 //else if (is_water_ok) // 3D system under water and above ground (swimming mode)
70 dist
= dist
>=100.0f
? 10.0f
: sqrtf(dist
); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
71 // The fastest way to get an accurate result 90% of the time.
72 // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
73 nz
= map
->GetHeight(nx
,ny
,Z
+dist
-2.0f
,false); // Map check
76 nz
= map
->GetHeight(nx
,ny
,Z
-2.0f
,true); // Vmap Horizontal or above
79 nz
= map
->GetHeight(nx
,ny
,Z
+dist
-2.0f
,true); // Vmap Higher
81 return; // let's forget this bad coords where a z cannot be find and retry at next tick
86 Traveller
<Creature
> traveller(creature
);
87 creature
.SetOrientation(creature
.GetAngle(nx
,ny
));
88 i_destinationHolder
.SetDestination(traveller
, nx
, ny
, nz
);
89 creature
.addUnitState(UNIT_STAT_ROAMING
);
92 i_nextMoveTime
.Reset(i_destinationHolder
.GetTotalTravelTime());
93 creature
.AddMonsterMoveFlag(MONSTER_MOVE_FLY
);
95 //else if (is_water_ok) // Swimming mode to be done with more than this check
98 i_nextMoveTime
.Reset(urand(500+i_destinationHolder
.GetTotalTravelTime(),5000+i_destinationHolder
.GetTotalTravelTime()));
99 creature
.AddMonsterMoveFlag(MONSTER_MOVE_WALK
);
105 RandomMovementGenerator
<Creature
>::Initialize(Creature
&creature
)
107 if(!creature
.isAlive())
110 if (creature
.canFly())
111 creature
.AddMonsterMoveFlag(MONSTER_MOVE_FLY
);
113 else if(irand(0,RUNNING_CHANCE_RANDOMMV
) > 0)
114 creature
.AddMonsterMoveFlag(MONSTER_MOVE_WALK
);
116 creature
.RemoveMonsterMoveFlag(MONSTER_MOVE_WALK
); // run with 1/RUNNING_CHANCE_RANDOMMV chance
118 _setRandomLocation(creature
);
123 RandomMovementGenerator
<Creature
>::Reset(Creature
&creature
)
125 Initialize(creature
);
130 RandomMovementGenerator
<Creature
>::Update(Creature
&creature
, const uint32
&diff
)
132 if(creature
.hasUnitState(UNIT_STAT_ROOT
| UNIT_STAT_STUNNED
| UNIT_STAT_DISTRACTED
| UNIT_STAT_DIED
))
134 i_nextMoveTime
.Update(i_nextMoveTime
.GetExpiry()); // Expire the timer
135 creature
.clearUnitState(UNIT_STAT_ROAMING
);
139 i_nextMoveTime
.Update(diff
);
141 if(i_destinationHolder
.HasArrived() && !creature
.IsStopped() && !creature
.canFly())
142 creature
.clearUnitState(UNIT_STAT_ROAMING
);
144 if(!i_destinationHolder
.HasArrived() && creature
.IsStopped())
145 creature
.addUnitState(UNIT_STAT_ROAMING
);
147 CreatureTraveller
traveller(creature
);
149 if( i_destinationHolder
.UpdateTraveller(traveller
, diff
, false, true) )
151 if(i_nextMoveTime
.Passed())
153 if (creature
.canFly())
154 creature
.AddMonsterMoveFlag(MONSTER_MOVE_FLY
);
155 else if(irand(0,RUNNING_CHANCE_RANDOMMV
) > 0)
156 creature
.AddMonsterMoveFlag(MONSTER_MOVE_WALK
);
157 else // run with 1/RUNNING_CHANCE_RANDOMMV chance
158 creature
.RemoveMonsterMoveFlag(MONSTER_MOVE_WALK
);
160 _setRandomLocation(creature
);
162 else if(creature
.isPet() && creature
.GetOwner() && !creature
.IsWithinDist(creature
.GetOwner(),PET_FOLLOW_DIST
+2.5f
))
164 creature
.AddMonsterMoveFlag(MONSTER_MOVE_WALK
);
165 _setRandomLocation(creature
);