summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Expand-tilesets-from-192-tiles-to-255.md274
1 files changed, 273 insertions, 1 deletions
diff --git a/Expand-tilesets-from-192-tiles-to-255.md b/Expand-tilesets-from-192-tiles-to-255.md
index 68f8bf7..8c8526b 100644
--- a/Expand-tilesets-from-192-tiles-to-255.md
+++ b/Expand-tilesets-from-192-tiles-to-255.md
@@ -1,2 +1,274 @@
+By default, tilesets in Generation II are limited to 192 tiles.
+
![Screenshot](screenshots/192-tiles-vram.png)
-![Screenshot](screenshots/johto_modern.png)
+
+As you can see, the tileset is split into two chunks; tiles 0x0 through 0x5F and 0x80 through 0xDF. There's a lot of wastage - a huge portion of the text tiles go totally unused (the umlauted characters see use in German, but not in English, for example; of the bold letters in 0x60 through 0x6F, only V, S and the colon are used at all). We can pack this more efficiently.
+
+# Step 1: Change how tiles are loaded into VRAM.
+
+We'll leave tiles 0x70 through 0x7F where they are, move the handful of tiles from 0x60 through 0x6F which actually get used somewhere else and use all of 0x0 through 0x6F and 0x80 through 0xFF for map tiles. To start this process, edit `LoadTilesetGFX` in [home/map.asm](../blob/master/home/map.asm).
+
+```diff
+ ld a, e
+ ld de, wDecompressScratch
+ call FarDecompress
+
+ ld hl, wDecompressScratch
+ ld de, vTiles2
+- ld bc, $60 tiles
++ ld bc, $70 tiles
+ call CopyBytes
+
+ ld a, [rVBK]
+ push af
+ ld a, $1
+ ld [rVBK], a
+
+...
+
+ ld a, [rVBK]
+ push af
+ ld a, $1
+ ld [rVBK], a
+
+- ld hl, wDecompressScratch + $60 tiles
++ ld hl, wDecompressScratch + $70 tiles
+ ld de, vTiles2
+- ld bc, $60 tiles
++ ld bc, $80 tiles
+ call CopyBytes
+
+ pop af
+ ld [rVBK], a
+```
+
+# Step 2: Edit the images.
+
+Now we need to add a handful of tiles to the main text image, [gfx/font/font.png](../blob/master/gfx/font/font.png). All of these go on the same row as `ÄÖÜäöü`; it's a good idea to set up an 8x8 grid so you can see that everything is lined up right.
+
+* The black square in [gfx/font/black.png](../blob/master/gfx/font/black.png);
+* The up arrow in [gfx/font/up_arrow.png](../blob/master/gfx/font/up_arrow.png);
+* The telephone in [gfx/font/phone_icon.png](../blob/master/gfx/font/phone_icon.png);
+* The bold V, bold S and colon copied from the top row of [gfx/font/font_extra.png](../blob/master/gfx/font/font_extra.png);
+* The feet and inches indicators from [gfx/font/feet_inches.png](../blob/master/gfx/font/feet_inches.png) - note that these should be pasted side-by-side, rather than vertically as in the source image.
+
+# Step 3: Edit some code which loads text tiles into VRAM.
+
+Edit [engine/gfx/load_font.asm](../blob/master/engine/gfx/load_font.asm):
+
+```diff
+_LoadFontsExtra1:: ; fb48a
+- ld de, FontsExtra_SolidBlackGFX
+- ld hl, vTiles2 tile "■" ; $60
+- lb bc, BANK(FontsExtra_SolidBlackGFX), 1
+- call Get1bpp_2
+- ld de, PokegearPhoneIconGFX
+- ld hl, vTiles2 tile "☎" ; $62
+- lb bc, BANK(PokegearPhoneIconGFX), 1
+- call Get2bpp_2
+- ld de, FontExtra + 3 tiles ; "<BOLD_D>"
+- ld hl, vTiles2 tile "<BOLD_D>"
+- lb bc, BANK(FontExtra), 22 ; "<BOLD_D>" to "ぉ"
++ ld de, FontExtra + 16 tiles ; "<PO>"
++ ld hl, vTiles2 tile "<PO>" ; $70
++ lb bc, BANK(FontExtra), $6
+ call Get2bpp_2
+ jr LoadFrame
+; fb4b0
+
+_LoadFontsExtra2:: ; fb4b0
+- ld de, FontsExtra2_UpArrowGFX
+- ld hl, vTiles2 tile "▲" ; $61
+- ld b, BANK(FontsExtra2_UpArrowGFX)
+- ld c, 1
+- call Get2bpp_2
+ ret
+; fb4be
+```
+
+This stops the game clobbering the new map tiles at 0x60 through 0x6F.
+
+# Step 4: Update the character set.
+
+We need the text engine to know about the new tile arrangement. Edit [charmap.asm](../blob/master/charmap.asm):
+
+```diff
+; Actual characters (from gfx/font/font_extra.png)
+
+- charmap "<BOLD_A>", $60 ; unused
+- charmap "<BOLD_B>", $61 ; unused
+- charmap "<BOLD_C>", $62 ; unused
+- charmap "<BOLD_D>", $63 ; unused
+- charmap "<BOLD_E>", $64 ; unused
+- charmap "<BOLD_F>", $65 ; unused
+- charmap "<BOLD_G>", $66 ; unused
+- charmap "<BOLD_H>", $67 ; unused
+- charmap "<BOLD_I>", $68 ; unused
+- charmap "<BOLD_V>", $69
+- charmap "<BOLD_S>", $6a
+- charmap "<BOLD_L>", $6b ; unused
+- charmap "<BOLD_M>", $6c ; unused
+- charmap "<COLON>", $6d ; colon with tinier dots than ":"
+- charmap "ぃ", $6e ; hiragana small i, unused
+- charmap "ぅ", $6f ; hiragana small u, unused
+ charmap "<PO>", $70
+ charmap "<KE>", $71
+
+...
+
+; Actual characters (from other graphics files)
+
+- ; needed for _LoadFontsExtra1 (see engine/load_font.asm)
+- charmap "■", $60 ; gfx/font/black.2bpp
+- charmap "▲", $61 ; gfx/font/up_arrow.png
+- charmap "☎", $62 ; gfx/font/phone_icon.2bpp
+-
+- ; needed for MagikarpHouseSign (see engine/events/magikarp.asm)
+- charmap "′", $6e ; gfx/font/feet_inches.png
+- charmap "″", $6f ; gfx/font/feet_inches.png
+-
+ ; needed for StatsScreen_PlaceShinyIcon and PrintPartyMonPage1
+ charmap "⁂", $3f ; gfx/stats/stats_tiles.png, tile 14
+
+...
+
+ charmap "y", $b8
+ charmap "z", $b9
+
+ charmap "Ä", $c0
+ charmap "Ö", $c1
+ charmap "Ü", $c2
+ charmap "ä", $c3
+ charmap "ö", $c4
+ charmap "ü", $c5
++ charmap "■", $c6
++ charmap "▲", $c7
++ charmap "☎", $c8
++ charmap "′", $c9
++ charmap "″", $ca
++ charmap "<BOLD_V>", $cb
++ charmap "<BOLD_S>", $cc
++ charmap "<COLON>", $cd ; colon with tinier dots than ":"
+
+ charmap "'d", $d0
+ charmap "'l", $d1
+```
+
+# Step 5: Change the handful of hardcoded tile placements.
+
+Edit [engine/events/map_name_sign.asm](../blob/master/engine/events/map_name_sign.asm):
+
+```diff
+-MAP_NAME_SIGN_START EQU $60
++MAP_NAME_SIGN_START EQU $70
+```
+
+Edit [engine/menus/naming_screen.asm](../blob/master/engine/menus/naming_screen.asm):
+
+```diff
+NAMINGSCREEN_CURSOR EQU $7e
+
+-NAMINGSCREEN_BORDER EQUS "\"■\"" ; $60
++NAMINGSCREEN_BORDER EQUS "\"ぁ\"" ; $76
+NAMINGSCREEN_MIDDLELINE EQUS "\"→\"" ; $eb
+NAMINGSCREEN_UNDERLINE EQUS "\"<DOT>\"" ; $f2
+```
+
+# Step 6: Change how the game determines which tiles hide the player.
+
+This enables us to use tiles 0xE0 through 0xFF without them hiding the player.
+
+Edit `Function56cd` in [engine/overworld/map_objects.asm](../blob/master/engine/overworld/map_objects.asm):
+
+```diff
+ ld a, [hUsedSpriteIndex]
+ add d
+ dec a
+ cp SCREEN_WIDTH
+ jr nc, .ok8
+ ld c, a
+ push bc
+- call Coord2Tile
++ call Coord2Attr
+ pop bc
+-; NPCs disappear if standing on tile $60-$7f (or $e0-$ff),
+-; since those IDs are for text characters and textbox frames.
+ ld a, [hl]
+- cp FIRST_REGULAR_TEXT_CHAR
+- jr nc, .nope
++ and PALETTE_MASK
++ cp PAL_BG_TEXT
++ jr z, .nope
+.ok8
+ dec d
+ jr nz, .next
+.ok9
+ dec e
+ jr nz, .loop
+ and a
+ ret
+
+```
+
+# Step 7: Update all the tilesets to the new arrangement.
+
+First, we need to edit every `_metatiles.bin` file in the `data/tilesets` folder. This is tedious to do manually, so I wrote a Python script which will do it for you. Put it in the root of your project as a file named `convert.py` and run it from there with the command `python3 convert.py`.
+
+```python
+import glob
+
+path = "./data/tilesets/*_metatiles.bin"
+
+for filename in glob.glob(path):
+ with open(filename, "rb") as fh:
+ data = fh.read()
+ print("Converting {}".format(filename))
+ with open(filename, "wb") as fh:
+ for b in data:
+ if 0x60 <= b < 0x80:
+ b = 0xff
+ elif 0x80 <= b < 0x90:
+ b -= 0x20
+ elif 0x90 <= b:
+ b -= 0x10
+ fh.write(b.to_bytes(1, byteorder="little"))
+```
+
+Next, you need to edit every `_palette_map.asm` file in the `gfx/tilesets` folder. I'll show you the first one, [gfx/tilesets/aerodactyl_word_room_palette_map.asm](../blob/master/gfx/tilesets/aerodactyl_word_room_palette_map.asm), as an example; the rest all follow the same pattern of moving two `tilepal` lines from below the `rept` block to above it, changing the `1`s to `0`s, then halving the number after `rept`.
+
+```diff
+ tilepal 0, GRAY, GRAY, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 0, WATER, WATER, WATER, WATER, YELLOW, YELLOW, GRAY, GRAY
+ tilepal 0, YELLOW, YELLOW, BROWN, BROWN, YELLOW, YELLOW, YELLOW, YELLOW
+ tilepal 0, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, GRAY, GRAY
+ tilepal 0, YELLOW, YELLOW, YELLOW, YELLOW, BROWN, BROWN, BROWN, BROWN
+ tilepal 0, BROWN, BROWN, RED, RED, RED, GRAY, GRAY, GRAY
+ tilepal 0, YELLOW, YELLOW, YELLOW, YELLOW, BROWN, BROWN, YELLOW, YELLOW
+ tilepal 0, YELLOW, YELLOW, RED, RED, RED, GRAY, GRAY, GRAY
+ tilepal 0, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW
+ tilepal 0, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, BROWN, BROWN, BROWN
+ tilepal 0, GRAY, GRAY, GRAY, GRAY, BROWN, BROWN, BROWN, BROWN
+ tilepal 0, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
++ tilepal 0, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
++ tilepal 0, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+
+-rept 16
++rept 8
+ db $ff
+endr
+
+- tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+- tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+ tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN
+```
+
+If you've previously [added `PRIORITY` colors so map tiles can appear above sprites](Allow-map-tiles-to-appear-above-sprites-\(so-NPCs-can-walk-behind-tiles\)-with-PRIORITY-colors), you've already changed the number after `rept` to `32`, and should change it back to `16`.