4 $Date: 2008-10-05 17:22:44 -0700 (Sun, 05 Oct 2008) $
5 Author(s): Esamynn (esamynn at wowinterface.com), Zorba (see questhelper docs)
6 Inspired By: Gatherer by Norganna
7 MapLibrary by Kristofer Karlsson (krka at kth.se)
8 Documentation: http://wiki.esamynn.org/Astrolabe
9 SVN: http://svn.esamynn.org/astrolabe/
11 This is a library for the World of Warcraft UI system to place
12 icons accurately on both the Minimap and on Worldmaps.
13 This library also manages and updates the position of Minimap icons
16 Modified to support Death Knight starting zone.
18 Copyright (C) 2006-2008 James Carrothers
21 This library is free software; you can redistribute it and/or
22 modify it under the terms of the GNU Lesser General Public
23 License as published by the Free Software Foundation; either
24 version 2.1 of the License, or (at your option) any later version.
26 This library is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 Lesser General Public License for more details.
31 You should have received a copy of the GNU Lesser General Public
32 License along with this library; if not, write to the Free Software
33 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
36 This library's source code is specifically designed to work with
37 World of Warcraft's interpreted AddOn system. You have an implicit
38 licence to use this library with these facilities since that is its
39 designated purpose as per:
40 http://www.fsf.org/licensing/licenses/gpl-faq.html#InterpreterIncompat
43 QuestHelper_File
["AstrolabeQH/Astrolabe.lua"] = "Development Version"
44 QuestHelper_Loadtime
["AstrolabeQH/Astrolabe.lua"] = GetTime()
47 -- DO NOT MAKE CHANGES TO THIS LIBRARY WITHOUT FIRST CHANGING THE LIBRARY_VERSION_MAJOR
48 -- STRING (to something unique) OR ELSE YOU MAY BREAK OTHER ADDONS THAT USE THIS LIBRARY!!!
49 local LIBRARY_VERSION_MAJOR
= "Astrolabe-0.4-QuestHelper"
50 local LIBRARY_VERSION_MINOR
= 105 -- this is a completely randomly chosen number, the only point being that it was larger than the original 92 and larger than the later 100
52 if not DongleStub
then error(LIBRARY_VERSION_MAJOR
.. " requires DongleStub.") end
53 if not DongleStub
:IsNewerVersion(LIBRARY_VERSION_MAJOR
, LIBRARY_VERSION_MINOR
) then return end
57 local Minimap
= _G
.Minimap
59 -- define local variables for Data Tables (defined at the end of this file)
60 local WorldMapSize
, MinimapSize
, ValidMinimapShapes
, VirtualContinentIndexes
;
62 function Astrolabe
:GetVersion()
63 return LIBRARY_VERSION_MAJOR
, LIBRARY_VERSION_MINOR
;
67 --------------------------------------------------------------------------------------------------------------
69 --------------------------------------------------------------------------------------------------------------
71 local configConstants
= {
72 MinimapUpdateMultiplier
= true,
75 -- this constant is multiplied by the current framerate to determine
76 -- how many icons are updated each frame
77 Astrolabe
.MinimapUpdateMultiplier
= 1;
80 --------------------------------------------------------------------------------------------------------------
82 --------------------------------------------------------------------------------------------------------------
84 Astrolabe
.LastPlayerPosition
= { 0, 0, 0, 0 };
85 Astrolabe
.MinimapIcons
= {};
86 Astrolabe
.IconsOnEdge
= {};
87 Astrolabe
.IconsOnEdge_GroupChangeCallbacks
= {};
89 Astrolabe
.MinimapIconCount
= 0
90 Astrolabe
.ForceNextUpdate
= false;
91 Astrolabe
.IconsOnEdgeChanged
= false;
93 -- This variable indicates whether we know of a visible World Map or not.
94 -- The state of this variable is controlled by the AstrolabeMapMonitor library.
95 Astrolabe
.WorldMapVisible
= false;
97 local AddedOrUpdatedIcons
= {}
98 local MinimapIconsMetatable
= { __index
= AddedOrUpdatedIcons
}
101 --------------------------------------------------------------------------------------------------------------
102 -- Local Pointers for often used API functions
103 --------------------------------------------------------------------------------------------------------------
105 local twoPi
= math
.pi
* 2;
106 local atan2 = math
.atan2;
107 local sin = math
.sin;
108 local cos = math
.cos;
109 local abs = math
.abs;
110 local sqrt = math
.sqrt;
113 local yield
= coroutine
.yield
114 local GetFramerate
= GetFramerate
117 --------------------------------------------------------------------------------------------------------------
118 -- Internal Utility Functions
119 --------------------------------------------------------------------------------------------------------------
121 local function assert(level
,condition
,message
)
122 if not condition
then
127 local function argcheck(value
, num
, ...)
128 assert(1, type(num
) == "number", "Bad argument #2 to 'argcheck' (number expected, got " .. type(level
) .. ")")
130 for i
=1,select("#", ...) do
131 if type(value
) == select(i
, ...) then return end
134 local types
= strjoin(", ", ...)
135 local name
= string.match(debugstack(2,2,0), ": in function [`<](.-)['>]")
136 error(string.format("Bad argument #%d to 'Astrolabe.%s' (%s expected, got %s)", num
, name
, types
, type(value
)), 3)
139 local function getContPosition( zoneData
, z
, x
, y
)
141 zoneData
= zoneData
[z
];
142 x
= x
* zoneData
.width
+ zoneData
.xOffset
;
143 y
= y
* zoneData
.height
+ zoneData
.yOffset
;
145 x
= x
* zoneData
.width
;
146 y
= y
* zoneData
.height
;
151 --------------------------------------------------------------------------------------------------------------
152 -- Virtual Continent Functions
153 --------------------------------------------------------------------------------------------------------------
155 function Astrolabe
:GetCurrentVirtualMapCZ()
156 local C
, Z
= GetCurrentMapContinent(), GetCurrentMapZone();
157 if C
== -1 and Z
== 0 then
159 local mapname
= GetMapInfo()
160 if VirtualContinentIndexes
[mapname
] and GetCurrentMapDungeonLevel() == 0 then
161 C
= VirtualContinentIndexes
[mapname
]
163 elseif mapname
and VirtualContinentIndexes
[mapname
.. GetCurrentMapDungeonLevel()] then
164 C
= VirtualContinentIndexes
[mapname
.. GetCurrentMapDungeonLevel()]
166 elseif mapname
== "CoTStratholme" and GetCurrentMapDungeonLevel() == 0 then
167 -- why do you gotta make me angry, baby
168 C
= VirtualContinentIndexes
["CoTStratholme2"]
175 function Astrolabe
:GetCurrentVirtualMapContinent() local C
, Z
= self
:GetCurrentVirtualMapCZ() return C
end
176 function Astrolabe
:GetCurrentVirtualMapZone() local C
, Z
= self
:GetCurrentVirtualMapCZ() return Z
end
178 -- Does much the same as GetMapContinents, but returns as an array and includes the virtual continents in the mix
179 function Astrolabe
:GetMapVirtualContinents()
180 local rv
= {GetMapContinents()}
181 for k
, v
in pairs(VirtualContinentIndexes
) do
182 rv
[v
] = k
.. "_Continent"
187 -- Does much the same as GetMapContinents, but returns as an array and includes the virtual continents in the mix
188 function Astrolabe
:GetMapVirtualZones(zone
)
189 for k
, v
in pairs(VirtualContinentIndexes
) do
195 return {GetMapZones(zone
)}
198 function Astrolabe
:GetMapTexture(c
, z
)
199 for k
, v
in pairs(VirtualContinentIndexes
) do
200 if v
== c
and z
== 0 then
201 return k
.. "_Continent"
202 elseif v
== c
and z
== 1 then
208 return (GetMapInfo())
211 --------------------------------------------------------------------------------------------------------------
212 -- General Utility Functions
213 --------------------------------------------------------------------------------------------------------------
215 function Astrolabe
:ComputeDistance( c1
, z1
, x1
, y1
, c2
, z2
, x2
, y2
)
216 QuestHelper
: Assert(c1
and z1
and x1
and y1
and c2
and z2
and x2
and y2
)
218 argcheck(c1, 2, "number");
219 assert(3, c1 >= 0, "ComputeDistance: Illegal continent index to c1: "..c1);
220 argcheck(z1, 3, "number", "nil");
221 argcheck(x1, 4, "number");
222 argcheck(y1, 5, "number");
223 argcheck(c2, 6, "number");
224 assert(3, c2 >= 0, "ComputeDistance: Illegal continent index to c2: "..c2);
225 argcheck(z2, 7, "number", "nil");
226 argcheck(x2, 8, "number");
227 argcheck(y2, 9, "number");
233 local dist
, xDelta
, yDelta
;
234 if ( c1
== c2
and z1
== z2
) then
235 -- points in the same zone
236 local zoneData
= WorldMapSize
[c1
];
238 zoneData
= zoneData
[z1
];
240 xDelta
= (x2
- x1
) * zoneData
.width
;
241 yDelta
= (y2
- y1
) * zoneData
.height
;
243 elseif ( c1
== c2
) then
244 -- points on the same continent
245 local zoneData
= WorldMapSize
[c1
];
246 x1
, y1
= getContPosition(zoneData
, z1
, x1
, y1
);
247 x2
, y2
= getContPosition(zoneData
, z2
, x2
, y2
);
251 elseif ( c1
and c2
) then
252 local cont1
= WorldMapSize
[c1
];
253 local cont2
= WorldMapSize
[c2
];
254 if ( cont1
.parentContinent
== cont2
.parentContinent
) then
255 x1
, y1
= getContPosition(cont1
, z1
, x1
, y1
);
256 x2
, y2
= getContPosition(cont2
, z2
, x2
, y2
);
257 if ( c1
~= cont1
.parentContinent
) then
258 x1
= x1
+ cont1
.xOffset
;
259 y1
= y1
+ cont1
.yOffset
;
261 if ( c2
~= cont2
.parentContinent
) then
262 x2
= x2
+ cont2
.xOffset
;
263 y2
= y2
+ cont2
.yOffset
;
271 if ( xDelta
and yDelta
) then
272 dist
= sqrt(xDelta
*xDelta
+ yDelta
*yDelta
);
274 return dist
, xDelta
, yDelta
;
277 function Astrolabe
:TranslateWorldMapPosition( C
, Z
, xPos
, yPos
, nC
, nZ
)
279 argcheck(C, 2, "number");
280 argcheck(Z, 3, "number", "nil");
281 argcheck(xPos, 4, "number");
282 argcheck(yPos, 5, "number");
283 argcheck(nC, 6, "number");
284 argcheck(nZ, 7, "number", "nil");
289 if ( nC
< 0 and nC
> -77 ) then
294 if ( C
== nC
and Z
== nZ
) then
297 elseif ( C
== nC
) then
298 -- points on the same continent
299 zoneData
= WorldMapSize
[C
];
300 xPos
, yPos
= getContPosition(zoneData
, Z
, xPos
, yPos
);
302 zoneData
= WorldMapSize
[C
][nZ
];
303 xPos
= xPos
- zoneData
.xOffset
;
304 yPos
= yPos
- zoneData
.yOffset
;
307 elseif ( C
and nC
) and ( WorldMapSize
[C
].parentContinent
== WorldMapSize
[nC
].parentContinent
) then
308 -- different continents, same world
309 zoneData
= WorldMapSize
[C
];
310 local parentContinent
= zoneData
.parentContinent
;
311 xPos
, yPos
= getContPosition(zoneData
, Z
, xPos
, yPos
);
312 if ( C
~= parentContinent
) then
313 -- translate up to world map if we aren't there already
314 xPos
= xPos
+ zoneData
.xOffset
;
315 yPos
= yPos
+ zoneData
.yOffset
;
316 zoneData
= WorldMapSize
[parentContinent
];
318 if ( nC
~= parentContinent
) then
319 -- translate down to the new continent
320 zoneData
= WorldMapSize
[nC
];
321 xPos
= xPos
- zoneData
.xOffset
;
322 yPos
= yPos
- zoneData
.yOffset
;
324 zoneData
= zoneData
[nZ
];
325 xPos
= xPos
- zoneData
.xOffset
;
326 yPos
= yPos
- zoneData
.yOffset
;
334 return (xPos
/ zoneData
.width
), (yPos
/ zoneData
.height
);
337 function Astrolabe
:GetAbsoluteContinentPosition( C
, Z
, xPos
, yPos
)
338 if C
== -1 then -- We're in a battleground that doesn't have a virtual continent, we're just kind of fucked.
342 assert(0, type(WorldMapSize
[C
].parentContinent
) == "number")
344 local x
, y
= Astrolabe
:TranslateWorldMapPosition(C
, Z
, xPos
, yPos
, WorldMapSize
[C
].parentContinent
, 0)
345 if not x
or not y
then return end
346 local zoneData
= WorldMapSize
[WorldMapSize
[C
].parentContinent
]
347 return WorldMapSize
[C
].parentContinent
, (x
* zoneData
.width
), (y
* zoneData
.height
)
350 function Astrolabe
:FromAbsoluteContinentPosition(C
, xPos
, yPos
)
351 return C
, xPos
/ WorldMapSize
[C
].width
, yPos
/ WorldMapSize
[C
].height
354 function Astrolabe
:GetZoneWidth(c
, z
)
356 return WorldMapSize
[c
][z
].width
358 return WorldMapSize
[c
].width
362 --*****************************************************************************
363 -- This function will do its utmost to retrieve some sort of valid position
364 -- for the specified unit, including changing the current map zoom (if needed).
365 -- Map Zoom is returned to its previous setting before this function returns.
366 --*****************************************************************************
367 function Astrolabe
:GetUnitPosition( unit
, noMapChange
)
368 local x
, y
= GetPlayerMapPosition(unit
);
369 if ( x
<= 0 and y
<= 0 ) then
370 if ( noMapChange
) then
371 -- no valid position on the current map, and we aren't allowed
372 -- to change map zoom, so return
375 local lastCont
, lastZone
= GetCurrentMapContinent(), GetCurrentMapZone();
376 SetMapToCurrentZone();
377 x
, y
= GetPlayerMapPosition(unit
);
378 if ( x
<= 0 and y
<= 0 ) then
379 SetMapZoom(GetCurrentMapContinent());
380 x
, y
= GetPlayerMapPosition(unit
);
381 if ( x
<= 0 and y
<= 0 ) then
382 -- we are in an instance or otherwise off the continent map
386 local C
, Z
= GetCurrentMapContinent(), GetCurrentMapZone();
387 if ( C
~= lastCont
or Z
~= lastZone
) then
388 SetMapZoom(lastCont
, lastZone
); -- set map zoom back to what it was before
392 return self
:GetCurrentVirtualMapContinent(), self
:GetCurrentVirtualMapZone(), x
, y
;
395 --*****************************************************************************
396 -- This function will do its utmost to retrieve some sort of valid position
397 -- for the specified unit, including changing the current map zoom (if needed).
398 -- However, if a monitored WorldMapFrame (See AstrolabeMapMonitor.lua) is
399 -- visible, then will simply return nil if the current zoom does not provide
400 -- a valid position for the player unit. Map Zoom is returned to its previous
401 -- setting before this function returns, if it was changed.
402 --*****************************************************************************
403 function Astrolabe
:GetCurrentPlayerPosition()
404 local x
, y
= GetPlayerMapPosition("player");
405 if ( x
<= 0 and y
<= 0 ) then
406 if ( self
.WorldMapVisible
) then
407 -- we know there is a visible world map, so don't cause
408 -- WORLD_MAP_UPDATE events by changing map zoom
411 local lastCont
, lastZone
= GetCurrentMapContinent(), GetCurrentMapZone();
412 SetMapToCurrentZone();
413 x
, y
= GetPlayerMapPosition("player");
414 if ( x
<= 0 and y
<= 0 ) then
415 SetMapZoom(GetCurrentMapContinent());
416 x
, y
= GetPlayerMapPosition("player");
417 if ( x
<= 0 and y
<= 0 ) then
418 -- we are in an instance or otherwise off the continent map
422 local C
, Z
= GetCurrentMapContinent(), GetCurrentMapZone();
424 if ( C
~= lastCont
or Z
~= lastZone
) then
425 SetMapZoom(lastCont
, lastZone
); --set map zoom back to what it was before
430 return self
:GetCurrentVirtualMapContinent(), self
:GetCurrentVirtualMapZone(), x
, y
;
434 --------------------------------------------------------------------------------------------------------------
435 -- Working Table Cache System
436 --------------------------------------------------------------------------------------------------------------
438 local tableCache
= {};
439 tableCache
["__mode"] = "v";
440 setmetatable(tableCache
, tableCache
);
442 local function GetWorkingTable( icon
)
443 if ( tableCache
[icon
] ) then
444 return tableCache
[icon
];
447 tableCache
[icon
] = T
;
453 --------------------------------------------------------------------------------------------------------------
454 -- Minimap Icon Placement
455 --------------------------------------------------------------------------------------------------------------
457 --*****************************************************************************
458 -- local variables specifically for use in this section
459 --*****************************************************************************
460 local minimapRotationEnabled
= false;
461 local minimapShape
= false;
463 local MinimapCompassTexture
= MinimapCompassTexture
;
464 local MinimapCompassRing
= MiniMapCompassRing
;
465 function Astrolabe
:GetFacing()
466 if MinimapCompassRing
then -- 3.1 hackery
467 return MinimapCompassRing
:GetFacing()
469 return -GetPlayerFacing()
472 local minimapRotationOffset
= -Astrolabe
.GetFacing()
474 local function placeIconOnMinimap( minimap
, minimapZoom
, mapWidth
, mapHeight
, icon
, dist
, xDist
, yDist
)
476 if ( Astrolabe
.minimapOutside
) then
477 mapDiameter
= MinimapSize
.outdoor
[minimapZoom
];
479 mapDiameter
= MinimapSize
.indoor
[minimapZoom
];
481 local mapRadius
= mapDiameter
/ 2;
482 local xScale
= mapDiameter
/ mapWidth
;
483 local yScale
= mapDiameter
/ mapHeight
;
484 local iconDiameter
= ((icon
:GetWidth() / 2) + 3) * xScale
;
485 local iconOnEdge
= nil;
486 local isRound
= true;
488 if ( minimapRotationEnabled
) then
489 local sinTheta
= sin(minimapRotationOffset
)
490 local cosTheta
= cos(minimapRotationOffset
)
493 The math that is acutally going on in the next 3 lines is:
494 local dx, dy = xDist, -yDist
495 xDist = (dx * cosTheta) + (dy * sinTheta)
496 yDist = -((-dx * sinTheta) + (dy * cosTheta))
498 This is because the origin for map coordinates is the top left corner
499 of the map, not the bottom left, and so we have to reverse the vertical
500 distance when doing the our rotation, and then reverse the result vertical
501 distance because this rotation formula gives us a result with the origin based
502 in the bottom left corner (of the (+, +) quadrant).
503 The actual code is a simplification of the above.
505 local dx
, dy
= xDist
, yDist
506 xDist
= (dx
* cosTheta
) - (dy
* sinTheta
)
507 yDist
= (dx
* sinTheta
) + (dy
* cosTheta
)
510 if ( minimapShape
and not (xDist
== 0 or yDist
== 0) ) then
511 isRound
= (xDist
< 0) and 1 or 3;
512 if ( yDist
< 0 ) then
513 isRound
= minimapShape
[isRound
];
515 isRound
= minimapShape
[isRound
+ 1];
519 -- for non-circular portions of the Minimap edge
520 if not ( isRound
) then
521 dist
= max(abs(xDist
), abs(yDist
))
524 if ( (dist
+ iconDiameter
) > mapRadius
) then
525 -- position along the outside of the Minimap
527 local factor
= (mapRadius
- iconDiameter
) / dist
;
528 xDist
= xDist
* factor
;
529 yDist
= yDist
* factor
;
532 if ( Astrolabe
.IconsOnEdge
[icon
] ~= iconOnEdge
) then
533 Astrolabe
.IconsOnEdge
[icon
] = iconOnEdge
;
534 Astrolabe
.IconsOnEdgeChanged
= true;
537 icon
:ClearAllPoints();
538 icon
:SetPoint("CENTER", minimap
, "CENTER", xDist
/xScale
, -yDist
/yScale
);
541 function Astrolabe
:PlaceIconOnMinimap( icon
, continent
, zone
, xPos
, yPos
)
542 -- check argument types
543 argcheck(icon
, 2, "table");
544 assert(3, icon
.SetPoint
and icon
.ClearAllPoints
, "Usage Message");
545 argcheck(continent
, 3, "number");
546 argcheck(zone
, 4, "number", "nil");
547 argcheck(xPos
, 5, "number");
548 argcheck(yPos
, 6, "number");
550 local lC
, lZ
, lx
, ly
= unpack(self
.LastPlayerPosition
);
551 local dist
, xDist
, yDist
= self
:ComputeDistance(lC
, lZ
, lx
, ly
, continent
, zone
, xPos
, yPos
);
553 --icon's position has no meaningful position relative to the player's current location
557 local iconData
= GetWorkingTable(icon
);
558 if ( self
.MinimapIcons
[icon
] ) then
559 self
.MinimapIcons
[icon
] = nil;
561 self
.MinimapIconCount
= self
.MinimapIconCount
+ 1
564 -- We know this icon's position is valid, so we need to make sure the icon placement
565 -- system is active. We call this here so that if this is the first icon being added to
566 -- an empty buffer, the full recalc will not completely redo the work done by this function
567 -- because the icon has not yet actually been placed in the buffer.
568 self
.processingFrame
:Show()
570 AddedOrUpdatedIcons
[icon
] = iconData
571 iconData
.continent
= continent
;
572 iconData
.zone
= zone
;
573 iconData
.xPos
= xPos
;
574 iconData
.yPos
= yPos
;
575 iconData
.dist
= dist
;
576 iconData
.xDist
= xDist
;
577 iconData
.yDist
= yDist
;
579 minimapRotationEnabled
= GetCVar("rotateMinimap") ~= "0"
580 if ( minimapRotationEnabled
) then
581 minimapRotationOffset
= -Astrolabe
.GetFacing()
584 -- check Minimap Shape
585 minimapShape
= GetMinimapShape
and ValidMinimapShapes
[GetMinimapShape()];
587 -- place the icon on the Minimap and :Show() it
589 placeIconOnMinimap(map
, map
:GetZoom(), map
:GetWidth(), map
:GetHeight(), icon
, dist
, xDist
, yDist
);
595 function Astrolabe
:RemoveIconFromMinimap( icon
)
596 if not ( self
.MinimapIcons
[icon
] ) then
599 AddedOrUpdatedIcons
[icon
] = nil
600 self
.MinimapIcons
[icon
] = nil;
601 self
.IconsOnEdge
[icon
] = nil;
604 local MinimapIconCount
= self
.MinimapIconCount
- 1
605 if ( MinimapIconCount
<= 0 ) then
606 -- no icons left to manage
607 self
.processingFrame
:Hide()
608 MinimapIconCount
= 0 -- because I'm paranoid
610 self
.MinimapIconCount
= MinimapIconCount
615 function Astrolabe
:RemoveAllMinimapIcons()
616 self
:DumpNewIconsCache()
617 local MinimapIcons
= self
.MinimapIcons
;
618 local IconsOnEdge
= self
.IconsOnEdge
;
619 for k
, v
in pairs(MinimapIcons
) do
620 MinimapIcons
[k
] = nil;
621 IconsOnEdge
[k
] = nil;
624 self
.MinimapIconCount
= 0
625 self
.processingFrame
:Hide()
628 local lastZoom
; -- to remember the last seen Minimap zoom level
630 -- local variables to track the status of the two update coroutines
631 local fullUpdateInProgress
= true
632 local resetIncrementalUpdate
= false
633 local resetFullUpdate
= false
635 -- Incremental Update Code
637 -- local variables to track the incremental update coroutine
638 local incrementalUpdateCrashed
= true
639 local incrementalUpdateThread
641 local function UpdateMinimapIconPositions( self
)
645 self
:DumpNewIconsCache() -- put new/updated icons into the main datacache
647 resetIncrementalUpdate
= false -- by definition, the incremental update is reset if it is here
649 local C
, Z
, x
, y
= self
:GetCurrentPlayerPosition();
650 if ( C
and C
~= -1 ) then
651 local lastPosition
= self
.LastPlayerPosition
;
652 local lC
, lZ
, lx
, ly
= unpack(lastPosition
);
654 minimapRotationEnabled
= GetCVar("rotateMinimap") ~= "0"
655 if ( minimapRotationEnabled
) then
656 minimapRotationOffset
= -Astrolabe
.GetFacing()
659 -- check current frame rate
660 local numPerCycle
= min(50, GetFramerate() * (self
.MinimapUpdateMultiplier
or 1))
662 -- check Minimap Shape
663 minimapShape
= GetMinimapShape
and ValidMinimapShapes
[GetMinimapShape()];
665 if ( lC
== C
and lZ
== Z
and lx
== x
and ly
== y
) then
666 -- player has not moved since the last update
667 if ( lastZoom
~= Minimap
:GetZoom() or self
.ForceNextUpdate
or minimapRotationEnabled
) then
668 local currentZoom
= Minimap
:GetZoom();
669 lastZoom
= currentZoom
;
670 local mapWidth
= Minimap
:GetWidth();
671 local mapHeight
= Minimap
:GetHeight();
672 numPerCycle
= numPerCycle
* 2
674 for icon
, data
in pairs(self
.MinimapIcons
) do
675 placeIconOnMinimap(Minimap
, currentZoom
, mapWidth
, mapHeight
, icon
, data
.dist
, data
.xDist
, data
.yDist
);
678 if ( count
> numPerCycle
) then
681 -- check if the incremental update cycle needs to be reset
682 -- because a full update has been run
683 if ( resetIncrementalUpdate
) then
688 self
.ForceNextUpdate
= false;
691 local dist
, xDelta
, yDelta
= self
:ComputeDistance(lC
, lZ
, lx
, ly
, C
, Z
, x
, y
);
693 local currentZoom
= Minimap
:GetZoom();
694 lastZoom
= currentZoom
;
695 local mapWidth
= Minimap
:GetWidth();
696 local mapHeight
= Minimap
:GetHeight();
698 for icon
, data
in pairs(self
.MinimapIcons
) do
699 local xDist
= data
.xDist
- xDelta
;
700 local yDist
= data
.yDist
- yDelta
;
701 local dist
= sqrt(xDist
*xDist
+ yDist
*yDist
);
702 placeIconOnMinimap(Minimap
, currentZoom
, mapWidth
, mapHeight
, icon
, dist
, xDist
, yDist
);
709 if ( count
>= numPerCycle
) then
712 -- check if the incremental update cycle needs to be reset
713 -- because a full update has been run
714 if ( resetIncrementalUpdate
) then
719 if not ( resetIncrementalUpdate
) then
726 self
:RemoveAllMinimapIcons()
734 if not ( self
.WorldMapVisible
) then
735 self
.processingFrame
:Hide();
739 -- if we've been reset, then we want to start the new cycle immediately
740 if not ( resetIncrementalUpdate
) then
746 function Astrolabe
:UpdateMinimapIconPositions()
747 if ( fullUpdateInProgress
) then
748 -- if we're in the middle a a full update, we want to finish that first
749 self
:CalculateMinimapIconPositions()
751 if ( incrementalUpdateCrashed
) then
752 incrementalUpdateThread
= coroutine
.wrap(UpdateMinimapIconPositions
)
753 incrementalUpdateThread(self
) --initialize the thread
755 incrementalUpdateCrashed
= true
756 incrementalUpdateThread()
757 incrementalUpdateCrashed
= false
764 -- local variables to track the full update coroutine
765 local fullUpdateCrashed
= true
766 local fullUpdateThread
768 local function CalculateMinimapIconPositions( self
)
772 self
:DumpNewIconsCache() -- put new/updated icons into the main datacache
774 resetFullUpdate
= false -- by definition, the full update is reset if it is here
776 fullUpdateInProgress
= true -- set the flag the says a full update is in progress
778 local C
, Z
, x
, y
= self
:GetCurrentPlayerPosition();
779 if ( C
and C
~= -1 ) then
780 minimapRotationEnabled
= GetCVar("rotateMinimap") ~= "0"
781 if ( minimapRotationEnabled
) then
782 minimapRotationOffset
= Astrolabe
.GetFacing()
785 -- check current frame rate
786 local numPerCycle
= GetFramerate() * (self
.MinimapUpdateMultiplier
or 1) * 2
788 -- check Minimap Shape
789 minimapShape
= GetMinimapShape
and ValidMinimapShapes
[GetMinimapShape()];
791 local currentZoom
= Minimap
:GetZoom();
792 lastZoom
= currentZoom
;
793 local mapWidth
= Minimap
:GetWidth();
794 local mapHeight
= Minimap
:GetHeight();
796 for icon
, data
in pairs(self
.MinimapIcons
) do
797 local dist
, xDist
, yDist
= self
:ComputeDistance(C
, Z
, x
, y
, data
.continent
, data
.zone
, data
.xPos
, data
.yPos
);
799 placeIconOnMinimap(Minimap
, currentZoom
, mapWidth
, mapHeight
, icon
, dist
, xDist
, yDist
);
805 self
:RemoveIconFromMinimap(icon
)
809 if ( count
>= numPerCycle
) then
812 -- check if we need to restart due to the full update being reset
813 if ( resetFullUpdate
) then
819 if not ( resetFullUpdate
) then
820 local lastPosition
= self
.LastPlayerPosition
;
826 resetIncrementalUpdate
= true
829 if not ( self
.WorldMapVisible
) then
830 self
.processingFrame
:Hide();
834 -- if we've been reset, then we want to start the new cycle immediately
835 if not ( resetFullUpdate
) then
836 fullUpdateInProgress
= false
842 function Astrolabe
:CalculateMinimapIconPositions( reset
)
843 if ( fullUpdateCrashed
) then
844 fullUpdateThread
= coroutine
.wrap(CalculateMinimapIconPositions
)
845 fullUpdateThread(self
) --initialize the thread
846 elseif ( reset
) then
847 resetFullUpdate
= true
849 fullUpdateCrashed
= true
851 fullUpdateCrashed
= false
853 -- return result flag
854 if ( fullUpdateInProgress
) then
855 return 1 -- full update started, but did not complete on this cycle
858 if ( resetIncrementalUpdate
) then
859 return 0 -- update completed
861 return -1 -- full update did no occur for some reason
868 function Astrolabe
:GetDistanceToIcon( icon
)
869 local data
= self
.MinimapIcons
[icon
];
871 return data
.dist
, data
.xDist
, data
.yDist
;
875 function Astrolabe
:IsIconOnEdge( icon
)
876 return self
.IconsOnEdge
[icon
];
879 function Astrolabe
:GetDirectionToIcon( icon
)
880 local data
= self
.MinimapIcons
[icon
];
882 local dir
= atan2(data
.xDist
, -(data
.yDist
))
891 function Astrolabe
:Register_OnEdgeChanged_Callback( func
, ident
)
892 -- check argument types
893 argcheck(func
, 2, "function");
895 self
.IconsOnEdge_GroupChangeCallbacks
[func
] = ident
;
898 --*****************************************************************************
899 -- INTERNAL USE ONLY PLEASE!!!
900 -- Calling this function at the wrong time can cause errors
901 --*****************************************************************************
902 function Astrolabe
:DumpNewIconsCache()
903 local MinimapIcons
= self
.MinimapIcons
904 for icon
, data
in pairs(AddedOrUpdatedIcons
) do
905 MinimapIcons
[icon
] = data
906 AddedOrUpdatedIcons
[icon
] = nil
908 -- we now need to restart any updates that were in progress
909 resetIncrementalUpdate
= true
910 resetFullUpdate
= true
914 --------------------------------------------------------------------------------------------------------------
915 -- World Map Icon Placement
916 --------------------------------------------------------------------------------------------------------------
918 function Astrolabe
:PlaceIconOnWorldMap( worldMapFrame
, icon
, continent
, zone
, xPos
, yPos
)
919 -- check argument types
920 argcheck(worldMapFrame
, 2, "table");
921 assert(3, worldMapFrame
.GetWidth
and worldMapFrame
.GetHeight
, "Usage Message");
922 argcheck(icon
, 3, "table");
923 assert(3, icon
.SetPoint
and icon
.ClearAllPoints
, "Usage Message");
924 argcheck(continent
, 4, "number");
925 argcheck(zone
, 5, "number", "nil");
926 argcheck(xPos
, 6, "number");
927 argcheck(yPos
, 7, "number");
929 local C
, Z
= self
:GetCurrentVirtualMapCZ();
930 local nX
, nY
= self
:TranslateWorldMapPosition(continent
, zone
, xPos
, yPos
, C
, Z
);
932 -- anchor and :Show() the icon if it is within the boundry of the current map, :Hide() it otherwise
933 if ( nX
and nY
and (0 < nX
and nX
<= 1) and (0 < nY
and nY
<= 1) ) then
934 icon
:ClearAllPoints();
935 icon
:SetPoint("CENTER", worldMapFrame
, "TOPLEFT", nX
* worldMapFrame
:GetWidth(), -nY
* worldMapFrame
:GetHeight());
944 --------------------------------------------------------------------------------------------------------------
946 --------------------------------------------------------------------------------------------------------------
948 function Astrolabe
:OnEvent( frame
, event
)
949 if ( event
== "MINIMAP_UPDATE_ZOOM" ) then
950 -- update minimap zoom scale
951 local curZoom
= Minimap
:GetZoom();
952 if ( GetCVar("minimapZoom") == GetCVar("minimapInsideZoom") ) then
953 if ( curZoom
< 2 ) then
954 Minimap
:SetZoom(curZoom
+ 1);
956 Minimap
:SetZoom(curZoom
- 1);
959 if ( GetCVar("minimapZoom")+0 == Minimap
:GetZoom() ) then
960 self
.minimapOutside
= true;
962 self
.minimapOutside
= false;
964 Minimap
:SetZoom(curZoom
);
966 -- re-calculate all Minimap Icon positions
967 if ( frame
:IsVisible() ) then
968 self
:CalculateMinimapIconPositions(true);
971 elseif ( event
== "PLAYER_LEAVING_WORLD" ) then
972 frame
:Hide(); -- yes, I know this is redunant
973 self
:RemoveAllMinimapIcons(); --dump all minimap icons
975 elseif ( event
== "PLAYER_ENTERING_WORLD" ) then
977 if not ( frame
:IsVisible() ) then
978 -- do the minimap recalculation anyways if the OnShow script didn't execute
979 -- this is done to ensure the accuracy of information about icons that were
980 -- inserted while the Player was in the process of zoning
981 self
:CalculateMinimapIconPositions(true);
984 elseif ( event
== "ZONE_CHANGED_NEW_AREA" ) then
991 function Astrolabe
:OnUpdate( frame
, elapsed
)
992 -- on-edge group changed call-backs
993 if ( self
.IconsOnEdgeChanged
) then
994 self
.IconsOnEdgeChanged
= false;
995 for func
in pairs(self
.IconsOnEdge_GroupChangeCallbacks
) do
1000 self
:UpdateMinimapIconPositions();
1003 function Astrolabe
:OnShow( frame
)
1004 -- set the world map to a zoom with a valid player position
1005 if not ( self
.WorldMapVisible
) then
1006 SetMapToCurrentZone();
1008 local C
, Z
= Astrolabe
:GetCurrentPlayerPosition();
1009 if ( C
and C
~= -1 ) then
1010 if C
>= 0 then -- If we're in Wackyland, we can't change the world map anyway, so at least it's probably right
1018 -- re-calculate minimap icon positions
1019 self
:CalculateMinimapIconPositions(true);
1021 if ( self
.MinimapIconCount
<= 0 ) then
1022 -- no icons left to manage
1023 self
.processingFrame
:Hide()
1027 -- called by AstrolabMapMonitor when all world maps are hidden
1028 function Astrolabe
:AllWorldMapsHidden()
1029 if ( IsLoggedIn() ) then
1030 self
.processingFrame
:Hide();
1031 self
.processingFrame
:Show();
1035 function Astrolabe
:SetMinimapObject(minimap
)
1037 self
:UpdateMinimapIconPositions()
1040 --------------------------------------------------------------------------------------------------------------
1041 -- Library Registration
1042 --------------------------------------------------------------------------------------------------------------
1044 local function activate( newInstance
, oldInstance
)
1045 if ( oldInstance
) then -- this is an upgrade activate
1046 if ( oldInstance
.DumpNewIconsCache
) then
1047 oldInstance
:DumpNewIconsCache()
1049 for k
, v
in pairs(oldInstance
) do
1050 if ( type(v
) ~= "function" and (not configConstants
[k
]) ) then
1054 -- sync up the current MinimapIconCount value
1056 for _
in pairs(newInstance
.MinimapIcons
) do
1057 iconCount
= iconCount
+ 1
1059 newInstance
.MinimapIconCount
= iconCount
1061 Astrolabe
= oldInstance
;
1063 local frame
= CreateFrame("Frame");
1064 newInstance
.processingFrame
= frame
;
1066 newInstance
.ContinentList
= Astrolabe
:GetMapVirtualContinents();
1068 for C
in pairs(newInstance
.ContinentList
) do
1069 local zones
= Astrolabe
:GetMapVirtualZones(C
);
1070 newInstance
.ContinentList
[C
] = zones
;
1071 for Z
in ipairs(zones
) do
1072 zones
[Z
] = Astrolabe
:GetMapTexture(C
, Z
);
1076 configConstants
= nil -- we don't need this anymore
1078 local frame
= newInstance
.processingFrame
;
1080 frame
:SetParent("Minimap");
1081 frame
:UnregisterAllEvents();
1082 frame
:RegisterEvent("MINIMAP_UPDATE_ZOOM");
1083 frame
:RegisterEvent("PLAYER_LEAVING_WORLD");
1084 frame
:RegisterEvent("PLAYER_ENTERING_WORLD");
1085 frame
:RegisterEvent("ZONE_CHANGED_NEW_AREA");
1086 frame
:SetScript("OnEvent",
1087 function( frame
, event
, ... )
1088 Astrolabe
:OnEvent(frame
, event
, ...);
1091 frame
:SetScript("OnUpdate",
1092 function( frame
, elapsed
)
1093 Astrolabe
:OnUpdate(frame
, elapsed
);
1096 frame
:SetScript("OnShow",
1098 Astrolabe
:OnShow(frame
);
1102 setmetatable(Astrolabe
.MinimapIcons
, MinimapIconsMetatable
)
1105 --------------------------------------------------------------------------------------------------------------
1107 --------------------------------------------------------------------------------------------------------------
1109 -- diameter of the Minimap in game yards at
1110 -- the various possible zoom levels
1121 [0] = 466 + 2/3, -- scale
1123 [2] = 333 + 1/3, -- 1.4
1124 [3] = 266 + 2/6, -- 1.75
1126 [5] = 133 + 1/3, -- 3.5
1130 ValidMinimapShapes
= {
1131 -- { upper-left, lower-left, upper-right, lower-right }
1132 ["SQUARE"] = { false, false, false, false },
1133 ["CORNER-TOPLEFT"] = { true, false, false, false },
1134 ["CORNER-TOPRIGHT"] = { false, false, true, false },
1135 ["CORNER-BOTTOMLEFT"] = { false, true, false, false },
1136 ["CORNER-BOTTOMRIGHT"] = { false, false, false, true },
1137 ["SIDE-LEFT"] = { true, true, false, false },
1138 ["SIDE-RIGHT"] = { false, false, true, true },
1139 ["SIDE-TOP"] = { true, false, true, false },
1140 ["SIDE-BOTTOM"] = { false, true, false, true },
1141 ["TRICORNER-TOPLEFT"] = { true, true, true, false },
1142 ["TRICORNER-TOPRIGHT"] = { true, false, true, true },
1143 ["TRICORNER-BOTTOMLEFT"] = { true, true, false, true },
1144 ["TRICORNER-BOTTOMRIGHT"] = { false, true, true, true },
1147 -- distances across and offsets of the world maps
1150 -- World Map of Azeroth
1152 parentContinent
= 0,
1153 height
= 29688.932932224,
1154 width
= 44537.340058402,
1158 parentContinent
= 0,
1159 height
= 24533.025279205,
1160 width
= 36800.210572494,
1161 xOffset
= -8311.793923510446,
1162 yOffset
= 1815.215685280706,
1165 height
= 3843.722811451077,
1166 width
= 5766.728884700476,
1167 xOffset
= 15366.76755576002,
1168 yOffset
= 8126.925260781192,
1172 height
= 3381.225696279877,
1173 width
= 5070.888165752819,
1174 xOffset
= 20343.90485013144,
1175 yOffset
= 7458.180046130774,
1179 height
= 2714.561862167815,
1180 width
= 4070.883253576282,
1181 xOffset
= 9966.70736478994,
1182 yOffset
= 5460.278138661794,
1186 height
= 6756.202067150937,
1187 width
= 10133.44343943073,
1188 xOffset
= 14443.84117394525,
1189 yOffset
= 11187.32013604393,
1193 height
= 2174.984710698752,
1194 width
= 3262.517428121028,
1195 xOffset
= 9541.713418184554,
1196 yOffset
= 3424.874558234072,
1200 height
= 4366.636219106706,
1201 width
= 6550.06962983463,
1202 xOffset
= 14125.08809600818,
1203 yOffset
= 4466.534412478246,
1207 height
= 705.7248633938184,
1208 width
= 1058.342927027606,
1209 xOffset
= 14128.39258617903,
1210 yOffset
= 2561.565012455802,
1214 height
= 2997.895174253872,
1215 width
= 4495.882023201739,
1216 xOffset
= 12833.40729836031,
1217 yOffset
= 12347.72848626745,
1221 height
= 3524.975114832228,
1222 width
= 5287.558038649864,
1223 xOffset
= 19029.30699887344,
1224 yOffset
= 10991.48801260963,
1228 height
= 3499.975146240067,
1229 width
= 5250.057259791282,
1230 xOffset
= 18041.79657043901,
1231 yOffset
= 14833.12751666842,
1235 height
= 3833.305958270781,
1236 width
= 5750.062034325837,
1237 xOffset
= 15425.10163773161,
1238 yOffset
= 5666.526367166872,
1242 height
= 4633.30011661694,
1243 width
= 6950.075260353015,
1244 xOffset
= 11625.06045254075,
1245 yOffset
= 15166.45834829251,
1249 height
= 1539.572509508711,
1250 width
= 2308.356845256911,
1251 xOffset
= 18448.05172159372,
1252 yOffset
= 4308.20254319874,
1256 height
= 3424.975945100366,
1257 width
= 5137.555355060729,
1258 xOffset
= 15018.84750987729,
1259 yOffset
= 13072.72336630089,
1263 height
= 935.4100697456119,
1264 width
= 1402.621211455915,
1265 xOffset
= 20747.42666130799,
1266 yOffset
= 10525.94769396873,
1270 height
= 2322.899061688691,
1271 width
= 3483.371975265956,
1272 xOffset
= 14529.25864164056,
1273 yOffset
= 18758.10068625832,
1276 StonetalonMountains
= {
1277 height
= 3256.226691571251,
1278 width
= 4883.385977951072,
1279 xOffset
= 13820.91773479217,
1280 yOffset
= 9883.162892509636,
1284 height
= 4599.965662459992,
1285 width
= 6900.073766103516,
1286 xOffset
= 17285.539010128,
1287 yOffset
= 18674.7673661939,
1291 height
= 3393.726923234355,
1292 width
= 5091.720903621394,
1293 xOffset
= 13252.16205313556,
1294 yOffset
= 968.6418744503761,
1298 height
= 704.6826864472878,
1299 width
= 1056.781131437323,
1300 xOffset
= 10533.08314172693,
1301 yOffset
= 6276.205331713322,
1305 height
= 2933.312180524323,
1306 width
= 4400.046681282484,
1307 xOffset
= 17500.12437633161,
1308 yOffset
= 16766.44698282704,
1312 height
= 695.8282721105132,
1313 width
= 1043.761263579803,
1314 xOffset
= 16550.11410485969,
1315 yOffset
= 13649.80260929285,
1319 height
= 2466.647220780505,
1320 width
= 3700.040077455555,
1321 xOffset
= 16533.44712326324,
1322 yOffset
= 18766.4334494793,
1326 height
= 4733.299561046713,
1327 width
= 7100.077599808275,
1328 xOffset
= 17383.45606038691,
1329 yOffset
= 4266.536453420381,
1336 parentContinent
= 0,
1337 height
= 27149.795290881,
1338 width
= 40741.175327834,
1339 xOffset
= 14407.1086092051,
1340 yOffset
= 290.3230897653046,
1343 height
= 1866.673586850316,
1344 width
= 2800.000436369314,
1345 xOffset
= 17388.63313899802,
1346 yOffset
= 9676.382605411302,
1350 height
= 2400.0092446309,
1351 width
= 3599.999380663208,
1352 xOffset
= 19038.63328411639,
1353 yOffset
= 11309.72201070757,
1357 height
= 1658.340965090961,
1358 width
= 2487.498490907989,
1359 xOffset
= 20251.1337564772,
1360 yOffset
= 17065.99404487956,
1364 height
= 2233.343415116865,
1365 width
= 3349.999381676505,
1366 xOffset
= 19413.63362865575,
1367 yOffset
= 21743.09582955139,
1371 height
= 1952.091972408385,
1372 width
= 2929.16694293186,
1373 xOffset
= 18438.633261567,
1374 yOffset
= 18207.66513379744,
1378 height
= 1666.673818905317,
1379 width
= 2499.999888210889,
1380 xOffset
= 19005.29993968603,
1381 yOffset
= 21043.0932328648,
1385 height
= 3283.345779814337,
1386 width
= 4924.998791911572,
1387 xOffset
= 16369.8840376619,
1388 yOffset
= 15053.48695195484,
1392 height
= 1800.007653419076,
1393 width
= 2699.999669551933,
1394 xOffset
= 17338.63354148773,
1395 yOffset
= 20893.09259181909,
1398 EasternPlaguelands
= {
1399 height
= 2687.510360231216,
1400 width
= 4031.249051993366,
1401 xOffset
= 20459.46801235962,
1402 yOffset
= 7472.207045901617,
1406 height
= 2314.591970284716,
1407 width
= 3470.831971412848,
1408 xOffset
= 16636.55099386465,
1409 yOffset
= 19116.0027890283,
1413 height
= 3283.346366715794,
1414 width
= 4924.998483501337,
1415 xOffset
= 20259.46725884782,
1416 yOffset
= 2534.687567863296,
1420 height
= 2200.008945183733,
1421 width
= 3300.002855743766,
1422 xOffset
= 21055.29786070095,
1423 yOffset
= 5309.698546426793,
1427 height
= 2133.341840477916,
1428 width
= 3200.000391416799,
1429 xOffset
= 17105.29968281043,
1430 yOffset
= 10776.38652289269,
1434 height
= 2566.676323518885,
1435 width
= 3849.998492380244,
1436 xOffset
= 19746.96704279287,
1437 yOffset
= 9709.715966757984,
1441 height
= 527.6056771582851,
1442 width
= 790.6252518322632,
1443 xOffset
= 18885.55815177769,
1444 yOffset
= 15745.64795436116,
1448 height
= 1839.590356444166,
1449 width
= 2758.33360594204,
1450 xOffset
= 20165.71623436714,
1451 yOffset
= 15663.90573348468,
1455 height
= 1447.922213393415,
1456 width
= 2170.833229570681,
1457 xOffset
= 19742.79960560691,
1458 yOffset
= 19751.42209395218,
1462 height
= 1487.505203229038,
1463 width
= 2231.250200533406,
1464 xOffset
= 18494.88325409831,
1465 yOffset
= 17276.41231120941,
1469 height
= 806.7751969249011,
1470 width
= 1211.458551923779,
1471 xOffset
= 22172.71573747824,
1472 yOffset
= 3422.647395021269,
1476 height
= 2800.011187621704,
1477 width
= 4200.000573479695,
1478 xOffset
= 14721.96646274185,
1479 yOffset
= 9509.714741967448,
1483 height
= 1158.33686894901,
1484 width
= 1737.498058940429,
1485 xOffset
= 16449.05164642256,
1486 yOffset
= 19172.25350774846,
1490 height
= 4254.18312444072,
1491 width
= 6381.248484543122,
1492 xOffset
= 15951.13375783437,
1493 yOffset
= 22345.18258706305,
1497 height
= 2218.756638064149,
1498 width
= 3327.084777999942,
1499 xOffset
= 21074.0484502027,
1500 yOffset
= 7.595267688679496,
1504 height
= 1529.173695058727,
1505 width
= 2293.753807610138,
1506 xOffset
= 20394.88183258176,
1507 yOffset
= 20797.25913588854,
1511 height
= 3012.510490816506,
1512 width
= 4518.749381850256,
1513 xOffset
= 15138.63417865412,
1514 yOffset
= 7338.874503644808,
1518 height
= 640.1067253394195,
1519 width
= 959.3752013853186,
1520 xOffset
= 17298.77399735696,
1521 yOffset
= 9298.435338905521,
1524 WesternPlaguelands
= {
1525 height
= 2866.677213191588,
1526 width
= 4299.998717025251,
1527 xOffset
= 17755.30067544475,
1528 yOffset
= 7809.708745090687,
1532 height
= 2333.342039971409,
1533 width
= 3500.001170481545,
1534 xOffset
= 15155.29922254704,
1535 yOffset
= 20576.42557120998,
1539 height
= 2756.260286844545,
1540 width
= 4135.414389381328,
1541 xOffset
= 18561.55091405621,
1542 yOffset
= 13324.31339403164,
1549 parentContinent
= 3,
1550 height
= 11642.355227091,
1551 width
= 17463.987300595,
1553 BladesEdgeMountains
= {
1554 height
= 3616.553511321226,
1555 width
= 5424.972055480694,
1556 xOffset
= 4150.184214583454,
1557 yOffset
= 1412.98225932006,
1561 height
= 3443.642450656037,
1562 width
= 5164.556104714847,
1563 xOffset
= 7456.417230912641,
1564 yOffset
= 4339.973750274888,
1568 height
= 3683.218538167106,
1569 width
= 5524.971495006054,
1570 xOffset
= 2700.192018521809,
1571 yOffset
= 5779.511974812862,
1575 height
= 3716.550608724641,
1576 width
= 5574.970083688359,
1577 xOffset
= 7512.667416095402,
1578 yOffset
= 365.0979827402549,
1581 ShadowmoonValley
= {
1582 height
= 3666.552070430093,
1583 width
= 5499.971770418525,
1584 xOffset
= 8770.993458280615,
1585 yOffset
= 7769.033264592288,
1589 height
= 870.8059516186869,
1590 width
= 1306.242821388422,
1591 xOffset
= 6860.744740098593,
1592 yOffset
= 7295.086120456203,
1596 height
= 3599.887783533737,
1597 width
= 5399.971351016305,
1598 xOffset
= 5912.675516998205,
1599 yOffset
= 6821.146319031154,
1603 height
= 3351.978710181591,
1604 width
= 5027.057650868489,
1605 xOffset
= 3521.020638264577,
1606 yOffset
= 3885.821278366336,
1613 --- WotLK Adjustments, now permanently enabled. Someday I should probably merge these in.
1615 WorldMapSize
[0].height
= 31809.64859753034;
1616 WorldMapSize
[0].width
= 47714.27770954026;
1618 WorldMapSize
[1].xOffset
= -8590.409362625034;
1619 WorldMapSize
[1].yOffset
= 5628.694276155668;
1621 WorldMapSize
[2].xOffset
= 18542.31268111796;
1622 WorldMapSize
[2].yOffset
= 3585.574682467752;
1626 parentContinent
= 0,
1627 height
= 11834.31067391958,
1628 width
= 17751.3936186856,
1629 xOffset
= 16020.94093549576,
1630 yOffset
= 454.2464807713226,
1633 height
= 3843.765503862232,
1634 width
= 5764.58206497758,
1635 xOffset
= 646.3186767730767,
1636 yOffset
= 5695.480016983896,
1639 CrystalsongForest
= {
1640 height
= 1814.590053385046,
1641 width
= 2722.916164555434,
1642 xOffset
= 7773.400227973558,
1643 yOffset
= 4091.307437548815,
1647 height
= 553.3419356683534,
1648 width
= 830.014625253355,
1649 xOffset
= 8164.640128758279,
1650 yOffset
= 4526.722218200071,
1654 height
= 3739.597759999098,
1655 width
= 5608.331259502691,
1656 xOffset
= 5590.067753073641,
1657 yOffset
= 5018.394106536425,
1661 height
= 3500.013349296343,
1662 width
= 5249.9986179934,
1663 xOffset
= 10327.56614428777,
1664 yOffset
= 5076.727864214266,
1668 height
= 4031.266275060274,
1669 width
= 6045.831339550668,
1670 xOffset
= 10615.0658552538,
1671 yOffset
= 7476.736868262738,
1675 height
= 4181.266519840844,
1676 width
= 6270.832975322177,
1677 xOffset
= 3773.401695036191,
1678 yOffset
= 1166.296622984233,
1682 height
= 1983.342901980711,
1683 width
= 2974.999377667768,
1684 xOffset
= 4887.984320612982,
1685 yOffset
= 4876.725348039468,
1689 height
= 2904.177559586215,
1690 width
= 4356.248328680455,
1691 xOffset
= 2287.985279107324,
1692 yOffset
= 3305.887993444818,
1696 height
= 4741.684940421732,
1697 width
= 7112.498205872217,
1698 xOffset
= 7375.483315518691,
1699 yOffset
= 395.4596828327046,
1703 height
= 3329.179510740043,
1704 width
= 4993.747919923504,
1705 xOffset
= 9817.150055203074,
1706 yOffset
= 2924.636381254688,
1709 HrothgarsLanding
= {
1712 xOffset
= 23967.599 - 17549.182,
1713 yOffset
= 1027.392 - 1215.431,
1718 local function VContinent(index
, name
, size
)
1719 assert(1, not WorldMapSize
[index
], "denied")
1721 WorldMapSize
[index
] = {
1722 parentContinent
= index
,
1727 WorldMapSize
[index
].zoneData
[name
] = {
1735 VContinent(-77, "ScarletEnclave", 2125)
1738 VContinent(-80, "UtgardeKeep1", 100) -- temporary value
1739 VContinent(-81, "UtgardeKeep2", 100) -- temporary value
1740 VContinent(-82, "UtgardeKeep3", 100) -- temporary value
1742 VContinent(-83, "TheNexus", 734.2)
1744 VContinent(-84, "AzjolNerub1", 100) -- temporary value
1745 VContinent(-85, "AzjolNerub2", 100) -- temporary value
1746 VContinent(-86, "AzjolNerub3", 100) -- temporary value
1748 VContinent(-87, "Ahnkahet", 648.3)
1750 VContinent(-88, "DrakTharonKeep1", 100) -- temporary value
1751 VContinent(-89, "DrakTharonKeep2", 100) -- temporary value
1753 VContinent(-90, "VioletHold", 170.83)
1755 VContinent(-91, "Gundrak", 603.35)
1757 VContinent(-92, "Ulduar77", 613.5) -- Halls of Stone
1759 VContinent(-93, "HallsofLightning1", 100) -- temporary value
1760 VContinent(-94, "HallsofLightning2", 100) -- temporary value
1762 VContinent(-95, "Nexus801", 100) -- temporary value -- Oculus
1763 VContinent(-96, "Nexus802", 100) -- temporary value
1764 VContinent(-97, "Nexus803", 100) -- temporary value
1765 VContinent(-98, "Nexus804", 100) -- temporary value
1767 VContinent(-99, "CoTStratholme1", 750.2)
1768 VContinent(-100, "CoTStratholme2", 1216.66)
1770 VContinent(-101, "UtgardePinnacle1", 100) -- temporary value -- hey they spelled it right
1771 VContinent(-102, "UtgardePinnacle2", 100) -- temporary value
1773 VContinent(-103, "VaultofArchavon", 603.25) -- temporary value -- Weirdly, Emalon is actually within the "Vault of Archavon"
1775 VContinent(-104, "Naxxramas1", 1237.5) -- construct quarter
1776 VContinent(-105, "Naxxramas2", 1237.5) -- arachnid quarter
1777 VContinent(-106, "Naxxramas3", 1237.5) -- military quarter
1778 VContinent(-107, "Naxxramas4", 1237.5) -- plague quarter
1779 VContinent(-108, "Naxxramas5", 1379.9) -- overview
1780 VContinent(-109, "Naxxramas6", 437.3) -- lair
1782 VContinent(-110, "TheObsidianSanctum", 775.1)
1784 VContinent(-111, "TheEyeOfEternity", 286.7)
1786 VContinent(-112, "Ulduar", 2191.7) -- temporary value
1787 VContinent(-113, "Ulduar1", 446.5) -- temporary value
1788 VContinent(-114, "Ulduar2", 885.6) -- temporary value
1789 VContinent(-115, "Ulduar3", 100) -- temporary value
1790 VContinent(-116, "Ulduar4", 100) -- temporary value
1793 VirtualContinentIndexes
= { -- Don't change values here, since programs might want to store them
1794 ["ScarletEnclave"] = -77,
1796 ["UtgardeKeep1"] = -80,
1797 ["UtgardeKeep2"] = -81,
1798 ["UtgardeKeep3"] = -82,
1802 ["AzjolNerub1"] = -84,
1803 ["AzjolNerub2"] = -85,
1804 ["AzjolNerub3"] = -86,
1808 ["DrakTharonKeep1"] = -88,
1809 ["DrakTharonKeep2"] = -89,
1811 ["VioletHold"] = -90,
1815 ["Ulduar77"] = -92, -- Halls of Stone
1817 ["HallsofLightning1"] = -93,
1818 ["HallsofLightning2"] = -94,
1820 ["Nexus801"] = -95, -- Oculus
1825 ["CoTStratholme1"] = -99,
1826 ["CoTStratholme2"] = -100,
1828 ["UtgardePinnacle1"] = -101, -- hey they spelled it right
1829 ["UtgardePinnacle2"] = -102,
1831 ["VaultofArchavon"] = -103, -- Weirdly, Emalon is actually within the "Vault of Archavon"
1833 ["Naxxramas1"] = -104,
1834 ["Naxxramas2"] = -105,
1835 ["Naxxramas3"] = -106,
1836 ["Naxxramas4"] = -107,
1837 ["Naxxramas5"] = -108,
1838 ["Naxxramas6"] = -109,
1840 ["TheObsidianSanctum"] = -110,
1842 ["TheEyeOfEternity"] = -111,
1851 DongleStub
:Register(Astrolabe
, activate
)
1854 zeroData
= { xOffset
= 0, height
= 0, yOffset
= 0, width
= 0, __index
= function() return zeroData
end };
1855 setmetatable(zeroData
, zeroData
);
1856 setmetatable(WorldMapSize
, zeroData
);
1858 for continent
, zones
in pairs(Astrolabe
.ContinentList
) do
1859 local mapData
= WorldMapSize
[continent
];
1860 for index
, mapName
in pairs(zones
) do
1861 if not ( mapData
.zoneData
[mapName
] ) then
1862 --WE HAVE A PROBLEM!!!
1863 ChatFrame1
:AddMessage("Astrolabe is missing data for "..select(index
, GetMapZones(continent
))..".");
1864 mapData
.zoneData
[mapName
] = zeroData
;
1866 mapData
[index
] = mapData
.zoneData
[mapName
];
1867 mapData
.zoneData
[mapName
] = nil;
1872 -- register this library with AstrolabeMapMonitor, this will cause a full update if PLAYER_LOGIN has already fired
1873 local AstrolabeMapMonitor
= DongleStub("AstrolabeMapMonitor");
1874 AstrolabeMapMonitor
:RegisterAstrolabeLibrary(Astrolabe
, LIBRARY_VERSION_MAJOR
);
1877 QH_Astrolabe_Ready
= true