Every map in the game is surrounded by a repeating group of metatiles called the border. In Emerald, these borders are always 2x2, while in FireRed/LeafGreen they can have different dimensions.
This tutorial will go over the steps to allow borders with different dimensions to be created in Emerald.
Note that Porymap version ≥ 4.0.0 supports this feature, so after these changes are made you will be able to edit the border dimensions in Porymap like you would for a pokefirered project.
1. Add dimension fields to MapLayout
First we will add 2 new fields to struct MapLayout
in include/global.fieldmap.h to hold the width and height of the border.
struct MapLayout
{
/*0x00*/ s32 width;
/*0x04*/ s32 height;
/*0x08*/ u16 *border;
/*0x0c*/ u16 *map;
/*0x10*/ struct Tileset *primaryTileset;
/*0x14*/ struct Tileset *secondaryTileset;
+ u8 borderWidth;
+ u8 borderHeight;
};
2. Use dimensions fields to read border data
Next we need to use these new fields when we're trying to access border data. Depending on which repo you're using, find the definition of GetBorderBlockAt
in src/fieldmap.c, and replace it with the version below.
pokeemerald
#define GetBorderBlockAt(x, y) ({ \
u16 block; \
s32 xprime; \
s32 yprime; \
\
const struct MapLayout *mapLayout = gMapHeader.mapLayout; \
\
xprime = x - MAP_OFFSET; \
xprime += 8 * mapLayout->borderWidth; \
xprime %= mapLayout->borderWidth; \
\
yprime = y - MAP_OFFSET; \
yprime += 8 * mapLayout->borderHeight; \
yprime %= mapLayout->borderHeight; \
\
block = mapLayout->border[xprime + yprime * mapLayout->borderWidth] | MAPGRID_COLLISION_MASK; \
})
pokeemerald-expansion
static inline u16 GetBorderBlockAt(int x, int y)
{
u16 block;
s32 xPrime;
s32 yPrime;
const struct MapLayout *mapLayout = gMapHeader.mapLayout;
xPrime = x - MAP_OFFSET;
xPrime += 8 * mapLayout->borderWidth;
xPrime %= mapLayout->borderWidth;
yPrime = y - MAP_OFFSET;
yPrime += 8 * mapLayout->borderHeight;
yPrime %= mapLayout->borderHeight;
return (mapLayout->border[xPrime + yPrime * mapLayout->borderWidth] | MAPGRID_COLLISION_MASK);
}
3. Add border dimension data
Now we need to specify what the border dimensions are for each map layout. Because Emerald's are all 2x2 by default, this can be done quickly with a find and replace. In data/layouts/layouts.json, make the following substitution.
Find:
"primary_tileset"
Replace:
"border_width": 2,
"border_height": 2,
"primary_tileset"
4. Update the mapjson tool
The tool that converts layouts.json to data needs to know what to do with these fields. Update generate_layout_headers_text
in tools/mapjson/mapjson.cpp.
<< "\t.4byte " << json_to_string(layout, "secondary_tileset") << "\n";
- if (version == "firered") {
text << "\t.byte " << json_to_string(layout, "border_width") << "\n"
<< "\t.byte " << json_to_string(layout, "border_height") << "\n"
<< "\t.2byte 0\n";
- }
text << "\n";
Note the .2byte 0
is because structs are aligned to 4 byte boundaries. The new border width/height fields are 1 byte each, so we need an additional 2 bytes of padding. This may not be true if you've already made other changes to struct MapLayout
, or if you use different sizes for the new dimension fields.
5. Rebuild and test in Porymap
-
Make sure to
make clean
and rebuild before attempting changes to ensure mapjson and all the map data gets rebuilt with the new map layout. -
Open your project with Porymap, and under the
Maps
tab inOptions -> Project Settings...
check theEnable Custom Border Size
option. Then selectOK
and reload your project. -
You should now be able to change the size of the border with the
Change Dimensions
button while on theMap
tab.