rlm@145
|
1 (ns com.aurellem.exp.pokemon
|
rlm@145
|
2 "Here I find out how pokemon are stored in memory."
|
rlm@145
|
3 (:use (com.aurellem.gb gb-driver items assembly util
|
rlm@166
|
4 constants
|
rlm@166
|
5 characters species moves))
|
rlm@161
|
6 (:import java.io.File)
|
rlm@145
|
7 (:import [com.aurellem.gb.gb_driver SaveState]))
|
rlm@145
|
8
|
rlm@145
|
9
|
rlm@145
|
10 (def pidgeot-lvl-36 (mid-game))
|
rlm@145
|
11
|
rlm@145
|
12
|
rlm@145
|
13 (def pidgeot-lvl-37 (read-state "pidgeot-lvl-37"))
|
rlm@145
|
14
|
rlm@145
|
15
|
rlm@145
|
16 (def pidgeot-lvl-38 (read-state "pidgeot-lvl-38"))
|
rlm@145
|
17
|
rlm@145
|
18
|
rlm@145
|
19 (def pidgeot-lvl-39 (read-state "pidgeot-lvl-39"))
|
rlm@145
|
20
|
rlm@145
|
21
|
rlm@145
|
22 (def pidgeot-lvl-40 (read-state "pidgeot-lvl-40"))
|
rlm@145
|
23
|
rlm@145
|
24
|
rlm@145
|
25 (defn level-analysis []
|
rlm@145
|
26 (apply common-differences
|
rlm@145
|
27 (map (comp vec memory)
|
rlm@145
|
28 [pidgeot-lvl-36
|
rlm@145
|
29 pidgeot-lvl-37
|
rlm@145
|
30 pidgeot-lvl-38
|
rlm@145
|
31 pidgeot-lvl-39
|
rlm@145
|
32 pidgeot-lvl-40])))
|
rlm@145
|
33
|
rlm@145
|
34 ;; inconclusive -- implies that level is calculated from
|
rlm@145
|
35 ;; some other values.
|
rlm@145
|
36
|
rlm@145
|
37
|
rlm@145
|
38 (def name-pidgeotto (read-state "name-pidgeotto"))
|
rlm@145
|
39 (def named-A (read-state "named-A"))
|
rlm@145
|
40 (def named-B (read-state "named-B"))
|
rlm@145
|
41 (def named-C (read-state "named-C"))
|
rlm@145
|
42 (def named-D (read-state "named-D"))
|
rlm@145
|
43 (def named-E (read-state "named-E"))
|
rlm@145
|
44 (def named-F (read-state "named-F"))
|
rlm@145
|
45
|
rlm@145
|
46 (defn name-analysis []
|
rlm@145
|
47 (apply common-differences
|
rlm@145
|
48 (map (comp vec memory)
|
rlm@145
|
49 [named-A
|
rlm@145
|
50 named-B
|
rlm@145
|
51 named-C
|
rlm@145
|
52 named-D
|
rlm@145
|
53 named-E
|
rlm@145
|
54 named-F])))
|
rlm@145
|
55
|
rlm@145
|
56 ;; resluted in 3 separate locations that could
|
rlm@145
|
57 ;; possibly hold the first letter of the pokemon's name
|
rlm@145
|
58
|
rlm@145
|
59 0xCF4A
|
rlm@145
|
60 0xD2EB
|
rlm@145
|
61 0xCEED
|
rlm@145
|
62
|
rlm@145
|
63 ;; try changing each of them
|
rlm@145
|
64
|
rlm@145
|
65
|
rlm@145
|
66 (defn test-cf4a []
|
rlm@145
|
67 (continue!
|
rlm@145
|
68 (set-memory named-A 0xCF4A (character->character-code "Z"))))
|
rlm@145
|
69 ;; result -- pidgeotto named "A"
|
rlm@145
|
70
|
rlm@145
|
71 (defn test-d2eb []
|
rlm@145
|
72 (continue!
|
rlm@145
|
73 (set-memory named-A 0xD2EB (character->character-code "Z"))))
|
rlm@145
|
74 ;; result -- pidgeotto named "Z"
|
rlm@145
|
75
|
rlm@145
|
76 (defn test-ceed []
|
rlm@145
|
77 (continue!
|
rlm@145
|
78 (set-memory named-A 0xCEED (character->character-code "Z"))))
|
rlm@145
|
79 ;; result -- pidgeotto named "A"
|
rlm@145
|
80
|
rlm@145
|
81 (def sixth-pokemon-name-start 0xD2EB)
|
rlm@145
|
82
|
rlm@145
|
83
|
rlm@145
|
84 (defn set-sixth-pokemon-name-first-character
|
rlm@145
|
85 ([state character]
|
rlm@145
|
86 (set-memory state sixth-pokemon-name-start
|
rlm@145
|
87 (character->character-code character)))
|
rlm@145
|
88 ([character]
|
rlm@145
|
89 (set-sixth-pokemon-name-first-character @current-state
|
rlm@145
|
90 character)))
|
rlm@145
|
91
|
rlm@145
|
92
|
rlm@146
|
93 (def end-of-name-marker 0x50)
|
rlm@147
|
94 (def max-name-length 10)
|
rlm@147
|
95 (def name-width 11)
|
rlm@147
|
96
|
rlm@148
|
97 (defn read-name [codes]
|
rlm@147
|
98 (character-codes->str
|
rlm@147
|
99 (take-while
|
rlm@147
|
100 (partial not= end-of-name-marker) codes)))
|
rlm@147
|
101
|
rlm@145
|
102
|
rlm@146
|
103 (defn sixth-pokemon-name [^SaveState state]
|
rlm@148
|
104 (read-name
|
rlm@146
|
105 (subvec (vec (memory state))
|
rlm@146
|
106 sixth-pokemon-name-start
|
rlm@146
|
107 (+ (inc max-name-length)
|
rlm@147
|
108 sixth-pokemon-name-start))))
|
rlm@145
|
109
|
rlm@147
|
110 (defn rename-sixth-pokemon
|
rlm@147
|
111 ([^SaveState state new-name]
|
rlm@147
|
112 (assert (< (count new-name) max-name-length))
|
rlm@147
|
113 (set-memory-range state sixth-pokemon-name-start
|
rlm@147
|
114 (concat (str->character-codes new-name)
|
rlm@147
|
115 [end-of-name-marker])))
|
rlm@147
|
116 ([new-name]
|
rlm@147
|
117 (rename-sixth-pokemon @current-state new-name)))
|
rlm@147
|
118
|
rlm@147
|
119 (defn print-text
|
rlm@147
|
120 ([^SaveState state begin end]
|
rlm@147
|
121 (dorun
|
rlm@147
|
122 (map (fn [character-code line]
|
rlm@147
|
123 (println
|
rlm@147
|
124 (format "0x%04X: " line)
|
rlm@149
|
125 (str (character-code->character character-code))))
|
rlm@147
|
126 (subvec (vec (memory state)) begin end)
|
rlm@147
|
127 (range begin end)))
|
rlm@147
|
128 state)
|
rlm@147
|
129 ([begin end]
|
rlm@147
|
130 (print-text @current-state begin end)))
|
rlm@147
|
131
|
rlm@147
|
132 (defn examine-name-memory []
|
rlm@147
|
133 (print-text
|
rlm@147
|
134 named-A
|
rlm@147
|
135 (- sixth-pokemon-name-start 100)
|
rlm@147
|
136 (+ sixth-pokemon-name-start 100)))
|
rlm@147
|
137
|
rlm@147
|
138 ;; results:
|
rlm@147
|
139 ;; 0xD287: end-of-name-sentinel
|
rlm@147
|
140 ;; 0xD288: R
|
rlm@147
|
141 ;; 0xD289: L
|
rlm@147
|
142 ;; 0xD28A: M
|
rlm@147
|
143 ;; 0xD28B: end-of-pokemon-name-sentinel
|
rlm@147
|
144 ;; 0xD28C: end-of-name-sentinel
|
rlm@147
|
145 ;; 0xD28D: end-of-name-sentinel
|
rlm@147
|
146 ;; 0xD28E: end-of-name-sentinel
|
rlm@147
|
147 ;; 0xD28F: end-of-name-sentinel
|
rlm@147
|
148 ;; 0xD290: end-of-name-sentinel
|
rlm@147
|
149 ;; 0xD291: end-of-name-sentinel
|
rlm@147
|
150 ;; 0xD292: end-of-name-sentinel
|
rlm@147
|
151 ;; 0xD293: R
|
rlm@147
|
152 ;; 0xD294: L
|
rlm@147
|
153 ;; 0xD295: M
|
rlm@147
|
154 ;; 0xD296: end-of-pokemon-name-sentinel
|
rlm@147
|
155 ;; 0xD297: end-of-name-sentinel
|
rlm@147
|
156 ;; 0xD298: end-of-name-sentinel
|
rlm@147
|
157 ;; 0xD299: end-of-name-sentinel
|
rlm@147
|
158 ;; 0xD29A: end-of-name-sentinel
|
rlm@147
|
159 ;; 0xD29B: end-of-name-sentinel
|
rlm@147
|
160 ;; 0xD29C: end-of-name-sentinel
|
rlm@147
|
161 ;; 0xD29D: end-of-name-sentinel
|
rlm@147
|
162 ;; 0xD29E: R
|
rlm@147
|
163 ;; 0xD29F: L
|
rlm@147
|
164 ;; 0xD2A0: M
|
rlm@147
|
165 ;; 0xD2A1: end-of-pokemon-name-sentinel
|
rlm@147
|
166 ;; 0xD2A2: end-of-name-sentinel
|
rlm@147
|
167 ;; 0xD2A3: end-of-name-sentinel
|
rlm@147
|
168 ;; 0xD2A4: end-of-name-sentinel
|
rlm@147
|
169 ;; 0xD2A5: end-of-name-sentinel
|
rlm@147
|
170 ;; 0xD2A6: end-of-name-sentinel
|
rlm@147
|
171 ;; 0xD2A7: end-of-name-sentinel
|
rlm@147
|
172 ;; 0xD2A8: end-of-name-sentinel
|
rlm@147
|
173 ;; 0xD2A9: R
|
rlm@147
|
174 ;; 0xD2AA: L
|
rlm@147
|
175 ;; 0xD2AB: M
|
rlm@147
|
176 ;; 0xD2AC: end-of-pokemon-name-sentinel
|
rlm@147
|
177 ;; 0xD2AD: end-of-name-sentinel
|
rlm@147
|
178 ;; 0xD2AE: end-of-name-sentinel
|
rlm@147
|
179 ;; 0xD2AF: end-of-name-sentinel
|
rlm@147
|
180 ;; 0xD2B0: end-of-name-sentinel
|
rlm@147
|
181 ;; 0xD2B1: end-of-name-sentinel
|
rlm@147
|
182 ;; 0xD2B2: end-of-name-sentinel
|
rlm@147
|
183 ;; 0xD2B3: end-of-name-sentinel
|
rlm@147
|
184 ;; 0xD2B4: P
|
rlm@147
|
185 ;; 0xD2B5: I
|
rlm@147
|
186 ;; 0xD2B6: D
|
rlm@147
|
187 ;; 0xD2B7: G
|
rlm@147
|
188 ;; 0xD2B8: E
|
rlm@147
|
189 ;; 0xD2B9: O
|
rlm@147
|
190 ;; 0xD2BA: T
|
rlm@147
|
191 ;; 0xD2BB: end-of-pokemon-name-sentinel
|
rlm@147
|
192 ;; 0xD2BC: end-of-pokemon-name-sentinel
|
rlm@147
|
193 ;; 0xD2BD: end-of-pokemon-name-sentinel
|
rlm@147
|
194 ;; 0xD2BE: end-of-pokemon-name-sentinel
|
rlm@147
|
195 ;; 0xD2BF: P
|
rlm@147
|
196 ;; 0xD2C0: I
|
rlm@147
|
197 ;; 0xD2C1: K
|
rlm@147
|
198 ;; 0xD2C2: A
|
rlm@147
|
199 ;; 0xD2C3: C
|
rlm@147
|
200 ;; 0xD2C4: H
|
rlm@147
|
201 ;; 0xD2C5: U
|
rlm@147
|
202 ;; 0xD2C6: end-of-pokemon-name-sentinel
|
rlm@147
|
203 ;; 0xD2C7: end-of-pokemon-name-sentinel
|
rlm@147
|
204 ;; 0xD2C8: end-of-pokemon-name-sentinel
|
rlm@147
|
205 ;; 0xD2C9: end-of-pokemon-name-sentinel
|
rlm@147
|
206 ;; 0xD2CA: C
|
rlm@147
|
207 ;; 0xD2CB: H
|
rlm@147
|
208 ;; 0xD2CC: A
|
rlm@147
|
209 ;; 0xD2CD: R
|
rlm@147
|
210 ;; 0xD2CE: I
|
rlm@147
|
211 ;; 0xD2CF: Z
|
rlm@147
|
212 ;; 0xD2D0: A
|
rlm@147
|
213 ;; 0xD2D1: R
|
rlm@147
|
214 ;; 0xD2D2: D
|
rlm@147
|
215 ;; 0xD2D3: end-of-pokemon-name-sentinel
|
rlm@147
|
216 ;; 0xD2D4: end-of-pokemon-name-sentinel
|
rlm@147
|
217 ;; 0xD2D5: V
|
rlm@147
|
218 ;; 0xD2D6: E
|
rlm@147
|
219 ;; 0xD2D7: N
|
rlm@147
|
220 ;; 0xD2D8: U
|
rlm@147
|
221 ;; 0xD2D9: S
|
rlm@147
|
222 ;; 0xD2DA: A
|
rlm@147
|
223 ;; 0xD2DB: U
|
rlm@147
|
224 ;; 0xD2DC: R
|
rlm@147
|
225 ;; 0xD2DD: end-of-pokemon-name-sentinel
|
rlm@147
|
226 ;; 0xD2DE: end-of-pokemon-name-sentinel
|
rlm@147
|
227 ;; 0xD2DF: end-of-pokemon-name-sentinel
|
rlm@147
|
228 ;; 0xD2E0: P
|
rlm@147
|
229 ;; 0xD2E1: R
|
rlm@147
|
230 ;; 0xD2E2: I
|
rlm@147
|
231 ;; 0xD2E3: M
|
rlm@147
|
232 ;; 0xD2E4: E
|
rlm@147
|
233 ;; 0xD2E5: A
|
rlm@147
|
234 ;; 0xD2E6: P
|
rlm@147
|
235 ;; 0xD2E7: E
|
rlm@147
|
236 ;; 0xD2E8: end-of-pokemon-name-sentinel
|
rlm@147
|
237 ;; 0xD2E9: end-of-pokemon-name-sentinel
|
rlm@147
|
238 ;; 0xD2EA: end-of-pokemon-name-sentinel
|
rlm@147
|
239 ;; 0xD2EB: A
|
rlm@147
|
240 ;; 0xD2EC: end-of-pokemon-name-sentinel
|
rlm@147
|
241 ;; 0xD2ED: S
|
rlm@147
|
242 ;; 0xD2EE: T
|
rlm@147
|
243 ;; 0xD2EF: E
|
rlm@147
|
244 ;; 0xD2F0: R
|
rlm@147
|
245 ;; 0xD2F1:
|
rlm@147
|
246 ;; 0xD2F2: B
|
rlm@147
|
247 ;; 0xD2F3: A
|
rlm@147
|
248 ;; 0xD2F4: L
|
rlm@147
|
249 ;; 0xD2F5: L
|
rlm@147
|
250 ;; 0xD2F6:
|
rlm@147
|
251 ;; 0xD2F7: A
|
rlm@147
|
252 ;; 0xD2F8:
|
rlm@147
|
253 ;; 0xD2F9:
|
rlm@147
|
254 ;; 0xD2FA: end-of-name-sentinel
|
rlm@147
|
255 ;; 0xD2FB: end-of-name-sentinel
|
rlm@147
|
256 ;; 0xD2FC: A
|
rlm@147
|
257 ;; 0xD2FD:
|
rlm@147
|
258 ;; 0xD2FE: end-of-name-sentinel
|
rlm@147
|
259 ;; 0xD2FF: end-of-name-sentinel
|
rlm@147
|
260 ;; 0xD300: end-of-name-sentinel
|
rlm@147
|
261 ;; 0xD301: end-of-name-sentinel
|
rlm@147
|
262 ;; 0xD302: end-of-name-sentinel
|
rlm@147
|
263 ;; 0xD303: end-of-name-sentinel
|
rlm@147
|
264 ;; 0xD304: end-of-name-sentinel
|
rlm@147
|
265 ;; 0xD305: end-of-name-sentinel
|
rlm@147
|
266 ;; 0xD306: end-of-name-sentinel
|
rlm@147
|
267 ;; 0xD307: end-of-name-sentinel
|
rlm@147
|
268 ;; 0xD308: end-of-name-sentinel
|
rlm@147
|
269 ;; 0xD309:
|
rlm@147
|
270 ;; 0xD30A: w
|
rlm@147
|
271 ;; 0xD30B:
|
rlm@147
|
272 ;; 0xD30C: V
|
rlm@147
|
273 ;; 0xD30D:
|
rlm@147
|
274 ;; 0xD30E:
|
rlm@147
|
275 ;; 0xD30F: K
|
rlm@147
|
276 ;; 0xD310:
|
rlm@147
|
277 ;; 0xD311:
|
rlm@147
|
278 ;; 0xD312:
|
rlm@147
|
279 ;; 0xD313: A
|
rlm@147
|
280 ;; 0xD314:
|
rlm@147
|
281 ;; 0xD315:
|
rlm@147
|
282 ;; 0xD316:
|
rlm@147
|
283 ;; 0xD317: i
|
rlm@147
|
284 ;; 0xD318:
|
rlm@147
|
285 ;; 0xD319:
|
rlm@147
|
286 ;; 0xD31A: end-of-name-sentinel
|
rlm@147
|
287 ;; 0xD31B: end-of-name-sentinel
|
rlm@147
|
288 ;; 0xD31C:
|
rlm@147
|
289 ;; 0xD31D:
|
rlm@147
|
290 ;; 0xD31E:
|
rlm@147
|
291 ;; 0xD31F:
|
rlm@147
|
292 ;; 0xD320:
|
rlm@147
|
293 ;; 0xD321:
|
rlm@147
|
294 ;; 0xD322:
|
rlm@147
|
295 ;; 0xD323:
|
rlm@147
|
296 ;; 0xD324:
|
rlm@147
|
297 ;; 0xD325:
|
rlm@147
|
298 ;; 0xD326:
|
rlm@147
|
299 ;; 0xD327:
|
rlm@147
|
300 ;; 0xD328:
|
rlm@147
|
301 ;; 0xD329:
|
rlm@147
|
302 ;; 0xD32A:
|
rlm@147
|
303 ;; 0xD32B:
|
rlm@147
|
304 ;; 0xD32C:
|
rlm@147
|
305 ;; 0xD32D:
|
rlm@147
|
306 ;; 0xD32E:
|
rlm@147
|
307 ;; 0xD32F:
|
rlm@147
|
308 ;; 0xD330:
|
rlm@147
|
309 ;; 0xD331: 9
|
rlm@147
|
310 ;; 0xD332: end-of-name-sentinel
|
rlm@147
|
311 ;; 0xD333: 9
|
rlm@147
|
312 ;; 0xD334:
|
rlm@147
|
313 ;; 0xD335: 9
|
rlm@147
|
314 ;; 0xD336:
|
rlm@147
|
315 ;; 0xD337: 9
|
rlm@147
|
316 ;; 0xD338: end-of-name-sentinel
|
rlm@147
|
317 ;; 0xD339: end-of-name-sentinel
|
rlm@147
|
318 ;; 0xD33A: end-of-name-sentinel
|
rlm@147
|
319 ;; 0xD33B: end-of-name-sentinel
|
rlm@147
|
320 ;; 0xD33C: end-of-name-sentinel
|
rlm@147
|
321 ;; 0xD33D: end-of-name-sentinel
|
rlm@147
|
322 ;; 0xD33E: end-of-name-sentinel
|
rlm@147
|
323 ;; 0xD33F: end-of-name-sentinel
|
rlm@147
|
324 ;; 0xD340: end-of-name-sentinel
|
rlm@147
|
325 ;; 0xD341: end-of-name-sentinel
|
rlm@147
|
326 ;; 0xD342: end-of-name-sentinel
|
rlm@147
|
327 ;; 0xD343: end-of-name-sentinel
|
rlm@147
|
328 ;; 0xD344: end-of-name-sentinel
|
rlm@147
|
329 ;; 0xD345: end-of-name-sentinel
|
rlm@147
|
330 ;; 0xD346:
|
rlm@147
|
331 ;; 0xD347:
|
rlm@147
|
332 ;; 0xD348:
|
rlm@147
|
333 ;; 0xD349: G
|
rlm@147
|
334 ;; 0xD34A: A
|
rlm@147
|
335 ;; 0xD34B: R
|
rlm@147
|
336 ;; 0xD34C: Y
|
rlm@147
|
337 ;; 0xD34D: end-of-pokemon-name-sentinel
|
rlm@147
|
338 ;; 0xD34E: J
|
rlm@147
|
339
|
rlm@147
|
340
|
rlm@147
|
341 ;; from this, it looks like the pokemon names are stored all
|
rlm@147
|
342 ;; together in one location that begins at 0xD2B4 and
|
rlm@147
|
343 ;; extends until 0xD2F5, with each name taking up 11 bytes.
|
rlm@147
|
344 ;;
|
rlm@147
|
345 ;; rival's name again clearly starts at 0xD349.
|
rlm@147
|
346
|
rlm@147
|
347
|
rlm@147
|
348 (def pokemon-names-start 0xD2B4)
|
rlm@147
|
349
|
rlm@147
|
350
|
rlm@147
|
351 ;; determine whether "number of pokemon in party"
|
rlm@147
|
352 ;; might be kept in RAM and if so, where?
|
rlm@147
|
353
|
rlm@147
|
354 (def six-pokemon (read-state "6-pokemon"))
|
rlm@147
|
355 (def five-pokemon (read-state "5-pokemon"))
|
rlm@147
|
356 (def four-pokemon (read-state "4-pokemon"))
|
rlm@147
|
357 (def three-pokemon (read-state "3-pokemon"))
|
rlm@147
|
358 (def two-pokemon (read-state "2-pokemon"))
|
rlm@147
|
359 (def one-pokemon (read-state "1-pokemon"))
|
rlm@147
|
360
|
rlm@147
|
361
|
rlm@147
|
362 (defn analyze-num-pokemon []
|
rlm@147
|
363 (apply common-differences
|
rlm@147
|
364 (map (comp vec memory)
|
rlm@147
|
365 [one-pokemon
|
rlm@147
|
366 two-pokemon
|
rlm@147
|
367 three-pokemon
|
rlm@147
|
368 four-pokemon
|
rlm@147
|
369 five-pokemon
|
rlm@147
|
370 six-pokemon])))
|
rlm@147
|
371
|
rlm@147
|
372 ;; ;; results
|
rlm@147
|
373 ;; ([53602 (1 2 3 4 5 6)]
|
rlm@147
|
374 ;; [65314 (105 61 93 60 92 34)]
|
rlm@147
|
375 ;; [55875 (34 36 43 52 7 0)]
|
rlm@147
|
376 ;; [55876 (18 0 33 52 54 30)]
|
rlm@147
|
377 ;; [49158 (197 194 77 117 174 134)]
|
rlm@147
|
378 ;; [49160 (29 26 57 239 15 243)]
|
rlm@147
|
379 ;; [49736 (74 93 34 89 91 59)]
|
rlm@147
|
380 ;; [49162 (165 162 182 179 197 109)]
|
rlm@147
|
381 ;; [49227 (187 105 204 5 90 238)]
|
rlm@147
|
382 ;; [53067 (128 136 132 145 135 11)]
|
rlm@147
|
383 ;; [53068 (147 131 141 136 128 7)]
|
rlm@147
|
384 ;; [53069 (136 134 148 140 145 2)]
|
rlm@147
|
385 ;; [49904 (2 11 10 3 27 12)]
|
rlm@147
|
386 ;; [49172 (100 109 213 195 68 104)]
|
rlm@147
|
387 ;; [65492 (11 103 128 160 19 56)]
|
rlm@147
|
388 ;; [49173 (80 77 72 75 76 67)]
|
rlm@147
|
389 ;; [49334 (8 10 11 5 3 1)]
|
rlm@147
|
390 ;; [49335 (49 10 11 19 17 15)]
|
rlm@147
|
391 ;; [49336 (8 10 11 5 3 1)]
|
rlm@147
|
392 ;; [49720 (106 14 118 0 38 11)]
|
rlm@147
|
393 ;; [65304 (32 88 19 114 106 33)]
|
rlm@147
|
394 ;; [53561 (59 229 48 17 155 103)]
|
rlm@147
|
395 ;; [55935 (6 5 4 3 2 1)])
|
rlm@147
|
396
|
rlm@147
|
397
|
rlm@147
|
398 ;; two canidates : 0xD162 or 0xDA7F
|
rlm@147
|
399 ;; they seem to always sum to 6...
|
rlm@147
|
400
|
rlm@147
|
401 ;; try to set both of them when having only one pokemon.
|
rlm@147
|
402
|
rlm@147
|
403 (defn change-party-number [^SaveState state new-num]
|
rlm@147
|
404 (set-memory state 0xD162 new-num))
|
rlm@147
|
405
|
rlm@147
|
406 ;; (continue! (change-party-number one-pokemon 3))
|
rlm@147
|
407 ;; result -- can scroll down beyone first pokemon, finding
|
rlm@147
|
408 ;; glitched pokemon in places where there were previously no
|
rlm@147
|
409 ;; pokemon.
|
rlm@147
|
410
|
rlm@147
|
411
|
rlm@147
|
412 (defn change-party-number* [^SaveState state new-num]
|
rlm@147
|
413 (set-memory state 0xDA7F new-num))
|
rlm@147
|
414
|
rlm@147
|
415
|
rlm@147
|
416 ;; (continue! (change-party-number* one-pokemon 3))
|
rlm@147
|
417 ;; cannot widthdraw any pokemon from box 1 past the third
|
rlm@147
|
418 ;; pokemon.
|
rlm@147
|
419
|
rlm@147
|
420 (def party-number-address 0xD162)
|
rlm@147
|
421
|
rlm@147
|
422 (defn party-number
|
rlm@147
|
423 ([^SaveState state]
|
rlm@147
|
424 (aget (memory state) party-number-address))
|
rlm@147
|
425 ([] (party-number @current-state)))
|
rlm@147
|
426
|
rlm@147
|
427 (def pokemon-in-box-1-address 0xDA7F)
|
rlm@147
|
428
|
rlm@147
|
429 (defn party-names
|
rlm@147
|
430 ([^SaveState state]
|
rlm@147
|
431 (let [raw-names
|
rlm@147
|
432 (subvec (vec (memory state))
|
rlm@147
|
433 pokemon-names-start
|
rlm@147
|
434 (+ pokemon-names-start
|
rlm@148
|
435 (* name-width 6)))]
|
rlm@147
|
436 (map
|
rlm@148
|
437 read-name
|
rlm@147
|
438 (take
|
rlm@147
|
439 (party-number state)
|
rlm@147
|
440 (partition name-width
|
rlm@147
|
441 raw-names)))))
|
rlm@147
|
442 ([] (party-names @current-state)))
|
rlm@147
|
443
|
rlm@148
|
444
|
rlm@148
|
445 (defn rename-pokemon
|
rlm@148
|
446 ([^SaveState state n new-name]
|
rlm@148
|
447 (assert (<= 0 n (dec (party-number state))))
|
rlm@148
|
448 (assert (<= (count new-name) max-name-length))
|
rlm@148
|
449 (set-memory-range
|
rlm@148
|
450 state
|
rlm@148
|
451 (+ (* n name-width) pokemon-names-start)
|
rlm@148
|
452 (concat (str->character-codes new-name) [end-of-name-marker])))
|
rlm@148
|
453 ([n new-name]
|
rlm@148
|
454 (rename-pokemon @current-state n new-name)))
|
rlm@148
|
455
|
rlm@148
|
456 ;; on further analysis, it appears that the original
|
rlm@148
|
457 ;; trainer info for each pokemon is also stored together,
|
rlm@148
|
458 ;; starting at 0xD272 and continuing to 0xD2B3, with
|
rlm@148
|
459 ;; 11 bytes reserved for each OT name.
|
rlm@148
|
460
|
rlm@148
|
461 (def OT-start 0xD272)
|
rlm@148
|
462
|
rlm@148
|
463 (defn original-trainers
|
rlm@148
|
464 ([^SaveState state]
|
rlm@148
|
465 (let [raw-names
|
rlm@148
|
466 (subvec (vec (memory state))
|
rlm@148
|
467 OT-start
|
rlm@148
|
468 (+ OT-start
|
rlm@148
|
469 (* name-width 6)))]
|
rlm@148
|
470 (map read-name
|
rlm@148
|
471 (take (party-number state)
|
rlm@148
|
472 (partition name-width raw-names)))))
|
rlm@148
|
473 ([] (original-trainers @current-state)))
|
rlm@148
|
474
|
rlm@148
|
475 (defn set-original-trainer
|
rlm@148
|
476 "Set the OT name for a pokemon.
|
rlm@148
|
477 Note that a pokemon is still considered 'yours' if
|
rlm@148
|
478 the OT ID is the same as your own."
|
rlm@148
|
479 ([^SaveState state n new-name]
|
rlm@148
|
480 (assert (<= 0 n (dec (party-number state))))
|
rlm@148
|
481 (assert (<= (count new-name) max-name-length))
|
rlm@148
|
482 (set-memory-range
|
rlm@148
|
483 state
|
rlm@148
|
484 (+ (* n name-width) OT-start)
|
rlm@148
|
485 (concat (str->character-codes new-name) [end-of-name-marker])))
|
rlm@148
|
486 ([n new-name]
|
rlm@148
|
487 (set-original-trainer @current-state n new-name)))
|
rlm@148
|
488
|
rlm@148
|
489 ;; PIKACHU stops following if you set it's OT to another name
|
rlm@148
|
490 ;; and then back to you own.
|
rlm@148
|
491 ;; But not if you set it to your own name, obviously.
|
rlm@149
|
492
|
rlm@149
|
493
|
rlm@150
|
494
|
rlm@150
|
495
|
rlm@150
|
496 ;; OT ID Numbers.
|
rlm@152
|
497 ;; My own id is 05195. A quick search of memory between
|
rlm@150
|
498 ;; 0xD162 and 0xD31B revealed the pattern 0x144B exactly
|
rlm@150
|
499 ;; six times.
|
rlm@150
|
500
|
rlm@150
|
501 ;; the locations were:
|
rlm@150
|
502
|
rlm@150
|
503 (def OT-ID-addresses [0xD176 0xD1A2 0xD1CE 0xD1FA 0xD228 0xD252])
|
rlm@150
|
504
|
rlm@150
|
505
|
rlm@150
|
506 (defn set-pokemon-id
|
rlm@150
|
507 ([^SaveState state n new-id]
|
rlm@150
|
508 (assert (<= 0 n (dec (party-number state))))
|
rlm@150
|
509 (assert (<= 0 new-id 0xFFFF))
|
rlm@150
|
510 (set-memory-range
|
rlm@150
|
511 state
|
rlm@150
|
512 (OT-ID-addresses n)
|
rlm@151
|
513 [(bit-shift-right (bit-and new-id 0xFF00) 8)
|
rlm@151
|
514 (bit-and new-id 0xFF)
|
rlm@151
|
515 ]))
|
rlm@150
|
516 ([n new-id]
|
rlm@151
|
517 (set-pokemon-id @current-state n new-id)))
|
rlm@152
|
518
|
rlm@152
|
519
|
rlm@152
|
520
|
rlm@160
|
521
|
rlm@160
|
522
|
rlm@160
|
523 (defn get-pokemon-1-info
|
rlm@160
|
524 ([state]
|
rlm@160
|
525 (subvec (vec (memory state))
|
rlm@160
|
526 0xD162 0xD197))
|
rlm@160
|
527 ([] (get-pokemon-1-info @current-state)))
|
rlm@160
|
528
|
rlm@160
|
529 (def baseline (File. "/home/r/baseline-poke"))
|
rlm@160
|
530
|
rlm@160
|
531
|
rlm@160
|
532
|
rlm@160
|
533
|
rlm@160
|
534 (import java.io.File)
|
rlm@160
|
535
|
rlm@160
|
536 (defn set-baseline [state]
|
rlm@160
|
537 (clojure.java.io/copy
|
rlm@160
|
538 (with-out-str (print-listing state 0xD162 0xD197))
|
rlm@160
|
539 baseline))
|
rlm@160
|
540
|
rlm@160
|
541 (defn compare-pokemon
|
rlm@160
|
542 ([state]
|
rlm@160
|
543 (let [target (File. "/home/r/temp-poke")]
|
rlm@160
|
544 (clojure.java.io/copy
|
rlm@160
|
545 (with-out-str (print-listing state 0xD162 0xD197))
|
rlm@160
|
546 target)
|
rlm@160
|
547 (println (:out
|
rlm@160
|
548 (clojure.java.shell/sh "diff"
|
rlm@160
|
549 (.getCanonicalPath baseline)
|
rlm@160
|
550 (.getCanonicalPath target))))))
|
rlm@161
|
551 ([] (compare-pokemon @current-state)))
|
rlm@160
|
552
|
rlm@160
|
553
|
rlm@160
|
554 (defn crazy-pid []
|
rlm@160
|
555 (read-state "crazy-pidgeot"))
|
rlm@166
|
556
|
rlm@168
|
557 (def unknown "[[[UNKNOWN]]]")
|
rlm@168
|
558
|
rlm@166
|
559 (def unknown "")
|
rlm@166
|
560
|
rlm@166
|
561 (def pokemon-1-info
|
rlm@166
|
562 {0xD16A "Color Map" ;; 0
|
rlm@166
|
563 0xD16B "Current-HP (h)" ;; 1
|
rlm@166
|
564 0xD16C "Current-HP (l)" ;; 2
|
rlm@166
|
565 0XD16D unknown ;; 3
|
rlm@166
|
566 0xD16E unknown ;; 4
|
rlm@166
|
567 0xD16F unknown ;; 5
|
rlm@166
|
568 0xD170 unknown ;; 6
|
rlm@166
|
569 0xD171 unknown ;; 7
|
rlm@166
|
570 0xD172 "Move 1 ID" ;; 8
|
rlm@166
|
571 0xD173 "Move 2 ID" ;; 9
|
rlm@166
|
572 0xD174 "Move 3 ID" ;; 10
|
rlm@166
|
573 0xD175 "Move 4 ID" ;; 11
|
rlm@166
|
574 0xD176 "OT-ID (h)" ;; 12
|
rlm@166
|
575 0xD177 "OT-ID (l)" ;; 13
|
rlm@166
|
576 0xD178 "Exp. Points (h)" ;; 14
|
rlm@166
|
577 0xD179 "Exp. Points (m)" ;; 15
|
rlm@166
|
578 0xD17A "Exp. Points (l)" ;; 16
|
rlm@168
|
579 0xD17B "HP Exp. (h)" ;; 17
|
rlm@168
|
580 0xD17C "HP Exp. (l)" ;; 18
|
rlm@168
|
581 0xD17D "Attack Exp. (h)" ;; 19
|
rlm@168
|
582 0xD17E "Attack Exp. (l)" ;; 20
|
rlm@168
|
583 0xD17F "Defense Exp. (h)" ;; 21
|
rlm@168
|
584 0xD180 "Defense Exp. (l)" ;; 22
|
rlm@168
|
585 0xD181 "Speed Exp. (h)" ;; 23
|
rlm@168
|
586 0xD182 "Speed Exp. (l)" ;; 24
|
rlm@168
|
587 0xD183 "Special Exp. (h)" ;; 25
|
rlm@168
|
588 0xD184 "Special Exp. (l)" ;; 26
|
rlm@166
|
589 0xD185 unknown ;; 27
|
rlm@166
|
590 0xD186 unknown ;; 28
|
rlm@166
|
591 0xD187 "PP Move 1" ;; 29
|
rlm@166
|
592 0xD188 "PP Move 2" ;; 30
|
rlm@166
|
593 0xD189 "PP Move 3" ;; 31
|
rlm@166
|
594 0xD18A "PP Move 4" ;; 32
|
rlm@166
|
595 0xD18B "Current Level" ;; 33
|
rlm@166
|
596 0xD18C "HP Total (h)" ;; 34
|
rlm@166
|
597 0xD18D "HP Total (l)" ;; 35
|
rlm@166
|
598 0xD18E "Attack (h)" ;; 36
|
rlm@166
|
599 0xD18F "Attack (l)" ;; 37
|
rlm@166
|
600 0xD190 "Defense (h)" ;; 38
|
rlm@166
|
601 0xD191 "Defense (l)" ;; 39
|
rlm@166
|
602 0xD192 "Speed (h)" ;; 40
|
rlm@166
|
603 0xD193 "Speed (l)" ;; 41
|
rlm@166
|
604 0xD194 "Special (h)" ;; 42
|
rlm@168
|
605 0xD195 "Special (l)" ;; 43
|
rlm@166
|
606 })
|
rlm@166
|
607
|
rlm@166
|
608 (defn pokemon-data
|
rlm@166
|
609 ([^SaveState state pokemon-num]
|
rlm@166
|
610 (assert (<= 0 pokemon-num 5))
|
rlm@166
|
611 (let [base (+ (* pokemon-num pokemon-record-width) 0xD16A)]
|
rlm@166
|
612 (subvec (vec (memory state)) base
|
rlm@166
|
613 (+ base pokemon-record-width))))
|
rlm@166
|
614 ([pokemon-num] (pokemon-data @current-state pokemon-num)))
|
rlm@166
|
615
|
rlm@166
|
616 (defn set-pokemon-data
|
rlm@166
|
617 ([^SaveState state pokemon-num new-data]
|
rlm@166
|
618 (assert (<= 0 pokemon-num 5))
|
rlm@166
|
619 (let [base (+ (* pokemon-num pokemon-record-width) 0xD16A)]
|
rlm@166
|
620 (set-memory-range state base new-data)))
|
rlm@166
|
621 ([pokemon-num new-data]
|
rlm@166
|
622 (set-pokemon-data @current-state pokemon-num new-data)))
|
rlm@166
|
623
|
rlm@167
|
624 (defn print-pokemon-data
|
rlm@167
|
625 ([^SaveState state pokemon-num]
|
rlm@167
|
626 (assert (<= 0 pokemon-num 5))
|
rlm@167
|
627 (let [poke-data (pokemon-data state pokemon-num)
|
rlm@167
|
628 backbone (sort (keys pokemon-1-info))]
|
rlm@168
|
629 (println "Pokemon " pokemon-num " -- "
|
rlm@168
|
630 (nth (party-names state)
|
rlm@168
|
631 pokemon-num) \newline)
|
rlm@168
|
632
|
rlm@168
|
633 (println " Desc. | Hex | Dec | Binary |")
|
rlm@168
|
634 (println "-------------------+------+-----+----------+")
|
rlm@167
|
635 (dorun
|
rlm@167
|
636 (map
|
rlm@167
|
637 (comp println
|
rlm@167
|
638 (fn [desc data]
|
rlm@168
|
639 (format "%-16s | 0x%02X | %3d | %s |"
|
rlm@168
|
640 desc data data
|
rlm@168
|
641 (let [s (Integer/toBinaryString data)]
|
rlm@168
|
642 (apply
|
rlm@168
|
643 str
|
rlm@168
|
644 (concat (repeat (- 8 (count s)) "0" )
|
rlm@168
|
645 s)))
|
rlm@168
|
646
|
rlm@168
|
647
|
rlm@168
|
648 )))
|
rlm@167
|
649
|
rlm@167
|
650 (map pokemon-1-info backbone)
|
rlm@167
|
651 poke-data))))
|
rlm@167
|
652 ([pokemon-num]
|
rlm@167
|
653 (print-pokemon-data @current-state pokemon-num)))
|
rlm@167
|
654
|
rlm@166
|
655
|
rlm@166
|
656
|
rlm@167
|
657 (defn pre-battle [] (read-state "prepare-for-battle"))
|
rlm@167
|
658
|
rlm@168
|
659
|
rlm@169
|
660 (defn pika-lvl-100-DV-0 []
|
rlm@169
|
661 (read-state "at-pc-lv-100-pikachu"))
|
rlm@168
|
662
|
rlm@169
|
663 ;; Performed following experiment:
|
rlm@169
|
664 ;; Raised Pikachu to Lvl 100 with rare-candies,
|
rlm@169
|
665 ;; then put it at the head of the party and
|
rlm@169
|
666 ;; set 0xD185 and 0xD186 to zero.
|
rlm@168
|
667
|
rlm@169
|
668 ;; then, for each pattern, deposited pikachu into
|
rlm@169
|
669 ;; Box 1 and immediately widthdrew it and observed the
|
rlm@169
|
670 ;; stats.
|
rlm@168
|
671
|
rlm@169
|
672
|
rlm@169
|
673 ;; Pikachu L:100 Base Stats with DVs = 0
|
rlm@169
|
674 ;; HP : 187
|
rlm@169
|
675 ;; Attack : 123
|
rlm@169
|
676 ;; Defense : 73
|
rlm@169
|
677 ;; Speed : 194
|
rlm@169
|
678 ;; Special : 112
|
rlm@169
|
679
|
rlm@169
|
680 ;; 0xD185:
|
rlm@169
|
681
|
rlm@169
|
682 ;; 00000001
|
rlm@169
|
683 ;; Defense => 75 (+2)
|
rlm@169
|
684 ;; HP => 195 (+8)
|
rlm@169
|
685
|
rlm@169
|
686 ;; 00000010
|
rlm@169
|
687 ;; Defense => 77 (+4)
|
rlm@169
|
688
|
rlm@169
|
689 ;; 00000100
|
rlm@169
|
690 ;; Defense => 81 (+8)
|
rlm@169
|
691
|
rlm@169
|
692 ;; 00001000
|
rlm@169
|
693 ;; Defense => 89 (+16)
|
rlm@169
|
694
|
rlm@169
|
695 ;; 00010000
|
rlm@169
|
696 ;; HP => 203 (+16)
|
rlm@169
|
697 ;; Attack => 125 (+2)
|
rlm@169
|
698
|
rlm@169
|
699 ;; 00100000
|
rlm@169
|
700 ;; Attack => 127 (+4)
|
rlm@169
|
701
|
rlm@169
|
702 ;; 01000000
|
rlm@169
|
703 ;; Attack -> 131 (+8)
|
rlm@169
|
704
|
rlm@169
|
705 ;; 10000000
|
rlm@169
|
706 ;; Attack -> 139 (+16)
|
rlm@169
|
707
|
rlm@169
|
708 ;; 0xD186
|
rlm@169
|
709
|
rlm@169
|
710 ;; 00000001
|
rlm@169
|
711 ;; HP => 189 (+2)
|
rlm@169
|
712 ;; Special => (+2)
|
rlm@169
|
713
|
rlm@169
|
714 ;; 00000010
|
rlm@169
|
715 ;; Special => 116 (+4)
|
rlm@169
|
716
|
rlm@169
|
717 ;; 00000100
|
rlm@169
|
718 ;; Special => 120 (+8)
|
rlm@169
|
719
|
rlm@169
|
720 ;; 00001000
|
rlm@169
|
721 ;; Special => 128 (+16)
|
rlm@169
|
722
|
rlm@169
|
723 ;; 00010000
|
rlm@169
|
724 ;; HP => 191 (+4)
|
rlm@169
|
725 ;; Speed => 196 (+2)
|
rlm@169
|
726
|
rlm@169
|
727 ;; 00100000
|
rlm@169
|
728 ;; Speed => 198 (+4)
|
rlm@169
|
729
|
rlm@169
|
730 ;; 01000000
|
rlm@169
|
731 ;; Speed => 202 (+8)
|
rlm@169
|
732
|
rlm@169
|
733 ;; 10000000
|
rlm@169
|
734 ;; Speed => 210 (+16)
|
rlm@169
|
735
|
rlm@169
|
736 (def pokemon-1-DV-start 0xD185)
|
rlm@169
|
737
|
rlm@169
|
738 (defn pokemon-DV-start-point [poke-num]
|
rlm@169
|
739 (+ (* poke-num pokemon-record-width)
|
rlm@169
|
740 pokemon-1-DV-start))
|
rlm@169
|
741
|
rlm@169
|
742 (def reverse-4-bit
|
rlm@169
|
743 {0 0
|
rlm@169
|
744 1 8
|
rlm@169
|
745 2 4
|
rlm@169
|
746 3 12
|
rlm@169
|
747 5 10
|
rlm@169
|
748 6 6
|
rlm@169
|
749 7 14
|
rlm@169
|
750 9 9
|
rlm@169
|
751 15 15
|
rlm@169
|
752 13 11
|
rlm@169
|
753
|
rlm@169
|
754 8 1
|
rlm@169
|
755 4 2
|
rlm@169
|
756 12 3
|
rlm@169
|
757 10 5
|
rlm@169
|
758 11 13
|
rlm@169
|
759 14 7 })
|
rlm@169
|
760
|
rlm@169
|
761 (defn read-DV
|
rlm@169
|
762 ([^SaveState state poke-num]
|
rlm@169
|
763 (assert (<= 0 poke-num 5))
|
rlm@169
|
764 (let [[raw-DV-1
|
rlm@169
|
765 raw-DV-2]
|
rlm@169
|
766 (subvec (vec (memory state))
|
rlm@169
|
767 (pokemon-DV-start-point poke-num)
|
rlm@169
|
768 (+ 2 (pokemon-DV-start-point poke-num)))
|
rlm@169
|
769 defense-DV (bit-and raw-DV-1 0x0F)
|
rlm@169
|
770 attack-DV (bit-shift-right
|
rlm@169
|
771 (bit-and raw-DV-1 0xF0)
|
rlm@169
|
772 4)
|
rlm@169
|
773 special-DV (bit-and raw-DV-2 0x0F)
|
rlm@169
|
774 speed-DV (bit-shift-right
|
rlm@169
|
775 (bit-and raw-DV-2 0xF0)
|
rlm@169
|
776 4)
|
rlm@169
|
777 HP-DV
|
rlm@169
|
778 (+
|
rlm@169
|
779 (if (bit-test special-DV 0) 1 0)
|
rlm@169
|
780 (if (bit-test speed-DV 0) 2 0)
|
rlm@169
|
781 (if (bit-test defense-DV 0) 4 0)
|
rlm@169
|
782 (if (bit-test attack-DV 0) 8 0))]
|
rlm@169
|
783 {:attack attack-DV
|
rlm@169
|
784 :defense defense-DV
|
rlm@169
|
785 :speed speed-DV
|
rlm@169
|
786 :special special-DV
|
rlm@169
|
787 :hp HP-DV}))
|
rlm@169
|
788 ([poke-num]
|
rlm@169
|
789 (read-DV @current-state poke-num)))
|
rlm@169
|
790
|
rlm@169
|
791
|
rlm@169
|
792 (defn give-DV
|
rlm@169
|
793 ([^SaveState state poke-num dv-values]
|
rlm@169
|
794
|
rlm@169
|
795 (assert (<= 0 poke-num 5))
|
rlm@169
|
796 (map #(assert (<= 0 % 15)) (vals dv-values))
|
rlm@169
|
797 (let [raw-dv-1*
|
rlm@169
|
798 (+ (:defense dv-values)
|
rlm@169
|
799 (bit-shift-left (:attack dv-values) 4))
|
rlm@169
|
800 raw-dv-2*
|
rlm@169
|
801 (+ (:special dv-values)
|
rlm@169
|
802 (bit-shift-left (:speed dv-values) 4))
|
rlm@169
|
803 hp-dv (:hp dv-values)
|
rlm@169
|
804 hp-masks-1
|
rlm@169
|
805 [[0 (bit-test hp-dv 2)]
|
rlm@169
|
806 [4 (bit-test hp-dv 3)]]
|
rlm@169
|
807 hp-masks-2
|
rlm@169
|
808 [[0 (bit-test hp-dv 0)]
|
rlm@169
|
809 [4 (bit-test hp-dv 1)]]
|
rlm@169
|
810 set-hp-bits
|
rlm@169
|
811 (fn [init [index hp?]]
|
rlm@169
|
812 (if hp?
|
rlm@169
|
813 (bit-set init index)
|
rlm@169
|
814 (bit-clear init index)))
|
rlm@169
|
815
|
rlm@169
|
816 raw-dv-1 (reduce set-hp-bits raw-dv-1*
|
rlm@169
|
817 hp-masks-1)
|
rlm@169
|
818
|
rlm@169
|
819 raw-dv-2 (reduce set-hp-bits raw-dv-2*
|
rlm@169
|
820 hp-masks-2)
|
rlm@169
|
821
|
rlm@169
|
822 dv-start (pokemon-DV-start-point poke-num)]
|
rlm@169
|
823
|
rlm@169
|
824 (if (or (not= raw-dv-1* raw-dv-1)
|
rlm@169
|
825 (not= raw-dv-2* raw-dv-2))
|
rlm@169
|
826 (println "Warning: inconsistent DV-values."
|
rlm@169
|
827 "Using HP settings."))
|
rlm@169
|
828
|
rlm@169
|
829 (set-memory
|
rlm@169
|
830 (set-memory state dv-start raw-dv-1)
|
rlm@169
|
831 (inc dv-start) raw-dv-2)))
|
rlm@169
|
832 ([poke-num dv-values]
|
rlm@169
|
833 (give-DV @current-state poke-num dv-values)))
|
rlm@169
|
834
|
rlm@169
|
835 (def good-DVs
|
rlm@169
|
836 {:attack 15
|
rlm@169
|
837 :defense 15
|
rlm@169
|
838 :speed 15
|
rlm@169
|
839 :special 15
|
rlm@169
|
840 :hp 15})
|
rlm@169
|
841
|
rlm@169
|
842 (def bad-DVs
|
rlm@169
|
843 {:attack 0
|
rlm@169
|
844 :defense 0
|
rlm@169
|
845 :speed 0
|
rlm@169
|
846 :special 0
|
rlm@169
|
847 :hp 0})
|
rlm@169
|
848
|
rlm@169
|
849 |