Mercurial > vba-clojure
comparison org/total-control.org @ 609:65b7c5b47de1
first draft of explination.
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Thu, 22 Nov 2012 10:54:59 -0600 |
parents | 2c348cc68bac |
children | 4dd5ebf224cd |
comparison
equal
deleted
inserted
replaced
608:2c348cc68bac | 609:65b7c5b47de1 |
---|---|
7 #+INCLUDE: ../../aurellem/org/level-0.org | 7 #+INCLUDE: ../../aurellem/org/level-0.org |
8 #+BABEL: :exports both :noweb yes :cache no :mkdirp yes | 8 #+BABEL: :exports both :noweb yes :cache no :mkdirp yes |
9 #+OPTIONS: num:2 | 9 #+OPTIONS: num:2 |
10 | 10 |
11 | 11 |
12 Full Source : http://hg.bortreb.com/vba-clojure | |
13 | |
14 Youtube Video w/ Visual Keypresses: http://www.youtube.com/watch?v=p5T81yHkHtI | |
15 | |
16 Special Thanks to: | |
17 | |
18 - http://tasvideos.org/2913S.html for the save corruption hack which | |
19 is used at the start of this run. | |
20 - http://www.everyponysings.com/ for providing the midi file I used | |
21 to create the song at the end. | |
22 - http://www.zophar.net/ for the terminal font. | |
23 | |
24 | |
25 * Introduction | |
26 | |
27 Think of pokemon yellow as creating a little universe with certain | |
28 rules. Inside that universe, you can buy items, defeat rival trainers, | |
29 and raise your pokemon. But within that universe, you are bound by the | |
30 rules of pokemon. You can't build new buildings, or change the music, | |
31 or change your clothes.. There are some games (like chess), where it | |
32 is not possible to alter the rules of the game from within the | |
33 game. No matter what moves you make in chess, you can never change the | |
34 rules of the game so that it becomes checkers or basketball. The point | |
35 of this run is to show that you CAN change the rules in pokemon | |
36 yellow. There is a certain sequence of valid actions like walking from | |
37 one place to another or buying items that will allow you to transform | |
38 pokemon yellow into Pacman, or Tetris, or Pong, or a MIDI player, or | |
39 anything else you can imagine. | |
40 | |
41 * Background | |
42 | |
43 [[http://tasvideos.org/2913S.html][This speedrun]] by Felipe Lopes de Freitas (p4wn3r), beats pokemon | |
44 yellow in only 1 minute and 36 seconds. It does it by corrupting the | |
45 in-game item list so that he can advance the list past its normal | |
46 limit of 20 items. The memory immediately after the item list includes | |
47 the warp points for the current map, and by treating that data as | |
48 items and switching and dropping them, he can make the door from his | |
49 house take him directly to the end of the game. | |
50 | |
51 When I first saw that speedrun, I was amazed at how fast pokemon | |
52 yellow could be beaten, and that it was possible to manipulate the | |
53 game from the inside, using only the item list. I wondeered how far I | |
54 could extend the techniques found in p4wn3r's run. | |
55 | |
56 The gameboy is an 8 bit computer. That means that ultimately, anything | |
57 that happens in pokemon is a result of the gameboy's CPU reading a | |
58 stream of 8 bit numbers and doing whatever those numbers mean. For | |
59 example, in the gameboy, the numbers: | |
60 | |
61 [62 16 37 224 47 240 37 230 15 55] | |
62 | |
63 mean to check which buttons are currently pressed and copy that result | |
64 into the "A" register. With enough numbers, you can spell out an | |
65 interactive program that reads input from the buttons and allows you | |
66 to write any program you want to the gameboy. Once you have assembled | |
67 such a program and forced the game to run it, you have won, since you | |
68 can use that program to write any other program (like tetirs or | |
69 pacman) over pokemon yellow's code. I call a program that allows you | |
70 to write any other program a "bootstrapping program". So, the goal is | |
71 to somehow get a bootstrapping program into pokemon yellow and then | |
72 force yellow to run that program instead of its own. | |
73 | |
74 How can we spell out such a program? Everything in the game is | |
75 ultimately nunbers, including all items, pokemon, levels, etc. In | |
76 particular, the item list looks like: | |
77 | |
78 item-one-id (0-255) | |
79 item-one-quantity (0-255) | |
80 item-two-id (0-255) | |
81 item-two-quantity (0-255) | |
82 . | |
83 . | |
84 . | |
85 | |
86 Let's consider the button measuring program [37 62 16 37 224 37 240 | |
87 37 230 15 55] from before. Interpreted as items and item quantities, it is | |
88 | |
89 lemonade x16 | |
90 guard spec. x224 | |
91 leaf stone x240 | |
92 guard spec. x230 | |
93 parlyz heal x55 | |
94 | |
95 So, if we can get the right items in the right quantities, we can | |
96 spell out a bootstrapping program. Likewise, when writing the | |
97 bootstrapping program, we must be careful to only use numbers that are | |
98 also valid items and quantities. This is hard because there aren't | |
99 many different items to work with, and many machine instructions | |
100 actually take 2 or even 3 numbers in a row, which severely restricts | |
101 the types of items you can use. I ended up needing about 92 numbers to | |
102 implement a bootstrap program. Half of those numbers were elaborate | |
103 ways of doing nothing and were just there so that the entire program | |
104 was also a valid item list. | |
105 | |
106 The final part of the hack is getting pokemon yellow to execute the | |
107 new program after it has been assembled with items. Fortunately, | |
108 pokemon keeps a number called a function pointer within easy reach of | |
109 the corrupted item list. This function pointer is the starting point | |
110 (address) of a program which the game runs every so often to check for | |
111 poison and do general maintaiance. By shifting an item over this | |
112 function pointer, I can rewrite that address to point to the | |
113 bootstrapping program, and make the game execute it. Without this | |
114 function pointer, it would not be possible to take over the game. | |
115 | |
116 * The Run | |
117 | |
118 I start off and name my rival Lpk. These characters will eventually be | |
119 treated as items and shifted over the function pointer, causing it to | |
120 execute the bootstrapping program that will soon be constructed. I | |
121 start the run the same as p4wn3r's and restart the game while saving, | |
122 so that the pokemon list is corrupted. By switching the 8th and 10th | |
123 pokemon, I corrupt the item list and can now scroll down past the 20th | |
124 item. I shift items around to increase the text speed to maximum and | |
125 rewrite the warp point of my house to Celadon Dept. Store. (p4wn3r | |
126 used this to go directly to the hall of fame and win the game in his | |
127 run.) I deposit many 0x00 glitch items into the PC from my corrupted | |
128 inventory for later use. Then, I widthdraw the potion from the | |
129 PC. This repairs my item list by overflowing the item counter from | |
130 0xFF back to 0x00, though the potion is obliterated in the process. I | |
131 then take 255 glitch items with ID 0x00 from the computer into my | |
132 personal items. | |
133 | |
134 Leaving my house takes me directly to Celadon Dept. store, where I | |
135 sell two 0x00 items for 414925 each, giving myself essentially max | |
136 money. I hit every floor of the department store, gathering the | |
137 following items: | |
138 | |
139 #+begin_example | |
140 +-------------------+----------+ | |
141 |##| Item | Quantity | | |
142 +--+----------------+----------+ | |
143 |1 | TM02 | 98 | | |
144 |2 | TM37 | 71 | | |
145 |3 | TM05 | 1 | | |
146 |4 | TM09 | 1 | | |
147 |5 | burn-heal | 12 | | |
148 |6 | ice-heal | 55 | | |
149 |7 | parlyz-heal | 99 | | |
150 |8 | parlyz-heal | 55 | | |
151 |9 | TM18 | 1 | | |
152 |10| fire-stone | 23 | | |
153 |11| water-stone | 29 | | |
154 |12| x-accuracy | 58 | | |
155 |13| guard-spec | 99 | | |
156 |14| guard-spec | 24 | | |
157 |15| lemonade | 16 | | |
158 |16| TM13 | 1 | | |
159 +--+----------------+----------+ | |
160 #+end_example | |
161 | |
162 After gathering these items, I deposit them in the appropriate order | |
163 into the item PC to spell out my bootstrapping program. Writing a full | |
164 bootstrap program in one go using only items turned out to be too | |
165 hard, so I split the process up into three parts. The program that I | |
166 actually construct using items is very limited. It reads only from the | |
167 A, B, start, and select buttons, and writes 4 bits each frame to a | |
168 fixed point in memory. After it writes 200 or so bytes, it jumps | |
169 directly to what it just wrote. In my run, I use this program to write | |
170 another bootstrapping program that can write to any number of bytes to | |
171 any location in memory, and then jump to any location in memory. This | |
172 new program also can write 8 bits per frame by using all the | |
173 buttons. Using this new bootstrap program, I write a final | |
174 bootstrapping program that does everything the provious bootstrapping | |
175 program does except it also displays the bytes it is writing to memory | |
176 on the screen. | |
177 | |
178 After completing this bootstrapping program, I go to the celadon | |
179 mansion, because I find the metaness of that building to be | |
180 sufficiently high to serve as an exit point for the pokemon | |
181 universe. I corrupt my item list again by switching corrupted pokemon, | |
182 scroll down to my rival's name and discard untill it is equal to the | |
183 address of my bootstrapping program, and then swap it with the | |
184 function pointer. Once the menu is closed, the boostrapping program | |
185 takes over, and I write the payload.... | |
186 | |
187 * Infrastructure | |
188 | |
189 The entire video was completely produced by bots --- I didn't manually | |
190 play the game at all to produce this speedrun. Here is a brief account | |
191 of the infrastructure I build to make the video. The entire source of | |
192 the project is available at http://hg.bortreb.com/vba-clojure | |
193 | |
194 The first step was to build a programatic interface to pokemon | |
195 yellow. So, I downloaded vba-rerecording from | |
196 http://code.google.com/p/vba-rerecording/. After repairing their | |
197 broken auto-tools scripts so that it would compile on GNU/Linux, I | |
198 added a low level C interface that I could call from Java via | |
199 JNI. This C interface gives me basic control over the emulator: I can | |
200 step the emulator either one clock cycle or one frame, and I can get | |
201 the contents of any memory location or register. The interface also | |
202 allows me to freeze the state of the emulator, save it to a Java | |
203 object, and reload that state again at any time. | |
204 | |
205 I built a layer of [[http://clojure.org/][clojure]] code on top of the JNI bindings to get an | |
206 entirely functional interface to vba-rerecording. This interface | |
207 treats state of the emulator as an immutable object, and allows me to | |
208 do everything I could do with the lower level C interface in a | |
209 functional manner. Using this functional code, I wrote search programs | |
210 that take a particular game-state and try out different combinations | |
211 of button prosses to get any desired effect. By combining different | |
212 styles of search with different initial conditions, I created high | |
213 level functions that could each accomplish a certain general task, | |
214 like walking and buying items. For example, here is some actual code: | |
215 | |
216 #+begin_src clojure | |
217 (defn-memo viridian-store->oaks-lab | |
218 ([] (viridian-store->oaks-lab | |
219 (get-oaks-parcel))) | |
220 ([script] | |
221 (->> script | |
222 (walk [↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ | |
223 ← ← ← ← ← ← ← ← ← | |
224 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ | |
225 ← ← | |
226 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ | |
227 ↓ ↓ ↓ ↓ ↓ ↓ ↓ | |
228 → → → → → → → → | |
229 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ | |
230 ← ← ← ← ← | |
231 ↓ ↓ ↓ ↓ | |
232 ]) | |
233 (walk-thru-grass | |
234 [↓ ↓ ↓ ↓ ↓ ↓ ↓]) | |
235 (walk [↓ ↓ ← ↓ ↓ ↓ ← | |
236 ↓ ↓ ↓ ↓ ↓ ↓ | |
237 → → → ↑]) | |
238 | |
239 (do-nothing 1)))) | |
240 #+end_src | |
241 | |
242 This script walks from the Viridian City pokemon store to Oak's | |
243 Lab in the most efficient way possible. The walk-thru-grass function | |
244 gaurantees that no wild battles will happen by manipulating the game's | |
245 random number generator. | |
246 | |
247 #+begin_src clojure | |
248 (defn-memo hacking-10 | |
249 ([] (hacking-10 (hacking-9))) | |
250 ([script] | |
251 (->> script | |
252 begin-deposit | |
253 (deposit-held-item 17 230) | |
254 (deposit-held-item-named :parlyz-heal 55) | |
255 (deposit-held-item 14 178) | |
256 (deposit-held-item-named :water-stone 29) | |
257 (deposit-held-item 14 32) | |
258 (deposit-held-item-named :TM18 1) | |
259 (deposit-held-item 13 1) | |
260 (deposit-held-item 13 191) | |
261 (deposit-held-item-named :TM02 98) | |
262 (deposit-held-item-named :TM09 1) | |
263 close-menu))) | |
264 #+end_src | |
265 | |
266 This script calculates the fastest sequence of key presses to deposit | |
267 the requested items into a pc, assuming that the character starts out | |
268 in front of a computer. | |
269 | |
270 I also wrote functions that coudl grovel through the game's memory and | |
271 present the internal data structures in useable ways. For example, the | |
272 function =print-inventory= returns the current inventory in a human | |
273 readable format. | |
274 | |
275 #+begin_src clojure :results output | |
276 (com.aurellem.gb.items/print-inventory) | |
277 #+end_src | |
278 | |
279 #+results: | |
280 #+begin_example | |
281 +-------------------+----------+ | |
282 |##| Item | Quantity | | |
283 +--+----------------+----------+ | |
284 |0 | poke-ball | 14 | | |
285 |1 | TM28 | 1 | | |
286 |2 | TM11 | 1 | | |
287 |3 | TM45 | 1 | | |
288 |4 | nugget | 1 | | |
289 |5 | s.s.ticket | 1 | | |
290 |6 | helix-fossil | 1 | | |
291 |7 | moon-stone | 1 | | |
292 +--+----------------+----------+ | |
293 | |
294 #+end_example | |
295 | |
296 | |
297 Armed with these functions, I constructed a bootstrapping program that | |
298 could be expressed as items. This is particurally hard, since many | |
299 useful opcodes do not correspond any item, and the item quantities | |
300 must all be less than 99. | |
301 | |
302 Here is the first bootstrapping program in all its glory. | |
303 | |
304 #+begin_src clojure | |
305 (defn pc-item-writer-program | |
306 [] | |
307 (let [;;limit 75 | |
308 limit 201 ;; (item-hack 201 is the smallest I could make this.) | |
309 [target-high target-low] (disect-bytes-2 pokemon-list-start)] | |
310 (flatten | |
311 [[0x00 ;; (item-hack) no-op (can't buy repel (1E) at celadon) | |
312 0x1E ;; load limit into E | |
313 limit | |
314 0x3F ;; (item-hack) set carry flag no-op | |
315 | |
316 ;; load 2 into C. | |
317 0x0E ;; C == 1 means input-first nybble | |
318 0x04 ;; C == 0 means input-second nybble | |
319 | |
320 0x21 ;; load target into HL | |
321 target-low | |
322 target-high | |
323 0x37 ;; (item-hack) set carry flag no-op | |
324 | |
325 0x00 ;; (item-hack) no-op | |
326 0x37 ;; (item-hack) set carry flag no-op | |
327 | |
328 0x00 ;; (item-hack) no-op | |
329 0xF3 ;; disable interrupts | |
330 ;; Input Section | |
331 | |
332 0x3E ;; load 0x20 into A, to measure buttons | |
333 0x10 | |
334 | |
335 0x00 ;; (item-hack) no-op | |
336 0xE0 ;; load A into [FF00] | |
337 0x00 | |
338 | |
339 0xF0 ;; load 0xFF00 into A to get | |
340 0x00 ;; button presses | |
341 | |
342 0xE6 | |
343 0x0F ;; select bottom four bits of A | |
344 0x37 ;; (item-hack) set carry flag no-op | |
345 | |
346 0x00 ;; (item-hack) no-op | |
347 0xB8 ;; see if input is different (CP A B) | |
348 | |
349 0x00 ;; (item-hack) (INC SP) | |
350 0x28 ;; repeat above steps if input is not different | |
351 ;; (jump relative backwards if B != A) | |
352 0xED ;; (literal -19) (item-hack) -19 == egg bomb (TM37) | |
353 | |
354 0x47 ;; load A into B | |
355 | |
356 0x0D ;; dec C | |
357 0x37 ;; (item-hack) set-carry flag | |
358 ;; branch based on C: | |
359 0x20 ;; JR NZ | |
360 23 ;; skip "input second nybble" and "jump to target" below | |
361 | |
362 ;; input second nybble | |
363 | |
364 0x0C ;; inc C | |
365 0x0C ;; inc C | |
366 | |
367 0x00 ;; (item-hack) no-op | |
368 0xE6 ;; select bottom bits | |
369 0x0F | |
370 0x37 ;; (item-hack) set-carry flag no-op | |
371 | |
372 0x00 ;; (item-hack) no-op | |
373 0xB2 ;; (OR A D) -> A | |
374 | |
375 0x22 ;; (do (A -> (HL)) (INC HL)) | |
376 | |
377 0x1D ;; (DEC E) | |
378 | |
379 0x00 ;; (item-hack) | |
380 0x20 ;; jump back to input section if not done | |
381 0xDA ;; literal -36 == TM 18 (counter) | |
382 0x01 ;; (item-hack) set BC to literal (no-op) | |
383 | |
384 ;; jump to target | |
385 0x00 ;; (item-hack) these two bytes can be anything. | |
386 0x01 | |
387 | |
388 0x00 ;; (item-hack) no-op | |
389 0xBF ;; (CP A A) ensures Z | |
390 | |
391 0xCA ;; (item-hack) jump if Z | |
392 target-low | |
393 target-high | |
394 0x01 ;; (item-hack) will never be reached. | |
395 | |
396 ;; input first nybble | |
397 0x00 | |
398 0xCB | |
399 0x37 ;; swap nybbles on A | |
400 | |
401 0x57 ;; A -> D | |
402 | |
403 0x37 ;; (item-hack) set carry flag no-op | |
404 0x18 ;; relative jump backwards | |
405 0xCD ;; literal -51 == TM05; go back to input section | |
406 0x01 ;; (item-hack) will never reach this instruction | |
407 | |
408 ] | |
409 (repeat 8 [0x00 0x01]);; these can be anything | |
410 | |
411 [;; jump to actual program | |
412 0x00 | |
413 0x37 ;; (item-hack) set carry flag no-op | |
414 | |
415 0x2E ;; 0x3A -> L | |
416 0x3A | |
417 | |
418 | |
419 0x00 ;; (item-hack) no-op | |
420 0x26 ;; 0xD5 -> L | |
421 0xD5 | |
422 0x01 ;; (item-hack) set-carry BC | |
423 | |
424 0x00 ;; (item-hack) these can be anything | |
425 0x01 | |
426 | |
427 0x00 | |
428 0xE9 ;; jump to (HL) | |
429 ]]))) | |
430 | |
431 #+end_src | |
432 | |
433 I use the glitch items 0x00 and 0xFF to great effect in my run. 0x00 | |
434 sells for almost half of max_money, and I use just 3 of them to | |
435 finance the purchace of all the other items I need. 0x00 is also a | |
436 NO-OP in the gameboy's machine language, which means that I can stick | |
437 them anywhere where I need to break up an other wise illegal pair of | |
438 opcodes. 0xFF is also extremely useful because it is the end-of-list | |
439 sentinel. Normally, the game will "compact" your items whenever you | |
440 make a purchase or deposit. For example, if you deposit a pokeball, | |
441 then deposit another pokeball, the item list looks like: | |
442 | |
443 pokeball x2 | |
444 | |
445 instead of: | |
446 | |
447 pokeball x1 | |
448 pokeball x1 | |
449 | |
450 However, the compaction stops after the first 0xFF item, so if there | |
451 is an 0xFF item at the beginning of the list, it will "shield" all the | |
452 items below it from compaction. It the beginning of the run, I stick | |
453 an 0xFF item at the top of the PC item list, allowing me to put items | |
454 in with impunity. At the end, I toss the 0xFF away to reveal the | |
455 completed bootstrap program. | |
456 | |
457 The final payload program is actually multiple programs. I created a | |
458 reduced form of MIDI and implemented it in gameboy machine | |
459 language. Then I translated a midi file from | |
460 http://www.everyponysings.com/ into this reduced MIDI language. The | |
461 payload program contains both the music data and the MIDI interpreter | |
462 to play that data. The picture works in a similiar way. There is code | |
463 to translate a png file into a form that can be displayed on a | |
464 gameboy, and other code to actually display that image. Both the image | |
465 and the display code are also written by the final bootstrapping | |
466 program. Even though my final payload is rather simple, you can write | |
467 any program at all as the payload. The source for the sound and image | |
468 displaying code is at http://hg.bortreb.com/vba-clojure. | |
469 | |
470 |