Skip to content

Longer Move Names (13 or 14 characters)

Porygondolier edited this page Apr 14, 2026 · 7 revisions

Introduction

Greetings. This tutorial will cover the modifications necessary to expand the maximum length of a move name from the vanilla 12 characters to 13 or 14 characters.

If you only need 13 characters, you can follow the first section and stop. For 14 characters, first follow Section 1, and then apply the additional changes of Section 2 on top.

If you are interested in understanding the full background of what makes longer move names a challenge, read on, otherwise, feel free to jump to Section 1.

How move names work

Move names are described in data/moves/names.asm where you will see them defines as follows:

	li "SKY ATTACK"

Here, li is a compiler side macro that simply appends an "@" to the end of the move name as a terminal.

In otherwords, the name of the move is stored in the game more like this:

	SKY ATTACK@

(This is simplifying it slightly, but good enough for this explanation)

When the game needs to display a move, the GetMoveName function is called. This function will copy 20 bytes of data from the list of names, into wNameBuffer. In the original game, move names are never more than 12 characters. Therefore, including the final "@", move names never take up more than 13 bytes. This means that wNameBuffer is already more than big enough to support longer names.

In the case of using TMs, a different buffer is used: wTempMoveNameBuffer this one is only designed to hold 14 bytes, so we'll take care with this one later in the tutorial.

The limitations of the text box

image

The text box is able to display 18 characters in the first row, and (typically) 17 characters in subsequent rows. The reason for the difference here is the downward facing arrow icon we see at the end of line 2. In some cases, the arrow is not displayed, which allows for 18 characters on line 2.

With this in mind, as we increase the maximum length of move names, we need to account for every case of move names being displayed in the text box.

Scenario Image Problem for 13 Characters? Problem for 14 Characters?
Booting up TM image X X
Use TM? image
Pokemon incompatible with TM image X X
Can't learn the move image X X
Move already known image X X
Trying to learn move image X X
Make room for move? image X
Abandon learning move? image X X
Did not learn move image X X
Learned move image X X
Player's Pokemon used move image
Opponents's Pokemon used move image
Move was disabled image X
Move is disabled image X X
Temporarily learned a move via Mimic image X X

Other places that display move names

Aside from text boxes, we can see move names displayed on the following screens:

Scenario Image Problem for 13 Characters? Problem for 14 Characters?
Status screen image X X
Fight menu image X
Select a move to Mimic screen image X
PP UP or restore PP with an Ether image X
Select a move to forget screen image X

Interestingly, we can see that move selection boxes always have space for 13 character move names. When we consider that the smallest buffer used for a move name is 14 bytes (13 characters + "@"), we might imagine that at some point during development, Game Freak were planning to have at least one more with a 13 character name. This is purely speculation, but if I had to guess, I think POISONPOWDER may have been POISON POWDER at one point.

1. 13 Characters

The game is already broadly able to deal with 13 character move names. We only need to make changes to deal with two scenarios:

image image

Teach ************* to a Pokemon?

For this one, I recommend simply tweaking the text. To do that, modify data/text/text_6.asm

_TeachMachineMoveText::
	text "It contained"
	line "@"
	text_ram wStringBuffer
	text "!"

-	para "Teach @"
+	para "Teach a #MON"
+	line "@"
	text_ram wStringBuffer
+	text "?"
-	text_start
-	line "to a #MON?"
	done

The result in game should look like this:

image

As you can see, this also makes plenty of space for the additional increase to 14 characters.

Enemy VICTREEBEL used *************!

I chose the title for this section deliberately to highlight a point.

If we look at the example I showed above, it appears we could easily move the "used" portion of the text onto the above line. However, when an enemy uses an attack, "Enemy" is added before the Pokemon's name. The Pokemon's name is up to 10 characters, meaning the first line is pretty full.

There is no one single correct answer to this problem, but before showing what I did, I'll mention all the alternatives that I came up with. One of these options may be more to your taste.

  • Split the text over 3 lines
    • I personally feel this would make the battles feel more sluggish
  • Remove the "Enemy" part of the text, and place "used" on the top line
    • This may be a little confusing during a classic battle of METAPOD vs METAPOD.
  • "Foe VICTREEBEL used"
    • Unfortunately, this is still 19 characters, so no good.
  • Change the text, for example to:
