Guides:TMless 0x1500 ACE

From Glitch City Wiki
Jump to navigation Jump to search


WARNING: This guide is outdated and has been replaced by a faster and easier setup. It is only kept for legacy purposes. You can find all up-to-date guides on the TimoVM's Gen 2 ACE setups article.

This is a guide on how to execute and/or exploit a glitch. For a more technical overview of the glitch involved, see 0x1500 control code arbitrary code execution.

This page serves as a repository on a 0x1500 ACE setup for the English, French, German, Italian and Spanish versions of Pokémon Crystal. It is part of the TimoVM's Gen 2 ACE setups set of guides.

The guide is split up between guides applicable for players starting a new game or continuing from an old game. Please make sure to fully read every step of the guide before executing them.

The preparation is best done during nighttime in-game. If needed, you can change the in-game clock with the help of this tool.

If you encounter any issues when going through this guide or would like to provide feedback, please contact TimoVM on the Glitch City Research Institute Discord.

When playing on cartridge or emulator, it is required to have previously cleared an old save by pressing SELECT + UP + B simultaneously on the start screen at least once since obtaining the cart. Otherwise you will not be able to obtain a bad clone or an unterminated name pokémon.

General overview

Pokémon Crystal contains two important differences compared to its predecessors. Firstly, Crystal won't abort the text printing function when it encounters a $00 value, instead printing a '?' instead. Secondly, Crystal added new printing funtions related to the Mobile Game Boy Adapter, a Japanese exclusive peripheral that allowed internet connectivity through a mobile phone.

By obtaining a pokémon whose name does not contain the usual text terminator, we can force the game into printing much larger amounts of texts than would otherwise be possible. By abusing an illegal Mobile Adapter function and setting up memory in a specific way, we can escape the text printing function and trigger arbitrary code execution based on the data of the last viewed party pokémon.

In practice, the initial ACE setup will be created using the following general process:

  1. Train a pokémon that can redirect the effect of 0x1500 ACE to the last read mail.
  2. Obtain an unterminated name pokémon.
  3. Set up the currently buffered memory in such a way that we can trigger 0x1500 ACE upon seeing the name of the unterminated name pokémon.

Regarding PKHex

At the moment, this guide is incompatible with saves exported from PKHex. Upon exporting a save, PKHex will fill all currently unused data for the OT name and nickname of all boxes with text terminators, making it impossible to obtain an unterminated name pokémon.

Starting from a new game

Step 1: Preparing the Onix

Start playing the game as you normally would, the starter doesn't matter. It is recommended that you don’t fight the bug catcher on route 31.

  1. Once you reach route 31, catch a bellsprout (20% spawn odds, all day).
  2. Proceed to Violet City. In the house to the left of the pokémon center, trade your Bellsprout for Rocky the Onix. In case you have already traded and used Onix prior to reading this guide, an alternative setup is provided further on in the page.
  3. With Onix, defeat the following Pokémon. It is imperative that Onix is the only pokémon that gains experience during these battles:
    • Spinarak (30% spawn odds on route 31, only during nighttime)
    • Spinarak (30% spawn odds on route 31, only during nighttime)
    • Spinarak (30% spawn odds on route 31, only during nighttime)
    • Caterpie (30% spawn odds on route 30, only during morning and midday. The trainer on route 31 has three Caterpie you can fight)
    • Caterpie (30% spawn odds on route 30, only during morning and midday. The trainer on route 31 has three Caterpie you can fight)
  4. Make sure Onix doesn’t hold any item, check that Tackle is set as its first move.
  5. Go to Violet City’s pokémon mart. Buy 22 flower mails. If you’re starting from a new save, make sure that you have at least one poké ball left in the ball pocket.

Step 2: Preparing the bad clone and remaining items

  1. Use the bad clone glitch to obtain a pokémon with an unterminated name.
    1. For this, use a box that has never been full at any point in time. It’s recommended to start with an empty box.
    2. Deposit a single pokémon. Attempt to save the game using "Move Pokémon w/o mail" but reset the game a bit just after the game has fully printed "SAVING... DON'T TURN OFF THE POWER".
    3. After rebooting the game, use a potion up to where the game brings up the party screen. the potion doesn't have to actually be used, you can cancel from here), then check the newly deposited pokémon.
    4. If the newly deposited pokémon’s nickname was changed to a bunch of question marks, you can continue with the next step. If the pokémon wasn't saved, that means the reset too early. If the pokémon was cloned, this means the reset was too late.
    5. If the amount of pokémon in the box exceeds 15, release the cloned pokémon and save the game afterwards to set the amount of stored pokémon to 15 before repeating step 2.
  2. Now that you have an unterminated name pokémon, put it in box 1. Either release or move all other pokémon in the box so that the unterminated name pokémon is the only pokémon left in box 1.
  3. Finally, give another pokémon (Can not be Onix) a mail to hold with the following text:
English French German Italian Spanish





Testing the setup

In order to be able to test the setup, rename box 1 to the following names:

English French German Italian Spanish





This box name code will be used to test the setup. It has no effect outside of safely exiting ACE and returning the game's state back to normal. Please note that, for specific languages, the mail code included in the setup will overwrite some box name characters. This effect is normal and has no permanent effect.

Step 3: using the ACE setup

Before executing ACE, arrange your party as follow:

  • Slot 1 - Rocky the Onix, no held item
  • Slot 2 - Any pokémon, holding previously written mail
  • Slots 3-6 aren't relevant for this setup.

In order to execute ACE, do the following actions:

  1. Stand in front of the PC on the second floor of any pokémon center. Save and reset the game.
  2. Take exactly one step down and open the start menu.
  3. Open the summary of Onix and close it.
  4. Read the mail you've previously written.
  5. Open the item bag and select the option to toss mails. Change the amount to be tossed to 21, then cancel with B.
  6. Switch to the ball pocket, go to the bottommost CANCEL button, then press A while your cursor is on the CANCEL button to leave the item pack. Additional note: Ensure that the bottommost item of the pocket you're exiting from is an item with less than 10 total characters.
  7. Take one step up and open the PC. Open the withdraw screen so that the unterminated name pokémon's name would be displayed. Displaying this name will trigger ACE. NOTE: If the name of the pokémon in the box ends with a decimal dot ".", you will need to exit the withdraw screen and open it again to trigger ACE.

If the game doesn't crash, the setup was a success and you can continue to the end of the page.

Starting from an older save

Step 1: Preparing the Sandshrew

Continue playing the game as you normally would.

  1. Once you reach Union Cave, catch a Sandshrew (30% spawn odds, only during morning and midday). It is recommended to use TM31 to teach it Mud-slap (Obtained by beating Falkner).
  2. With Sandshrew, defeat the following Pokémon. It is imperative that Sandshrew is the only pokémon that gains experience during these battles:
    • Geodude (30% spawn odds in Union Cave, 20% spawn odds on route 33, entire day)
    • Geodude (30% spawn odds in Union Cave, 20% spawn odds on route 33, entire day)
    • Hoppip (15% spawn odds on route 33, only during morning and midday)
  3. Talk to the guard in the gate between Ilex Forest and route 34 to obtain Kenya the Spearow. If Kenya is not available, it can be substituted by any other wild Spearow.
  4. Once you reach Goldenrod City, go to the Goldenrod Dept. Buy a Flower Mail and a Lemonade (can be bought from the vending machines at the top floor).
  5. Give Sandshrew the Lemonade as a held item, ensure it has Scratch as its first move.

Step 2: Preparing the bad clone and remaining items

  1. Use the bad clone glitch to obtain a pokémon with an unterminated name.
    1. For this, use a box that has never been full at any point in time. It’s recommended to start with an empty box.
    2. Deposit a single pokémon. Attempt to save the game using "Move Pokémon w/o mail" but reset the game a bit just after the game has fully printed "SAVING... DON'T TURN OFF THE POWER".
    3. After rebooting the game, use a potion up to where the game brings up the party screen. the potion doesn't have to actually be used, you can cancel from here), then check the newly deposited pokémon.
    4. If the newly deposited pokémon’s nickname was changed to a bunch of question marks, you can continue with the next step. If the pokémon wasn't saved, that means the reset too early. If the pokémon was cloned, this means the reset was too late.
    5. If the amount of pokémon in the box exceeds 15, release the cloned pokémon and save the game afterwards to set the amount of stored pokémon to 15 before repeating step 2.
  2. Now that you have an unterminated name pokémon, put it in box 1. Either release or move all other pokémon in the box so that the unterminated name pokémon is the only pokémon left in box 1.
  3. Finally, give your Spearow (either Kenya or another Spearow) a mail to hold with the following text:
English French German Italian Spanish





Testing the setup

In order to be able to test the setup, rename box 1 to the following names:

English French German Italian Spanish





This box name code will be used to test the setup. It has no effect outside of safely exiting ACE and returning the game's state back to normal. Please note that, for specific languages, the mail code included in the setup will overwrite some box name characters. This effect is normal and has no permanent effect.

Step 3: Using the ACE setup

Before executing ACE, arrange your party as follow:

  • Slot 1 - Spearow, holding mail
  • Slot 2 - Sandshrew, holding Lemonade
  • Slots 3-6 aren't relevant for this setup.

