summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGriffinR <griffin.g.richards@gmail.com>2020-10-12 13:38:27 -0400
committerGriffinR <griffin.g.richards@gmail.com>2020-10-12 13:38:27 -0400
commit2fbb76fced1fc62a4feff5d838431428f69379c7 (patch)
treed898738adf6ced5517128a8c24eab71a60b065ae
parent44f1bcedec8d54f414ae043e4f0f705dc6100120 (diff)
Created Custom Border Dimensions (markdown)
-rw-r--r--Custom-Border-Dimensions.md154
1 files changed, 154 insertions, 0 deletions
diff --git a/Custom-Border-Dimensions.md b/Custom-Border-Dimensions.md
new file mode 100644
index 0000000..e7ddb97
--- /dev/null
+++ b/Custom-Border-Dimensions.md
@@ -0,0 +1,154 @@
+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 the 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](https://github.com/pret/pokeemerald/blob/master/include/global.fieldmap.h) to hold the width and height of the border.
+```diff
+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
+The following changes will all be in [src/fieldmap.c](https://github.com/pret/pokeemerald/blob/master/src/fieldmap.c).
+
+We'll be simplifying some existing functions with a few new macros. First, insert the following above `MapGridGetZCoordAt`.
+```c
+#define MapGridGetBorderTileAt(x, y) ({ \
+ u16 block; \
+ s32 xprime; \
+ s32 yprime; \
+ \
+ const struct MapLayout *mapLayout = gMapHeader.mapLayout; \
+ \
+ xprime = x - 7; \
+ xprime += 8 * mapLayout->borderWidth; \
+ xprime %= mapLayout->borderWidth; \
+ \
+ yprime = y - 7; \
+ yprime += 8 * mapLayout->borderHeight; \
+ yprime %= mapLayout->borderHeight; \
+ \
+ block = mapLayout->border[xprime + yprime * mapLayout->borderWidth] | METATILE_COLLISION_MASK; \
+})
+
+#define AreCoordsWithinMapGridBounds(x, y) (x >= 0 && x < gBackupMapLayout.width && y >= 0 && y < gBackupMapLayout.height)
+
+#define MapGridGetTileAt(x, y) (AreCoordsWithinMapGridBounds(x, y) ? gBackupMapLayout.map[x + gBackupMapLayout.width * y] : MapGridGetBorderTileAt(x, y))
+```
+
+Now we'll use these new macros. Replace the `MapGridGetZCoordAt`, `MapGridIsImpassableAt`, and `MapGridGetMetatileIdAt` functions with the versions below.
+```c
+u8 MapGridGetZCoordAt(int x, int y)
+{
+ u16 block = MapGridGetTileAt(x, y);
+
+ if (block == METATILE_ID_UNDEFINED)
+ return 0;
+
+ return block >> METATILE_ELEVATION_SHIFT;
+}
+
+u8 MapGridIsImpassableAt(int x, int y)
+{
+ u16 block = MapGridGetTileAt(x, y);
+
+ if (block == METATILE_ID_UNDEFINED)
+ return 1;
+
+ return (block & METATILE_COLLISION_MASK) >> METATILE_COLLISION_SHIFT;
+}
+
+u32 MapGridGetMetatileIdAt(int x, int y)
+{
+ u16 block = MapGridGetTileAt(x, y);
+
+ if (block == METATILE_ID_UNDEFINED)
+ return MapGridGetBorderTileAt(x, y) & METATILE_ID_MASK;
+
+ return block & METATILE_ID_MASK;
+}
+```
+Then in `GetMapBorderIdAt`, make the following change.
+```diff
+ int GetMapBorderIdAt(int x, int y)
+ {
+- struct MapLayout const *mapLayout;
+- u16 block, block2;
+- int i, j;
+- if (x >= 0 && x < gBackupMapLayout.width
+- && y >= 0 && y < gBackupMapLayout.height)
+- {
+- i = gBackupMapLayout.width;
+- i *= y;
+- block = gBackupMapLayout.map[x + i];
+- if (block == METATILE_ID_UNDEFINED)
+- {
+- goto fail;
+- }
+- }
+- else
+- {
+- mapLayout = gMapHeader.mapLayout;
+- j = (x + 1) & 1;
+- j += ((y + 1) & 1) * 2;
+- block2 = METATILE_COLLISION_MASK | mapLayout->border[j];
+- if (block2 == METATILE_ID_UNDEFINED)
+- {
+- goto fail;
+- }
+- }
+- goto success;
+-fail:
+- return -1;
+-success:
++ if (MapGridGetTileAt(x, y) == METATILE_ID_UNDEFINED)
++ return -1;
+
+ if (x >= (gBackupMapLayout.width - 8))
+ {
+```
+
+## 3. Adding 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](https://github.com/pret/pokeemerald/blob/master/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](https://github.com/pret/pokeemerald/blob/master/tools/mapjson/mapjson.cpp).
+```diff
+ << "\t.4byte " << layout["primary_tileset"].string_value() << "\n"
+- << "\t.4byte " << layout["secondary_tileset"].string_value() << "\n\n";
++ << "\t.4byte " << layout["secondary_tileset"].string_value() << "\n"
++ << "\t.byte " << layout["border_width"].int_value() << "\n"
++ << "\t.byte " << layout["border_height"].int_value() << "\n"
++ << "\t.2byte 0\n\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.
+
+- If you've opened your project with Porymap before there will be a `porymap.project.cfg` file in your root folder. In that file, set `use_custom_border_size` to `1`.
+
+- Open your project with Porymap and you should now be able to change the size of the border with the `Change Dimensions` button while on the Map tab.