Quantcast

Add MapUtils, an API abstraction for mapping data

James Whitehead II [12-06-10 - 18:20]
Add MapUtils, an API abstraction for mapping data

This API will attempt to use either LibMapData or Astrolabe as
appropriate, but these will likely go away entirely as the mapping API
for World of Warcraft is opened up.
Filename
MapUtils.lua
TomTomLite.lua
TomTomLite.toc
diff --git a/MapUtils.lua b/MapUtils.lua
new file mode 100644
index 0000000..be2a9db
--- /dev/null
+++ b/MapUtils.lua
@@ -0,0 +1,139 @@
+local addonName, addon = ...
+local L = addon.L
+
+local astrolabe = DongleStub("Astrolabe-1.0")
+local mapdata = LibStub("LibMapData-1.0")
+
+local PI2 = math.pi * 2
+
+-- This file is an API abstraction over the mapping system in World of
+-- Warcraft, however it does not aim to be a complete abstraction. Instead, we
+-- merely provide those functions that are relevant to TomTom, and try to
+-- provide a way for the necessary data to be obtained without care for how it
+-- is obtained.
+
+local function getDirection(xd, yd)
+    if not xd or not yd then
+        return nil
+    end
+
+    local angle = math.atan2(xd, -yd)
+    if angle > 0 then
+        angle = PI2 - angle
+    else
+        angle = -angle
+    end
+
+    return angle
+end
+
+-- Calculates the distance (in yards) and angle (in radians) between two points
+-- on the map. This may be two points within the same map file, or two points
+-- on different maps. In the case that the points are on different maps and
+-- there's no 'distance' that quite makes sense, this function will simply
+-- return nil
+
+function addon:GetVector(sm, sf, sx, sy, dm, df, dx, dy)
+    if smap == dmap and sfloor == dfloor then
+        -- The waypoints are on the same map, so calculate directly using map data
+
+        if mapdata then
+            local dist, xd, yd = mapdata:Distance(sm, sf, sx, sy, dx, dy)
+            local angle = getDirection(xd, yd)
+
+            if dist and angle then
+                return dist, angle
+            end
+        elseif astrolabe then
+            local dist, xd, yd = astrolabe:ComputeDistance(sm, sf, sx, sy, dm, df, dx, dy)
+            local angle = GetDirection(xd, yd)
+            if dist and angle then
+                return dist, angle
+            end
+        else
+            error("No map data available for 'GetVector'")
+        end
+    else
+        -- The waypoints are on different maps
+
+        if mapdata then
+            local dist, xd, yd = mapdata:DistanceWithinContinent(sm, sf, sx, sy, dm, df, dx, dy)
+            local angle = GetDirection(xd, yd)
+            if dist and angle then
+                return dist, angle
+            end
+        elseif astrolabe then
+            local dist, xd, yd = astrolabe:ComputeDistance(sm, sf, sx, sy, dm, df, dx, dy)
+            local angle = GetDistance(xd, yd)
+            if dist and angle then
+                return dist, angle
+            end
+        else
+            error("No map data available for 'GetVector'")
+        end
+    end
+end
+
+-- Get the distance (in yards) and angle (in radians) from the player's current
+-- position to a position on the map.
+
+function addon:GetVectorFromCurrent(map, floor, x, y)
+
+    -- First we need to obtain the player's current position. Attempt, at all
+    -- costs to do this without changing the map zoom, as it shouldn't be
+    -- necessary.
+
+    local cmap, cfloor = GetCurrentMapAreaID()
+    local cx, cy = GetPlayerMapPosition("player")
+
+    if map and floor and x and y then
+        return self:GetVector(cmap, cfloor, cx, cy, map, floor, x, y)
+    end
+end
+
+-- This function returns the display name for a given map. If the name is not
+-- available, then "Unknown map: %d" is displayed
+function addon:GetMapDisplayName(map)
+    if mapdata then
+        local name = mapdata:MapLocalize(map)
+        return name or string.format("Unknown map: %d", map)
+    elseif astrolabe then
+        return string.format("Unknown map: %d", map)
+    end
+end
+
+-- This data is hardcoded, and should be able to be automatically obtained
+local continents = {
+    -- Map for cosmic (both ways)
+    [WORLDMAP_COSMIC_ID] = -1,   -- Cosmic map (-1)
+
+    -- Map from mapId to continentIndex
+    [13] = 1,                    -- Kalimdor (1)
+    [14] = 2,                    -- Eastern Kingdoms (2)
+    [466] = 3,                   -- Outland (3)
+    [485] = 4,                   -- Northrend (4)
+    [751] = 5,                   -- Maelstrom (5)
+
+    -- Map from continentIndex to mapId
+    [1] = 13,
+    [2] = 14,
+    [3] = 466,
+    [4] = 485,
+    [5] = 751,
+}
+
+-- Returns if a given map file is a continent map
+function addon:IsContinentMap(map)
+    return not not continents[map]
+end
+
+-- Returns the continent map that 'owns' a given map. This does NOT return the
+-- continent index, but rather the continent map file.
+function addon:GetMapContinentMap(map)
+    if mapdata then
+        local cindex = mapdata:GetContinentFromMap(map)
+        local cmap = continents[cindex]
+        return cmap
+    elseif astrolabe then
+    end
+end
diff --git a/TomTomLite.lua b/TomTomLite.lua
index 6f3026e..110d7fa 100644
--- a/TomTomLite.lua
+++ b/TomTomLite.lua
@@ -6,7 +6,6 @@ local addonName, addon = ...
 local L = addon.L

 addon.callbacks = LibStub("CallbackHandler-1.0"):New(addon)
-addon.mapdata = LibStub("LibMapData-1.0")
 addon.libwindow = LibStub("LibWindow-1.1")

 -- Set up some tables to track waypoints
@@ -95,29 +94,8 @@ function addon:CreateCrazyArrow(name, parent)

     -- Set up the OnUpdate handler
     frame:SetScript("OnUpdate", function(self, elapsed)
-        -- Get the current location
-        local cmap = GetCurrentMapAreaID()
-        local cx, cy = GetPlayerMapPosition("player")
         local map, floor, x, y = unpack(self.waypoint)
-        if not (cmap and cx and cy and map and floor and x and y) then
-            -- This shouldn't happen, but bail out in this case
-            return
-        end
-
-        -- If on the cosmic map, do nothing
-        if cmap == -1 then
-            return
-        end
-
-
-        local distance, xd, yd = addon.mapdata:DistanceWithinContinent(cmap, 0, cx, cy, map, floor, x, y)
-
-        local angle = math.atan2(xd, yd)
-        if angle > 0 then
-            angle = PI2 - angle
-        else
-            angle = -angle
-        end
+        local distance, angle = addon:GetVectorFromCurrent(map, floor, x, y)

         local facing = GetPlayerFacing()
         local faceangle = angle - facing
@@ -215,7 +193,7 @@ function addon:UpdateArrow()
     if closest then
         -- Set the crazy arrow to display this waypoint
         local zone, floor, x, y = unpack(closest)
-        local lzone = self.mapdata:MapLocalize(zone)
+        local lzone = self:GetMapDisplayName(zone)

         self.arrow.waypoint = closest
         self.arrow.title:SetText(closest.title or L["Unknown waypoint"])
@@ -233,7 +211,7 @@ function addon:UpdateQuestObjectives()
     floor = floor or 0

     -- Do not set any NEW waypoints if we're on the continent map
-    if self.mapdata:IsContinentMap(map) then
+    if self:IsContinentMap(map) then
         return
     end

diff --git a/TomTomLite.toc b/TomTomLite.toc
index 345167b..ae036a0 100755
--- a/TomTomLite.toc
+++ b/TomTomLite.toc
@@ -17,6 +17,7 @@ libs\AceDB-3.0\AceDB-3.0.xml
 libs\LibMapData-1.0\library.lua
 libs\LibWindow-1.1.lua

+MapUtils.lua
 Utils.lua
 DatabaseDefaults.lua