public static bool checkGroundUnderWoWPoint(WoWPoint point, WoWPoint pool)
{
// Create two points, ahead and under
// the one we're going to test
WoWPoint top, bottom;
top = bottom = point;
top.Z += 2.0F;
bottom.Z -= 4.0F;
// Create a line which connects the two new points
WorldLine line = new WorldLine(top, bottom);
Stopwatch sw = new Stopwatch();
sw.Start();
// Check whenever the line intersects ground or a structure
bool groundOrLevel = GameWorld.TraceLine(top, bottom, GameWorld.CGWorldFrameHitFlags.HitTestGroundAndStructures);
// Check whenever the line doesn't cross lava (we don't want to be cooked!)
bool lava = GameWorld.TraceLine(top, bottom, GameWorld.CGWorldFrameHitFlags.HitTestLiquid2);
bool LOS = GameWorld.TraceLine(point, pool, GameWorld.CGWorldFrameHitFlags.HitTestLOS);
// True if there is a collision with a structure or ground
// and not with Liquid2 (lava). False otherwise
return groundOrLevel && !lava && LOS;
}
public static float? findNearestPointHeight(WoWPoint point, float minHeight) { return findNearestPointHeight(point, minHeight, Single.MaxValue); }
public static float? findNearestPointHeight(WoWPoint point, float minHeight, float maxDiff)
{
List<float> heights = Navigator.FindHeights(point.X, point.Y);
// No heights found, return null as "not found"
if (heights.Count == 0)
return null;
// Only one height found, return it
if (heights.Count == 1)
return heights.First();
float? candidate = Single.MaxValue;
// Multiple heights, take the nearest from the minHeight
foreach (float height in heights)
{
float diff = height - minHeight;
// height is higher than minHeight, the difference
// is lower than the previous candidate and the diff
// is not out of bounds
if (diff <= maxDiff && diff > 0 && diff < (candidate - minHeight))
candidate = height;
}
// no candidate found
if (candidate != Single.MaxValue)
return null;
return candidate;
}
public static bool checkWoWPointStaticStay(WoWPoint point)
{
// Take 4 points around the one
// we're going to test, check whenever the
// Z difference is too high for staying on it
WoWPoint up, down, left, right;
up = down = left = right = point;
up.Y += 3.0F;
down.Y -= 3.0F;
left.X -= 3.0F;
right.X += 3.0F;
// Calculate points height
// Maximum tolerance 2 yards
// If any of the height are above or under 2 yards
// the check fails
float tolerance = 2.0F;
return findNearestPointHeight(up, up.Z - tolerance, tolerance) != null &&
findNearestPointHeight(down, down.Z - tolerance, tolerance) != null &&
findNearestPointHeight(left, left.Z - tolerance, tolerance) != null &&
findNearestPointHeight(right, right.Z - tolerance, tolerance) != null;
}
public static WoWPoint calculateLandingPoint(WoWPoint pool, List<WoWPoint> candidates)
{
Stopwatch sw = new Stopwatch();
sw.Start();
SharedData sd = SharedData.Instance;
bool[] groundResult, liquid2Result, losResult = {};
List<WorldLine> lines = new List<WorldLine>();
WoWPoint selected = WoWPoint.Empty;
foreach (WoWPoint point in candidates)
{
WoWPoint top, bottom;
top = bottom = point;
top.Z += 3.0F;
bottom.Z -= 2.0F;
lines.Add(new WorldLine(top, bottom));
}
GameWorld.MassTraceLine(lines.ToArray(), GameWorld.CGWorldFrameHitFlags.HitTestGroundAndStructures, out groundResult);
GameWorld.MassTraceLine(lines.ToArray(), GameWorld.CGWorldFrameHitFlags.HitTestLiquid2, out liquid2Result);
GameWorld.MassTraceLine(lines.ToArray(), GameWorld.CGWorldFrameHitFlags.HitTestLOS, out losResult);
for (int i = 0; i < groundResult.Count(); i++)
{
if (groundResult[i] && !liquid2Result[i] && losResult[i] && checkWoWPointStaticStay(candidates[i]))
{
if (selected == WoWPoint.Empty || ObjectManager.Me.Location.Distance(candidates[i]) < ObjectManager.Me.Location.Distance(selected))
selected = candidates[i];
}
}
DebugLog("I took {0}ms to calculate {1} WoWPoints.", sw.ElapsedMilliseconds, candidates.Count);
return selected;
}
public static WoWPoint getNearestLandingPointFromPool(WoWObject pool)
{
Stopwatch sw = new Stopwatch();
sw.Start();
/* Check all around the pool in circles, with variable angles,
* searching for a valid point where to cast
* Fishing, starting from 10 up to 20 yards (step: 1 yard).
*
* Return the nearest WoWPoint if found, WoWPoint.Empty otherwise.
*/
LocalPlayer Me = ObjectManager.Me;
WoWPoint candidate = new WoWPoint();
List<WoWPoint> candidates = new List<WoWPoint>();
SharedData sd = SharedData.Instance;
DebugLog("Searching for a valid landing point around pool at {0}", pool.Location);
// Circles cycle
// from 10 to 20 yards, step = 1 yards
// This will fill the possible candidates
for (int range = 10; range <= 20; range++)
{
// 35? (10yrd) -> 25? (20yrd)
float radians = WoWMathHelper.DegreesToRadians(35.0F + 10.0F - (float)range);
int totalChecks = (int)(2 * Math.PI / radians);
for (int i = 0; i < totalChecks; i++)
{
// Before inserting the point, calculate its height
candidate = pool.Location.RayCast(radians * i, range);
float? height = findNearestPointHeight(candidate, pool.Location.Z);
if (height != null)
{
candidate.Z = height.Value;
candidates.Add(candidate);
}
}
}
// No candidates found
if (candidates.Count == 0)
{
DebugLog("No landing candidate found for pool at {0}", pool.Location);
return WoWPoint.Empty;
}
DebugLog("Calculating valid points ({0} possible candidates)...", candidates.Count);
// Check the candidates via a threaded method
candidate = calculateLandingPoint(pool.Location, candidates);
if (candidate == WoWPoint.Empty)
DebugLog("No landing point candidate found for pool at {0}", pool.Location);
return candidate;
}