Skip to content

Expand tilesets from 192 to 255 tiles

mid-kid edited this page Apr 17, 2019 · 38 revisions

By default, tilesets in Gen 2 are limited to 192 tiles. But we can see with BGB's VRAM viewer that there's room for more:

Screenshot

VRAM is divided into six areas, each 128 tiles large. The bottom-left and bottom-right areas are mostly for map tiles: $00–$5F on the left, $80–$DF on the right. The middle-left area ($80–$FF), and the bottom two rows of the bottom-left area ($60–$7F), are for text character tiles. The bottom two rows of the bottom-right area ($E0–$FF) are unused. Furthermore, many of the text tiles are unused as well, including the ümläuted letters, most of the bold letters, etc.

It's fairly simple to use $E0–$FF for 32 more map tiles. We can also use $60–$7E by moving its necessary text tiles into the main font area, leaving only $7F for the space character and allowing 255 map tiles.

(The code for this feature was adapted from Pokémon Polished Crystal.)

Contents

  1. Move necessary text tiles to the main font graphics
  2. Update the character set
  3. Load the updated font graphics
  4. Delete the unused font graphics
  5. Load tile graphics into $60–$7F and $E0–$FF
  6. Update the tilesets' graphics to not skip $60–$7F
  7. Update the tilesets' palette maps to not skip $60–$7F
  8. Don't hide sprites behind $60–$7E or $E0–$FE
  9. Change some hard-coded tile placements
  10. Correct other implicit assumptions about tiles

1. Move necessary text tiles to the main font graphics

Of the 32 tiles in the $60–$7F range, only 18 are actually used:

The prime marks in gfx/font/feet_inches.png are also used. Meanwhile, the six ümläuted letters in gfx/font/font.png are unused, and the decimal point character is identical to the period. So replace them like this:

gfx/font/font.png

Do the same for gfx/font/font_inversed.png:

gfx/font/font_inversed.png

And gfx/font/overworld.png:

gfx/font/overworld.png

Note that the textbox frames aren't present in these graphics. That's because they would be overwritten by whichever frame is actually chosen, so it would waste space to replicate them here.

2. Update the character set

Edit charmap.asm:

-; 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
-	charmap "“",         $72 ; opening quote
-	charmap "”",         $73 ; closing quote
-	charmap "·",         $74 ; middle dot, unused
-	charmap "…",         $75 ; ellipsis
-	charmap "ぁ",         $76 ; hiragana small a, unused
-	charmap "ぇ",         $77 ; hiragana small e, unused
-	charmap "ぉ",         $78 ; hiragana small o, unused
-
-	charmap "┌",         $79
-	charmap "─",         $7a
-	charmap "┐",         $7b
-	charmap "│",         $7c
-	charmap "└",         $7d
-	charmap "┘",         $7e
-	charmap " ",         $7f

 ...

 ; 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
+	charmap " ",         $7f ; gfx/frames/space.png

 	; needed for StatsScreen_PlaceShinyIcon and PrintPartyMonPage1
 	charmap "⁂",         $3f ; gfx/stats/stats_tiles.png, tile 14

 ...

-	charmap "Ä",         $c0
-	charmap "Ö",         $c1
-	charmap "Ü",         $c2
-	charmap "ä",         $c3
-	charmap "ö",         $c4
-	charmap "ü",         $c5
+	charmap "┌",         $ba
+	charmap "─",         $bb
+	charmap "┐",         $bc
+	charmap "│",         $bd
+	charmap "└",         $be
+	charmap "┘",         $bf
+
+	charmap "′",         $ce
+	charmap "″",         $cf

	charmap "'d",        $d0
	charmap "'l",        $d1
	charmap "'m",        $d2
	charmap "'r",        $d3
	charmap "'s",        $d4
	charmap "'t",        $d5
	charmap "'v",        $d6
+
+	charmap "■",         $d7
+	charmap "▲",         $d8
+	charmap "☎",         $d9
+	charmap "<BOLD_V>",  $da
+	charmap "<BOLD_S>",  $db
+	charmap "<COLON>",   $dc ; colon with tinier dots than ":"
+	charmap "“",         $dd ; opening quote
+	charmap "”",         $de ; closing quote

 	charmap "←",         $df
 	charmap "'",         $e0
 	charmap "<PK>",      $e1
 	charmap "<MN>",      $e2
 	charmap "-",         $e3
+
+	charmap "<PO>",      $e4
+	charmap "<KE>",      $e5

 	charmap "?",         $e6
 	charmap "!",         $e7
 	charmap ".",         $e8