Enemy VICTREEBEL:
MATCHA GOTCHA

or

Enemy VICTREEBEL's
MATCHA GOTCHA

I just didn't really like these, but there's nothing wrong with this approach.

For my implementation, I ultimately opted for a hybrid approach. If a move name is 12 characters or less, everything will display as per the original game. If the move name exceeds 12 characters, "Enemy" will be omitted and "used" will be appended to line 1.

Modify constant/charmap.asm

...
	charmap "<ROCKET>",  $5e ; "ROCKET"
	charmap "<DEXEND>",  $5f
+	charmap "<USER2>",   $78 ; Same as <USER> but appends "Enemy" conditionally
...
	charmap "ぁ",         $76 ; hiragana small a, unused
	charmap "ぇ",         $77 ; hiragana small e, unused
-	charmap "ぉ",         $78 ; hiragana small o, unused

Modify home/text.asm

...
	dict "<TARGET>",  PlaceMoveTargetsName
	dict "<USER>",    PlaceMoveUsersName
+	dict "<USER2>",   PlaceMoveUsersName2
...
PlaceMoveTargetsName::
	ldh a, [hWhoseTurn]
	xor 1
	jr PlaceMoveUsersName.place

+PlaceMoveUsersName2::
+	ldh a, [hWhoseTurn]
+
+.place:
+	push de
+	and a
+	jr z, PlaceMoveUsersName.jumpInFrom2
+; enemy: determine if move name is 13 or more characters or not
+	push hl
+	ld hl, wStringBuffer
+	ld a, 13
+	ld d, a
+.loop
+	ld a, [hli]
+	cp $50 ;@
+	jr z, .twelveOrLess
+	dec d
+	jr nz, .loop
+.thirteenOrMore
+	pop hl
+	jr PlaceMoveUsersName.enemy2
+	
+.twelveOrLess
+	pop hl
+	jr PlaceMoveUsersName.enemy

PlaceMoveUsersName::
	ldh a, [hWhoseTurn]

.place:
	push de
	and a
	jr nz, .enemy

+.jumpInFrom2
	ld de, wBattleMonNick
	jr PlaceCommandCharacter

.enemy
	ld de, EnemyText
	call PlaceString
+.enemy2
	ld h, b
	ld l, c
	ld de, wEnemyMonNick
	; fallthrough

PlaceCommandCharacter::
	call PlaceString
	ld h, b

Modify data/text/text_2.asm

...
_MonName1Text::
-	text "<USER>@"
+	text "<USER2>@"
	text_end
_Used1Text::
	text_start
	line "used @"
	text_end

_Used2Text::
	text_start
	line "used @"
	text_end
	
+_UsedSameLineText::
+	text " used"
+	line "@"
+	text_end

Modify engine/battle/core.asm

...
MonName1Text:
	text_far _MonName1Text
	text_asm
	ldh a, [hWhoseTurn]
	and a
	ld a, [wPlayerMoveNum]
	ld hl, wPlayerUsedMove
	jr z, .playerTurn
	ld a, [wEnemyMoveNum]
	ld hl, wEnemyUsedMove
.playerTurn
	ld [hl], a
	ld [wMoveGrammar], a
+	push bc
+	ld hl, wStringBuffer
+	ld a, 13
+	ld c, a
+.loop
+	ld a, [hli]
+	cp $50 ;@
+	jr z, .twelveOrLess
+	dec c
+	jr nz, .loop
+.thirteenOrMore
+	pop bc
+	call DetermineExclamationPointTextNum ; useless, eliminate it later
+	ld hl, UsedSameLineText
+	ret
	
+.twelveOrLess
+	pop bc
	call DetermineExclamationPointTextNum
	ld a, [wMonIsDisobedient]
	and a
	ld hl, Used2Text
	ret nz
	ld a, [wMoveGrammar]
	cp 3
	ld hl, Used2Text
	ret c
	ld hl, Used1Text
	ret

+UsedSameLineText:
+	text_far _UsedSameLineText
+	text_asm
+	jr PrintInsteadText

Used1Text:
	text_far _Used1Text
	text_asm
	jr PrintInsteadText

The new <USER2> text function we just created works identically to <USER> when the move user is the player. However, when the enemy is attacking, it checks the length of the move name by searching for the "@" symbol. If "@" if not found in the first 13 characters, the move name is determined to be longer than 12 characters. In this case, it displays the enemy Pokemon name without appending "Enemy" to the beginning.

The second part of what we did is to use alternative "used" text when the move name exceeds 12 characters. The logic is similar, but this one runs in the battle core. Additionally, this is applied for both the player and the opponent.

To test this new functionality, I recommend temporaily changing the name of LEECH LIFE, first to an 11 character name, then 12 and then 13. Go to Mt.Moon and battle some Zubats. In the case of 11 characters it should display:

Enemy ZUBAT
used ELEVEN CHAR!

For 12 characters, it should display like this:

Enemy ZUBAT
used TWELVE CHARA!

And for 13 characters it should display like this:

ZUBAT used
THIRTEEN CHAR!

2. 14 Characters

For this part of the tutorial, I will be using MOONGEIST BEAM as my go-to 14 character move.

A buffer too small

Before we return to the topic of making things fit on the screen, we need to look at that 14 byte buffer I mentioned in the introduction: wTempMoveNameBuffer.

This buffer is only used when learning a move via TM/HM. (Caution: if you have implemented move tutors, it may also be used there)

Because only 14 bytes are copied to the buffer, when we try to teach a TM with a 14 character name, we get a result like this:

image

This is likely because the "@" terminator is missing.

Fortunately, there are two unused bytes after the buffer in the game, so it is a simple case of increasing the buffer size, and changing the code to copy 15 bytes instead of 14.

Modify ram/wram.asm

...
UNION
-wTempMoveNameBuffer:: ds 14
+wTempMoveNameBuffer:: ds 15
NEXTU
; The name of the mon that is learning a move.
wLearnMoveMonName:: ds NAME_LENGTH
ENDU

-	ds 2
+	ds 1
...

Modify engine/items/item_effects.asm

...
.useMachine
	ld a, [wWhichPokemon]
	push af
	ld a, [wCurItem]
	push af
.chooseMon
	ld hl, wStringBuffer
	ld de, wTempMoveNameBuffer
-	ld bc, 14
+	ld bc, 15
	call CopyData ; save the move name because DisplayPartyMenu will overwrite it
	ld a, $ff
	ld [wUpdateSpritesEnabled], a
	ld a, TMHM_PARTY_MENU
	ld [wPartyMenuTypeOrMessageID], a
	call DisplayPartyMenu
	push af
	ld hl, wTempMoveNameBuffer
	ld de, wStringBuffer
-	ld bc, 14
+	ld bc, 15
	call CopyData
...

That should have solved the issue as shown below, and we can now move onto the adjustments.

image

Make room for ... learning a 14 character move!

This mod deals with the issue we see in the last image of the previous section. My solution for this is to modify the text as follows:

Before:

"Delete an older"
"move to make room"
"for MOONGEIST BEAM?"

After:

"Delete a move to"
"make room for"
"MOONGEIST BEAM?"

Of course, tweak this to your personal taste, but the point is to remove "for" from the final line.

Modify data/text/text_4.asm

...
-	para "Delete an older"
-	line "move to make room"
-	cont "for @"
+	para "Delete a move"
+	line "to make room for"
+	cont "@"
	text_ram wStringBuffer
	text "?"
	done
...

The result should look something like this:

image

14 character move... was disabled!

For this one, we simple need to move "was" to the following line.

Modify data/text/text_3.asm

_MoveWasDisabledText::
	text "<TARGET>'s"
	line "@"
	text_ram wNameBuffer
-	text " was"
-	cont "disabled!"
+	text_start
+	cont "was disabled!"
	prompt

Result:

image

Choose a (14 character) move!

With the text box scenarios out of the way, we just need to deal with the move selection boxes, we'll start by doing three at once, the fight menu, the Mimic menu, and the PP restore/PP UP menu.

image

Modify engine/battle/core.asm

...
.regularmenu
	call AnyMoveToSelect
	ret z
	ld hl, wBattleMonMoves
	call .loadmoves
-	hlcoord 4, 12
+	hlcoord 3, 12
	ld b, 4
-	ld c, 14
+	ld c, 15
	di ; out of pure coincidence, it is possible for vblank to occur between the di and ei
	   ; so it is necessary to put the di ei block to not cause tearing
	call TextBoxBorder
-	hlcoord 4, 12
+	hlcoord 3, 12
	ld [hl], "─"
	hlcoord 10, 12
	ld [hl], "┘"
	ei
-	hlcoord 6, 13
+	hlcoord 5, 13
	call .writemoves
-	ld b, $5
+	ld b, $4
	ld a, $c
	jr .menuset
.mimicmenu
	ld hl, wEnemyMonMoves
	call .loadmoves
	hlcoord 0, 7
	ld b, 4
-	ld c, 14
+	ld c, 15
	call TextBoxBorder
	hlcoord 2, 8
	call .writemoves
	ld b, $1
	ld a, $7
	jr .menuset
.relearnmenu
	ld a, [wWhichPokemon]
	ld hl, wPartyMon1Moves
	ld bc, wPartyMon2 - wPartyMon1
	call AddNTimes
	call .loadmoves
-	hlcoord 4, 7
+	hlcoord 3, 7
	ld b, 4
-	ld c, 14
	ld c, 15
	call TextBoxBorder
-	hlcoord 6, 8
+	hlcoord 5, 8
	call .writemoves
-	ld b, $5
+	ld b, $4
	ld a, $7
...

Result:

Scenario Image
Fight Menu image
Mimic Menu image
PP UP or PP Restore image

Forget a (14 character) move!

Although the box for selecting a move to forget (when learning a new move) looks identical to the three boxes in the previous section, it is coded separately.

Modify engine/pokemon/learn_move.asm

...
.loop
	push hl
	ld hl, WhichMoveToForgetText
	call PrintText
-	hlcoord 4, 7
+	hlcoord 3, 7
	ld b, 4
-	ld c, 14
+	ld c, 15
	call TextBoxBorder
-	hlcoord 6, 8
+	hlcoord 5, 8
	ld de, wMovesString
	ldh a, [hUILayoutFlags]
	set BIT_SINGLE_SPACED_LINES, a
	ldh [hUILayoutFlags], a
	call PlaceString
	ldh a, [hUILayoutFlags]
	res BIT_SINGLE_SPACED_LINES, a
	ldh [hUILayoutFlags], a
	ld hl, wTopMenuItemY
	ld a, 8
	ld [hli], a ; wTopMenuItemY
-	ld a, 5
+	ld a, 4
	ld [hli], a ; wTopMenuItemX

Result:

image

And with that, you have successfully increased the character limit to 14.

Going Beyond 14 Characters

This tutorial does not cover even longer move names, but if you want to attempt it, here are some things to consider:

  • The move selection box on the party screen will grow even larger, meaning that some party icons will need to be hidden. Otherwise, they will show up on top of the box.
  • The in-battle text string "is disabled" will become problematic, so care needs to be taken there.

An alternative to going longer than 14 characters

Since the number of moves with more than 14 characters is relatively small, you might consider the ILLUSIYELLOW approach.

This involves creating some narrow font characters and including them in the empty spaces of: gfx/font/font.png

The same technique can also be used to deal with Pokemon names that exceed 10 characters, and here is some video covering that topic if it is of interest: LEASTPOLTEISPHALLTER

Outroduction

Thank you for reading this tutorial. I was careful to ensure that I covered all of the scenarios, but if you find something which I didn't cover, please let me know by messaging my on discord, in the pret server @porygondolier.

Finally, I'd like to wish you a wonderful day!

Clone this wiki locally