Pokémon Crystal any% speedrun route: Difference between revisions

Jump to navigation Jump to search
m
typo
>Bbbbbbbbba
m (→‎Arbitrary code execution: Change "jp (hl)" to "jp hl")
>Bbbbbbbbba
m (typo)
Line 6:
 
==Preparations==
 
* Clear saves between resets.
** This is required any time you start a New Game, since your lucky ID persists regardless of having a save file.
* [https://youtu.be/LgQiDpcPpDQ '''Manipulate for a Trainer ID of 0x26FB (09979) and Lucky ID of 0x186F (06255).''']
* [https://youtu.be/zqTlMDVPg0oLgQiDpcPpDQ '''Manipulate for a CyndaquilTrainer withID DVsof E9xx''']0x26FB (see09979) theand originalLucky routeID guideof for0x186F detailed inputs(06255).''']
*[https://youtu.be/zqTlMDVPg0o '''Manipulate for a Cyndaquil with DVs E9xx'''] (see the original route guide for detailed inputs).
** This manipulation needs the player name to be 3 characters (the preset name "MAT" will do).
* Swap Leer and Tackle during the Rival fight to set up the move order.
*Swap WinLeer and Tackle during the rivalRival fight to levelset up andthe learnmove Smokescreenorder.
*Win the rival fight to level up and learn Smokescreen.
** '''The moves of Cyndaquil should be Leer, Tackle, Smokescreen in this order''' (Tackle, Smokescreen, Leer also works, but takes more time).
* Catch any encounter (2 Pokémon are required for cloning).
* Run from all other encounters (guarantees safe experience values).
 
==Bad clone glitch==
 
* Go to the PC on the 2nd floor of Cherrygrove Pokémon Center.
* '''Rename boxes:'''
** BOX 1: T 0 'v é N 5 'v 's
** BOX 21: éT n 60 'v f é RN 5 'v 's
** BOX 32: f é on 6 p'v éf ''é'' 6R 5
** BOX 43: f é ''5''o 56 <PK>p <PK>é 'd'é'' 6
** BOX 14: T 0é 'v é N'5'' 5 'v<PK> <PK> 'sd
** Note: Characters in italic doesndon't matter (they are overwritten by the ACE).
* '''Move Cyndaquil to the second slot in party''', and save the game ("move PkMn w/o mail" is the fastest way to achieve both).
* '''Do the [[bad clone glitch]] by depositing one of the Pokémon, switching boxes and hard resetting during the save.'''
** Either a "real" bad clone (level 0) or a "pseudo" bad clone (correct level, but unterminated nickname; referred to as "friendly clone" in the original route guide) will work.
 
==Arbitrary code execution==
 
* After reloading the save, go down 1 tile, then right 4 tiles.
* Open Pokédex and scroll to the position of Spearow (0x15).
** '''This sets the temporary variable $D265 to 0x15. $D266 (wFailedToFlee) should remain 0x00 after reset.'''
** Notice that where the accessible Pokédex ends will depend on what Pokémon you have seen. In case the only wild Pokémon you have seen is Pidgey, Spearow would be out of reach in new Pokédex mode, so the player will need to go to old Pokédex mode (where Cyndaquil comes after Spearow).
* Close out of Pokédex, go left 4 tiles then up 1 tile to get back to PC.
** '''This movement sets up an array at $CD70 that stores some pointers for the background map to begin with "D8 9B DA 9B DC 9B ...".''' <!-- TODO: Elaborate. -->
* Open PC and go to the withdraw screen.
** '''The game will try to show the [[unterminated name Pokémon (Generation II)|unterminated nickname]] starting from $D073.''' There are a lot of data between there and $D265, but after a reset they are predictable, and won't contain any terminators or other problematic control characters. Finally, after a few B presses for control characters, the text engine reaches $D265 and triggers [[0x1500 control code arbitrary code execution]], making the program counter jump to $CD52.
** Relevant register states:
*** a = 0x52 (temporary variable for reading out the jump destination $CD52)
*** e = 0xFF (jumptable index minus one)
***e carry= flag unset0xFF (calculating the address of jumptable entry 255index didn'tminus overflowone)
***carry flag unset (calculating the address of jumptable entry 255 didn't overflow)
 
{|
|-
|
{| border="1" width="100%" align="left" style="background:#f0f0f0; border:1px solid #000000; border-collapse:collapse;"
|- style="background: silver;"
! Program counter !! Hex !! ASM !! In-game meaning !! In-game value !! Comments
|-
| $CD52 ~ $CD6F || 00 (*30) || nop || <!-- TODO --> || ||
|-
| $CD70 || D8 || ret c || rowspan="3" | Pointers to background map tiles || rowspan="3" | $9BD8, $9BDA, $9BDC... || Jump not taken
|-
| $CD71 || 9B || '''sbc e''' || Sets the carry flag (0x52 - 0xFF)
|-
| $CD72 || DA 9B DC || '''jp c, $DC9B''' || Jump taken
|-
| $DC9B ~ $DC9E || 00 (*4) || nop || Unused || ||
|-
| $DC9F || 18 6F || '''jr 0x6F''' || Lucky ID || 06255 (0x186F) || Jumps to $DD10
|-
| $DD10 || AD / 00 || xor l / nop || Held item of second party Pokémon (Cyndaquil) || Berry / nothing ||
|-
| $DD11 || 2B || dec hl || First move of Cyndaquil || Leer ||
|-
| $DD12 || 21 6C 00 || '''ld hl, 0x006C''' || Second to fourth move of Cyndaquil || Tackle, Smokescreen, empty slot || hl = 0x006C
|-
| $DD15 || 26 FB || '''ld h, 0xFB''' || Original Trainer ID of Cyndaquil || 09979 (0x26FB) || hl = 0xFB6C
|-
| $DD17 ~ $DD18 || 00 00 || nop || rowspan="2" | Experience of Cyndaquil<br /><br /> || rowspan="2" | 205 (0x0000CD) ||
|-
| rowspan="2" | $DD19 || rowspan="2" | CD 00 32 || rowspan="2" | '''call $3200''' || rowspan="2" | Calls WaitBGMap2, which calls DelayFrames;<br />a = 0x00, c = 0x00
|-
| Stat experience (HP) of Cyndaquil || 50 (0x0032)
|-
| $DD1C || 00 || nop || rowspan="2" | Stat experience (Attack) of Cyndaquil || rowspan="2" | 65 (0x0041) ||
|-
| $DD1D || 41 || ''ld b, c'' || b = 0x00
|-
| $DD1E || 00 || nop || rowspan="2" | Stat experience (Defense) of Cyndaquil || rowspan="2" | 64 (0x0040) ||
|-
| $DD1F || 40 || ld b, b ||
|-
| $DD20 || 00 || nop || rowspan="2" | Stat experience (Speed) of Cyndaquil || rowspan="2" | 43 (0x002B) ||
|-
| $DD21 || 2B || '''dec hl''' || hl = 0xFB6B
|-
| $DD22 || 00 || nop || rowspan="2" | Stat experience (Special) of Cyndaquil || rowspan="2" | 44 (0x002C) ||
|-
| $DD23 || 2C || '''inc l''' || hl = 0xFB6C
|-
| $DD24 || E9 || '''jp hl''' || First byte of DVs of Cyndaquil || 0xE9 || Jumps to 0xFB6C (Echo RAM, equivalent to $DB6C)
|-
| $FB6C ~ $FB71 || 00 (*6) || nop || Unused || ||
|-
| $FB72 || 00 || nop || Index of current box (0-based) || Box 1 ||
|-
| $FB73 ~ $FB74 || 00 00 || nop || Unused || ||
|-
| $FB75 || 93 || '''sub e''' || rowspan="5" | Box 1 name || T || a = 0x01
|-
| $FB76 || F6 D6 || '''or a, 0xD6''' || 0 'v || a = 0xD7
|-
| $FB78 || EA 8D FB || '''ld ($FB8D), a''' || é N 5 || ($FB8D) = 0xD7
|-
| $FB7B || D6 D4 || '''sub a, 0xD4''' || 'v 's || a = 0x03
|-
| $FB7D || 50 || ld d, b || (terminator) ||
|-
| $FB7E || EA AD FC || '''ld ($FCAD), a''' || rowspan="4" | Box 2 name || é n 6 || [wBackupMapGroup] = 0x03
|-
| $FB81 || D6 A5 || '''sub a, 0xA5''' || 'v f || a = 0x5E
|-
| $FB83 || EA B1 FB || '''ld ($FB91), a''' || é R 5 || ($FB91) = 0x5E
|-
| $FB86 || 50 || ld d, b || (terminator) ||
|-
| $FB87 || A5 || '''and l''' || rowspan="5" | Box 3 name ($FB8D overwritten by previous code) || f || a = 0x4C
|-
| $FB88 || EA AE FC || '''ld ($FCAE), a''' || é o 6 || [wBackupMapNumber] = 0x4C
|-
| $FB8B || AF || '''xor a''' || p || a = 0x00; clears the carry flag
|-
| $FB8C || EA D6 FC || '''ld ($FCD7), a''' || é (0xD7) 6 || [wPartyCount] = 0x00
|-
| $FB8F || 50 || ''ld d, b'' || (terminator) || d = 0x00
|-
| $FB90 || EA 5D FB || '''ld ($FB5E), a''' || rowspan="5" | Box 4 name ($FB91 overwritten by previous code) || é (0x5E) 5 || [wEventFlags + 236] = 0x00
|-
| $FB93 || E1 || '''pop hl''' || <PK> || Pops text pointer
|-
| $FB94 || E1 || '''pop hl''' || <PK> || Pops return pointer in RunMobileScript
|-
| $FB94 || D0 || '''ret nc''' || 'd || Returns to MobileScriptChar
|}
|}
 
* The text engine continues to try to display text from de = 0x00FF, prints some more garbage, but eventually encounters a 0x50 terminator.
* Close the PC, and go downstairs.
** Since the 2nd floor of Pokémon centers are in fact a shared map, the downstairs warp uses wBackupMapGroup and wBackupMapNumber to determine which map to return to. Map 0x4C in map group 0x03 is Red's room in Mt. Silver. Before the ACE, the game is supposed to return the player to warp 0x03 in the 1st floor of Cherrygrove Pokémon Center, so now the game will try to return the player to warp 0x03 in Red's room. Warp 0x03 is invalid, but it turns out to be at coordinate (13, 7), which is conveniently close to Red at (9, 10).
* Talk to Red.
** Normally, Red only appears in Mt. Silver after the Hall of Fame sequence, but setting [wEventFlags + 236] = 0x00 resets the appropriate event flag and lets him appear.
** At this point, we have no Pokémon in our party (more precisely, our party count is 0), so the [[instant victory glitch (Generation II)|"instant victory effect"]] is triggered. Since the player never entered a battle since loading the save file, the overworld script acts as if the player won. In the case of Red, this means going to the credit roll.
 
{{Youtube|qaVUIAgsLpY|Pokeguy84}}
 
==See also==
 
* [http://wiki.pokemonspeedruns.com/index.php?title=Pok%C3%A9mon_Crystal/Any%25_Guide The full current Crystal any% route]
 
[[Category:Speedrun routes]]
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu