rlm@170
|
1 (ns com.aurellem.exp.item-bridge
|
rlm@179
|
2 (:use (com.aurellem.gb saves util constants gb-driver vbm items assembly))
|
rlm@319
|
3 (:use (com.aurellem.run util title save-corruption))
|
rlm@179
|
4 ;;(:use (com.aurellem.exp pokemon))
|
rlm@154
|
5 (:import [com.aurellem.gb.gb_driver SaveState]))
|
rlm@130
|
6
|
rlm@131
|
7 (defn corrupt-item-state []
|
rlm@131
|
8 (second (destroy-item-end-of-list-marker)))
|
rlm@131
|
9
|
rlm@131
|
10 (defn corrupt-item-state []
|
rlm@131
|
11 (read-state "corrupt-items"))
|
rlm@131
|
12
|
rlm@313
|
13 (defn view-memory-range
|
rlm@313
|
14 ([start end]
|
rlm@313
|
15 (view-memory-range
|
rlm@313
|
16 @current-state start end))
|
rlm@313
|
17 ([state start end]
|
rlm@313
|
18 (dorun
|
rlm@313
|
19 (map (fn [loc val]
|
rlm@313
|
20 (println (format "%04X : %02X" loc val)))
|
rlm@313
|
21 (range start end) (subvec (vec (memory state)) start end)))
|
rlm@313
|
22 state))
|
rlm@131
|
23
|
rlm@133
|
24 (defn almost-broken
|
rlm@133
|
25 "if one more memory location is turned into 0x03, the game crashes."
|
rlm@133
|
26 [n]
|
rlm@133
|
27 (view-memory-range
|
rlm@133
|
28 (set-inv-mem (mid-game)
|
rlm@133
|
29 (concat [0xFF] (repeat 64 0x03)
|
rlm@133
|
30 (subvec (vec (memory (mid-game)))
|
rlm@133
|
31 (+ item-list-start 65)
|
rlm@133
|
32 (+ item-list-start 65 n))
|
rlm@170
|
33 (repeat (- 255 65 n) 0x03)))
|
rlm@133
|
34 item-list-start (+ item-list-start 255)))
|
rlm@131
|
35
|
rlm@133
|
36 (defn actually-broken
|
rlm@170
|
37 "if this memory location is turned into 0x03, the game crashes."
|
rlm@133
|
38 []
|
rlm@133
|
39 (set-memory (mid-game) 0xD35D 0x03))
|
rlm@131
|
40
|
rlm@131
|
41
|
rlm@133
|
42 ;; (almost-broken 20) more or less works
|
rlm@133
|
43
|
rlm@133
|
44 (defn capture-program-counter
|
rlm@133
|
45 "records the program counter for each tick"
|
rlm@133
|
46 [^SaveState state ticks]
|
rlm@133
|
47 (let [i (atom 0)]
|
rlm@133
|
48 (reduce (fn [[program-counters state] _]
|
rlm@133
|
49 (println (swap! i inc))
|
rlm@133
|
50 [(conj program-counters (PC state))
|
rlm@133
|
51 (tick state)])
|
rlm@133
|
52 [[] state]
|
rlm@133
|
53 (range ticks))))
|
rlm@133
|
54
|
rlm@133
|
55
|
rlm@133
|
56 (defn capture-program-counter
|
rlm@133
|
57 [^SaveState state ticks]
|
rlm@176
|
58 (tick state)
|
rlm@176
|
59
|
rlm@133
|
60 (loop [i 0
|
rlm@133
|
61 pcs []]
|
rlm@133
|
62 (if (= i ticks)
|
rlm@179
|
63 (filter (partial < 0x2000)(sort (set pcs)))
|
rlm@133
|
64 (do
|
rlm@133
|
65 (com.aurellem.gb.Gb/tick)
|
rlm@133
|
66 (recur (inc i)
|
rlm@133
|
67 (conj pcs (first (registers))))))))
|
rlm@170
|
68
|
rlm@170
|
69 (defn loop-program []
|
rlm@174
|
70 [0x00 ;0xD31D ;; disable-interrupts
|
rlm@170
|
71
|
rlm@170
|
72 0xC3 ;; loop forever
|
rlm@170
|
73 0x1D
|
rlm@170
|
74 0xD3])
|
rlm@170
|
75
|
rlm@170
|
76 (def map-function-address-start 0xD36D)
|
rlm@170
|
77
|
rlm@170
|
78 (defn test-loop []
|
rlm@174
|
79 (continue!
|
rlm@170
|
80 (-> (mid-game)
|
rlm@170
|
81 (set-memory-range 0xD31D (loop-program))
|
rlm@170
|
82 (set-memory-range
|
rlm@170
|
83 map-function-address-start
|
rlm@174
|
84 [0xD3 0x1D]))))
|
rlm@174
|
85
|
rlm@170
|
86 (defn-memo corrupt-moves []
|
rlm@170
|
87 (concat
|
rlm@170
|
88 (first
|
rlm@170
|
89 (->>
|
rlm@170
|
90 [[] (mid-game)]
|
rlm@319
|
91 (first-difference [:b] [:b :start] AF)
|
rlm@319
|
92 (first-difference [] [:d] AF)
|
rlm@170
|
93 (play-moves [[] [] [] [:d] [] [] [] [:d] [] [] [:a]])
|
rlm@319
|
94 (do-nothing 200)
|
rlm@319
|
95 (play-moves [[:a]])
|
rlm@170
|
96 (play-moves
|
rlm@170
|
97 ;; this section is copied from speedrun-2942
|
rlm@170
|
98 ;; and corrupts the save so that the end-of-list marker
|
rlm@170
|
99 ;; for the pokemon roster is destroyed, but the save is still
|
rlm@170
|
100 ;; playable.
|
rlm@170
|
101 [[] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] []
|
rlm@170
|
102 [] [] [] [] [] [] [] [] [] [] [:select] [:restart]])
|
rlm@250
|
103 (title)
|
rlm@319
|
104 (first-difference [] [:start] AF)
|
rlm@319
|
105 (first-difference [] [:a] AF)
|
rlm@319
|
106 (first-difference [:a] [:a :start] AF)))
|
rlm@170
|
107 [[]]))
|
rlm@170
|
108
|
rlm@170
|
109 (defn corrupt
|
rlm@170
|
110 "enter the codes to destroy the
|
rlm@170
|
111 pokemon list using save corruption"
|
rlm@170
|
112 ([^SaveState state]
|
rlm@170
|
113 (run-moves
|
rlm@170
|
114 state
|
rlm@170
|
115 (corrupt-moves)))
|
rlm@171
|
116 ([] (corrupt @current-state)))
|
rlm@173
|
117
|
rlm@173
|
118 (defn mid-game-corrupt []
|
rlm@173
|
119 (read-state "corrupt-mid-game"))
|
rlm@170
|
120
|
rlm@235
|
121 (defn gen-start-game-corrupt []
|
rlm@250
|
122 (->> (second (intro))
|
rlm@319
|
123 (first-difference [:b] [:a :b :start] AF)
|
rlm@235
|
124 (play-moves (corrupt-moves))))
|
rlm@212
|
125
|
rlm@235
|
126 (defn start-game-corrupt []
|
rlm@235
|
127 (read-state "corrupt-start-game"))
|
rlm@212
|
128
|
rlm@187
|
129 (defn test-memory-fun [n]
|
rlm@187
|
130 (capture-program-counter
|
rlm@187
|
131 (set-memory-range
|
rlm@187
|
132 (tick (mid-game))
|
rlm@187
|
133 0xD36D
|
rlm@187
|
134 [0 0])
|
rlm@187
|
135 n))
|
rlm@170
|
136
|
rlm@187
|
137 ;;(def good (test-memory-fun 17000))
|
rlm@187
|
138
|
rlm@187
|
139 ;;(def bad (test-memory-fun 18000))
|
rlm@187
|
140
|
rlm@187
|
141
|
rlm@212
|
142
|
rlm@212
|
143 (defn menu-open-state []
|
rlm@212
|
144 (read-state "menu-open"))
|
rlm@212
|
145
|
rlm@212
|
146 (defn prepare-memory
|
rlm@212
|
147 ([^SaveState state]
|
rlm@212
|
148 (-> state
|
rlm@212
|
149 (set-memory-range 0xD31D (loop-program))
|
rlm@212
|
150 (set-memory-range 0xD36D [0x1D 0xD3])))
|
rlm@212
|
151 ([] (prepare-memory @current-state)))
|
rlm@212
|
152
|
rlm@233
|
153 (def memory-function-address-start 0xD36D)
|
rlm@233
|
154
|
rlm@233
|
155 (defn read-map-function-address
|
rlm@233
|
156 ([^SaveState state]
|
rlm@233
|
157 (let [mem (memory state)]
|
rlm@233
|
158 [(aget mem memory-function-address-start)
|
rlm@233
|
159 (aget mem (inc memory-function-address-start))]))
|
rlm@233
|
160 ([] (read-map-function-address @current-state)))
|
rlm@212
|
161
|
rlm@212
|
162 (defn succesful-PC-capture
|
rlm@212
|
163 "This function demonstrates successful PC capturing by
|
rlm@212
|
164 setting 0xD36D to the value of the start location of
|
rlm@212
|
165 a specially prepared program.
|
rlm@212
|
166
|
rlm@212
|
167 You must run the function and then exit the open menu
|
rlm@212
|
168 to see the effect."
|
rlm@212
|
169 []
|
rlm@212
|
170 (dorun
|
rlm@212
|
171 (map #(println (Integer/toHexString %))
|
rlm@212
|
172 (capture-program-counter
|
rlm@212
|
173 (prepare-memory (menu-open-state))
|
rlm@212
|
174 9000000))))
|
rlm@233
|
175
|
rlm@233
|
176 (defn trampoline-assembly [^SaveState state]
|
rlm@233
|
177 (flatten
|
rlm@233
|
178 [0x3E ;;
|
rlm@233
|
179 0x3E ;; load lemonade into A
|
rlm@233
|
180
|
rlm@233
|
181 0xEA
|
rlm@233
|
182 0x1D
|
rlm@233
|
183 0xD3 ;; set first item to lemonade
|
rlm@233
|
184
|
rlm@238
|
185 0xC3 ;; return control to the game via absolute jump.
|
rlm@233
|
186 (read-map-function-address state)
|
rlm@233
|
187 ]))
|
rlm@233
|
188
|
rlm@233
|
189 (defn test-trampoline
|
rlm@233
|
190 "Demonstrates item-program execution via the map-function that
|
rlm@233
|
191 returns control to the main pokemon game after one loop."
|
rlm@238
|
192 [assembly-fn state]
|
rlm@233
|
193 (let [insertion-address 0xD33D
|
rlm@233
|
194 insertion-address-bits [0x3D 0xD3]]
|
rlm@233
|
195 (->
|
rlm@238
|
196 state
|
rlm@233
|
197 (set-memory-range
|
rlm@233
|
198 insertion-address
|
rlm@238
|
199 (assembly-fn state))
|
rlm@233
|
200 (set-memory-range
|
rlm@233
|
201 memory-function-address-start
|
rlm@235
|
202 insertion-address-bits))))
|
rlm@235
|
203
|
rlm@239
|
204 (def lemonade-trampoline
|
rlm@239
|
205 (partial test-trampoline
|
rlm@239
|
206 trampoline-assembly
|
rlm@239
|
207 (menu-open-state)))
|
rlm@235
|
208
|
rlm@238
|
209 (defn trampoline-assembly-burn-heal [^SaveState state]
|
rlm@238
|
210 (flatten
|
rlm@238
|
211 [0x3E ;;
|
rlm@238
|
212 0x3E ;; load lemonade into A
|
rlm@238
|
213
|
rlm@238
|
214 0xEA
|
rlm@238
|
215 0x1D
|
rlm@238
|
216 0xD3 ;; set first item to lemonade
|
rlm@238
|
217
|
rlm@239
|
218 0xC3 ;; return control to the game via absolute jump
|
rlm@239
|
219 0x0C ;; to Route 3's map-function
|
rlm@238
|
220 0x55
|
rlm@238
|
221 ]))
|
rlm@235
|
222
|
rlm@235
|
223
|
rlm@247
|
224
|
rlm@247
|
225 (def pc-item-list-start 0xD539)
|
rlm@247
|
226 (def pc-item-list-width 101)
|
rlm@247
|
227
|
rlm@247
|
228 (def corrupted-items-width 512)
|
rlm@247
|
229
|
rlm@247
|
230 (defn items-record
|
rlm@247
|
231 ([^SaveState state]
|
rlm@247
|
232 (subvec (vec (memory state))
|
rlm@247
|
233 item-list-start
|
rlm@247
|
234 (+ item-list-start corrupted-items-width)))
|
rlm@247
|
235 ([] (items-record @current-state)))
|
rlm@247
|
236
|
rlm@247
|
237 (defn pc-items-record
|
rlm@247
|
238 ([^SaveState state]
|
rlm@247
|
239 (subvec (vec (memory state))
|
rlm@247
|
240 pc-item-list-start
|
rlm@247
|
241 (+ pc-item-list-width pc-item-list-start)))
|
rlm@247
|
242 ([] (pc-items-record @current-state)))
|
rlm@247
|
243
|
rlm@247
|
244 (defn print-listing-items
|
rlm@247
|
245 ([^SaveState state]
|
rlm@247
|
246 (print-listing state item-list-start
|
rlm@247
|
247 (+ item-list-start corrupted-items-width))
|
rlm@247
|
248 state)
|
rlm@247
|
249 ([] (print-listing-items @current-state)))
|
rlm@247
|
250
|
rlm@247
|
251 (defn print-listing-pc-items
|
rlm@247
|
252 ([^SaveState state]
|
rlm@247
|
253 (print-listing
|
rlm@247
|
254 state
|
rlm@247
|
255 pc-item-list-start
|
rlm@247
|
256 (+ pc-item-list-width pc-item-list-start))
|
rlm@247
|
257 state)
|
rlm@247
|
258 ([] (print-listing-pc-items @current-state)))
|
rlm@247
|
259
|
rlm@247
|
260
|
rlm@247
|
261 |