EQ2MAP works by creating an alternate version of EQ2's Map interface. In order to integrate our map into EQ2MAP, we will need to create an entry in XML which tell EQ2MAP and EQ2 how to display the map. In this section we will cover the different EQ2MAP files and locations you will need to edit. We will also cover, in depth, ZoneRect and other map XML attributes and how they affect how the map is displayed.
One note on editing the XML files. It helps to have a nice Syntax Highlighting text editor. Syntax highlighting colors the keywords, attributes, quoted strings, and numbers making complex XML documents much easier to read. It can also clearly identify if you have left an open quote somewhere. Note that you may have to install an XML specifc 'wordfile', which describes the syntax of a langauge for the editor, to enable XML syntax highlighting.
Free Syntax Highlighting Editors
Figure 6.1 - UI Folder Layout
Files and Locations
If EQ2MAP is the only UI add-on you've installed, by default it will install to the Everquest II\UI\EQ2MAP folder. If you have installed other UI add-ons, you should know which folder you used. Within that folder are a standard set of files and locations you will need to know about:
- eq2map2\core_mapstyles.xml (Do Not Edit This File)
Contains the map styles for every map that EQ2MAP displays, including SOE provided maps. Do not edit this file directly, it is automatically generated by EQ2MAP and will be overwritten every time you run the updater. This file is an excellent reference for map XML.
- eq2map2\_User_MapStyles.xml (This is the file you edit)
Uses the same format at core_mapstyles, but it not overwritten by the updater. This is the file you will edit when testing your map(s).
This is the location where your DDS files will go. Copy the DDS files you created from your maps into this folder.
Map XML Reference
Each user generated map entry in core_mapstyles.xml takes the form of an ImageStyle tag wrapped around an ImageFrame tag. Each tag has attributes in the form AttributeName="AttributeValue". Figure 6.2 shows an example of a complete user generated XML map entry. This is the minimum amount of information needed for a map to show up in-game and in the EQ2MAP drop downs. There are additional attributes, such as availablerect and heightmin which are used to determine which map of a multi-map zone is displayed.
<ImageStyle Name="qey_catacomb01" displayname="The Down Below" menugroup="Karan" zonerect="-46, -261, 239, 68">
<ImageFrame Source="images/maps/map_qey_catacomb01.dds" SourceRect="0,0,436,506" />
Figure 6.2 - MAP XML Example
A note about special characters. If you want to put an ampersand or a quote in any attribute, you must use the HTML Special characters of '&' and '"' respectively. If you put a naked ampersand in an attribute you will break your ImageStyle and every map which occurs after yours.
These attributes are generally required for a user created map to display. However, in special cases the menugroup can be omitted.
- Name="<map style name>[_#]"
The Name attribute is the most critical part of the ImageStyle tag. Each zone in EQ2 has a internal map style name which you can show by typing the command /show_map_style_name 1 before entering the zone you want to map - the internal map style name will then be shown in your chat window when you zone in (use /show_map_style_name 0 to turn this functionality off again). To determine which map to show EQ2 searches the XML for an ImageStyle with a name that matches that zone's internal map style name.
Note that most internal map style names end in the _ (underscore) character. This character is ignored, so if the internal map style name is example_zone_ then in the XML you ImageStyle name must be example_zone.
You cannot have more than one ImageStyle with the same name. However, if you need to create multiple maps for the same zone, e.g. to map multiple levels of that zone, you can append a number to the ImageStyle name in the format _#. The numbering must start at 0 and subsequent numbers must be consecutive. If you map three levels in example_zone then you would have three separate ImageStyle entries in the XML with names example_zone_0, example_zone_1, and example_zone_2.
If you create multiple maps for a zone in this way, EQ2 uses the zonerect and other display control attributes to determine which map is to be displayed depending on your location in the zone..
- displayname="Drop Down Map Name"
The displayname attribute is used to populate the drop down menus in-game, as well as on the web site. Note that you should not use a displayname of more than 32 characters. Any more characters and they begin to wrap in the in-game drop down and look funky.
- menugroup="<Map Menu Group Name>"
Assigns this map to a category in the in-game drop down There are currently 14 allowed values, one of which your menugroup must match exactly:
- The Enchanted Lands
- Everfrost (Island)
- Feerrott (Island)
- Lavastorm (Island)
- Desert of Ro
The ZoneRect establishes the relationship between the the world coordinates of your character and map image's SourceRect. It is used to calculate the position of the Character and POI icons on your in-game map and mini-map. Calculating your map's zonerect is covered in depth in the section Understanding and Calculating ZoneRect below.
Display Control Attributes
These attributes are used to control which map is displayed when your character is within overlapping zonerects. These attributes are covered in more depth in the section Understanding Display Control below.
Establishes the limits of where this map will be displayed, in world coordinates. Used in conjunction with availablepriority to determine which map is displayed. If this attribute is not set, it defaults to the zonerect.
This attribute, along with the availablerect tells EQ2 which map to display when maps overlap. The lowest number will always display when zonerects or availablerects overlap. This attribute can be assigned a negative number, so you can override the display on built-in maps. If this attribute is not set it has a default value of 0.
Sets the maximum height at which this map will display, in world coordinates. It is used to set the transition from a lower map to a higher map. If this attribute is not set, it is assumed to be infinite.
Sets the minimum height at which this map will display, in world coordinates. It is used to set the transition from a higher map to a lower map. If this attribute is not set, it is assumed to be negative infinity.
The ImageFrame defines the source graphic file, the DDS file, that we produced as our final map. There are only two attributes and they are both always required for user generated maps. SOE produced maps do not have an ImageFrame, as they are defined internally to EQ2.
The source points to the actual DDS file on your drive. The file will always be in the images\maps\ folder.
- SourceRect="<Left, Top, Right, Bottom>"
This attribute tells EQ2 what portion of the DDS file to display as the map texture. While it is theoretically possible to have multiple maps in a single file with different SourceRects, the EQ2MAP infrastructure does not support it. Your map must always start in the upper-left most corner of the file. If you need to make your DDS file slightly larger than your displayed map, you can have the SourceRect be smaller. The standard map size of 436x506px comes from a file which was previously 512x512 square with 76px of unused space on the side and 6px unused at the bottom. This file is now a more thrifty 436x508px, since DDS files must have dimensions evenly divisible by 4.
Understanding and Calculating ZoneRect
The ZoneRect can be one of the hardest parts of mapping to understand. The ZoneRect establishes the relationship between the actual map image and world coordinates. In order to calculate the ZoneRect, you must determine the relationship between world coordinates and image coordinates.
The ZoneRect is in the format "-West, North, -East, South". This is important to remember later when you are adjusting it.
The key to understanding the ZoneRect is that it is the world coordinates of the absolute edges of the displayed map as defined by the map's SourceRect. Even though you can't actually reach there, the ZoneRect is the edges of the "paper" that the map is drawn on. If you were able to move your character up to the upper left most corner, coordinates 0,0 in pixels, you would be at world coordinates -W,N of the ZoneRect.
Figure 6.3 - ZoneRect Calculator
(Click to Enlarge)
The Easy Explanation (Use the Tool)
The easy way to calculate ZoneRect is to use Tacoman's ZoneRect tool. He implements the algorithm below in a simple .NET application. You will need 4 sets of coordinates: The world and image coordinates of the upper left and lower right blue crosses. The image coordinates are what you collected at the end of the last chapter. The world coordinates can be found at the bottom of your SVG file as "UL:" and "LR:". These points represent the "A" and B" on figure 6.4 below. You will also need the size of your map image, if it differs from the standard size.
Enter the coordinates into the appropriate locations, click "Calculate" and you have your ZoneRect. Place it into your map XML entry in the _User_MapStyles.xml file.
The Complicated Explanation (For Completeness)
This section is supplied for reference and understanding only. Please do not attempt to manually calculate your ZoneRect. No, really, don't.
Reference: SOE_Bobble's Original post on the topic
See Figure 6.4 below for point references.
In order to determine the ZoneRect, we must determine the ratio between world coordinates and pixels on our image. To do this we will need four sets of coordinates:
- The Upper Left most extent of the mapped area (Point A)
- In In-Game coordinates (LOC_A)
- Image coordinates (MAP_A)
- The Lower Right most extent of the mapped area (Point B) in:
- In-Game coordinates (LOC_B)
- Image coordinates (MAP_B)
We have the image coordinates because we made a note of them at the end of the previous section. We have the world coordinates from the bottom of the SVG file that Mapper2 produced. You can see in Figures 6.4 and 6.5 that the LOC_A and LOC_B coordinates are typically the farthest extents of of our mapped area. This is useful because it increases the precision with which we can calculate the zonerect.
Since we know the horizontal distance between points A and B in both pixels and world coordinates, we can calculate the ratio between the two, which we will call the world distance per pixel (wdpp). The wdpp should be the same for both the X and Y dimensions, unless our map was squashed in some way.
Once we know the wdpp, we can calculate the distance from Point A to the edge of the map in pixels and then convert it to world coordinates. Do this for each axis and for each point and you have the location, in world coordinates, of the extents of the image, AKA, the zonerect. The same process can be applied to determine the rest of the extents. The example numbers are not exact because I rounded, or the final zonerect may have been adjusted by hand.
Zonerect="-W, N, -E, S"
Figure 6.4 - ZoneRect Example
Figure 6.5 - Poets Palace Extents
Figure 6.6 - Befallen Extents
Understanding Display Control
We covered the basics of display control and the attributes which control it, in this section we will go into depth on how to make sure the map you want displays when you want it to. Note that these attributes almost always limit when a map particular map will be displayed.
If you have no display attributes set and your character is within the zonerects of two maps, the map with the lowest number will always display (IE: map_blah_0 > map_blah_1 > map_blah_2). This will hold true whenever there is overlap between display control attributes: the lowest numbered map will always display first.
Heightmax and Heightmin
Figure 6.7 - Heightmin/max
Most dungeon zones are stacked vertically. This makes it trivial to control your map display using the heightmax and heightmin attributes. Typically you will determine a height that is half way down the stairs between levels. For every heightmax entry you have, you should always have an identical heightmin value for the next level and visa versa. If a level is between two layers, it should have both heightmax and a heightmin entries, matching their adjacent layers heightmin and heightmax respectively.
Most vertically stacked maps will have clean breakpoints. It is common to see floors at 0 and -10 or -15 units apart, making a breakpoint of -5 or -7.5 correct. This also eases transitions when you are drawing your maps, since you can fade our a staircase halfway down. Do take care, though, some maps have recessed areas on their top floor. The Mapper Tool will always tell you what the min and max heights are contained in a level, so be sure to understand that before you proceed.
Example 6.1 shows a very basic heightmin/max split. The floors were at an elevation of 0 and -10, so the split was placed at -5.
<ImageStyle Name="fprt_guildhall_tier2_0" displayname="Guild Hall Tier 2 (Floors 1 & 2)" menugroup="DLere" zonerect="-62, -95, 64, 32" heightmin="-5 ">
<ImageFrame Source="images/maps/map_fprt_guildhall_tier2_0.dds" SourceRect="0,0,512,512" />
<ImageStyle Name="fprt_guildhall_tier2_1" displayname="Guild Hall Tier 2 (Basement)" menugroup="DLere" zonerect="-62, -95, 64, 32" heightmax="-5 ">
<ImageFrame Source="images/maps/map_fprt_guildhall_tier2_1.dds" SourceRect="0,0,512,512" />
Example 6.1 - Height Min/Max
(Scroll Right to see Highlights)
Figure 6.8 - Availablerect
Prior to the new mapping system being released, it was common to see zones split into two parts, east and west. Typically there would be a little bit of overlap on the maps, showing a small bit off the adjacent area. Since a portion of the zonerects overlap, only the lower number map would display until you ran off the side of the map. Availablerect is used to limit the area that a map represents, allowing a hard transition between adjacent maps without running of the edge of the map.
Availablerect could be seen as sort of a North/South/East/West max attribute of the map. If your map abuts a map to the east, its east availablerect limit should match up with the west limit on the adjacent map. Figure 6.8 shows a possible map overlap scenario. The center part of the overall map, the portion that overlaps, would appear on both maps, but only be active to the left of the red line on the yellow map and to the right of the red line on the blue map.
With the ability in place to make significantly larger maps, it may no longer be necessary to use Availablerect help when a zone is split in half, but there are other potential uses for this tool (see Subzones and Special Cases section below).
Example 6.2 shows the map XML for all four Living Tombs maps. Remember that the east and west coordinates are negative the value listed. The four maps abut one another at various locations you can see by the shared coordinates. Trade abuts Residence at -535 E-W (Yellow). Residence abuts Princess at 240 N-S (Green), and Statue at -248 E-W (Cyan). Princess actually overlaps Statue by about 12 units (240 S vs 228 N), going south. Because Princess has a lower map number, it will be displayed for that distance. Note that even with new mapping capabilities, it may still make sense to split this zone in this way, due to the large amount of unused space between the Trade and Princess courts.
<ImageStyle Name="exp01_dun_living_tombs_0" displayname="Living Tombs: Trade Court" menugroup="Desert of Ro" zonerect="492, 66, 776, 395" availablerect="535, 66, 776, 395">
<ImageFrame Source="images/maps/map_exp01_dun_living_tombs_0.dds" SourceRect="0,0,436,506" />
<ImageStyle Name="exp01_dun_living_tombs_1" displayname="Living Tombs: Residence Court" menugroup="Desert of Ro" zonerect="229, 204, 577, 608" availablerect="248, 240 , 535 , 608">
<ImageFrame Source="images/maps/map_exp01_dun_living_tombs_1.dds" SourceRect="0,0,436,506" />
<ImageStyle Name="exp01_dun_living_tombs_2" displayname="Living Tombs: Princess Court" menugroup="Desert of Ro" zonerect="55, -49, 383, 332" availablerect="55, -49, 383, 240">
<ImageFrame Source="images/maps/map_exp01_dun_living_tombs_2.dds" SourceRect="0,0,436,506" />
<ImageStyle Name="exp01_dun_living_tombs_3" displayname="Living Tombs: Statue Court" menugroup="Desert of Ro" zonerect="-12, 228, 261, 544" availablerect="-12, 228, 248, 544">
<ImageFrame Source="images/maps/map_exp01_dun_living_tombs_3.dds" SourceRect="0,0,436,506" />
Example 6.2 - Living Tombs AvailableRect
(Scroll Right to see Highlights)
The availablepriority attribute exists to override the natural ordering of maps where the lowest number map is displayed first. The map with the lowest priority number will be displayed first, when other factors are equal. In most cases this simply won't be needed. So long as you have organized your maps correctly, with proper heightmin/maxes and availablerect, you should never need this.
However, there is one instance where it becomes very useful: Overriding built in maps. By assigning a negative number to your availablepriority you can force the display of your map over one provided by SOE. This is useful for uninstanced dungeons in larger zones. Some examples of this usage are The Temple of Ro in Lavastorm, The Croc Caves in Sinking Sands, or the Zek Mines in Zek. When you enter those areas, the map switches to the smaller region.
Example 6.3 shows the map XML for the Zek Mines. All three maps have an availablepriority of -1, to override the SOE supplied zone map and use height min/max values to control the transitions between them and the SOE map.
<ImageStyle Name="orcishwastes_0" displayname="Zek Mines Level 1" zonerect="-411, -228, -225, -12" availablerect="-411, -228, -225, -12" heightmax="-90" availablepriority="-1">
<ImageFrame Source="images/maps/map_zek_mines_1.dds" SourceRect="0,0,436,506" />
<ImageStyle Name="orcishwastes_1" displayname="Zek Mines Level 2" zonerect="-411, -228, -225, -12" availablerect="-411, -228, -225, -12" heightmin="-90" heightmax="-64" availablepriority="-1">
<ImageFrame Source="images/maps/map_zek_mines_2.dds" SourceRect="0,0,436,506" />
<ImageStyle Name="orcishwastes_2" displayname="Zek Mines Level 3" zonerect="-411, -228, -225, -12" availablerect="-411, -228, -225, -12" heightmin="-64" heightmax="-10" availablepriority="-1">
<ImageFrame Source="images/maps/map_zek_mines_3.dds" SourceRect="0,0,436,506" />
Example 6.3 - Zek Mines
(Scroll Right to see Highlights)
Subzones and Special Cases
Sometimes the areas you wish to map are just not that rectangular, and they abut other zones or areas in unusual ways. The way to deal with these unusual maps is through a subzone. A subzone is just a special case of a map XML entry where it has no mapgroup, and shares a zonerect with its parent map. Subzones will also recieve duplicates of their parent zone's POI XML, which is important because if they did not, you would only see POIs while in the parent zone.
A subzone may point to the same image as another map, but different display control attributes. A subzone may also have a completely different image and slightly different display attributes. A subzone does not show up in any menu, so the menugroup attribute is not set. Subzones should have the same zonerect as their parent zone or their POIs will not display correctly. Subzone's displayname should match their parent zone.
Another reason to use a subzone is to have multiple views of a single floor that are not sufficiently distinct to deserve their own name. Exmaple 6.4 shows the map XML for the bottom of the Shimmering Citadel. The first entry is for the parent zone, which is displayed in the menu, the second is the bottom part which is a subzone and not displayed in the menu. When you are below the heightmin of 80, the lower portion of the map will be displayed. The differences between the two levels are significant enough to get their own map image, but not enough to be on the dropdown.
<ImageStyle Name="exp01_dun_shimmering_citadel_0" displayname="Shimmering Citadel: Basement" menugroup="Desert of Ro" zonerect="-188, -316, 303, 254" heightmin="80" heightmax="125">
<ImageFrame Source="images/maps/map_exp01_dun_shimmering_citadel_0.dds" SourceRect="0,0,436,506" />
<ImageStyle Name="exp01_dun_shimmering_citadel_1" displayname="Shimmering Citadel: Basement" zonerect="-188, -316, 303, 254" heightmax="80">
<ImageFrame Source="images/maps/map_exp01_dun_shimmering_citadel_1.dds" SourceRect="0,0,436,506" />
Example 6.4 - Shimmering Citadel Basement
Some maps are essentially close ups or alternate views of other overland zones. For example, Onerock Isle is an alternate view of the Sinking Sands, and North and South Quenos are in the same zone. If a zone is flagged as a Combined Zone, each will recieve all of the POIs which occur in the others. If you are doing an overland zoom in, you should be sure to tell the Admins to flag it as a Combined Zone.
These case studies look at some advanced uses of subzones.
Case Study: The Croc Caves
The Croc Caves in the The Sinking Sands are interesting not just for its use of the negative availablepriority, but also for its use of five sets of map XML to display properly. The croc caves run along the inside of the eastern cliff of The Sinking Sands, parallel to the beach. Unfortunately, they follow the cliff fairly closely. Because the caves themselves are so thin, the zonerect for the zone stretches all the way out onto the beach. Even if you were to do a single availablerect (shown as a red outline, Figure 6.10), you would still start showing the map when you were on the beach.
Name="exp01_rgn_sinking_sands_2" zonerect="762, -1129, 1594, -167" availablerect="1010, -780, 1348, -650"
Name="exp01_rgn_sinking_sands_3" zonerect="762, -1129, 1594, -167" availablerect="1010, -650, 1262, -333"
Name="exp01_rgn_sinking_sands_4" zonerect="762, -1129, 1594, -167" availablerect="1010, -333, 1075, -167"
Name="exp01_rgn_sinking_sands_5" zonerect="762, -1129, 1594, -167" availablerect="1010, -1129, 1270, -940"
Name="exp01_rgn_sinking_sands_6" zonerect="762, -1129, 1594, -167" availablerect="1010, -940, 1298, -780"
Figure 6.9 - Croc Caves Partial Map XML
The author of the Croc Caves instead used a main map XML and 4 subzone XML entries to capture the outline of the caves more closely, without overlapping into the adjacent beach. Figure 6.9 shows the Name and Availablerects for that zone, and Figure 6.10 shows colored outline of what each availablerect covers. Within the game and on the EQ2MAP site, the map shows as a single image.
Figure 6.10 - Croc Cave Availablerects
Figure 6.11 - Obelisk of Lost Souls
Case Study: The Obelisk of Lost Souls
The Obelisk of Lost Souls has an interesting property - there is a small portion of the second level which projects vertically beyond the lowest point of the floor above it. With a straight heightmax/heightmin pairing, when you go up to the top of the library area shown on the map in Figure 6.11, you would actually see yourself in the cave above. The cave has a large pillar that the upper portion of the library projects into.
The solution (Example 6.5) was to make a small subzone entry, just containing the upper floor of the library and with a heightmax (622) that is above the heightmin (610) of the cave above it. In order to force it to display, the availablepriorities had to be set in descending order, with the cave being a 4, the subzone a 3, the next floor a 2 and so on (Yellow). In retrospect, it may have made more sense to order the levels the other way around, rather than setting the availablepriority.
<ImageStyle Name="obelisk_of_lostsouls_0" displayname="Obelisk of Lost Souls - Cave" menugroup="Miscellaneous" zonerect="-174, 114, 131, 469" availablerect="-174, 114, 131, 469" heightmin="610" availablepriority="4">
<ImageFrame Source="images/maps/map_obelisk_of_lostsouls_0.dds" SourceRect="0,0,436,506" />
<ImageStyle Name="obelisk_of_lostsouls_1" displayname="Obelisk of Lost Souls - Level 1" menugroup="Miscellaneous" zonerect="-60, 143, 215, 461" availablerect="-60, 143, 215, 461" heightmax="610" availablepriority="3">
<ImageFrame Source="images/maps/map_obelisk_of_lostsouls_1.dds" SourceRect="0,0,436,506" />
<ImageStyle Name="obelisk_of_lostsouls_2" displayname="Obelisk of Lost Souls - Level 1" zonerect="-60, 143, 215, 461" availablerect="16, 329, 40, 354" heightmax="622" availablepriority="2">
<ImageFrame Source="images/maps/map_obelisk_of_lostsouls_1.dds" SourceRect="0,0,436,506" />
Example 6.5 - Obelisk of Lost Souls Map XML
(Scroll Right to see Highlights)
Creating your own Entry
You should now know enough about map XML to create your own entry in _User_Mapstyles.xml for testing. It is usually best to start by making a copy of a similar zone out of the core_mapstyles.xml file and editing the attributes to fit your own map. Remember not to edit your core_mapstyles.xml, since it will be overwritten by the updater.
In the next section we'll talk about testing your XML and fine tuning your ZoneRect.