In order to execute ACE, do the following actions:

  1. Stand in front of the PC on the second floor of any pokémon center. Save and reset the game.
  2. Take exactly one step down and open the start menu.
  3. Open the summary of Sandshrew and close it.
  4. Take exactly one step up so you’re in front of the PC. Open the start menu again
  5. Read the mail you've previously given to Spearow (the Spearow needs to be at the very top of your party list).
  6. Open the PC. Open the withdraw screen so that the unterminated name pokémon's name would be displayed. Displaying this name will trigger ACE.
  7. If the game doesn't crash, the setup was a success and you can now continue. For the Japanese version, after executing ACE for the first time, the first item in your main item pocket will have been changed to a TM15. With the current box name, using this TM15 will not have any effect yet.

What to do with this ACE setup

Now that the ACE setup has been succesfully tested, we can start expanding the setup to more easily write arbitrary data and be more convenient to use. This will be done by installing the Mail writer, a small program installed using a set of box name codes.

Use the following link to continue to the next guide: Mail writer C

Appendix: In-depth explanation of the setup

Effect of Onix

Defeating the provided list of pokémon and viewing Onix's summary will result in the following values starting from the buffered species ID at $D10E, assuming the pokémon is in party slot #2:

5F		ld e, a
00		nop
21 67 00	ld hl, $0067	; Determined by Onix's moves, Tackle and Screech
00		nop
BF		cp a, a
1E 00		ld e, $00	; $BF1E corresponds to Onix's OTID of 48926
01 XX 00	ld bc, $00XX	; $XX is determined by the exact level of the opponents fought
D2 00 F0	jp nc, $F000

After the effect of 0x1500 ACE is triggered and execution is redirected to $D10E, execution slides harmlessly through move, OTID and experience data before jumping to $F000, which is echo RAM for $D000 and is located two bytes before the last buffered mail.

Effect of Sandshrew

Defeating the provided list of pokémon and viewing Sandshrew's summary will result in the following values starting from the buffered species ID at $D10E, assuming the pokémon is in party slot #2:

1B		dec de
30 0A		jr .jump
XX XX XX XX XX XX XX XX XX 73	; Move, OTID and experience is skipped over by the jr instruction
00		nop		; .jump
C3 00 F0	jp $F000

After the effect of 0x1500 ACE is triggered and execution is redirected to $D10E, execution jumps over move, OTID and experience data, followed by another jump to $F000, which is echo RAM for $D000 and is located two bytes before the last buffered mail.

Effect of the mail

The last read mail is buffered from $D002 onward. Please note that viewing the bad clone in box #1 will write the value $01 to $D003 and $D004. Converting the characters from the mail to assembly results in the following, ordered by language:

English

FA 01 01	ld a, ($0101)	; a = $C3
A7		and a, a		; Reset carry flag
D4 75 FB	call nc, wBoxNames
A7		and a, a		; Reset carry flag
E1		pop hl		; After returning from 0x1500 ACE, this prevents the print function from printing text in WRAM.
D0		ret nc

French

FA 01 01	ld a, ($0101)	; a = $C3
D6 F5		sub $F5		; a = $CE, TM15's item ID
EA 93 F8	ld (wItems), a	; Main item pocket, first item ID
D6 F3		sub $F3		; a = $DB
EA 86 FB	ld ($FB86), a
EA E9 FB	ld ($FBE9), a
4E		ld a, a
D6 BA		sub $BA		; a = $21
EA 75 FB	ld (wBoxNames), a
D6 FF		sub $FF		; a = $22
EA B7 FB	ld ($FBB7), a
AF		xor a		; a = $00, set zero flag
CC 75 DB	call z, wBoxNames
E1		pop hl		; After returning from 0x1500 ACE, this prevents the print function from printing text in WRAM.
D0		ret nc

German

FA 01 01	ld a, ($0101)	; a = $C3
87		add a, a		; a = $86
C6 9C		add $9C		; a = $22
EA A9 FB	ld ($FBA9), a
C6 FF		add $FF		; a = $21
EA 75 FB	ld (wBoxNames), a
AF		xor a		; a = $00
F6 4E		or $4E		; a = $4E
F6 80		or $80		; a : $CE
EA 93 F8	ld (wItems), a	; Main item pocket, first item ID
F0 F0		ld a, ($FFF0)	; a = 0, zero flag is NOT reset
C4 75 FB	call z, wBoxNames
E1		pop hl		; After returning from 0x1500 ACE, this prevents the print function from printing text in WRAM.
C0		ret nz

Italian & Spanish

FA 01 01	ld a, ($0101)	; a = $C3
D6 A1		sub $A1		; a = $22
EA C8 FB	ld ($FBC8), a
AF		xor a		; a = $00
CD 75 FB	call wBoxNames
EA 9F FB	ld ($FB9F), a	; Prevent a game crash when viewing the box name
F6 4E		or $4E		; a = $DE
C6 F0		add $F0		; a = $CE
EA 93 F8	ld (wItems), a	; Main item pocket, first item ID
E1		pop hl		; After returning from 0x1500 ACE, this prevents the print function from printing text in WRAM.
C9		ret

Effect of the box name

Box name data starts from $D8BF onward. Converting the provided mail code to assembly results in the following:

English

F6 FF		or $FF		; a = $FF, reset carry flag
D0		ret nc		; Safely return to normal game operation

French

21 80 80	ld hl, $8080
C9		ret		; Safely return to normal game operation

German

21 80 80	ld hl, $8080
F6 FF		or $FF		; a = $FF, reset carry & zero flag
C0		ret nz		; Safely return to normal game operation

Italian & Spanish

C9		ret		; Safely return to normal game operation

Explanation on the 0x1500 ACE setup

This setup uses 0x1500 control code ACE. Since the page already contains an explanation on how it works, this page will focus on what the setup does to achieve its effect.

Relevant addresses for this explanation:

Address Function
$D002 Address where the last read mail is stored.
$D073 Address where the names of pokémon are buffered.
$D086 Address where the names of used items are buffered.
$D108 Address where the current selected party pokémon’s species is buffered.
$D109 Address where the current selected party pokémon’s party slot is buffered.
$D10C Address where the amount of items tossed is buffered.
$D10D Address where the amount of the last selected item is buffered.
$D10E Address where the data of the last viewed pokémon is buffered.
  • Attempting to toss 21 items will buffer $15 at $D10C.
  • For a list at the highest size it has ever been, the "Quantity" of the CANCEL button will be $00, which will be buffered at $D10D when the CANCEL button is used with A. This forms the required $1500 to start executing ACE.
  • By opening the start menu and moving one step up at the specified location, the game will load in a $C0 (ret nz) at $CD70, allowing safe return from the effects of $1500. The game will resume executing from $D10E onward.
  • The last pokémon viewed is buffered from $D10E onward. Setting Tackle ($21) as its first move allows safe passage over Screech ($67).
  • Rocky’s trainer ID is fixed and will be $BF (cp a, which resets the carry flag) and $1E. Both values are safe to pass.
  • Rocky’s XP total will end up between 326 and 350. This is always interpreted as $01 and $XX. since the high HP stat exp byte is always $00, the total is interpreted as ld bc, $00XX. This means that exp is always safe to pass.
  • Due to the specific pokémon defeated, the data in the stat experience fields will be read as $D2 $00 $F0. This is interpreted as jp nc $F000, due to echo ram this will redirect execution to $D000, which is where the last read mail was buffered. The nc condition is always fulfilled thanks to the previous $BF (cp a) in Onix’s Trainer ID.
  • At this point, the mail will redirect execution to $FB75. Due to echo ram, this will effectively redirect execution to $DB75, the start of box name 1. Please note that $D003 and $D004 are overwritten by opening the withdraw screen to the values of the current box and slot of the currently selected stored pokémon. These values are taken care of by setting the first character of the mail to $FA, which is interpreted along with the next two values as ld a, (YYXX).
  • Afterwards, the game will simply execute the box name code.
  • For the alternative method, selecting Spearow to read its mail will buffer both its species and party slot to $D108 and $D109. By putting a Spearow in the topmost party slot, this will buffer a $15 and $00 respectively. One drawback of this approach is that these RAM values are more volatile and are immediately overwritten after executing ACE. Luckily, Onix’s species ID ($5F) acts as a text terminator, preventing users from accidentally crashing the game if they forget to reset these values.

Additional note: $D086 isn’t actually relevant to the setup. The reason it’s mentioned here is because using an item buffers the item’s name to this location, placing a $50 terminator just a bit after where the pokémon’s name is normally buffered. Having this terminator in place will allow you to safely view an unterminated pokémon’s name.

Plain text transcript for codes

  • Mail
Language Mail content
English
4 4 4 h ‘s … 5 h Pk ‘d 
French
4 4 4 j' ♀ é T 2 j' / é G 5 é & 5
j' à é ... 5 j' 9 é x 5 p î ... s' Pk ô 
German
4 4 4 H ë : é j 5 ë 9 é ... 5 p 0
0 A é T 2 $ $ ö ... 5 Pk Ä
Italian
4 4 4 ° b é Ì 5 p Ù ... 5 é ] 5 0
È $ é T 2 Pk Í
Spanish
4 4 4 ° b é Ì 5 p Ù ... 5 é ] 5 0
È $ é T 2 Pk Í
"..." refers to a single ellipsis character, “pk” refers to a single pk symbol.
  • Test box code
English French German Italian Spanish
0 9 'd
A A A ô
A A A 0 9 Ä
Í
Í