+	charmap "<DOT>",     $e8 ; decimal point; same as "."
 	charmap "&",         $e9

 	charmap "é",         $ea
 	charmap "→",         $eb
 	charmap "▷",         $ec
 	charmap "▶",         $ed
 	charmap "▼",         $ee
 	charmap "♂",         $ef
 	charmap "¥",         $f0
 	charmap "×",         $f1
-	charmap "<DOT>",     $f2 ; decimal point; same as "." in English
+	charmap "…",         $f2 ; ellipsis
 	charmap "/",         $f3
 	charmap ",",         $f4
 	charmap "♀",         $f5

3. Load the updated font graphics

Edit engine/gfx/load_font.asm:

 _LoadStandardFont::
-	ld de, Font
-	ld hl, vTiles1
-	lb bc, BANK(Font), 128 ; "A" to "9"
-	ldh a, [rLCDC]
-	bit rLCDC_ENABLE, a
-	jp z, Copy1bpp
-
 	ld de, Font
 	ld hl, vTiles1
 	lb bc, BANK(Font), 32 ; "A" to "]"
 	call Get1bpp_2
 	ld de, Font + 32 * LEN_1BPP_TILE
 	ld hl, vTiles1 tile $20
-	lb bc, BANK(Font), 32 ; "a" to $bf
+	lb bc, BANK(Font), 26 ; "a" to "z" (skip "┌" to "┘")
 	call Get1bpp_2
 	ld de, Font + 64 * LEN_1BPP_TILE
 	ld hl, vTiles1 tile $40
-	lb bc, BANK(Font), 32 ; "Ä" to "←"
+	lb bc, BANK(Font), 32 ; $c0 to "←"
 	call Get1bpp_2
 	ld de, Font + 96 * LEN_1BPP_TILE
 	ld hl, vTiles1 tile $60
 	lb bc, BANK(Font), 32 ; "'" to "9"
 	call Get1bpp_2
 	ret

 _LoadFontsExtra1::
-	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 "ぉ"
-	call Get2bpp_2
 	jr LoadFrame

 _LoadFontsExtra2::
-	ld de, FontsExtra2_UpArrowGFX
-	ld hl, vTiles2 tile "▲" ; $61
-	ld b, BANK(FontsExtra2_UpArrowGFX)
-	ld c, 1
-	call Get2bpp_2
 	ret

And edit mobile/mobile_41.asm:

 Function106464::
-	ld de, FontsExtra_SolidBlackGFX
-	ld hl, vTiles2 tile "■" ; $60
-	lb bc, BANK(FontsExtra_SolidBlackGFX), 1
-	call Get2bpp
-	ld de, FontsExtra2_UpArrowGFX
-	ld hl, vTiles2 tile "▲" ; $61
-	lb bc, BANK(FontsExtra2_UpArrowGFX), 1
-	call Get2bpp
 	ld de, GFX_106514
-	ld hl, vTiles2 tile "☎" ; $62
+	ld hl, vTiles2 tile $62
 	ld c, 9
 	ld b, BANK(GFX_106514)
 	call Get2bpp
 	ld de, $40b0
 	ld hl, vTiles2 tile $6b
 	ld b, $f ; XXX no graphics at 0f:40b0
 	call Get2bpp
 	farcall LoadFrame
 	ret

4. Delete the unused font graphics

Delete gfx/font/font_extra.png, gfx/font/phone_icon.png, gfx/font/black.png, gfx/font/up_arrow.png, and gfx/font/feet_inches.png.

Edit gfx/font.asm:

-FontExtra:
-INCBIN "gfx/font/font_extra.2bpp"

 ...

-PokegearPhoneIconGFX:
-INCBIN "gfx/font/phone_icon.2bpp"

 ...

-FontsExtra_SolidBlackGFX:
-INCBIN "gfx/font/black.1bpp"

 ...

-FontsExtra2_UpArrowGFX:
-INCBIN "gfx/font/up_arrow.2bpp"

Edit engine/events/magikarp.asm:

-Magikarp_LoadFeetInchesChars:
-	ld hl, vTiles2 tile "′" ; $6e
-	ld de, .feetinchchars
-	lb bc, BANK(.feetinchchars), 2
-	call Request2bpp
-	ret
-
-.feetinchchars
-INCBIN "gfx/font/feet_inches.2bpp"
-
 PrintMagikarpLength:
-	call Magikarp_LoadFeetInchesChars
 	ld hl, wStringBuffer1
 	ld de, wMagikarpLength
 	lb bc, PRINTNUM_RIGHTALIGN | 1, 2
 	call PrintNum
 	ld [hl], "′"
 	inc hl
 	ld de, wMagikarpLength + 1
 	lb bc, PRINTNUM_RIGHTALIGN | 1, 2
 	call PrintNum
 	ld [hl], "″"
 	inc hl
 	ld [hl], "@"
 	ret

5. Load tile graphics into $60–$7F and $E0–$FF

Edit home/map.asm.

 LoadTilesetGFX::
 	...

 	ld a, e
 	ld de, wDecompressScratch
 	call FarDecompress

 	ld hl, wDecompressScratch
 	ld de, vTiles2
-	ld bc, $60 tiles
+	ld bc, $7f tiles
 	call CopyBytes

 	ldh a, [rVBK]
 	push af
 	ld a, $1
 	ldh [rVBK], a

 ...

 	ldh a, [rVBK]
 	push af
 	ld a, $1
 	ldh [rVBK], a

-	ld hl, wDecompressScratch + $60 tiles
+	ld hl, wDecompressScratch + $80 tiles
 	ld de, vTiles2
-	ld bc, $60 tiles
+	ld bc, $80 tiles
 	call CopyBytes

 	pop af
 	ldh [rVBK], a

Now instead of loading tileset graphics into tiles $00–$5F and $80–$DF, they'll be loaded into $00–$7E and $80–$FF. That's nearly four more rows, or 63 more tiles, usable for maps. (Note that only the first $7F tiles are loaded instead of the full $80; tile $7F, is not loaded because the space character goes there.)

6. Update the tilesets' graphics to not skip $60–$7F

