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 uint32 mapid
=creature
.GetMapId();
38 Map
const* map
= MapManager::Instance().GetBaseMap(mapid
);
40 // For 2D/3D system selection
41 //bool is_land_ok = creature.canWalk(); // not used?
42 //bool is_water_ok = creature.canSwim(); // not used?
43 bool is_air_ok
= creature
.canFly();
45 const float angle
= rand_norm()*(M_PI
*2);
46 const float range
= rand_norm()*wander_distance
;
47 const float distanceX
= range
* cos(angle
);
48 const float distanceY
= range
* sin(angle
);
53 // prevent invalid coordinates generation
54 MaNGOS::NormalizeMapCoord(nx
);
55 MaNGOS::NormalizeMapCoord(ny
);
57 dist
= distanceX
*distanceX
+ distanceY
*distanceY
;
59 if (is_air_ok
) // 3D system above ground and above water (flying mode)
61 const float distanceZ
= rand_norm() * sqrtf(dist
)/2; // Limit height change
63 float tz
= map
->GetHeight(nx
, ny
, nz
-2.0f
, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
64 float wz
= map
->GetWaterLevel(nx
, ny
);
65 if (tz
>= nz
|| wz
>= nz
)
66 return; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
68 //else if (is_water_ok) // 3D system under water and above ground (swimming mode)
71 dist
= dist
>=100.0f
? 10.0f
: sqrtf(dist
); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
72 // The fastest way to get an accurate result 90% of the time.
73 // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
74 nz
= map
->GetHeight(nx
,ny
,Z
+dist
-2.0f
,false); // Map check
77 nz
= map
->GetHeight(nx
,ny
,Z
-2.0f
,true); // Vmap Horizontal or above
80 nz
= map
->GetHeight(nx
,ny
,Z
+dist
-2.0f
,true); // Vmap Higher
82 return; // let's forget this bad coords where a z cannot be find and retry at next tick
87 Traveller
<Creature
> traveller(creature
);
88 creature
.SetOrientation(creature
.GetAngle(nx
,ny
));
89 i_destinationHolder
.SetDestination(traveller
, nx
, ny
, nz
);
90 creature
.addUnitState(UNIT_STAT_ROAMING
);
93 i_nextMoveTime
.Reset(i_destinationHolder
.GetTotalTravelTime());
94 creature
.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2
);
96 //else if (is_water_ok) // Swimming mode to be done with more than this check
99 i_nextMoveTime
.Reset(urand(500+i_destinationHolder
.GetTotalTravelTime(),5000+i_destinationHolder
.GetTotalTravelTime()));
100 creature
.SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE
);
106 RandomMovementGenerator
<Creature
>::Initialize(Creature
&creature
)
108 if(!creature
.isAlive())
111 if (creature
.canFly())
112 creature
.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2
);
114 creature
.SetUnitMovementFlags(irand(0,RUNNING_CHANCE_RANDOMMV
) > 0 ? MOVEMENTFLAG_WALK_MODE
: MOVEMENTFLAG_NONE
);
115 _setRandomLocation(creature
);
120 RandomMovementGenerator
<Creature
>::Reset(Creature
&creature
)
122 Initialize(creature
);
127 RandomMovementGenerator
<Creature
>::Update(Creature
&creature
, const uint32
&diff
)
129 if(creature
.hasUnitState(UNIT_STAT_ROOT
| UNIT_STAT_STUNNED
| UNIT_STAT_DISTRACTED
))
131 i_nextMoveTime
.Update(i_nextMoveTime
.GetExpiry()); // Expire the timer
132 creature
.clearUnitState(UNIT_STAT_ROAMING
);
136 i_nextMoveTime
.Update(diff
);
138 if(i_destinationHolder
.HasArrived() && !creature
.IsStopped() && !creature
.canFly())
139 creature
.clearUnitState(UNIT_STAT_ROAMING
);
141 if(!i_destinationHolder
.HasArrived() && creature
.IsStopped())
142 creature
.addUnitState(UNIT_STAT_ROAMING
);
144 CreatureTraveller
traveller(creature
);
146 if( i_destinationHolder
.UpdateTraveller(traveller
, diff
, false, true) )
148 if(i_nextMoveTime
.Passed())
150 if (creature
.canFly())
151 creature
.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2
);
153 creature
.SetUnitMovementFlags(irand(0,RUNNING_CHANCE_RANDOMMV
) > 0 ? MOVEMENTFLAG_WALK_MODE
: MOVEMENTFLAG_NONE
);
154 _setRandomLocation(creature
);
156 else if(creature
.isPet() && creature
.GetOwner() && !creature
.IsWithinDist(creature
.GetOwner(),PET_FOLLOW_DIST
+2.5f
))
158 creature
.SetUnitMovementFlags(MOVEMENTFLAG_NONE
);
159 _setRandomLocation(creature
);