diff options
author | GriffinR <griffin.g.richards@gmail.com> | 2020-10-12 13:38:27 -0400 |
---|---|---|
committer | GriffinR <griffin.g.richards@gmail.com> | 2020-10-12 13:38:27 -0400 |
commit | 2fbb76fced1fc62a4feff5d838431428f69379c7 (patch) | |
tree | d898738adf6ced5517128a8c24eab71a60b065ae | |
parent | 44f1bcedec8d54f414ae043e4f0f705dc6100120 (diff) |
Created Custom Border Dimensions (markdown)
-rw-r--r-- | Custom-Border-Dimensions.md | 154 |
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. |