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
44 -- DO NOT MAKE CHANGES TO THIS LIBRARY WITHOUT FIRST CHANGING THE LIBRARY_VERSION_MAJOR
45 -- STRING (to something unique) OR ELSE YOU MAY BREAK OTHER ADDONS THAT USE THIS LIBRARY!!!
46 local LIBRARY_VERSION_MAJOR
= "Astrolabe-0.4-QuestHelper"
47 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
49 if not DongleStub
then error(LIBRARY_VERSION_MAJOR
.. " requires DongleStub.") end
50 if not DongleStub
:IsNewerVersion(LIBRARY_VERSION_MAJOR
, LIBRARY_VERSION_MINOR
) then return end
54 local Minimap
= _G
.Minimap
56 -- define local variables for Data Tables (defined at the end of this file)
57 local WorldMapSize
, MinimapSize
, ValidMinimapShapes
, VirtualContinentIndexes
;
59 function Astrolabe
:GetVersion()
60 return LIBRARY_VERSION_MAJOR
, LIBRARY_VERSION_MINOR
;
64 --------------------------------------------------------------------------------------------------------------
66 --------------------------------------------------------------------------------------------------------------
68 local configConstants
= {
69 MinimapUpdateMultiplier
= true,
72 -- this constant is multiplied by the current framerate to determine
73 -- how many icons are updated each frame
74 Astrolabe
.MinimapUpdateMultiplier
= 1;
77 --------------------------------------------------------------------------------------------------------------
79 --------------------------------------------------------------------------------------------------------------
81 Astrolabe
.LastPlayerPosition
= { 0, 0, 0, 0 };
82 Astrolabe
.MinimapIcons
= {};
83 Astrolabe
.IconsOnEdge
= {};
84 Astrolabe
.IconsOnEdge_GroupChangeCallbacks
= {};
86 Astrolabe
.MinimapIconCount
= 0
87 Astrolabe
.ForceNextUpdate
= false;
88 Astrolabe
.IconsOnEdgeChanged
= false;
90 -- This variable indicates whether we know of a visible World Map or not.
91 -- The state of this variable is controlled by the AstrolabeMapMonitor library.
92 Astrolabe
.WorldMapVisible
= false;
94 local AddedOrUpdatedIcons
= {}
95 local MinimapIconsMetatable
= { __index
= AddedOrUpdatedIcons
}
98 --------------------------------------------------------------------------------------------------------------
99 -- Local Pointers for often used API functions
100 --------------------------------------------------------------------------------------------------------------
102 local twoPi
= math
.pi
* 2;
103 local atan2 = math
.atan2;
104 local sin = math
.sin;
105 local cos = math
.cos;
106 local abs = math
.abs;
107 local sqrt = math
.sqrt;
110 local yield
= coroutine
.yield
111 local GetFramerate
= GetFramerate
114 --------------------------------------------------------------------------------------------------------------
115 -- Internal Utility Functions
116 --------------------------------------------------------------------------------------------------------------
118 local function assert(level
,condition
,message
)
119 if not condition
then
124 local function argcheck(value
, num
, ...)
125 assert(1, type(num
) == "number", "Bad argument #2 to 'argcheck' (number expected, got " .. type(level
) .. ")")
127 for i
=1,select("#", ...) do
128 if type(value
) == select(i
, ...) then return end
131 local types
= strjoin(", ", ...)
132 local name
= string.match(debugstack(2,2,0), ": in function [`<](.-)['>]")
133 error(string.format("Bad argument #%d to 'Astrolabe.%s' (%s expected, got %s)", num
, name
, types
, type(value
)), 3)
136 local function getContPosition( zoneData
, z
, x
, y
)
138 zoneData
= zoneData
[z
];
139 x
= x
* zoneData
.width
+ zoneData
.xOffset
;
140 y
= y
* zoneData
.height
+ zoneData
.yOffset
;
142 x
= x
* zoneData
.width
;
143 y
= y
* zoneData
.height
;
148 --------------------------------------------------------------------------------------------------------------
149 -- Virtual Continent Functions
150 --------------------------------------------------------------------------------------------------------------
152 function Astrolabe
:GetCurrentVirtualMapCZ()
153 local C
, Z
= GetCurrentMapContinent(), GetCurrentMapZone();
154 if C
== -1 and Z
== 0 then
156 local mapname
= GetMapInfo()
157 if VirtualContinentIndexes
[mapname
] and GetCurrentMapDungeonLevel() == 0 then
158 C
= VirtualContinentIndexes
[mapname
]
160 elseif mapname
and VirtualContinentIndexes
[mapname
.. GetCurrentMapDungeonLevel()] then
161 C
= VirtualContinentIndexes
[mapname
.. GetCurrentMapDungeonLevel()]
163 elseif mapname
== "CoTStratholme" and GetCurrentMapDungeonLevel() == 0 then
164 -- why do you gotta make me angry, baby
165 C
= VirtualContinentIndexes
["CoTStratholme2"]
172 function Astrolabe
:GetCurrentVirtualMapContinent() local C
, Z
= self
:GetCurrentVirtualMapCZ() return C
end
173 function Astrolabe
:GetCurrentVirtualMapZone() local C
, Z
= self
:GetCurrentVirtualMapCZ() return Z
end
175 -- Does much the same as GetMapContinents, but returns as an array and includes the virtual continents in the mix
176 function Astrolabe
:GetMapVirtualContinents()
177 local rv
= {GetMapContinents()}
178 for k
, v
in pairs(VirtualContinentIndexes
) do
179 rv
[v
] = k
.. "_Continent"
184 -- Does much the same as GetMapContinents, but returns as an array and includes the virtual continents in the mix
185 function Astrolabe
:GetMapVirtualZones(zone
)
186 for k
, v
in pairs(VirtualContinentIndexes
) do
192 return {GetMapZones(zone
)}
195 function Astrolabe
:GetMapTexture(c
, z
)
196 for k
, v
in pairs(VirtualContinentIndexes
) do
197 if v
== c
and z
== 0 then
198 return k
.. "_Continent"
199 elseif v
== c
and z
== 1 then
205 return (GetMapInfo())
208 --------------------------------------------------------------------------------------------------------------
209 -- General Utility Functions
210 --------------------------------------------------------------------------------------------------------------
212 function Astrolabe
:ComputeDistance( c1
, z1
, x1
, y1
, c2
, z2
, x2
, y2
)
213 QuestHelper
: Assert(c1
and z1
and x1
and y1
and c2
and z2
and x2
and y2
)
215 argcheck(c1, 2, "number");
216 assert(3, c1 >= 0, "ComputeDistance: Illegal continent index to c1: "..c1);
217 argcheck(z1, 3, "number", "nil");
218 argcheck(x1, 4, "number");
219 argcheck(y1, 5, "number");
220 argcheck(c2, 6, "number");
221 assert(3, c2 >= 0, "ComputeDistance: Illegal continent index to c2: "..c2);
222 argcheck(z2, 7, "number", "nil");
223 argcheck(x2, 8, "number");
224 argcheck(y2, 9, "number");
230 local dist
, xDelta
, yDelta
;
231 if ( c1
== c2
and z1
== z2
) then
232 -- points in the same zone
233 local zoneData
= WorldMapSize
[c1
];
235 zoneData
= zoneData
[z1
];
237 xDelta
= (x2
- x1
) * zoneData
.width
;
238 yDelta
= (y2
- y1
) * zoneData
.height
;
240 elseif ( c1
== c2
) then
241 -- points on the same continent
242 local zoneData
= WorldMapSize
[c1
];
243 x1
, y1
= getContPosition(zoneData
, z1
, x1
, y1
);
244 x2
, y2
= getContPosition(zoneData
, z2
, x2
, y2
);
248 elseif ( c1
and c2
) then
249 local cont1
= WorldMapSize
[c1
];
250 local cont2
= WorldMapSize
[c2
];
251 if ( cont1
.parentContinent
== cont2
.parentContinent
) then
252 x1
, y1
= getContPosition(cont1
, z1
, x1
, y1
);
253 x2
, y2
= getContPosition(cont2
, z2
, x2
, y2
);
254 if ( c1
~= cont1
.parentContinent
) then
255 x1
= x1
+ cont1
.xOffset
;
256 y1
= y1
+ cont1
.yOffset
;
258 if ( c2
~= cont2
.parentContinent
) then
259 x2
= x2
+ cont2
.xOffset
;
260 y2
= y2
+ cont2
.yOffset
;
268 if ( xDelta
and yDelta
) then
269 dist
= sqrt(xDelta
*xDelta
+ yDelta
*yDelta
);
271 return dist
, xDelta
, yDelta
;
274 function Astrolabe
:TranslateWorldMapPosition( C
, Z
, xPos
, yPos
, nC
, nZ
)
276 argcheck(C, 2, "number");
277 argcheck(Z, 3, "number", "nil");
278 argcheck(xPos, 4, "number");
279 argcheck(yPos, 5, "number");
280 argcheck(nC, 6, "number");
281 argcheck(nZ, 7, "number", "nil");
286 if ( nC
< 0 and nC
> -77 ) then
291 if ( C
== nC
and Z
== nZ
) then
294 elseif ( C
== nC
) then
295 -- points on the same continent
296 zoneData
= WorldMapSize
[C
];
297 xPos
, yPos
= getContPosition(zoneData
, Z
, xPos
, yPos
);
299 zoneData
= WorldMapSize
[C
][nZ
];
300 xPos
= xPos
- zoneData
.xOffset
;
301 yPos
= yPos
- zoneData
.yOffset
;
304 elseif ( C
and nC
) and ( WorldMapSize
[C
].parentContinent
== WorldMapSize
[nC
].parentContinent
) then
305 -- different continents, same world
306 zoneData
= WorldMapSize
[C
];
307 local parentContinent
= zoneData
.parentContinent
;
308 xPos
, yPos
= getContPosition(zoneData
, Z
, xPos
, yPos
);
309 if ( C
~= parentContinent
) then
310 -- translate up to world map if we aren't there already
311 xPos
= xPos
+ zoneData
.xOffset
;
312 yPos
= yPos
+ zoneData
.yOffset
;
313 zoneData
= WorldMapSize
[parentContinent
];
315 if ( nC
~= parentContinent
) then
316 -- translate down to the new continent
317 zoneData
= WorldMapSize
[nC
];
318 xPos
= xPos
- zoneData
.xOffset
;
319 yPos
= yPos
- zoneData
.yOffset
;
321 zoneData
= zoneData
[nZ
];
322 xPos
= xPos
- zoneData
.xOffset
;
323 yPos
= yPos
- zoneData
.yOffset
;
331 return (xPos
/ zoneData
.width
), (yPos
/ zoneData
.height
);
334 function Astrolabe
:GetAbsoluteContinentPosition( C
, Z
, xPos
, yPos
)
335 if C
== -1 then -- We're in a battleground that doesn't have a virtual continent, we're just kind of fucked.
339 assert(0, type(WorldMapSize
[C
].parentContinent
) == "number")
341 local x
, y
= Astrolabe
:TranslateWorldMapPosition(C
, Z
, xPos
, yPos
, WorldMapSize
[C
].parentContinent
, 0)
342 if not x
or not y
then return end
343 local zoneData
= WorldMapSize
[WorldMapSize
[C
].parentContinent
]
344 return WorldMapSize
[C
].parentContinent
, (x
* zoneData
.width
), (y
* zoneData
.height
)
347 function Astrolabe
:FromAbsoluteContinentPosition(C
, xPos
, yPos
)
348 return C
, xPos
/ WorldMapSize
[C
].width
, yPos
/ WorldMapSize
[C
].height
351 --*****************************************************************************
352 -- This function will do its utmost to retrieve some sort of valid position
353 -- for the specified unit, including changing the current map zoom (if needed).
354 -- Map Zoom is returned to its previous setting before this function returns.
355 --*****************************************************************************
356 function Astrolabe
:GetUnitPosition( unit
, noMapChange
)
357 local x
, y
= GetPlayerMapPosition(unit
);
358 if ( x
<= 0 and y
<= 0 ) then
359 if ( noMapChange
) then
360 -- no valid position on the current map, and we aren't allowed
361 -- to change map zoom, so return
364 local lastCont
, lastZone
= GetCurrentMapContinent(), GetCurrentMapZone();
365 SetMapToCurrentZone();
366 x
, y
= GetPlayerMapPosition(unit
);
367 if ( x
<= 0 and y
<= 0 ) then
368 SetMapZoom(GetCurrentMapContinent());
369 x
, y
= GetPlayerMapPosition(unit
);
370 if ( x
<= 0 and y
<= 0 ) then
371 -- we are in an instance or otherwise off the continent map
375 local C
, Z
= GetCurrentMapContinent(), GetCurrentMapZone();
376 if ( C
~= lastCont
or Z
~= lastZone
) then
377 SetMapZoom(lastCont
, lastZone
); -- set map zoom back to what it was before
381 return self
:GetCurrentVirtualMapContinent(), self
:GetCurrentVirtualMapZone(), x
, y
;
384 --*****************************************************************************
385 -- This function will do its utmost to retrieve some sort of valid position
386 -- for the specified unit, including changing the current map zoom (if needed).
387 -- However, if a monitored WorldMapFrame (See AstrolabeMapMonitor.lua) is
388 -- visible, then will simply return nil if the current zoom does not provide
389 -- a valid position for the player unit. Map Zoom is returned to its previous
390 -- setting before this function returns, if it was changed.
391 --*****************************************************************************
392 function Astrolabe
:GetCurrentPlayerPosition()
393 local x
, y
= GetPlayerMapPosition("player");
394 if ( x
<= 0 and y
<= 0 ) then
395 if ( self
.WorldMapVisible
) then
396 -- we know there is a visible world map, so don't cause
397 -- WORLD_MAP_UPDATE events by changing map zoom
400 local lastCont
, lastZone
= GetCurrentMapContinent(), GetCurrentMapZone();
401 SetMapToCurrentZone();
402 x
, y
= GetPlayerMapPosition("player");
403 if ( x
<= 0 and y
<= 0 ) then
404 SetMapZoom(GetCurrentMapContinent());
405 x
, y
= GetPlayerMapPosition("player");
406 if ( x
<= 0 and y
<= 0 ) then
407 -- we are in an instance or otherwise off the continent map
411 local C
, Z
= GetCurrentMapContinent(), GetCurrentMapZone();
413 if ( C
~= lastCont
or Z
~= lastZone
) then
414 SetMapZoom(lastCont
, lastZone
); --set map zoom back to what it was before
419 return self
:GetCurrentVirtualMapContinent(), self
:GetCurrentVirtualMapZone(), x
, y
;
423 --------------------------------------------------------------------------------------------------------------
424 -- Working Table Cache System
425 --------------------------------------------------------------------------------------------------------------
427 local tableCache
= {};
428 tableCache
["__mode"] = "v";
429 setmetatable(tableCache
, tableCache
);
431 local function GetWorkingTable( icon
)
432 if ( tableCache
[icon
] ) then
433 return tableCache
[icon
];
436 tableCache
[icon
] = T
;
442 --------------------------------------------------------------------------------------------------------------
443 -- Minimap Icon Placement
444 --------------------------------------------------------------------------------------------------------------
446 --*****************************************************************************
447 -- local variables specifically for use in this section
448 --*****************************************************************************
449 local minimapRotationEnabled
= false;
450 local minimapShape
= false;
452 local MinimapCompassTexture
= MinimapCompassTexture
;
453 local MinimapCompassRing
= MiniMapCompassRing
;
454 function Astrolabe
:GetFacing()
455 if MinimapCompassRing
then -- 3.1 hackery
456 return MinimapCompassRing
:GetFacing()
458 return -GetPlayerFacing()
461 local minimapRotationOffset
= -Astrolabe
.GetFacing()
463 local function placeIconOnMinimap( minimap
, minimapZoom
, mapWidth
, mapHeight
, icon
, dist
, xDist
, yDist
)
465 if ( Astrolabe
.minimapOutside
) then
466 mapDiameter
= MinimapSize
.outdoor
[minimapZoom
];
468 mapDiameter
= MinimapSize
.indoor
[minimapZoom
];
470 local mapRadius
= mapDiameter
/ 2;
471 local xScale
= mapDiameter
/ mapWidth
;
472 local yScale
= mapDiameter
/ mapHeight
;
473 local iconDiameter
= ((icon
:GetWidth() / 2) + 3) * xScale
;
474 local iconOnEdge
= nil;
475 local isRound
= true;
477 if ( minimapRotationEnabled
) then
478 local sinTheta
= sin(minimapRotationOffset
)
479 local cosTheta
= cos(minimapRotationOffset
)
482 The math that is acutally going on in the next 3 lines is:
483 local dx, dy = xDist, -yDist
484 xDist = (dx * cosTheta) + (dy * sinTheta)
485 yDist = -((-dx * sinTheta) + (dy * cosTheta))
487 This is because the origin for map coordinates is the top left corner
488 of the map, not the bottom left, and so we have to reverse the vertical
489 distance when doing the our rotation, and then reverse the result vertical
490 distance because this rotation formula gives us a result with the origin based
491 in the bottom left corner (of the (+, +) quadrant).
492 The actual code is a simplification of the above.
494 local dx
, dy
= xDist
, yDist
495 xDist
= (dx
* cosTheta
) - (dy
* sinTheta
)
496 yDist
= (dx
* sinTheta
) + (dy
* cosTheta
)
499 if ( minimapShape
and not (xDist
== 0 or yDist
== 0) ) then
500 isRound
= (xDist
< 0) and 1 or 3;
501 if ( yDist
< 0 ) then
502 isRound
= minimapShape
[isRound
];
504 isRound
= minimapShape
[isRound
+ 1];
508 -- for non-circular portions of the Minimap edge
509 if not ( isRound
) then
510 dist
= max(abs(xDist
), abs(yDist
))
513 if ( (dist
+ iconDiameter
) > mapRadius
) then
514 -- position along the outside of the Minimap
516 local factor
= (mapRadius
- iconDiameter
) / dist
;
517 xDist
= xDist
* factor
;
518 yDist
= yDist
* factor
;
521 if ( Astrolabe
.IconsOnEdge
[icon
] ~= iconOnEdge
) then
522 Astrolabe
.IconsOnEdge
[icon
] = iconOnEdge
;
523 Astrolabe
.IconsOnEdgeChanged
= true;
526 icon
:ClearAllPoints();
527 icon
:SetPoint("CENTER", minimap
, "CENTER", xDist
/xScale
, -yDist
/yScale
);
530 function Astrolabe
:PlaceIconOnMinimap( icon
, continent
, zone
, xPos
, yPos
)
531 -- check argument types
532 argcheck(icon
, 2, "table");
533 assert(3, icon
.SetPoint
and icon
.ClearAllPoints
, "Usage Message");
534 argcheck(continent
, 3, "number");
535 argcheck(zone
, 4, "number", "nil");
536 argcheck(xPos
, 5, "number");
537 argcheck(yPos
, 6, "number");
539 local lC
, lZ
, lx
, ly
= unpack(self
.LastPlayerPosition
);
540 local dist
, xDist
, yDist
= self
:ComputeDistance(lC
, lZ
, lx
, ly
, continent
, zone
, xPos
, yPos
);
542 --icon's position has no meaningful position relative to the player's current location
546 local iconData
= GetWorkingTable(icon
);
547 if ( self
.MinimapIcons
[icon
] ) then
548 self
.MinimapIcons
[icon
] = nil;
550 self
.MinimapIconCount
= self
.MinimapIconCount
+ 1
553 -- We know this icon's position is valid, so we need to make sure the icon placement
554 -- system is active. We call this here so that if this is the first icon being added to
555 -- an empty buffer, the full recalc will not completely redo the work done by this function
556 -- because the icon has not yet actually been placed in the buffer.
557 self
.processingFrame
:Show()
559 AddedOrUpdatedIcons
[icon
] = iconData
560 iconData
.continent
= continent
;
561 iconData
.zone
= zone
;
562 iconData
.xPos
= xPos
;
563 iconData
.yPos
= yPos
;
564 iconData
.dist
= dist
;
565 iconData
.xDist
= xDist
;
566 iconData
.yDist
= yDist
;
568 minimapRotationEnabled
= GetCVar("rotateMinimap") ~= "0"
569 if ( minimapRotationEnabled
) then
570 minimapRotationOffset
= -Astrolabe
.GetFacing()
573 -- check Minimap Shape
574 minimapShape
= GetMinimapShape
and ValidMinimapShapes
[GetMinimapShape()];
576 -- place the icon on the Minimap and :Show() it
578 placeIconOnMinimap(map
, map
:GetZoom(), map
:GetWidth(), map
:GetHeight(), icon
, dist
, xDist
, yDist
);
584 function Astrolabe
:RemoveIconFromMinimap( icon
)
585 if not ( self
.MinimapIcons
[icon
] ) then
588 AddedOrUpdatedIcons
[icon
] = nil
589 self
.MinimapIcons
[icon
] = nil;
590 self
.IconsOnEdge
[icon
] = nil;
593 local MinimapIconCount
= self
.MinimapIconCount
- 1
594 if ( MinimapIconCount
<= 0 ) then
595 -- no icons left to manage
596 self
.processingFrame
:Hide()
597 MinimapIconCount
= 0 -- because I'm paranoid
599 self
.MinimapIconCount
= MinimapIconCount
604 function Astrolabe
:RemoveAllMinimapIcons()
605 self
:DumpNewIconsCache()
606 local MinimapIcons
= self
.MinimapIcons
;
607 local IconsOnEdge
= self
.IconsOnEdge
;
608 for k
, v
in pairs(MinimapIcons
) do
609 MinimapIcons
[k
] = nil;
610 IconsOnEdge
[k
] = nil;
613 self
.MinimapIconCount
= 0
614 self
.processingFrame
:Hide()
617 local lastZoom
; -- to remember the last seen Minimap zoom level
619 -- local variables to track the status of the two update coroutines
620 local fullUpdateInProgress
= true
621 local resetIncrementalUpdate
= false
622 local resetFullUpdate
= false
624 -- Incremental Update Code
626 -- local variables to track the incremental update coroutine
627 local incrementalUpdateCrashed
= true
628 local incrementalUpdateThread
630 local function UpdateMinimapIconPositions( self
)
634 self
:DumpNewIconsCache() -- put new/updated icons into the main datacache
636 resetIncrementalUpdate
= false -- by definition, the incremental update is reset if it is here
638 local C
, Z
, x
, y
= self
:GetCurrentPlayerPosition();
639 if ( C
and C
~= -1 ) then
640 local lastPosition
= self
.LastPlayerPosition
;
641 local lC
, lZ
, lx
, ly
= unpack(lastPosition
);
643 minimapRotationEnabled
= GetCVar("rotateMinimap") ~= "0"
644 if ( minimapRotationEnabled
) then
645 minimapRotationOffset
= -Astrolabe
.GetFacing()
648 -- check current frame rate
649 local numPerCycle
= min(50, GetFramerate() * (self
.MinimapUpdateMultiplier
or 1))
651 -- check Minimap Shape
652 minimapShape
= GetMinimapShape
and ValidMinimapShapes
[GetMinimapShape()];
654 if ( lC
== C
and lZ
== Z
and lx
== x
and ly
== y
) then
655 -- player has not moved since the last update
656 if ( lastZoom
~= Minimap
:GetZoom() or self
.ForceNextUpdate
or minimapRotationEnabled
) then
657 local currentZoom
= Minimap
:GetZoom();
658 lastZoom
= currentZoom
;
659 local mapWidth
= Minimap
:GetWidth();
660 local mapHeight
= Minimap
:GetHeight();
661 numPerCycle
= numPerCycle
* 2
663 for icon
, data
in pairs(self
.MinimapIcons
) do
664 placeIconOnMinimap(Minimap
, currentZoom
, mapWidth
, mapHeight
, icon
, data
.dist
, data
.xDist
, data
.yDist
);
667 if ( count
> numPerCycle
) then
670 -- check if the incremental update cycle needs to be reset
671 -- because a full update has been run
672 if ( resetIncrementalUpdate
) then
677 self
.ForceNextUpdate
= false;
680 local dist
, xDelta
, yDelta
= self
:ComputeDistance(lC
, lZ
, lx
, ly
, C
, Z
, x
, y
);
682 local currentZoom
= Minimap
:GetZoom();
683 lastZoom
= currentZoom
;
684 local mapWidth
= Minimap
:GetWidth();
685 local mapHeight
= Minimap
:GetHeight();
687 for icon
, data
in pairs(self
.MinimapIcons
) do
688 local xDist
= data
.xDist
- xDelta
;
689 local yDist
= data
.yDist
- yDelta
;
690 local dist
= sqrt(xDist
*xDist
+ yDist
*yDist
);
691 placeIconOnMinimap(Minimap
, currentZoom
, mapWidth
, mapHeight
, icon
, dist
, xDist
, yDist
);
698 if ( count
>= numPerCycle
) then
701 -- check if the incremental update cycle needs to be reset
702 -- because a full update has been run
703 if ( resetIncrementalUpdate
) then
708 if not ( resetIncrementalUpdate
) then
715 self
:RemoveAllMinimapIcons()
723 if not ( self
.WorldMapVisible
) then
724 self
.processingFrame
:Hide();
728 -- if we've been reset, then we want to start the new cycle immediately
729 if not ( resetIncrementalUpdate
) then
735 function Astrolabe
:UpdateMinimapIconPositions()
736 if ( fullUpdateInProgress
) then
737 -- if we're in the middle a a full update, we want to finish that first
738 self
:CalculateMinimapIconPositions()
740 if ( incrementalUpdateCrashed
) then
741 incrementalUpdateThread
= coroutine
.wrap(UpdateMinimapIconPositions
)
742 incrementalUpdateThread(self
) --initialize the thread
744 incrementalUpdateCrashed
= true
745 incrementalUpdateThread()
746 incrementalUpdateCrashed
= false
753 -- local variables to track the full update coroutine
754 local fullUpdateCrashed
= true
755 local fullUpdateThread
757 local function CalculateMinimapIconPositions( self
)
761 self
:DumpNewIconsCache() -- put new/updated icons into the main datacache
763 resetFullUpdate
= false -- by definition, the full update is reset if it is here
765 fullUpdateInProgress
= true -- set the flag the says a full update is in progress
767 local C
, Z
, x
, y
= self
:GetCurrentPlayerPosition();
768 if ( C
and C
~= -1 ) then
769 minimapRotationEnabled
= GetCVar("rotateMinimap") ~= "0"
770 if ( minimapRotationEnabled
) then
771 minimapRotationOffset
= Astrolabe
.GetFacing()
774 -- check current frame rate
775 local numPerCycle
= GetFramerate() * (self
.MinimapUpdateMultiplier
or 1) * 2
777 -- check Minimap Shape
778 minimapShape
= GetMinimapShape
and ValidMinimapShapes
[GetMinimapShape()];
780 local currentZoom
= Minimap
:GetZoom();
781 lastZoom
= currentZoom
;
782 local mapWidth
= Minimap
:GetWidth();
783 local mapHeight
= Minimap
:GetHeight();
785 for icon
, data
in pairs(self
.MinimapIcons
) do
786 local dist
, xDist
, yDist
= self
:ComputeDistance(C
, Z
, x
, y
, data
.continent
, data
.zone
, data
.xPos
, data
.yPos
);
788 placeIconOnMinimap(Minimap
, currentZoom
, mapWidth
, mapHeight
, icon
, dist
, xDist
, yDist
);
794 self
:RemoveIconFromMinimap(icon
)
798 if ( count
>= numPerCycle
) then
801 -- check if we need to restart due to the full update being reset
802 if ( resetFullUpdate
) then
808 if not ( resetFullUpdate
) then
809 local lastPosition
= self
.LastPlayerPosition
;
815 resetIncrementalUpdate
= true
818 if not ( self
.WorldMapVisible
) then
819 self
.processingFrame
:Hide();
823 -- if we've been reset, then we want to start the new cycle immediately
824 if not ( resetFullUpdate
) then
825 fullUpdateInProgress
= false
831 function Astrolabe
:CalculateMinimapIconPositions( reset
)
832 if ( fullUpdateCrashed
) then
833 fullUpdateThread
= coroutine
.wrap(CalculateMinimapIconPositions
)
834 fullUpdateThread(self
) --initialize the thread
835 elseif ( reset
) then
836 resetFullUpdate
= true
838 fullUpdateCrashed
= true
840 fullUpdateCrashed
= false
842 -- return result flag
843 if ( fullUpdateInProgress
) then
844 return 1 -- full update started, but did not complete on this cycle
847 if ( resetIncrementalUpdate
) then
848 return 0 -- update completed
850 return -1 -- full update did no occur for some reason
857 function Astrolabe
:GetDistanceToIcon( icon
)
858 local data
= self
.MinimapIcons
[icon
];
860 return data
.dist
, data
.xDist
, data
.yDist
;
864 function Astrolabe
:IsIconOnEdge( icon
)
865 return self
.IconsOnEdge
[icon
];
868 function Astrolabe
:GetDirectionToIcon( icon
)
869 local data
= self
.MinimapIcons
[icon
];
871 local dir
= atan2(data
.xDist
, -(data
.yDist
))
880 function Astrolabe
:Register_OnEdgeChanged_Callback( func
, ident
)
881 -- check argument types
882 argcheck(func
, 2, "function");
884 self
.IconsOnEdge_GroupChangeCallbacks
[func
] = ident
;
887 --*****************************************************************************
888 -- INTERNAL USE ONLY PLEASE!!!
889 -- Calling this function at the wrong time can cause errors
890 --*****************************************************************************
891 function Astrolabe
:DumpNewIconsCache()
892 local MinimapIcons
= self
.MinimapIcons
893 for icon
, data
in pairs(AddedOrUpdatedIcons
) do
894 MinimapIcons
[icon
] = data
895 AddedOrUpdatedIcons
[icon
] = nil
897 -- we now need to restart any updates that were in progress
898 resetIncrementalUpdate
= true
899 resetFullUpdate
= true
903 --------------------------------------------------------------------------------------------------------------
904 -- World Map Icon Placement
905 --------------------------------------------------------------------------------------------------------------
907 function Astrolabe
:PlaceIconOnWorldMap( worldMapFrame
, icon
, continent
, zone
, xPos
, yPos
)
908 -- check argument types
909 argcheck(worldMapFrame
, 2, "table");
910 assert(3, worldMapFrame
.GetWidth
and worldMapFrame
.GetHeight
, "Usage Message");
911 argcheck(icon
, 3, "table");
912 assert(3, icon
.SetPoint
and icon
.ClearAllPoints
, "Usage Message");
913 argcheck(continent
, 4, "number");
914 argcheck(zone
, 5, "number", "nil");
915 argcheck(xPos
, 6, "number");
916 argcheck(yPos
, 7, "number");
918 local C
, Z
= self
:GetCurrentVirtualMapCZ();
919 local nX
, nY
= self
:TranslateWorldMapPosition(continent
, zone
, xPos
, yPos
, C
, Z
);
921 -- anchor and :Show() the icon if it is within the boundry of the current map, :Hide() it otherwise
922 if ( nX
and nY
and (0 < nX
and nX
<= 1) and (0 < nY
and nY
<= 1) ) then
923 icon
:ClearAllPoints();
924 icon
:SetPoint("CENTER", worldMapFrame
, "TOPLEFT", nX
* worldMapFrame
:GetWidth(), -nY
* worldMapFrame
:GetHeight());
933 --------------------------------------------------------------------------------------------------------------
935 --------------------------------------------------------------------------------------------------------------
937 function Astrolabe
:OnEvent( frame
, event
)
938 if ( event
== "MINIMAP_UPDATE_ZOOM" ) then
939 -- update minimap zoom scale
940 local curZoom
= Minimap
:GetZoom();
941 if ( GetCVar("minimapZoom") == GetCVar("minimapInsideZoom") ) then
942 if ( curZoom
< 2 ) then
943 Minimap
:SetZoom(curZoom
+ 1);
945 Minimap
:SetZoom(curZoom
- 1);
948 if ( GetCVar("minimapZoom")+0 == Minimap
:GetZoom() ) then
949 self
.minimapOutside
= true;
951 self
.minimapOutside
= false;
953 Minimap
:SetZoom(curZoom
);
955 -- re-calculate all Minimap Icon positions
956 if ( frame
:IsVisible() ) then
957 self
:CalculateMinimapIconPositions(true);
960 elseif ( event
== "PLAYER_LEAVING_WORLD" ) then
961 frame
:Hide(); -- yes, I know this is redunant
962 self
:RemoveAllMinimapIcons(); --dump all minimap icons
964 elseif ( event
== "PLAYER_ENTERING_WORLD" ) then
966 if not ( frame
:IsVisible() ) then
967 -- do the minimap recalculation anyways if the OnShow script didn't execute
968 -- this is done to ensure the accuracy of information about icons that were
969 -- inserted while the Player was in the process of zoning
970 self
:CalculateMinimapIconPositions(true);
973 elseif ( event
== "ZONE_CHANGED_NEW_AREA" ) then
980 function Astrolabe
:OnUpdate( frame
, elapsed
)
981 -- on-edge group changed call-backs
982 if ( self
.IconsOnEdgeChanged
) then
983 self
.IconsOnEdgeChanged
= false;
984 for func
in pairs(self
.IconsOnEdge_GroupChangeCallbacks
) do
989 self
:UpdateMinimapIconPositions();
992 function Astrolabe
:OnShow( frame
)
993 -- set the world map to a zoom with a valid player position
994 if not ( self
.WorldMapVisible
) then
995 SetMapToCurrentZone();
997 local C
, Z
= Astrolabe
:GetCurrentPlayerPosition();
998 if ( C
and C
~= -1 ) then
999 if C
>= 0 then -- If we're in Wackyland, we can't change the world map anyway, so at least it's probably right
1007 -- re-calculate minimap icon positions
1008 self
:CalculateMinimapIconPositions(true);
1010 if ( self
.MinimapIconCount
<= 0 ) then
1011 -- no icons left to manage
1012 self
.processingFrame
:Hide()
1016 -- called by AstrolabMapMonitor when all world maps are hidden
1017 function Astrolabe
:AllWorldMapsHidden()
1018 if ( IsLoggedIn() ) then
1019 self
.processingFrame
:Hide();
1020 self
.processingFrame
:Show();
1024 function Astrolabe
:SetMinimapObject(minimap
)
1026 self
:UpdateMinimapIconPositions()
1029 --------------------------------------------------------------------------------------------------------------
1030 -- Library Registration
1031 --------------------------------------------------------------------------------------------------------------
1033 local function activate( newInstance
, oldInstance
)
1034 if ( oldInstance
) then -- this is an upgrade activate
1035 if ( oldInstance
.DumpNewIconsCache
) then
1036 oldInstance
:DumpNewIconsCache()
1038 for k
, v
in pairs(oldInstance
) do
1039 if ( type(v
) ~= "function" and (not configConstants
[k
]) ) then
1043 -- sync up the current MinimapIconCount value
1045 for _
in pairs(newInstance
.MinimapIcons
) do
1046 iconCount
= iconCount
+ 1
1048 newInstance
.MinimapIconCount
= iconCount
1050 Astrolabe
= oldInstance
;
1052 local frame
= CreateFrame("Frame");
1053 newInstance
.processingFrame
= frame
;
1055 newInstance
.ContinentList
= Astrolabe
:GetMapVirtualContinents();
1057 for C
in pairs(newInstance
.ContinentList
) do
1058 local zones
= Astrolabe
:GetMapVirtualZones(C
);
1059 newInstance
.ContinentList
[C
] = zones
;
1060 for Z
in ipairs(zones
) do
1061 zones
[Z
] = Astrolabe
:GetMapTexture(C
, Z
);
1065 configConstants
= nil -- we don't need this anymore
1067 local frame
= newInstance
.processingFrame
;
1069 frame
:SetParent("Minimap");
1070 frame
:UnregisterAllEvents();
1071 frame
:RegisterEvent("MINIMAP_UPDATE_ZOOM");
1072 frame
:RegisterEvent("PLAYER_LEAVING_WORLD");
1073 frame
:RegisterEvent("PLAYER_ENTERING_WORLD");
1074 frame
:RegisterEvent("ZONE_CHANGED_NEW_AREA");
1075 frame
:SetScript("OnEvent",
1076 function( frame
, event
, ... )
1077 Astrolabe
:OnEvent(frame
, event
, ...);
1080 frame
:SetScript("OnUpdate",
1081 function( frame
, elapsed
)
1082 Astrolabe
:OnUpdate(frame
, elapsed
);
1085 frame
:SetScript("OnShow",
1087 Astrolabe
:OnShow(frame
);
1091 setmetatable(Astrolabe
.MinimapIcons
, MinimapIconsMetatable
)
1094 --------------------------------------------------------------------------------------------------------------
1096 --------------------------------------------------------------------------------------------------------------
1098 -- diameter of the Minimap in game yards at
1099 -- the various possible zoom levels
1110 [0] = 466 + 2/3, -- scale
1112 [2] = 333 + 1/3, -- 1.4
1113 [3] = 266 + 2/6, -- 1.75
1115 [5] = 133 + 1/3, -- 3.5
1119 ValidMinimapShapes
= {
1120 -- { upper-left, lower-left, upper-right, lower-right }
1121 ["SQUARE"] = { false, false, false, false },
1122 ["CORNER-TOPLEFT"] = { true, false, false, false },
1123 ["CORNER-TOPRIGHT"] = { false, false, true, false },
1124 ["CORNER-BOTTOMLEFT"] = { false, true, false, false },
1125 ["CORNER-BOTTOMRIGHT"] = { false, false, false, true },
1126 ["SIDE-LEFT"] = { true, true, false, false },
1127 ["SIDE-RIGHT"] = { false, false, true, true },
1128 ["SIDE-TOP"] = { true, false, true, false },
1129 ["SIDE-BOTTOM"] = { false, true, false, true },
1130 ["TRICORNER-TOPLEFT"] = { true, true, true, false },
1131 ["TRICORNER-TOPRIGHT"] = { true, false, true, true },
1132 ["TRICORNER-BOTTOMLEFT"] = { true, true, false, true },
1133 ["TRICORNER-BOTTOMRIGHT"] = { false, true, true, true },
1136 -- distances across and offsets of the world maps
1139 -- World Map of Azeroth
1141 parentContinent
= 0,
1142 height
= 29688.932932224,
1143 width
= 44537.340058402,
1147 parentContinent
= 0,
1148 height
= 24533.025279205,
1149 width
= 36800.210572494,
1150 xOffset
= -8311.793923510446,
1151 yOffset
= 1815.215685280706,
1154 height
= 3843.722811451077,
1155 width
= 5766.728884700476,
1156 xOffset
= 15366.76755576002,
1157 yOffset
= 8126.925260781192,
1160 height
= 3381.225696279877,
1161 width
= 5070.888165752819,
1162 xOffset
= 20343.90485013144,
1163 yOffset
= 7458.180046130774,
1166 height
= 2714.561862167815,
1167 width
= 4070.883253576282,
1168 xOffset
= 9966.70736478994,
1169 yOffset
= 5460.278138661794,
1172 height
= 6756.202067150937,
1173 width
= 10133.44343943073,
1174 xOffset
= 14443.84117394525,
1175 yOffset
= 11187.32013604393,
1178 height
= 2174.984710698752,
1179 width
= 3262.517428121028,
1180 xOffset
= 9541.713418184554,
1181 yOffset
= 3424.874558234072,
1184 height
= 4366.636219106706,
1185 width
= 6550.06962983463,
1186 xOffset
= 14125.08809600818,
1187 yOffset
= 4466.534412478246,
1190 height
= 705.7248633938184,
1191 width
= 1058.342927027606,
1192 xOffset
= 14128.39258617903,
1193 yOffset
= 2561.565012455802,
1196 height
= 2997.895174253872,
1197 width
= 4495.882023201739,
1198 xOffset
= 12833.40729836031,
1199 yOffset
= 12347.72848626745,
1202 height
= 3524.975114832228,
1203 width
= 5287.558038649864,
1204 xOffset
= 19029.30699887344,
1205 yOffset
= 10991.48801260963,
1208 height
= 3499.975146240067,
1209 width
= 5250.057259791282,
1210 xOffset
= 18041.79657043901,
1211 yOffset
= 14833.12751666842,
1214 height
= 3833.305958270781,
1215 width
= 5750.062034325837,
1216 xOffset
= 15425.10163773161,
1217 yOffset
= 5666.526367166872,
1220 height
= 4633.30011661694,
1221 width
= 6950.075260353015,
1222 xOffset
= 11625.06045254075,
1223 yOffset
= 15166.45834829251,
1226 height
= 1539.572509508711,
1227 width
= 2308.356845256911,
1228 xOffset
= 18448.05172159372,
1229 yOffset
= 4308.20254319874,
1232 height
= 3424.975945100366,
1233 width
= 5137.555355060729,
1234 xOffset
= 15018.84750987729,
1235 yOffset
= 13072.72336630089,
1238 height
= 935.4100697456119,
1239 width
= 1402.621211455915,
1240 xOffset
= 20747.42666130799,
1241 yOffset
= 10525.94769396873,
1244 height
= 2322.899061688691,
1245 width
= 3483.371975265956,
1246 xOffset
= 14529.25864164056,
1247 yOffset
= 18758.10068625832,
1249 StonetalonMountains
= {
1250 height
= 3256.226691571251,
1251 width
= 4883.385977951072,
1252 xOffset
= 13820.91773479217,
1253 yOffset
= 9883.162892509636,
1256 height
= 4599.965662459992,
1257 width
= 6900.073766103516,
1258 xOffset
= 17285.539010128,
1259 yOffset
= 18674.7673661939,
1262 height
= 3393.726923234355,
1263 width
= 5091.720903621394,
1264 xOffset
= 13252.16205313556,
1265 yOffset
= 968.6418744503761,
1268 height
= 704.6826864472878,
1269 width
= 1056.781131437323,
1270 xOffset
= 10533.08314172693,
1271 yOffset
= 6276.205331713322,
1274 height
= 2933.312180524323,
1275 width
= 4400.046681282484,
1276 xOffset
= 17500.12437633161,
1277 yOffset
= 16766.44698282704,
1280 height
= 695.8282721105132,
1281 width
= 1043.761263579803,
1282 xOffset
= 16550.11410485969,
1283 yOffset
= 13649.80260929285,
1286 height
= 2466.647220780505,
1287 width
= 3700.040077455555,
1288 xOffset
= 16533.44712326324,
1289 yOffset
= 18766.4334494793,
1292 height
= 4733.299561046713,
1293 width
= 7100.077599808275,
1294 xOffset
= 17383.45606038691,
1295 yOffset
= 4266.536453420381,
1301 parentContinent
= 0,
1302 height
= 27149.795290881,
1303 width
= 40741.175327834,
1304 xOffset
= 14407.1086092051,
1305 yOffset
= 290.3230897653046,
1308 height
= 1866.673586850316,
1309 width
= 2800.000436369314,
1310 xOffset
= 17388.63313899802,
1311 yOffset
= 9676.382605411302,
1314 height
= 2400.0092446309,
1315 width
= 3599.999380663208,
1316 xOffset
= 19038.63328411639,
1317 yOffset
= 11309.72201070757,
1320 height
= 1658.340965090961,
1321 width
= 2487.498490907989,
1322 xOffset
= 20251.1337564772,
1323 yOffset
= 17065.99404487956,
1326 height
= 2233.343415116865,
1327 width
= 3349.999381676505,
1328 xOffset
= 19413.63362865575,
1329 yOffset
= 21743.09582955139,
1332 height
= 1952.091972408385,
1333 width
= 2929.16694293186,
1334 xOffset
= 18438.633261567,
1335 yOffset
= 18207.66513379744,
1338 height
= 1666.673818905317,
1339 width
= 2499.999888210889,
1340 xOffset
= 19005.29993968603,
1341 yOffset
= 21043.0932328648,
1344 height
= 3283.345779814337,
1345 width
= 4924.998791911572,
1346 xOffset
= 16369.8840376619,
1347 yOffset
= 15053.48695195484,
1350 height
= 1800.007653419076,
1351 width
= 2699.999669551933,
1352 xOffset
= 17338.63354148773,
1353 yOffset
= 20893.09259181909,
1355 EasternPlaguelands
= {
1356 height
= 2581.259876367526,
1357 width
= 3870.832396995169,
1358 xOffset
= 20357.38356562001,
1359 yOffset
= 7376.373692430854,
1362 height
= 2314.591970284716,
1363 width
= 3470.831971412848,
1364 xOffset
= 16636.55099386465,
1365 yOffset
= 19116.0027890283,
1368 height
= 3283.346366715794,
1369 width
= 4924.998483501337,
1370 xOffset
= 20259.46725884782,
1371 yOffset
= 2534.687567863296,
1374 height
= 2200.008945183733,
1375 width
= 3300.002855743766,
1376 xOffset
= 21055.29786070095,
1377 yOffset
= 5309.698546426793,
1380 height
= 2133.341840477916,
1381 width
= 3200.000391416799,
1382 xOffset
= 17105.29968281043,
1383 yOffset
= 10776.38652289269,
1386 height
= 2566.676323518885,
1387 width
= 3849.998492380244,
1388 xOffset
= 19746.96704279287,
1389 yOffset
= 9709.715966757984,
1392 height
= 527.6056771582851,
1393 width
= 790.6252518322632,
1394 xOffset
= 18885.55815177769,
1395 yOffset
= 15745.64795436116,
1398 height
= 1839.590356444166,
1399 width
= 2758.33360594204,
1400 xOffset
= 20165.71623436714,
1401 yOffset
= 15663.90573348468,
1404 height
= 1447.922213393415,
1405 width
= 2170.833229570681,
1406 xOffset
= 19742.79960560691,
1407 yOffset
= 19751.42209395218,
1410 height
= 1487.505203229038,
1411 width
= 2231.250200533406,
1412 xOffset
= 18494.88325409831,
1413 yOffset
= 17276.41231120941,
1416 height
= 806.7751969249011,
1417 width
= 1211.458551923779,
1418 xOffset
= 22172.71573747824,
1419 yOffset
= 3422.647395021269,
1422 height
= 2800.011187621704,
1423 width
= 4200.000573479695,
1424 xOffset
= 14721.96646274185,
1425 yOffset
= 9509.714741967448,
1428 height
= 896.3598437319051,
1429 width
= 1344.270269919159,
1430 xOffset
= 16790.9956264139,
1431 yOffset
= 19455.27053790398,
1434 height
= 4254.18312444072,
1435 width
= 6381.248484543122,
1436 xOffset
= 15951.13375783437,
1437 yOffset
= 22345.18258706305,
1440 height
= 2218.756638064149,
1441 width
= 3327.084777999942,
1442 xOffset
= 21074.0484502027,
1443 yOffset
= 7.595267688679496,
1446 height
= 1529.173695058727,
1447 width
= 2293.753807610138,
1448 xOffset
= 20394.88183258176,
1449 yOffset
= 20797.25913588854,
1452 height
= 3012.510490816506,
1453 width
= 4518.749381850256,
1454 xOffset
= 15138.63417865412,
1455 yOffset
= 7338.874503644808,
1458 height
= 640.1067253394195,
1459 width
= 959.3752013853186,
1460 xOffset
= 17298.77399735696,
1461 yOffset
= 9298.435338905521,
1463 WesternPlaguelands
= {
1464 height
= 2866.677213191588,
1465 width
= 4299.998717025251,
1466 xOffset
= 17755.30067544475,
1467 yOffset
= 7809.708745090687,
1470 height
= 2333.342039971409,
1471 width
= 3500.001170481545,
1472 xOffset
= 15155.29922254704,
1473 yOffset
= 20576.42557120998,
1476 height
= 2756.260286844545,
1477 width
= 4135.414389381328,
1478 xOffset
= 18561.55091405621,
1479 yOffset
= 13324.31339403164,
1485 parentContinent
= 3,
1486 height
= 11642.355227091,
1487 width
= 17463.987300595,
1489 BladesEdgeMountains
= {
1490 height
= 3616.553511321226,
1491 width
= 5424.972055480694,
1492 xOffset
= 4150.184214583454,
1493 yOffset
= 1412.98225932006,
1496 height
= 3443.642450656037,
1497 width
= 5164.556104714847,
1498 xOffset
= 7456.417230912641,
1499 yOffset
= 4339.973750274888,
1502 height
= 3683.218538167106,
1503 width
= 5524.971495006054,
1504 xOffset
= 2700.192018521809,
1505 yOffset
= 5779.511974812862,
1508 height
= 3716.550608724641,
1509 width
= 5574.970083688359,
1510 xOffset
= 7512.667416095402,
1511 yOffset
= 365.0979827402549,
1513 ShadowmoonValley
= {
1514 height
= 3666.552070430093,
1515 width
= 5499.971770418525,
1516 xOffset
= 8770.993458280615,
1517 yOffset
= 7769.033264592288,
1520 height
= 870.8059516186869,
1521 width
= 1306.242821388422,
1522 xOffset
= 6860.744740098593,
1523 yOffset
= 7295.086120456203,
1526 height
= 3599.887783533737,
1527 width
= 5399.971351016305,
1528 xOffset
= 5912.675516998205,
1529 yOffset
= 6821.146319031154,
1532 height
= 3351.978710181591,
1533 width
= 5027.057650868489,
1534 xOffset
= 3521.020638264577,
1535 yOffset
= 3885.821278366336,
1541 --- WotLK Adjustments, now permanently enabled. Someday I should probably merge these in.
1543 WorldMapSize
[0].height
= 31809.64859753034;
1544 WorldMapSize
[0].width
= 47714.27770954026;
1546 WorldMapSize
[1].xOffset
= -8590.409362625034;
1547 WorldMapSize
[1].yOffset
= 5628.694276155668;
1549 WorldMapSize
[2].xOffset
= 18542.31268111796;
1550 WorldMapSize
[2].yOffset
= 3585.574682467752;
1551 WorldMapSize
[2].zoneData
.Stormwind
= {
1552 height
= 1158.33686894901,
1553 width
= 1737.498058940429,
1554 xOffset
= 16449.05164642256,
1555 yOffset
= 19172.25350774846,
1557 WorldMapSize
[2].zoneData
.EasternPlaguelands
= {
1558 height
= 2687.510360231216,
1559 width
= 4031.249051993366,
1560 xOffset
= 20459.46801235962,
1561 yOffset
= 7472.207045901617,
1565 parentContinent
= 0,
1566 height
= 11834.31067391958,
1567 width
= 17751.3936186856,
1568 xOffset
= 16020.94093549576,
1569 yOffset
= 454.2464807713226,
1572 height
= 3843.765503862232,
1573 width
= 5764.58206497758,
1574 xOffset
= 646.3186767730767,
1575 yOffset
= 5695.480016983896,
1577 CrystalsongForest
= {
1578 height
= 1814.590053385046,
1579 width
= 2722.916164555434,
1580 xOffset
= 7773.400227973558,
1581 yOffset
= 4091.307437548815,
1584 height
= 553.3419356683534,
1585 width
= 830.014625253355,
1586 xOffset
= 8164.640128758279,
1587 yOffset
= 4526.722218200071,
1590 height
= 3739.597759999098,
1591 width
= 5608.331259502691,
1592 xOffset
= 5590.067753073641,
1593 yOffset
= 5018.394106536425,
1596 height
= 3500.013349296343,
1597 width
= 5249.9986179934,
1598 xOffset
= 10327.56614428777,
1599 yOffset
= 5076.727864214266,
1602 height
= 4031.266275060274,
1603 width
= 6045.831339550668,
1604 xOffset
= 10615.0658552538,
1605 yOffset
= 7476.736868262738,
1608 height
= 4181.266519840844,
1609 width
= 6270.832975322177,
1610 xOffset
= 3773.401695036191,
1611 yOffset
= 1166.296622984233,
1614 height
= 1983.342901980711,
1615 width
= 2974.999377667768,
1616 xOffset
= 4887.984320612982,
1617 yOffset
= 4876.725348039468,
1620 height
= 2904.177559586215,
1621 width
= 4356.248328680455,
1622 xOffset
= 2287.985279107324,
1623 yOffset
= 3305.887993444818,
1626 height
= 4741.684940421732,
1627 width
= 7112.498205872217,
1628 xOffset
= 7375.483315518691,
1629 yOffset
= 395.4596828327046,
1632 height
= 3329.179510740043,
1633 width
= 4993.747919923504,
1634 xOffset
= 9817.150055203074,
1635 yOffset
= 2924.636381254688,
1637 HrothgarsLanding
= {
1640 xOffset
= 23967.599 - 17549.182,
1641 yOffset
= 1027.392 - 1215.431,
1646 local function VContinent(index
, name
, size
)
1647 assert(1, not WorldMapSize
[index
], "denied")
1649 WorldMapSize
[index
] = {
1650 parentContinent
= index
,
1655 WorldMapSize
[index
].zoneData
[name
] = {
1663 VContinent(-77, "ScarletEnclave", 2125)
1666 VContinent(-80, "UtgardeKeep1", 100) -- temporary value
1667 VContinent(-81, "UtgardeKeep2", 100) -- temporary value
1668 VContinent(-82, "UtgardeKeep3", 100) -- temporary value
1670 VContinent(-83, "TheNexus", 734.2)
1672 VContinent(-84, "AzjolNerub1", 100) -- temporary value
1673 VContinent(-85, "AzjolNerub2", 100) -- temporary value
1674 VContinent(-86, "AzjolNerub3", 100) -- temporary value
1676 VContinent(-87, "Ahnkahet", 648.3)
1678 VContinent(-88, "DrakTharonKeep1", 100) -- temporary value
1679 VContinent(-89, "DrakTharonKeep2", 100) -- temporary value
1681 VContinent(-90, "VioletHold", 170.83)
1683 VContinent(-91, "Gundrak", 603.35)
1685 VContinent(-92, "Ulduar77", 613.5) -- Halls of Stone
1687 VContinent(-93, "HallsofLightning1", 100) -- temporary value
1688 VContinent(-94, "HallsofLightning2", 100) -- temporary value
1690 VContinent(-95, "Nexus801", 100) -- temporary value -- Oculus
1691 VContinent(-96, "Nexus802", 100) -- temporary value
1692 VContinent(-97, "Nexus803", 100) -- temporary value
1693 VContinent(-98, "Nexus804", 100) -- temporary value
1695 VContinent(-99, "CoTStratholme1", 750.2)
1696 VContinent(-100, "CoTStratholme2", 1216.66)
1698 VContinent(-101, "UtgardePinnacle1", 100) -- temporary value -- hey they spelled it right
1699 VContinent(-102, "UtgardePinnacle2", 100) -- temporary value
1701 VContinent(-103, "VaultofArchavon", 603.25) -- temporary value -- Weirdly, Emalon is actually within the "Vault of Archavon"
1703 VContinent(-104, "Naxxramas1", 1237.5) -- construct quarter
1704 VContinent(-105, "Naxxramas2", 1237.5) -- arachnid quarter
1705 VContinent(-106, "Naxxramas3", 1237.5) -- military quarter
1706 VContinent(-107, "Naxxramas4", 1237.5) -- plague quarter
1707 VContinent(-108, "Naxxramas5", 1379.9) -- overview
1708 VContinent(-109, "Naxxramas6", 437.3) -- lair
1710 VContinent(-110, "TheObsidianSanctum", 775.1)
1712 VContinent(-111, "TheEyeOfEternity", 286.7)
1714 VContinent(-112, "Ulduar", 2191.7) -- temporary value
1715 VContinent(-113, "Ulduar1", 446.5) -- temporary value
1716 VContinent(-114, "Ulduar2", 885.6) -- temporary value
1717 VContinent(-115, "Ulduar3", 100) -- temporary value
1718 VContinent(-116, "Ulduar4", 100) -- temporary value
1721 VirtualContinentIndexes
= { -- Don't change values here, since programs might want to store them
1722 ["ScarletEnclave"] = -77,
1724 ["UtgardeKeep1"] = -80,
1725 ["UtgardeKeep2"] = -81,
1726 ["UtgardeKeep3"] = -82,
1730 ["AzjolNerub1"] = -84,
1731 ["AzjolNerub2"] = -85,
1732 ["AzjolNerub3"] = -86,
1736 ["DrakTharonKeep1"] = -88,
1737 ["DrakTharonKeep2"] = -89,
1739 ["VioletHold"] = -90,
1743 ["Ulduar77"] = -92, -- Halls of Stone
1745 ["HallsofLightning1"] = -93,
1746 ["HallsofLightning2"] = -94,
1748 ["Nexus801"] = -95, -- Oculus
1753 ["CoTStratholme1"] = -99,
1754 ["CoTStratholme2"] = -100,
1756 ["UtgardePinnacle1"] = -101, -- hey they spelled it right
1757 ["UtgardePinnacle2"] = -102,
1759 ["VaultofArchavon"] = -103, -- Weirdly, Emalon is actually within the "Vault of Archavon"
1761 ["Naxxramas1"] = -104,
1762 ["Naxxramas2"] = -105,
1763 ["Naxxramas3"] = -106,
1764 ["Naxxramas4"] = -107,
1765 ["Naxxramas5"] = -108,
1766 ["Naxxramas6"] = -109,
1768 ["TheObsidianSanctum"] = -110,
1770 ["TheEyeOfEternity"] = -111,
1779 DongleStub
:Register(Astrolabe
, activate
)
1782 zeroData
= { xOffset
= 0, height
= 0, yOffset
= 0, width
= 0, __index
= function() return zeroData
end };
1783 setmetatable(zeroData
, zeroData
);
1784 setmetatable(WorldMapSize
, zeroData
);
1786 for continent
, zones
in pairs(Astrolabe
.ContinentList
) do
1787 local mapData
= WorldMapSize
[continent
];
1788 for index
, mapName
in pairs(zones
) do
1789 if not ( mapData
.zoneData
[mapName
] ) then
1790 --WE HAVE A PROBLEM!!!
1791 ChatFrame1
:AddMessage("Astrolabe is missing data for "..select(index
, GetMapZones(continent
))..".");
1792 mapData
.zoneData
[mapName
] = zeroData
;
1794 mapData
[index
] = mapData
.zoneData
[mapName
];
1795 mapData
.zoneData
[mapName
] = nil;
1800 -- register this library with AstrolabeMapMonitor, this will cause a full update if PLAYER_LOGIN has already fired
1801 local AstrolabeMapMonitor
= DongleStub("AstrolabeMapMonitor");
1802 AstrolabeMapMonitor
:RegisterAstrolabeLibrary(Astrolabe
, LIBRARY_VERSION_MAJOR
);