rlm@614: Pokemon Yellow Total Control Hack. Reprogramming the game from the inside! rlm@614: rlm@614: !! Game objectives rlm@614: rlm@614: * Emulator used: vba-rerecording 23.5 rlm@614: * Reprogram the Game from the inside rlm@614: rlm@614: !! Comments rlm@614: rlm@614: I've included a detailed writeup here: rlm@614: http://aurellem.org/vba-clojure/html/total-control.html rlm@614: rlm@614: There is a video at: rlm@614: http://www.youtube.com/watch?v=p5T81yHkHtI with keypress visualizations rlm@614: rlm@614: The following are the highlights: rlm@614: rlm@614: ! Introduction rlm@614: rlm@614: Think of pokemon yellow as creating a little universe with certain rlm@614: rules. Inside that universe, you can buy items, defeat rival trainers, rlm@614: and raise your pokemon. But within that universe, you are bound by the rlm@614: rules of pokemon. You can't build new buildings, or change the music, rlm@614: or change your clothes.. There are some games (like chess), where it rlm@614: is not possible to alter the rules of the game from within the rlm@614: game. No matter what moves you make in chess, you can never change the rlm@614: rules of the game so that it becomes checkers or basketball. The point rlm@614: of this run is to show that you CAN change the rules in pokemon rlm@614: yellow. There is a certain sequence of valid actions (like walking rlm@614: from one place to another or buying items) that will allow you to rlm@614: transform pokemon yellow into Pacman, or Tetris, or Pong, or a MIDI rlm@614: player, or anything else you can imagine. rlm@614: rlm@614: rlm@614: ! Background rlm@614: rlm@614: The speedrun (http://tasvideos.org/2913S.html) by Felipe Lopes de rlm@614: Freitas (p4wn3r), beats pokemon yellow in only 1 minute and 36 rlm@614: seconds. It does it by corrupting the in-game item list so that he can rlm@614: advance the list past its normal limit of 20 items. The memory rlm@614: immediately after the item list includes the warp points for the rlm@614: current map, and by treating that data as items and switching and rlm@614: dropping them, he can make the door from his house take him directly rlm@614: to the end of the game. rlm@614: rlm@614: When I first saw that speedrun, I was amazed at how fast pokemon rlm@614: yellow could be beaten, and that it was possible to manipulate the rlm@614: game from the inside, using only the item list. I wondered how far I rlm@614: could extend the techniques found in p4wn3r's run. rlm@614: rlm@614: The gameboy is an 8 bit computer. That means that ultimately, anything rlm@614: that happens in pokemon is a result of the gameboy's CPU reading a rlm@614: stream of 8 bit numbers and doing whatever those numbers mean. For rlm@614: example, in the gameboy, the numbers: rlm@614: rlm@614: 62 16 37 224 47 240 37 230 15 55 rlm@614: rlm@614: mean to check which buttons are currently pressed and copy that result rlm@614: into the "A" register. With enough numbers, you can spell out an rlm@614: interactive program that reads input from the buttons and allows you rlm@614: to write any program you want to the gameboy. Once you have assembled rlm@614: such a program and forced the game to run it, you have won, since you rlm@614: can use that program to write any other program (like Tetris or rlm@614: Pacman) over pokemon yellow's code. I call a program that allows you rlm@614: to write any other program a "bootstrapping program". So, the goal is rlm@614: to somehow get a bootstrapping program into pokemon yellow and then rlm@614: force yellow to run that program instead of its own. rlm@614: rlm@614: How can we spell out such a program? Everything in the game is rlm@614: ultimately numbers, including all items, pokemon, levels, etc. In rlm@614: particular, the item list looks like: rlm@614: rlm@614: rlm@614: item-one-id (0-255) rlm@614: item-one-quantity (0-255) rlm@614: item-two-id (0-255) rlm@614: item-two-quantity (0-255) rlm@614: . rlm@614: . rlm@614: . rlm@614: rlm@614: rlm@614: Let's consider the button measuring program [37 62 16 37 224 37 240 rlm@614: 37 230 15 55] from before. Interpreted as items and item quantities, it is rlm@614: rlm@614: lemonade x16 rlm@614: guard spec. x224 rlm@614: leaf stone x240 rlm@614: guard spec. x230 rlm@614: parlyz heal x55 rlm@614: rlm@614: So, if we can get the right items in the right quantities, we can rlm@614: spell out a bootstrapping program. Likewise, when writing the rlm@614: bootstrapping program, we must be careful to only use numbers that are rlm@614: also valid items and quantities. This is hard because there aren't rlm@614: many different items to work with, and many machine instructions rlm@614: actually take 2 or even 3 numbers in a row, which severely restricts rlm@614: the types of items you can use. I ended up needing about 92 numbers to rlm@614: implement a bootstrap program. Half of those numbers were elaborate rlm@614: ways of doing nothing and were just there so that the entire program rlm@614: was also a valid item list. rlm@614: rlm@614: The final part of the hack is getting pokemon yellow to execute the rlm@614: new program after it has been assembled with items. Fortunately, rlm@614: pokemon keeps a number called a function pointer within easy reach of rlm@614: the corrupted item list. This function pointer is the starting point rlm@614: (address) of a program which the game runs every so often to check for rlm@614: poison and do general maintenance. By shifting an item over this rlm@614: function pointer, I can rewrite that address to point to the rlm@614: bootstrapping program, and make the game execute it. Without this rlm@614: function pointer, it would not be possible to take over the game. rlm@614: rlm@614: !! The Run rlm@614: rlm@614: ! Pallet rlm@614: rlm@614: I start off and name my rival Lp/k. These characters will eventually be rlm@614: treated as items and shifted over the function pointer, causing it to rlm@614: execute the bootstrapping program that will soon be constructed. I rlm@614: start the run the same as p4wn3r's and restart the game while saving, rlm@614: so that the pokemon list is corrupted. By switching the 8th and 10th rlm@614: pokemon, I corrupt the item list and can now scroll down past the 20th rlm@614: item. I shift items around to increase the text speed to maximum and rlm@614: rewrite the warp point of my house to Celadon Dept. Store. (p4wn3r rlm@614: used this to go directly to the hall of fame and win the game in his rlm@614: run.) I deposit many 0x00 glitch items into the PC from my corrupted rlm@614: inventory for later use. Then, I withdraw the potion from the rlm@614: PC. This repairs my item list by overflowing the item counter from rlm@614: 0xFF back to 0x00, though the potion is obliterated in the process. I rlm@614: then take 255 glitch items with ID 0x00 from the computer into my rlm@614: personal items. rlm@614: rlm@614: ! Celadon Dept. Store rlm@614: rlm@614: Leaving my house takes me directly to Celadon Dept. store, where I rlm@614: sell two 0x00 items for 414925 each, giving myself essentially max rlm@614: money. I hit every floor of the department store, gathering the rlm@614: following items: rlm@614: rlm@614: +-------------------+----------+ rlm@614: |##| Item | Quantity | rlm@614: +--+----------------+----------+ rlm@614: |1 | TM02 | 98 | rlm@614: |2 | TM37 | 71 | rlm@614: |3 | TM05 | 1 | rlm@614: |4 | TM09 | 1 | rlm@614: |5 | burn-heal | 12 | rlm@614: |6 | ice-heal | 55 | rlm@614: |7 | parlyz-heal | 99 | rlm@614: |8 | parlyz-heal | 55 | rlm@614: |9 | TM18 | 1 | rlm@614: |10| fire-stone | 23 | rlm@614: |11| water-stone | 29 | rlm@614: |12| x-accuracy | 58 | rlm@614: |13| guard-spec | 99 | rlm@614: |14| guard-spec | 24 | rlm@614: |15| lemonade | 16 | rlm@614: |16| TM13 | 1 | rlm@614: +--+----------------+----------+ rlm@614: rlm@614: rlm@614: After gathering these items, I deposit them in the appropriate order rlm@614: into the item PC to spell out my bootstrapping program. Writing a full rlm@614: bootstrap program in one go using only items turned out to be too rlm@614: hard, so I split the process up into three parts. The program that I rlm@614: actually construct using items is very limited. It reads only from the rlm@614: A, B, start, and select buttons, and writes 4 bits each frame starting rlm@614: at a fixed point in memory. After it writes 200 or so bytes, it jumps rlm@614: directly to what it just wrote. In my run, I use this program to write rlm@614: another bootstrapping program that can write any number of bytes to rlm@614: any location in memory, and then jump to any location in memory. This rlm@614: new program also can write 8 bits per frame by using all the rlm@614: buttons. Using this new bootstrap program, I write a final rlm@614: bootstrapping program that does everything the previous bootstrapping rlm@614: program does except it also displays the bytes it is writing to memory rlm@614: on the screen. rlm@614: rlm@614: ! Finale rlm@614: rlm@614: After completing this bootstrapping program, I go to the Celadon rlm@614: mansion, because I find the metaness of that building to be rlm@614: sufficiently high to serve as an exit point for the pokemon rlm@614: universe. I corrupt my item list again by switching corrupted pokemon, rlm@614: scroll down to my rival's name and discard until it is equal to the rlm@614: address of my bootstrapping program, and then swap it with the rlm@614: function pointer. Once the menu is closed, the bootstrapping program rlm@614: takes over, and I write the payload.... rlm@614: rlm@614: !! Other comments rlm@614: rlm@614: The entire video was played by the computer using bots. I used rlm@614: functional programming to write search programs over different rlm@614: possible game states to find the most efficient way of performing rlm@614: general actions. Some interesting things I developed but didn't use rlm@614: were pretty printing functions to display the game's internal data rlm@614: structures, and an "improbability drive" that forces improbable events rlm@614: to happen automatically using search. rlm@614: rlm@614: Here are a few example scripts: rlm@614: rlm@614: rlm@614: (defn-memo viridian-store->oaks-lab rlm@614: ([] (viridian-store->oaks-lab rlm@614: (get-oaks-parcel) ) ) rlm@614: ([ script \] rlm@614: (->> script rlm@614: (walk [↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ rlm@614: ← ← ← ← ← ← ← ← ← rlm@614: ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ rlm@614: ← ← rlm@614: ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ rlm@614: ↓ ↓ ↓ ↓ ↓ ↓ ↓ rlm@614: → → → → → → → → rlm@614: ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ rlm@614: ← ← ← ← ← rlm@614: ↓ ↓ ↓ ↓ rlm@614: ]) rlm@614: (walk-thru-grass rlm@614: [↓ ↓ ↓ ↓ ↓ ↓ ↓]) rlm@614: (walk [↓ ↓ ← ↓ ↓ ↓ ← rlm@614: ↓ ↓ ↓ ↓ ↓ ↓ rlm@614: → → → ↑]) rlm@614: rlm@614: (do-nothing 1) ) ) ) rlm@614: rlm@614: rlm@614: This script walks from the Viridian City pokemon store to Oak's rlm@614: Lab in the most efficient way possible. The walk-thru-grass function rlm@614: guarantees that no wild battles will happen by manipulating the game's rlm@614: random number generator. rlm@614: rlm@614: rlm@614: (defn-memo hacking-10 rlm@614: ([] (hacking-10 (hacking-9) ) ) rlm@614: ([ script \] rlm@614: (->> script rlm@614: begin-deposit rlm@614: (deposit-held-item 17 230) rlm@614: (deposit-held-item-named :parlyz-heal 55) rlm@614: (deposit-held-item 14 178) rlm@614: (deposit-held-item-named :water-stone 29) rlm@614: (deposit-held-item 14 32) rlm@614: (deposit-held-item-named :TM18 1) rlm@614: (deposit-held-item 13 1) rlm@614: (deposit-held-item 13 191) rlm@614: (deposit-held-item-named :TM02 98) rlm@614: (deposit-held-item-named :TM09 1) rlm@614: close-menu) ) ) rlm@614: rlm@614: rlm@614: This script calculates the fastest sequence of key presses to deposit rlm@614: the requested items into a PC, assuming that the character starts out rlm@614: in front of a computer. rlm@614: rlm@614: !! Other Comments rlm@614: rlm@614: The final payload program is multiple programs. I created a reduced rlm@614: form of MIDI and implemented it in gameboy machine language. Then I rlm@614: translated a midi file from http://www.everyponysings.com/ into this rlm@614: reduced MIDI language. The payload program contains both the music rlm@614: data and the MIDI interpreter to play that data. The picture works in rlm@614: a similar way. There is code to translate a png file into a form that rlm@614: can be displayed on a gameboy, and other code to actually display that rlm@614: image. Both the image and the display code are also written by the rlm@614: final bootstrapping program. Even though my final payload is rather rlm@614: simple, you can write any program at all as the payload. The source rlm@614: for the sound and image displaying code is at rlm@614: http://hg.bortreb.com/vba-clojure. rlm@614: rlm@614: This entire project is open source and I encourage anyone who wants to rlm@614: take the code and play around! rlm@614: rlm@614: rlm@614: !! Suggested Screenshots rlm@614: rlm@614: * http://aurellem.org/pokemon-hack/code.png rlm@614: * http://aurellem.org/pokemon-hack/code2.png rlm@614: * http://aurellem.org/pokemon-hack/matrix.png rlm@614: * http://aurellem.org/pokemon-hack/matrix2.png rlm@614: * http://aurellem.org/pokemon-hack/pinkie-pie.png rlm@614: rlm@614: Or whatever you all think would be best. rlm@614: rlm@614: I encoded the video with/without button visualization here: rlm@614: rlm@614: * http://aurellem.org/pokemon-hack/rlm-yellow-hack.avi rlm@614: * http://aurellem.org/pokemon-hack/rlm-yellow-hack-no-buttons.avi