From 1785f56e469f00c9b014eb21dcf067e42def35b6 Mon Sep 17 00:00:00 2001 From: Jim Whitehead Date: Wed, 20 Jul 2016 07:58:32 +0200 Subject: [PATCH] Updated embedded HereBeDragons --- libs/HereBeDragons-1.0/HereBeDragons-1.0.lua | 162 +++++++++++++++------ libs/HereBeDragons-1.0/HereBeDragons-Pins-1.0.lua | 40 +++-- 2 files changed, 150 insertions(+), 52 deletions(-) diff --git a/libs/HereBeDragons-1.0/HereBeDragons-1.0.lua b/libs/HereBeDragons-1.0/HereBeDragons-1.0.lua index caf5bff..3379d06 100755 --- a/libs/HereBeDragons-1.0/HereBeDragons-1.0.lua +++ b/libs/HereBeDragons-1.0/HereBeDragons-1.0.lua @@ -1,6 +1,6 @@ -- HereBeDragons is a data API for the World of Warcraft mapping system -local MAJOR, MINOR = "HereBeDragons-1.0", 11 +local MAJOR, MINOR = "HereBeDragons-1.0", 21 assert(LibStub, MAJOR .. " requires LibStub") local HereBeDragons, oldversion = LibStub:NewLibrary(MAJOR, MINOR) @@ -18,6 +18,8 @@ HereBeDragons.transforms = HereBeDragons.transforms or {} HereBeDragons.callbacks = CBH:New(HereBeDragons, nil, nil, false) +local IsLegion = select(4, GetBuildInfo()) >= 70000 + -- constants local TERRAIN_MATCH = "_terrain%d+$" @@ -43,13 +45,25 @@ local currentPlayerZoneMapID, currentPlayerLevel, currentMapFile, currentMapIsMi local instanceIDOverrides = { -- Draenor [1152] = 1116, -- Horde Garrison 1 - [1153] = 1116, -- Horde Garrison 2 - [1154] = 1116, -- Horde Garrison 3 + [1330] = 1116, -- Horde Garrison 2 + [1153] = 1116, -- Horde Garrison 3 + [1154] = 1116, -- Horde Garrison 4 (unused) [1158] = 1116, -- Alliance Garrison 1 - [1159] = 1116, -- Alliance Garrison 2 - [1160] = 1116, -- Alliance Garrison 3 + [1331] = 1116, -- Alliance Garrison 2 + [1159] = 1116, -- Alliance Garrison 3 + [1160] = 1116, -- Alliance Garrison 4 (unused) + [1191] = 1116, -- Ashran PvP Zone + [1203] = 1116, -- Frostfire Finale Scenario + [1207] = 1116, -- Talador Finale Scenario + [1277] = 1116, -- Defense of Karabor Scenario (SMV) + [1402] = 1116, -- Gorgrond Finale Scenario [1464] = 1116, -- Tanaan [1465] = 1116, -- Tanaan + -- Legion + [1478] = 1220, -- Temple of Elune Scenario (Val'Sharah) + [1502] = 1220, -- Dalaran Underbelly + [1533] = 0, -- Karazhan Artifact Scenario + [1612] = 1220, -- Feral Druid Artifact Scenario (Suramar) } -- unregister and store all WORLD_MAP_UPDATE registrants, to avoid excess processing when @@ -72,10 +86,11 @@ local function RestoreWMU() end -- gather map info, but only if this isn't an upgrade (or the upgrade version forces a re-map) -if not oldversion or oldversion < 10 then +if not oldversion or oldversion < 21 then -- wipe old data, if required, otherwise the upgrade path isn't triggered if oldversion then wipe(mapData) + wipe(microDungeons) end local MAPS_TO_REMAP = { @@ -163,6 +178,9 @@ if not oldversion or oldversion < 10 then mapData[id].instance = instanceID mapData[id].name = GetMapNameByID(id) + -- store the original instance id (ie. not remapped for map transforms) for micro dungeons + mapData[id].originalInstance = originalInstanceID + local mapFile = GetMapInfo() if mapFile then -- remove phased terrain from the map names @@ -177,10 +195,6 @@ if not oldversion or oldversion < 10 then mapData[id].Z = Z or -100 if mapData[id].C > 0 and mapData[id].Z >= 0 then - if not microDungeons[instanceID] then - microDungeons[instanceID] = {} - end - -- store C/Z lookup table if not continentZoneMap[C] then continentZoneMap[C] = {} @@ -190,25 +204,47 @@ if not oldversion or oldversion < 10 then end end - local numFloors = GetNumDungeonMapLevels() - if numFloors == 0 and GetCurrentMapDungeonLevel() == 1 then - numFloors = 1 - mapData[id].fakefloor = true + local floors + if IsLegion then + floors = { GetNumDungeonMapLevels() } + + -- offset floors for terrain map + if DungeonUsesTerrainMap() then + for i = 1, #floors do + floors[i] = floors[i] + 1 + end + end + else + floors = {} + for f = 1, GetNumDungeonMapLevels() do + floors[f] = f + end + end + if #floors == 0 and GetCurrentMapDungeonLevel() > 0 then + floors[1] = GetCurrentMapDungeonLevel() + mapData[id].fakefloor = GetCurrentMapDungeonLevel() end mapData[id].floors = {} - if numFloors > 0 then - for f = 1, numFloors do - SetDungeonMapLevel(f) - local _, right, bottom, left, top = GetCurrentMapDungeonLevel() - if left and top and right and bottom then - instanceID, left, right, top, bottom = applyMapTransforms(originalInstanceID, left, right, top, bottom) - mapData[id].floors[f] = { left - right, top - bottom, left, top } - mapData[id].floors[f].instance = mapData[id].instance - elseif f == 1 and DungeonUsesTerrainMap() then - mapData[id].floors[f] = { mapData[id][1], mapData[id][2], mapData[id][3], mapData[id][4] } - mapData[id].floors[f].instance = mapData[id].instance - end + mapData[id].numFloors = #floors + for i = 1, mapData[id].numFloors do + local f = floors[i] + SetDungeonMapLevel(f) + local _, right, bottom, left, top = GetCurrentMapDungeonLevel() + if left and top and right and bottom then + instanceID, left, right, top, bottom = applyMapTransforms(originalInstanceID, left, right, top, bottom) + mapData[id].floors[f] = { left - right, top - bottom, left, top } + mapData[id].floors[f].instance = mapData[id].instance + elseif f == 1 and DungeonUsesTerrainMap() then + mapData[id].floors[f] = { mapData[id][1], mapData[id][2], mapData[id][3], mapData[id][4] } + mapData[id].floors[f].instance = mapData[id].instance + end + end + + -- setup microdungeon storage if the its a zone map or has no floors of its own + if (mapData[id].C > 0 and mapData[id].Z > 0) or mapData[id].numFloors == 0 then + if not microDungeons[originalInstanceID] then + microDungeons[originalInstanceID] = {} end end end @@ -218,12 +254,13 @@ if not oldversion or oldversion < 10 then local floorIndex, minX, maxX, minY, maxY, terrainMapID, parentWorldMapID, flags = GetDungeonMapInfo(dID) -- apply transform + local originalTerrainMapID = terrainMapID terrainMapID, maxX, minX, maxY, minY = applyMapTransforms(terrainMapID, maxX, minX, maxY, minY) -- check if this zone can have microdungeons - if microDungeons[terrainMapID] then - microDungeons[terrainMapID][floorIndex] = { maxX - minX, maxY - minY, maxX, maxY } - microDungeons[terrainMapID][floorIndex].instance = terrainMapID + if microDungeons[originalTerrainMapID] then + microDungeons[originalTerrainMapID][floorIndex] = { maxX - minX, maxY - minY, maxX, maxY } + microDungeons[originalTerrainMapID][floorIndex].instance = terrainMapID end end end @@ -238,15 +275,38 @@ if not oldversion or oldversion < 10 then mapData[WORLDMAP_COSMIC_ID].Z = 0 mapData[WORLDMAP_COSMIC_ID].name = WORLD_MAP - -- fake world map - mapData[WORLDMAP_AZEROTH_ID] = {0, 0, 0, 0} - mapData[WORLDMAP_AZEROTH_ID].instance = -1 + -- fake azeroth world map + -- the world map has one "floor" per continent it contains, which allows + -- using these floors to translate coordinates from and to the world map. + -- note: due to artistic differences in the drawn azeroth maps, the values + -- used for the continents are estimates and not perfectly accurate + mapData[WORLDMAP_AZEROTH_ID] = { 63570, 42382, 53730, 19600 } -- Eastern Kingdoms, or floor 0 + mapData[WORLDMAP_AZEROTH_ID].floors = { + -- Kalimdor + [1] = { 65700, 43795, 11900, 23760, instance = 1 }, + -- Northrend + [571] = { 65700, 43795, 33440, 11960, instance = 571 }, + -- Pandaria + [870] = { 58520, 39015, 29070, 34410, instance = 870 }, + -- Broken Isles + [1220] = { 96710, 64476, 63100, 29960, instance = 1220 }, + } + mapData[WORLDMAP_AZEROTH_ID].instance = 0 mapData[WORLDMAP_AZEROTH_ID].mapFile = "World" - mapData[WORLDMAP_AZEROTH_ID].floors = {} mapData[WORLDMAP_AZEROTH_ID].C = 0 mapData[WORLDMAP_AZEROTH_ID].Z = 0 mapData[WORLDMAP_AZEROTH_ID].name = WORLD_MAP + -- we only have data for legion clients, zeroing the coordinates + -- and niling out the floors temporarily disables the logic on live + if not IsLegion then + mapData[WORLDMAP_AZEROTH_ID][1] = 0 + mapData[WORLDMAP_AZEROTH_ID][2] = 0 + mapData[WORLDMAP_AZEROTH_ID][3] = 0 + mapData[WORLDMAP_AZEROTH_ID][4] = 0 + mapData[WORLDMAP_AZEROTH_ID].floors = {} + end + -- alliance draenor garrison if mapData[971] then mapData[971].Z = 5 @@ -338,15 +398,15 @@ local function getMapDataTable(mapID, level) local data = mapData[mapID] if not data then return nil end - if (level == nil or level == 0) and data.fakefloor then - level = 1 + if (type(level) ~= "number" or level == 0) and data.fakefloor then + level = data.fakefloor end - if level and level > 0 then + if type(level) == "number" and level > 0 then if data.floors[level] then return data.floors[level] - elseif microDungeons[data.instance] and microDungeons[data.instance][level] then - return microDungeons[data.instance][level] + elseif data.originalInstance and microDungeons[data.originalInstance] and microDungeons[data.originalInstance][level] then + return microDungeons[data.originalInstance][level] end else return data @@ -490,9 +550,9 @@ function HereBeDragons:GetNumFloors(mapID) mapID = mapToID[mapID] end - if not mapData[mapID] then return 0 end + if not mapData[mapID] or not mapData[mapID].numFloors then return 0 end - return #(mapData[mapID].floors) + return mapData[mapID].numFloors end --- Get a list of all map IDs @@ -616,12 +676,28 @@ function HereBeDragons:GetWorldVector(instanceID, oX, oY, dX, dY) return angle, distance end +--- Get the current world position of the specified unit +-- The position is transformed to the current continent, if applicable +-- NOTE: The same restrictions as for the UnitPosition() API apply, +-- which means a very limited set of unit ids will actually work. +-- @param unitId Unit Id +-- @return x, y, instanceID +function HereBeDragons:GetUnitWorldPosition(unitId) + -- get the current position + local y, x, z, instanceID = UnitPosition(unitId) + if not x or not y then return nil, nil, nil end + + -- return transformed coordinates + return applyCoordinateTransforms(x, y, instanceID) +end + --- Get the current world position of the player -- The position is transformed to the current continent, if applicable -- @return x, y, instanceID function HereBeDragons:GetPlayerWorldPosition() -- get the current position local y, x, z, instanceID = UnitPosition("player") + if not x or not y then return nil, nil, nil end -- return transformed coordinates return applyCoordinateTransforms(x, y, instanceID) @@ -636,12 +712,14 @@ end --- Get the current position of the player on a zone level -- The returned values are local point coordinates, 0-1. The mapFile can represent a micro dungeon. +-- @param allowOutOfBounds Allow coordinates to go beyond the current map (ie. outside of the 0-1 range), otherwise nil will be returned -- @return x, y, mapID, level, mapFile, isMicroDungeon -function HereBeDragons:GetPlayerZonePosition() +function HereBeDragons:GetPlayerZonePosition(allowOutOfBounds) if not currentPlayerZoneMapID then return nil, nil, nil, nil end local x, y, instanceID = self:GetPlayerWorldPosition() + if not x or not y then return nil, nil, nil, nil end - x, y = self:GetZoneCoordinatesFromWorld(x, y, currentPlayerZoneMapID, currentPlayerLevel) + x, y = self:GetZoneCoordinatesFromWorld(x, y, currentPlayerZoneMapID, currentPlayerLevel, allowOutOfBounds) if x and y then return x, y, currentPlayerZoneMapID, currentPlayerLevel, currentMapFile, currentMapIsMicroDungeon end diff --git a/libs/HereBeDragons-1.0/HereBeDragons-Pins-1.0.lua b/libs/HereBeDragons-1.0/HereBeDragons-Pins-1.0.lua index 53f2216..cc004d8 100755 --- a/libs/HereBeDragons-1.0/HereBeDragons-Pins-1.0.lua +++ b/libs/HereBeDragons-1.0/HereBeDragons-Pins-1.0.lua @@ -1,6 +1,6 @@ -- HereBeDragons-Pins is a library to show pins/icons on the world map and minimap -local MAJOR, MINOR = "HereBeDragons-Pins-1.0", 11 +local MAJOR, MINOR = "HereBeDragons-Pins-1.0", 13 assert(LibStub, MAJOR .. " requires LibStub") local pins, oldversion = LibStub:NewLibrary(MAJOR, MINOR) @@ -276,6 +276,13 @@ local function UpdateMinimapZoom() end local function PositionWorldMapIcon(icon, data, currentMapID, currentMapFloor) + -- special handling for the azeroth world map + -- translating coordinates to the azeroth map requires passing the instance ID + -- of the origin continent, so the appropriate coordinates can be calculated + if currentMapID == WORLDMAP_AZEROTH_ID then + currentMapFloor = data.instanceID + end + local x, y = HBD:GetZoneCoordinatesFromWorld(data.x, data.y, currentMapID, currentMapFloor) if x and y then icon:ClearAllPoints() @@ -286,10 +293,22 @@ local function PositionWorldMapIcon(icon, data, currentMapID, currentMapFloor) end end +local function GetWorldMapLocation() + local mapID, mapFloor = GetCurrentMapAreaID(), GetCurrentMapDungeonLevel() + + -- override the mapID for the azeroth world map + if mapID == -1 and GetCurrentMapContinent() == 0 and GetCurrentMapZone() == 0 then + mapID = WORLDMAP_AZEROTH_ID + mapFloor = 0 + end + + return mapID, mapFloor +end + local function UpdateWorldMap() if not WorldMapButton:IsVisible() then return end - local mapID, mapFloor = GetCurrentMapAreaID(), GetCurrentMapDungeonLevel() + local mapID, mapFloor = GetWorldMapLocation() -- not viewing a valid map if not mapID or mapID == -1 then @@ -305,7 +324,7 @@ local function UpdateWorldMap() worldmapHeight = WorldMapButton:GetHeight() for icon, data in pairs(worldmapPins) do - if instanceID == data.instanceID and (not data.floor or (data.floor == mapFloor and (data.floor == 0 or data.mapID == mapID))) then + if (instanceID == data.instanceID or mapID == WORLDMAP_AZEROTH_ID) and (not data.floor or (data.floor == mapFloor and (data.floor == 0 or data.mapID == mapID))) then PositionWorldMapIcon(icon, data, mapID, mapFloor) else icon:Hide() @@ -388,7 +407,7 @@ function pins:AddMinimapIconWorld(ref, icon, instanceID, x, y, floatOnEdge) minimapPinRegistry[ref][icon] = true - local t = newCachedTable() + local t = minimapPins[icon] or newCachedTable() t.instanceID = instanceID t.x = x t.y = y @@ -503,7 +522,7 @@ function pins:AddWorldMapIconWorld(ref, icon, instanceID, x, y) worldmapPinRegistry[ref][icon] = true - local t = newCachedTable() + local t = worldmapPins[icon] or newCachedTable() t.instanceID = instanceID t.x = x t.y = y @@ -513,8 +532,8 @@ function pins:AddWorldMapIconWorld(ref, icon, instanceID, x, y) worldmapPins[icon] = t if WorldMapButton:IsVisible() then - local currentMapID, currentMapFloor = GetCurrentMapAreaID(), GetCurrentMapDungeonLevel() - if currentMapID and HBD.mapData[currentMapID] and HBD.mapData[currentMapID].instance == instanceID then + local currentMapID, currentMapFloor = GetWorldMapLocation() + if currentMapID and HBD.mapData[currentMapID] and (HBD.mapData[currentMapID].instance == instanceID or currentMapID == WORLDMAP_AZEROTH_ID) then PositionWorldMapIcon(icon, t, currentMapID, currentMapFloor) else icon:Hide() @@ -550,7 +569,7 @@ function pins:AddWorldMapIconMF(ref, icon, mapID, mapFloor, x, y) worldmapPinRegistry[ref][icon] = true - local t = newCachedTable() + local t = worldmapPins[icon] or newCachedTable() t.instanceID = instanceID t.x = xCoord t.y = yCoord @@ -560,8 +579,9 @@ function pins:AddWorldMapIconMF(ref, icon, mapID, mapFloor, x, y) worldmapPins[icon] = t if WorldMapButton:IsVisible() then - local currentMapID, currentMapFloor = GetCurrentMapAreaID(), GetCurrentMapDungeonLevel() - if currentMapID and HBD.mapData[currentMapID] and HBD.mapData[currentMapID].instance == instanceID and (not mapFloor or (currentMapFloor == mapFloor and (mapFloor == 0 or currentMapID == mapID))) then + local currentMapID, currentMapFloor = GetWorldMapLocation() + if currentMapID and HBD.mapData[currentMapID] and (HBD.mapData[currentMapID].instance == instanceID or currentMapID == WORLDMAP_AZEROTH_ID) + and (not mapFloor or (currentMapFloor == mapFloor and (mapFloor == 0 or currentMapID == mapID))) then PositionWorldMapIcon(icon, t, currentMapID, currentMapFloor) else icon:Hide() -- 1.7.9.5