Edit all the gfx/tilesets/*.png files with more than six rows of tiles. In each case, we need to add two rows of blank tiles for the $60–$7F range (that is, the seventh and eighth rows). Here's one example, gfx/tilesets/johto_modern.png:

gfx/tilesets/johto_modern.png

You can also copy the modified tilesets from here.

7. Update the tilesets' palette maps to not skip $60–$7F

Edit all 37 gfx/tilesets/*_palette_map.asm files. In each case, we need to replace the 16 $ff bytes that were placeholders for $60–$7F to be four tilepal lines.

Here's one example, gfx/tilesets/johto_modern_palette_map.asm:

	tilepal 0, GRAY, BROWN, BROWN, RED, GREEN, GREEN, GRAY, ROOF
	tilepal 0, RED, RED, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF
	tilepal 0, ROOF, ROOF, ROOF, GREEN, WATER, GREEN, BROWN, BROWN
	tilepal 0, RED, RED, BROWN, BROWN, BROWN, GRAY, GREEN, GREEN
	tilepal 0, GRAY, GRAY, BROWN, RED, RED, GRAY, YELLOW, BROWN
	tilepal 0, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, GRAY, RED
	tilepal 0, GRAY, BROWN, BROWN, GRAY, BROWN, GRAY, GRAY, YELLOW
	tilepal 0, YELLOW, BROWN, BROWN, BROWN, BROWN, BROWN, GREEN, GREEN
	tilepal 0, RED, BROWN, GRAY, GRAY, BROWN, BROWN, BROWN, BROWN
	tilepal 0, BROWN, WATER, GRAY, BROWN, BROWN, BROWN, GRAY, GRAY
	tilepal 0, GRAY, BROWN, BROWN, GRAY, BROWN, GRAY, GRAY, GRAY
	tilepal 0, WATER, GRAY, GRAY, GRAY, BROWN, BROWN, GRAY, GRAY
-
-rept 16
-	db $ff
-endr
-
+	tilepal 0, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF
+	tilepal 0, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF
+	tilepal 0, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF
+	tilepal 0, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF, TEXT
	tilepal 1, GRAY, BROWN, BROWN, RED, GREEN, GREEN, GRAY, ROOF
	tilepal 1, RED, RED, ROOF, ROOF, ROOF, ROOF, ROOF, ROOF
	tilepal 1, ROOF, ROOF, ROOF, GREEN, WATER, GREEN, BROWN, ROOF
	tilepal 1, ROOF, ROOF, ROOF, BROWN, BROWN, GRAY, GREEN, GREEN
	tilepal 1, GRAY, GRAY, BROWN, RED, RED, GRAY, YELLOW, BROWN
	tilepal 1, BROWN, BROWN, BROWN, BROWN, BROWN, BROWN, GRAY, RED
	tilepal 1, GRAY, BROWN, BROWN, GRAY, BROWN, GRAY, GRAY, YELLOW
	tilepal 1, YELLOW, BROWN, BROWN, BROWN, BROWN, BROWN, GREEN, GREEN
	tilepal 1, RED, BROWN, GRAY, GRAY, BROWN, BROWN, BROWN, BROWN
	tilepal 1, BROWN, WATER, GRAY, BROWN, BROWN, BROWN, GRAY, GRAY
	tilepal 1, GRAY, BROWN, BROWN, GRAY, RED, RED, GREEN, GREEN
	tilepal 1, YELLOW, ROOF, ROOF, ROOF, ROOF, ROOF, RED, ROOF

The ROOF values are for tiles $60–$7E, which can be used for maps, and the TEXT value is for $7F, the space character.

8. Don't hide sprites behind $60–$7E or $E0–$FE

By default, sprites will disappear when they're behind (on top of) tiles $60–$6F or $D0–$FF, as well as the regular font tiles. This is so they won't appear on top of textboxes. This is caused by engine/overworld/map_objects.asm:

Function56cd:
	...
	ld c, a
	push bc
	call Coord2Tile
	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
.ok8
	dec d
	jr nz, .next
.ok9
	dec e
	jr nz, .loop
	and a
	ret

Edit constants/text_constants.asm:

-FIRST_REGULAR_TEXT_CHAR EQU $60
+FIRST_REGULAR_TEXT_CHAR EQU $7f

Now tiles $60–$7E and $E0–$FE can safely have NPCs on top of them, but tiles $7F and $FF cannot. Tile $7F is the space character, so that's appropriate, but you'll have to remember not to place any sprites on tile $FF either.

(Until September 23, 2018, this step recommended that you edit Function56cd to call Coord2Attr instead of Coord2Tile, and check for the PAL_BG_TEXT color attribute instead of the FIRST_REGULAR_TEXT_CHAR tile ID. However, as ShinyDragonHunter noticed, this failed under certain circumstances involving the popup map name signs and automatic cutscenes—such as the Tin Tower scene where you battle Suicune.)

9. Change some hard-coded tile placements

Some parts of the code use "vTiles2 tile N" to hard-code the data for a tile from $00 to $7F. When such a tile is moved to the range $80–$FF, the offset is invalid, so it has to become "vTiles0 tile N".

Edit engine/gfx/load_font.asm again:

 LoadFrame:
 	ld a, [wTextboxFrame]
 	maskbits NUM_FRAMES
 	ld bc, 6 * LEN_1BPP_TILE
 	ld hl, Frames
 	call AddNTimes
 	ld d, h
 	ld e, l
-	ld hl, vTiles2 tile "┌" ; $79
+	ld hl, vTiles0 tile "┌" ; $ba
 	lb bc, BANK(Frames), 6 ; "┌" to "┘"
 	call Get1bpp_2
 	ld hl, vTiles2 tile " " ; $7f
 	ld de, TextboxSpaceGFX
 	lb bc, BANK(TextboxSpaceGFX), 1
 	call Get1bpp_2
 	ret

Edit mobile/mobile_41.asm again:

 Function10649b:
 	ld a, [wTextboxFrame]
 	maskbits NUM_FRAMES
 	ld bc, 6 * LEN_1BPP_TILE
 	ld hl, Frames
 	call AddNTimes
 	ld d, h
 	ld e, l
-	ld hl, vTiles2 tile "┌" ; $79
+	ld hl, vTiles0 tile "┌" ; $ba
 	ld c, 6 ; "┌" to "┘"
 	ld b, BANK(Frames)
 	call Function1064c3
 	ld hl, vTiles2 tile " " ; $7f
 	ld de, TextboxSpaceGFX
 	ld c, 1
 	ld b, BANK(TextboxSpaceGFX)
 	call Function1064c3
 	ret

Edit engine/menus/naming_screen.asm:

-NAMINGSCREEN_BORDER     EQU "■" ; $60
+NAMINGSCREEN_BORDER     EQU "■" ; $d7
 NAMINGSCREEN_MIDDLELINE EQU "→" ; $eb
-NAMINGSCREEN_UNDERLINE  EQU "<DOT>" ; $f2
+NAMINGSCREEN_UNDERLINE  EQU "☎" ; $d9

 LoadNamingScreenGFX:
 	...

-	ld de, vTiles2 tile NAMINGSCREEN_BORDER
+	ld de, vTiles0 tile NAMINGSCREEN_BORDER
 	ld hl, NamingScreenGFX_Border
 	ld bc, 1 tiles
 	ld a, BANK(NamingScreenGFX_Border)
 	call FarCopyBytes

(Older versions of pokecrystal before rgbds 0.3.8 can't understand constants like X_VALUE EQU "X", so they have to use X_VALUE EQUS "\"X\"" instead.)

Edit engine/events/map_name_sign.asm:

-MAP_NAME_SIGN_START EQU $60
+MAP_NAME_SIGN_START EQU $c0

 ...

 LoadMapNameSignGFX:
 	ld de, MapEntryFrameGFX
-	ld hl, vTiles2 tile MAP_NAME_SIGN_START
+	ld hl, vTiles0 tile MAP_NAME_SIGN_START
 	lb bc, BANK(MapEntryFrameGFX), 14
 	call Get2bpp
 	ret

Edit engine/events/halloffame.asm:

-HALLOFFAME_COLON EQU $63

 ...

 HOF_AnimatePlayerPic:
 	call ClearBGPalettes
-	ld hl, vTiles2 tile HALLOFFAME_COLON
-	ld de, FontExtra + 13 tiles ; "<COLON>"
-	lb bc, BANK(FontExtra), 1
-	call Request2bpp
 	hlcoord 0, 0
 	ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
 	ld a, " "
 	call ByteFill
 	...
-	ld [hl], HALLOFFAME_COLON
+	ld [hl], "<COLON>"
 	...

(If it's unclear to you why we have to do this, take a look at the VRAM screenshot again, noting that vTiles0 is the top-left sixth, vTiles1 is the middle-left, and vTiles2 is the bottom-left, with all three being sequential in memory.)

10. Correct other implicit assumptions about tiles

Edit engine/pokemon/correct_nick_errors.asm:

 .textcommands
 ; table defining which characters are actually text commands
 ; format:
 	;      ≥           <
 	db "<NULL>",   "ガ"
 	db "<PLAY_G>", "<JP_18>" + 1
 	db "<NI>",     "<NO>"    + 1
 	db "<ROUTE>",  "<GREEN>" + 1
 	db "<ENEMY>",  "<ENEMY>" + 1
 	db "<MOM>",    "<TM>"    + 1
-	db "<ROCKET>", "┘"       + 1
+	db "<ROCKET>", " "
 	db -1 ; end

The next two changes were already made to pokecrystal by pull requests #530 and #534 before July 2018, so if your copy is newer than that you can skip the rest of this step.

Edit engine/pokegear/pokegear.asm:

 .jump_return
 	push de
 	hlcoord 0, 12
 	lb bc, 4, 18
 	call Textbox
 	hlcoord 1, 14
-	ld [hl], $72
+	ld [hl], "“"
 	pop de
 	hlcoord 2, 14
 	call PlaceString
 	ld h, b
 	ld l, c
-	ld [hl], $73
+	ld [hl], "”"
 	call WaitBGMap
 	ret

And edit engine/link/link_2.asm:

 LinkTextbox2:
 	...
 
 .PlaceBorder:
 	push hl
 	ld a, $76
 	ld [hli], a
 	inc a
 	call .PlaceRow
 	inc a
 	ld [hl], a
 	pop hl
 	ld de, SCREEN_WIDTH
 	add hl, de
 .loop
 	push hl
-	ld a, "┌"
+	ld a, $79
 	ld [hli], a
 	ld a, " "
 	call .PlaceRow
-	ld [hl], "─"
+	ld [hl], $7a
 	pop hl
 	ld de, SCREEN_WIDTH
 	add hl, de
 	dec b
 	jr nz, .loop
 
-	ld a, "┐"
+	ld a, $7b
 	ld [hli], a
-	ld a, "│"
+	ld a, $7c
 	call .PlaceRow
-	ld [hl], "└"
+	ld [hl], $7d
 	ret
 
 .PlaceRow:
 	ld d, c
 .row_loop
 	ld [hli], a
 	dec d
 	jr nz, .row_loop
 	ret

Now the game will work just like before:

Screenshot

…except the VRAM now looks something like this, with 63 more tiles available to use for maps:

Screenshot

Furthermore, Polished Map (with the 256 Tiles option checked) will correctly load, edit, and save the enlarged tilesets:

Screenshot

Remember, tile $7F is reserved for the space character, so don't use it for a map tile.

This entire change is compatible with adding PRIORITY colors so NPCs can walk behind tiles; in step 7, you'll just be removing a rept 32 instead of a rept 16.

Note that tiles $C0–$CD are blank in the font graphics, but get overwritten by the popup map name sign tiles. It's still okay to use them for your own text characters ("É", "¿", "♪", "♥", etc), just don't use those tiles in any map names.

You can also easily get rid of some rarely-used characters if you need more font space:

Clone this wiki locally
You can’t perform that action at this time.