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 "MapManager.h"
21 #include "RandomMovementGenerator.h"
22 #include "DestinationHolderImp.h"
28 RandomMovementGenerator
<Creature
>::_setRandomLocation(Creature
&creature
)
30 float X
,Y
,Z
,z
,nx
,ny
,nz
,wander_distance
,ori
,dist
;
32 creature
.GetRespawnCoord(X
, Y
, Z
, &ori
, &wander_distance
);
34 z
= creature
.GetPositionZ();
35 Map
const* map
= creature
.GetBaseMap();
37 // For 2D/3D system selection
38 //bool is_land_ok = creature.canWalk(); // not used?
39 //bool is_water_ok = creature.canSwim(); // not used?
40 bool is_air_ok
= creature
.canFly();
42 const float angle
= rand_norm_f()*(M_PI_F
*2.0f
);
43 const float range
= rand_norm_f()*wander_distance
;
44 const float distanceX
= range
* cos(angle
);
45 const float distanceY
= range
* sin(angle
);
50 // prevent invalid coordinates generation
51 MaNGOS::NormalizeMapCoord(nx
);
52 MaNGOS::NormalizeMapCoord(ny
);
54 dist
= distanceX
*distanceX
+ distanceY
*distanceY
;
56 if (is_air_ok
) // 3D system above ground and above water (flying mode)
58 // Limit height change
59 const float distanceZ
= rand_norm_f() * sqrtf(dist
)/2.0f
;
61 float tz
= map
->GetHeight(nx
, ny
, nz
-2.0f
, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
62 float wz
= map
->GetWaterLevel(nx
, ny
);
64 // Problem here, we must fly above the ground and water, not under. Let's try on next tick
65 if (tz
>= nz
|| wz
>= nz
)
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)
73 // The fastest way to get an accurate result 90% of the time.
74 // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
75 nz
= map
->GetHeight(nx
, ny
, Z
+dist
-2.0f
, false);
77 if (fabs(nz
-Z
) > dist
) // Map check
79 nz
= map
->GetHeight(nx
, ny
, Z
-2.0f
, true); // Vmap Horizontal or above
81 if (fabs(nz
-Z
) > dist
)
84 nz
= map
->GetHeight(nx
, ny
, Z
+dist
-2.0f
, true);
86 // let's forget this bad coords where a z cannot be find and retry at next tick
87 if (fabs(nz
-Z
) > dist
)
93 Traveller
<Creature
> traveller(creature
);
95 creature
.SetOrientation(creature
.GetAngle(nx
, ny
));
96 i_destinationHolder
.SetDestination(traveller
, nx
, ny
, nz
);
97 creature
.addUnitState(UNIT_STAT_ROAMING_MOVE
);
101 i_nextMoveTime
.Reset(i_destinationHolder
.GetTotalTravelTime());
102 creature
.AddSplineFlag(SPLINEFLAG_UNKNOWN7
);
104 //else if (is_water_ok) // Swimming mode to be done with more than this check
107 i_nextMoveTime
.Reset(urand(500+i_destinationHolder
.GetTotalTravelTime(), 10000+i_destinationHolder
.GetTotalTravelTime()));
108 creature
.AddSplineFlag(SPLINEFLAG_WALKMODE
);
113 void RandomMovementGenerator
<Creature
>::Initialize(Creature
&creature
)
115 if (!creature
.isAlive())
118 if (creature
.canFly())
119 creature
.AddSplineFlag(SPLINEFLAG_UNKNOWN7
);
121 creature
.AddSplineFlag(SPLINEFLAG_WALKMODE
);
123 creature
.addUnitState(UNIT_STAT_ROAMING
|UNIT_STAT_ROAMING_MOVE
);
124 _setRandomLocation(creature
);
128 void RandomMovementGenerator
<Creature
>::Reset(Creature
&creature
)
130 Initialize(creature
);
134 void RandomMovementGenerator
<Creature
>::Interrupt(Creature
&creature
)
136 creature
.clearUnitState(UNIT_STAT_ROAMING
|UNIT_STAT_ROAMING_MOVE
);
140 void RandomMovementGenerator
<Creature
>::Finalize(Creature
&creature
)
142 creature
.clearUnitState(UNIT_STAT_ROAMING
|UNIT_STAT_ROAMING_MOVE
);
146 bool RandomMovementGenerator
<Creature
>::Update(Creature
&creature
, const uint32
&diff
)
148 if (creature
.hasUnitState(UNIT_STAT_NOT_MOVE
))
150 i_nextMoveTime
.Update(i_nextMoveTime
.GetExpiry()); // Expire the timer
151 creature
.clearUnitState(UNIT_STAT_ROAMING_MOVE
);
155 i_nextMoveTime
.Update(diff
);
157 if (i_destinationHolder
.HasArrived() && !creature
.IsStopped() && !creature
.canFly())
158 creature
.clearUnitState(UNIT_STAT_ROAMING_MOVE
);
160 if (!i_destinationHolder
.HasArrived() && creature
.IsStopped())
161 creature
.addUnitState(UNIT_STAT_ROAMING_MOVE
);
163 CreatureTraveller
traveller(creature
);
165 if (i_destinationHolder
.UpdateTraveller(traveller
, diff
, false, true))
167 if (!IsActive(creature
)) // force stop processing (movement can move out active zone with cleanup movegens list)
168 return true; // not expire now, but already lost
170 if (i_nextMoveTime
.Passed())
172 if (creature
.canFly())
173 creature
.AddSplineFlag(SPLINEFLAG_UNKNOWN7
);
175 creature
.AddSplineFlag(SPLINEFLAG_WALKMODE
);
177 _setRandomLocation(creature
);
179 else if (creature
.isPet() && creature
.GetOwner() && !creature
.IsWithinDist(creature
.GetOwner(), PET_FOLLOW_DIST
+2.5f
))
181 creature
.AddSplineFlag(SPLINEFLAG_WALKMODE
);
182 _setRandomLocation(creature
);
189 bool RandomMovementGenerator
<Creature
>::GetResetPosition(Creature
& c
, float& x
, float& y
, float& z
)
192 c
.GetRespawnCoord(x
, y
, z
, NULL
, &radius
);
194 // use current if in range
195 if (c
.IsWithinDist2d(x
,y
,radius
))
196 c
.GetPosition(x
,y
,z
);