Mercurial > vba-clojure
view clojure/com/aurellem/exp/pokemon.clj @ 172:63ec3db6f6d1
add DV info to print-pokemon-data
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Wed, 21 Mar 2012 03:24:18 -0500 |
parents | 4857f59f63a6 |
children | 95b2758dd517 |
line wrap: on
line source
1 (ns com.aurellem.exp.pokemon2 "Here I find out how pokemon are stored in memory."3 (:use (com.aurellem.gb gb-driver items assembly util4 constants5 characters species moves))6 (:import java.io.File)7 (:import [com.aurellem.gb.gb_driver SaveState]))10 (def pidgeot-lvl-36 (mid-game))13 (def pidgeot-lvl-37 (read-state "pidgeot-lvl-37"))16 (def pidgeot-lvl-38 (read-state "pidgeot-lvl-38"))19 (def pidgeot-lvl-39 (read-state "pidgeot-lvl-39"))22 (def pidgeot-lvl-40 (read-state "pidgeot-lvl-40"))25 (defn level-analysis []26 (apply common-differences27 (map (comp vec memory)28 [pidgeot-lvl-3629 pidgeot-lvl-3730 pidgeot-lvl-3831 pidgeot-lvl-3932 pidgeot-lvl-40])))34 ;; inconclusive -- implies that level is calculated from35 ;; some other values.38 (def name-pidgeotto (read-state "name-pidgeotto"))39 (def named-A (read-state "named-A"))40 (def named-B (read-state "named-B"))41 (def named-C (read-state "named-C"))42 (def named-D (read-state "named-D"))43 (def named-E (read-state "named-E"))44 (def named-F (read-state "named-F"))46 (defn name-analysis []47 (apply common-differences48 (map (comp vec memory)49 [named-A50 named-B51 named-C52 named-D53 named-E54 named-F])))56 ;; resluted in 3 separate locations that could57 ;; possibly hold the first letter of the pokemon's name59 0xCF4A60 0xD2EB61 0xCEED63 ;; try changing each of them66 (defn test-cf4a []67 (continue!68 (set-memory named-A 0xCF4A (character->character-code "Z"))))69 ;; result -- pidgeotto named "A"71 (defn test-d2eb []72 (continue!73 (set-memory named-A 0xD2EB (character->character-code "Z"))))74 ;; result -- pidgeotto named "Z"76 (defn test-ceed []77 (continue!78 (set-memory named-A 0xCEED (character->character-code "Z"))))79 ;; result -- pidgeotto named "A"81 (def sixth-pokemon-name-start 0xD2EB)84 (defn set-sixth-pokemon-name-first-character85 ([state character]86 (set-memory state sixth-pokemon-name-start87 (character->character-code character)))88 ([character]89 (set-sixth-pokemon-name-first-character @current-state90 character)))93 (def end-of-name-marker 0x50)94 (def max-name-length 10)95 (def name-width 11)97 (defn read-name [codes]98 (character-codes->str99 (take-while100 (partial not= end-of-name-marker) codes)))103 (defn sixth-pokemon-name [^SaveState state]104 (read-name105 (subvec (vec (memory state))106 sixth-pokemon-name-start107 (+ (inc max-name-length)108 sixth-pokemon-name-start))))110 (defn rename-sixth-pokemon111 ([^SaveState state new-name]112 (assert (< (count new-name) max-name-length))113 (set-memory-range state sixth-pokemon-name-start114 (concat (str->character-codes new-name)115 [end-of-name-marker])))116 ([new-name]117 (rename-sixth-pokemon @current-state new-name)))119 (defn print-text120 ([^SaveState state begin end]121 (dorun122 (map (fn [character-code line]123 (println124 (format "0x%04X: " line)125 (str (character-code->character character-code))))126 (subvec (vec (memory state)) begin end)127 (range begin end)))128 state)129 ([begin end]130 (print-text @current-state begin end)))132 (defn examine-name-memory []133 (print-text134 named-A135 (- sixth-pokemon-name-start 100)136 (+ sixth-pokemon-name-start 100)))138 ;; results:139 ;; 0xD287: end-of-name-sentinel140 ;; 0xD288: R141 ;; 0xD289: L142 ;; 0xD28A: M143 ;; 0xD28B: end-of-pokemon-name-sentinel144 ;; 0xD28C: end-of-name-sentinel145 ;; 0xD28D: end-of-name-sentinel146 ;; 0xD28E: end-of-name-sentinel147 ;; 0xD28F: end-of-name-sentinel148 ;; 0xD290: end-of-name-sentinel149 ;; 0xD291: end-of-name-sentinel150 ;; 0xD292: end-of-name-sentinel151 ;; 0xD293: R152 ;; 0xD294: L153 ;; 0xD295: M154 ;; 0xD296: end-of-pokemon-name-sentinel155 ;; 0xD297: end-of-name-sentinel156 ;; 0xD298: end-of-name-sentinel157 ;; 0xD299: end-of-name-sentinel158 ;; 0xD29A: end-of-name-sentinel159 ;; 0xD29B: end-of-name-sentinel160 ;; 0xD29C: end-of-name-sentinel161 ;; 0xD29D: end-of-name-sentinel162 ;; 0xD29E: R163 ;; 0xD29F: L164 ;; 0xD2A0: M165 ;; 0xD2A1: end-of-pokemon-name-sentinel166 ;; 0xD2A2: end-of-name-sentinel167 ;; 0xD2A3: end-of-name-sentinel168 ;; 0xD2A4: end-of-name-sentinel169 ;; 0xD2A5: end-of-name-sentinel170 ;; 0xD2A6: end-of-name-sentinel171 ;; 0xD2A7: end-of-name-sentinel172 ;; 0xD2A8: end-of-name-sentinel173 ;; 0xD2A9: R174 ;; 0xD2AA: L175 ;; 0xD2AB: M176 ;; 0xD2AC: end-of-pokemon-name-sentinel177 ;; 0xD2AD: end-of-name-sentinel178 ;; 0xD2AE: end-of-name-sentinel179 ;; 0xD2AF: end-of-name-sentinel180 ;; 0xD2B0: end-of-name-sentinel181 ;; 0xD2B1: end-of-name-sentinel182 ;; 0xD2B2: end-of-name-sentinel183 ;; 0xD2B3: end-of-name-sentinel184 ;; 0xD2B4: P185 ;; 0xD2B5: I186 ;; 0xD2B6: D187 ;; 0xD2B7: G188 ;; 0xD2B8: E189 ;; 0xD2B9: O190 ;; 0xD2BA: T191 ;; 0xD2BB: end-of-pokemon-name-sentinel192 ;; 0xD2BC: end-of-pokemon-name-sentinel193 ;; 0xD2BD: end-of-pokemon-name-sentinel194 ;; 0xD2BE: end-of-pokemon-name-sentinel195 ;; 0xD2BF: P196 ;; 0xD2C0: I197 ;; 0xD2C1: K198 ;; 0xD2C2: A199 ;; 0xD2C3: C200 ;; 0xD2C4: H201 ;; 0xD2C5: U202 ;; 0xD2C6: end-of-pokemon-name-sentinel203 ;; 0xD2C7: end-of-pokemon-name-sentinel204 ;; 0xD2C8: end-of-pokemon-name-sentinel205 ;; 0xD2C9: end-of-pokemon-name-sentinel206 ;; 0xD2CA: C207 ;; 0xD2CB: H208 ;; 0xD2CC: A209 ;; 0xD2CD: R210 ;; 0xD2CE: I211 ;; 0xD2CF: Z212 ;; 0xD2D0: A213 ;; 0xD2D1: R214 ;; 0xD2D2: D215 ;; 0xD2D3: end-of-pokemon-name-sentinel216 ;; 0xD2D4: end-of-pokemon-name-sentinel217 ;; 0xD2D5: V218 ;; 0xD2D6: E219 ;; 0xD2D7: N220 ;; 0xD2D8: U221 ;; 0xD2D9: S222 ;; 0xD2DA: A223 ;; 0xD2DB: U224 ;; 0xD2DC: R225 ;; 0xD2DD: end-of-pokemon-name-sentinel226 ;; 0xD2DE: end-of-pokemon-name-sentinel227 ;; 0xD2DF: end-of-pokemon-name-sentinel228 ;; 0xD2E0: P229 ;; 0xD2E1: R230 ;; 0xD2E2: I231 ;; 0xD2E3: M232 ;; 0xD2E4: E233 ;; 0xD2E5: A234 ;; 0xD2E6: P235 ;; 0xD2E7: E236 ;; 0xD2E8: end-of-pokemon-name-sentinel237 ;; 0xD2E9: end-of-pokemon-name-sentinel238 ;; 0xD2EA: end-of-pokemon-name-sentinel239 ;; 0xD2EB: A240 ;; 0xD2EC: end-of-pokemon-name-sentinel241 ;; 0xD2ED: S242 ;; 0xD2EE: T243 ;; 0xD2EF: E244 ;; 0xD2F0: R245 ;; 0xD2F1:246 ;; 0xD2F2: B247 ;; 0xD2F3: A248 ;; 0xD2F4: L249 ;; 0xD2F5: L250 ;; 0xD2F6:251 ;; 0xD2F7: A252 ;; 0xD2F8:253 ;; 0xD2F9:254 ;; 0xD2FA: end-of-name-sentinel255 ;; 0xD2FB: end-of-name-sentinel256 ;; 0xD2FC: A257 ;; 0xD2FD:258 ;; 0xD2FE: end-of-name-sentinel259 ;; 0xD2FF: end-of-name-sentinel260 ;; 0xD300: end-of-name-sentinel261 ;; 0xD301: end-of-name-sentinel262 ;; 0xD302: end-of-name-sentinel263 ;; 0xD303: end-of-name-sentinel264 ;; 0xD304: end-of-name-sentinel265 ;; 0xD305: end-of-name-sentinel266 ;; 0xD306: end-of-name-sentinel267 ;; 0xD307: end-of-name-sentinel268 ;; 0xD308: end-of-name-sentinel269 ;; 0xD309:270 ;; 0xD30A: w271 ;; 0xD30B:272 ;; 0xD30C: V273 ;; 0xD30D:274 ;; 0xD30E:275 ;; 0xD30F: K276 ;; 0xD310:277 ;; 0xD311:278 ;; 0xD312:279 ;; 0xD313: A280 ;; 0xD314:281 ;; 0xD315:282 ;; 0xD316:283 ;; 0xD317: i284 ;; 0xD318:285 ;; 0xD319:286 ;; 0xD31A: end-of-name-sentinel287 ;; 0xD31B: end-of-name-sentinel288 ;; 0xD31C:289 ;; 0xD31D:290 ;; 0xD31E:291 ;; 0xD31F:292 ;; 0xD320:293 ;; 0xD321:294 ;; 0xD322:295 ;; 0xD323:296 ;; 0xD324:297 ;; 0xD325:298 ;; 0xD326:299 ;; 0xD327:300 ;; 0xD328:301 ;; 0xD329:302 ;; 0xD32A:303 ;; 0xD32B:304 ;; 0xD32C:305 ;; 0xD32D:306 ;; 0xD32E:307 ;; 0xD32F:308 ;; 0xD330:309 ;; 0xD331: 9310 ;; 0xD332: end-of-name-sentinel311 ;; 0xD333: 9312 ;; 0xD334:313 ;; 0xD335: 9314 ;; 0xD336:315 ;; 0xD337: 9316 ;; 0xD338: end-of-name-sentinel317 ;; 0xD339: end-of-name-sentinel318 ;; 0xD33A: end-of-name-sentinel319 ;; 0xD33B: end-of-name-sentinel320 ;; 0xD33C: end-of-name-sentinel321 ;; 0xD33D: end-of-name-sentinel322 ;; 0xD33E: end-of-name-sentinel323 ;; 0xD33F: end-of-name-sentinel324 ;; 0xD340: end-of-name-sentinel325 ;; 0xD341: end-of-name-sentinel326 ;; 0xD342: end-of-name-sentinel327 ;; 0xD343: end-of-name-sentinel328 ;; 0xD344: end-of-name-sentinel329 ;; 0xD345: end-of-name-sentinel330 ;; 0xD346:331 ;; 0xD347:332 ;; 0xD348:333 ;; 0xD349: G334 ;; 0xD34A: A335 ;; 0xD34B: R336 ;; 0xD34C: Y337 ;; 0xD34D: end-of-pokemon-name-sentinel338 ;; 0xD34E: J341 ;; from this, it looks like the pokemon names are stored all342 ;; together in one location that begins at 0xD2B4 and343 ;; extends until 0xD2F5, with each name taking up 11 bytes.344 ;;345 ;; rival's name again clearly starts at 0xD349.348 (def pokemon-names-start 0xD2B4)351 ;; determine whether "number of pokemon in party"352 ;; might be kept in RAM and if so, where?354 (def six-pokemon (read-state "6-pokemon"))355 (def five-pokemon (read-state "5-pokemon"))356 (def four-pokemon (read-state "4-pokemon"))357 (def three-pokemon (read-state "3-pokemon"))358 (def two-pokemon (read-state "2-pokemon"))359 (def one-pokemon (read-state "1-pokemon"))362 (defn analyze-num-pokemon []363 (apply common-differences364 (map (comp vec memory)365 [one-pokemon366 two-pokemon367 three-pokemon368 four-pokemon369 five-pokemon370 six-pokemon])))372 ;; ;; results373 ;; ([53602 (1 2 3 4 5 6)]374 ;; [65314 (105 61 93 60 92 34)]375 ;; [55875 (34 36 43 52 7 0)]376 ;; [55876 (18 0 33 52 54 30)]377 ;; [49158 (197 194 77 117 174 134)]378 ;; [49160 (29 26 57 239 15 243)]379 ;; [49736 (74 93 34 89 91 59)]380 ;; [49162 (165 162 182 179 197 109)]381 ;; [49227 (187 105 204 5 90 238)]382 ;; [53067 (128 136 132 145 135 11)]383 ;; [53068 (147 131 141 136 128 7)]384 ;; [53069 (136 134 148 140 145 2)]385 ;; [49904 (2 11 10 3 27 12)]386 ;; [49172 (100 109 213 195 68 104)]387 ;; [65492 (11 103 128 160 19 56)]388 ;; [49173 (80 77 72 75 76 67)]389 ;; [49334 (8 10 11 5 3 1)]390 ;; [49335 (49 10 11 19 17 15)]391 ;; [49336 (8 10 11 5 3 1)]392 ;; [49720 (106 14 118 0 38 11)]393 ;; [65304 (32 88 19 114 106 33)]394 ;; [53561 (59 229 48 17 155 103)]395 ;; [55935 (6 5 4 3 2 1)])398 ;; two canidates : 0xD162 or 0xDA7F399 ;; they seem to always sum to 6...401 ;; try to set both of them when having only one pokemon.403 (defn change-party-number [^SaveState state new-num]404 (set-memory state 0xD162 new-num))406 ;; (continue! (change-party-number one-pokemon 3))407 ;; result -- can scroll down beyone first pokemon, finding408 ;; glitched pokemon in places where there were previously no409 ;; pokemon.412 (defn change-party-number* [^SaveState state new-num]413 (set-memory state 0xDA7F new-num))416 ;; (continue! (change-party-number* one-pokemon 3))417 ;; cannot widthdraw any pokemon from box 1 past the third418 ;; pokemon.420 (def party-number-address 0xD162)422 (defn party-number423 ([^SaveState state]424 (aget (memory state) party-number-address))425 ([] (party-number @current-state)))427 (def pokemon-in-box-1-address 0xDA7F)429 (defn party-names430 ([^SaveState state]431 (let [raw-names432 (subvec (vec (memory state))433 pokemon-names-start434 (+ pokemon-names-start435 (* name-width 6)))]436 (map437 read-name438 (take439 (party-number state)440 (partition name-width441 raw-names)))))442 ([] (party-names @current-state)))445 (defn rename-pokemon446 ([^SaveState state n new-name]447 (assert (<= 0 n (dec (party-number state))))448 (assert (<= (count new-name) max-name-length))449 (set-memory-range450 state451 (+ (* n name-width) pokemon-names-start)452 (concat (str->character-codes new-name) [end-of-name-marker])))453 ([n new-name]454 (rename-pokemon @current-state n new-name)))456 ;; on further analysis, it appears that the original457 ;; trainer info for each pokemon is also stored together,458 ;; starting at 0xD272 and continuing to 0xD2B3, with459 ;; 11 bytes reserved for each OT name.461 (def OT-start 0xD272)463 (defn original-trainers464 ([^SaveState state]465 (let [raw-names466 (subvec (vec (memory state))467 OT-start468 (+ OT-start469 (* name-width 6)))]470 (map read-name471 (take (party-number state)472 (partition name-width raw-names)))))473 ([] (original-trainers @current-state)))475 (defn set-original-trainer476 "Set the OT name for a pokemon.477 Note that a pokemon is still considered 'yours' if478 the OT ID is the same as your own."479 ([^SaveState state n new-name]480 (assert (<= 0 n (dec (party-number state))))481 (assert (<= (count new-name) max-name-length))482 (set-memory-range483 state484 (+ (* n name-width) OT-start)485 (concat (str->character-codes new-name) [end-of-name-marker])))486 ([n new-name]487 (set-original-trainer @current-state n new-name)))489 ;; PIKACHU stops following if you set it's OT to another name490 ;; and then back to you own.491 ;; But not if you set it to your own name, obviously.496 ;; OT ID Numbers.497 ;; My own id is 05195. A quick search of memory between498 ;; 0xD162 and 0xD31B revealed the pattern 0x144B exactly499 ;; six times.501 ;; the locations were:503 (def OT-ID-addresses [0xD176 0xD1A2 0xD1CE 0xD1FA 0xD228 0xD252])506 (defn set-pokemon-id507 ([^SaveState state n new-id]508 (assert (<= 0 n (dec (party-number state))))509 (assert (<= 0 new-id 0xFFFF))510 (set-memory-range511 state512 (OT-ID-addresses n)513 [(bit-shift-right (bit-and new-id 0xFF00) 8)514 (bit-and new-id 0xFF)515 ]))516 ([n new-id]517 (set-pokemon-id @current-state n new-id)))523 (defn get-pokemon-1-info524 ([state]525 (subvec (vec (memory state))526 0xD162 0xD197))527 ([] (get-pokemon-1-info @current-state)))529 (def baseline (File. "/home/r/baseline-poke"))534 (import java.io.File)536 (defn set-baseline [state]537 (clojure.java.io/copy538 (with-out-str (print-listing state 0xD162 0xD197))539 baseline))541 (defn compare-pokemon542 ([state]543 (let [target (File. "/home/r/temp-poke")]544 (clojure.java.io/copy545 (with-out-str (print-listing state 0xD162 0xD197))546 target)547 (println (:out548 (clojure.java.shell/sh "diff"549 (.getCanonicalPath baseline)550 (.getCanonicalPath target))))))551 ([] (compare-pokemon @current-state)))554 (defn crazy-pid []555 (read-state "crazy-pidgeot"))557 (def unknown "[[[UNKNOWN]]]")559 (def unknown "")561 (def pokemon-1-info562 {0xD16A "Color Map" ;; 0563 0xD16B "Current-HP (h)" ;; 1564 0xD16C "Current-HP (l)" ;; 2565 0XD16D unknown ;; 3566 0xD16E unknown ;; 4567 0xD16F unknown ;; 5568 0xD170 unknown ;; 6569 0xD171 unknown ;; 7570 0xD172 "Move 1 ID" ;; 8571 0xD173 "Move 2 ID" ;; 9572 0xD174 "Move 3 ID" ;; 10573 0xD175 "Move 4 ID" ;; 11574 0xD176 "OT-ID (h)" ;; 12575 0xD177 "OT-ID (l)" ;; 13576 0xD178 "Exp. Points (h)" ;; 14577 0xD179 "Exp. Points (m)" ;; 15578 0xD17A "Exp. Points (l)" ;; 16579 0xD17B "HP Exp. (h)" ;; 17580 0xD17C "HP Exp. (l)" ;; 18581 0xD17D "Attack Exp. (h)" ;; 19582 0xD17E "Attack Exp. (l)" ;; 20583 0xD17F "Defense Exp. (h)" ;; 21584 0xD180 "Defense Exp. (l)" ;; 22585 0xD181 "Speed Exp. (h)" ;; 23586 0xD182 "Speed Exp. (l)" ;; 24587 0xD183 "Special Exp. (h)" ;; 25588 0xD184 "Special Exp. (l)" ;; 26589 0xD185 "DV Atk/Def" ;; 27590 0xD186 "DV Speed/Spc" ;; 28591 0xD187 "PP Move 1" ;; 29592 0xD188 "PP Move 2" ;; 30593 0xD189 "PP Move 3" ;; 31594 0xD18A "PP Move 4" ;; 32595 0xD18B "Current Level" ;; 33596 0xD18C "HP Total (h)" ;; 34597 0xD18D "HP Total (l)" ;; 35598 0xD18E "Attack (h)" ;; 36599 0xD18F "Attack (l)" ;; 37600 0xD190 "Defense (h)" ;; 38601 0xD191 "Defense (l)" ;; 39602 0xD192 "Speed (h)" ;; 40603 0xD193 "Speed (l)" ;; 41604 0xD194 "Special (h)" ;; 42605 0xD195 "Special (l)" ;; 43606 })608 (defn pokemon-data609 ([^SaveState state pokemon-num]610 (assert (<= 0 pokemon-num 5))611 (let [base (+ (* pokemon-num pokemon-record-width) 0xD16A)]612 (subvec (vec (memory state)) base613 (+ base pokemon-record-width))))614 ([pokemon-num] (pokemon-data @current-state pokemon-num)))616 (defn set-pokemon-data617 ([^SaveState state pokemon-num new-data]618 (assert (<= 0 pokemon-num 5))619 (let [base (+ (* pokemon-num pokemon-record-width) 0xD16A)]620 (set-memory-range state base new-data)))621 ([pokemon-num new-data]622 (set-pokemon-data @current-state pokemon-num new-data)))624 (defn print-pokemon-data625 ([^SaveState state pokemon-num]626 (assert (<= 0 pokemon-num 5))627 (let [poke-data (pokemon-data state pokemon-num)628 backbone (sort (keys pokemon-1-info))]629 (println "Pokemon " pokemon-num " -- "630 (nth (party-names state)631 pokemon-num) \newline)633 (println " Desc. | Hex | Dec | Binary |")634 (println "-------------------+------+-----+----------+")635 (dorun636 (map637 (comp println638 (fn [desc data]639 (format "%-16s | 0x%02X | %3d | %s |"640 desc data data641 (let [s (Integer/toBinaryString data)]642 (apply643 str644 (concat (repeat (- 8 (count s)) "0" )645 s)))648 )))650 (map pokemon-1-info backbone)651 poke-data))))652 ([pokemon-num]653 (print-pokemon-data @current-state pokemon-num)))657 (defn pre-battle [] (read-state "prepare-for-battle"))660 (defn pika-lvl-100-DV-0 []661 (read-state "at-pc-lv-100-pikachu"))663 ;; Performed following experiment:664 ;; Raised Pikachu to Lvl 100 with rare-candies,665 ;; then put it at the head of the party and666 ;; set 0xD185 and 0xD186 to zero.668 ;; then, for each pattern, deposited pikachu into669 ;; Box 1 and immediately widthdrew it and observed the670 ;; stats.673 ;; Pikachu L:100 Base Stats with DVs = 0674 ;; HP : 187675 ;; Attack : 123676 ;; Defense : 73677 ;; Speed : 194678 ;; Special : 112680 ;; 0xD185:682 ;; 00000001683 ;; Defense => 75 (+2)684 ;; HP => 195 (+8)686 ;; 00000010687 ;; Defense => 77 (+4)689 ;; 00000100690 ;; Defense => 81 (+8)692 ;; 00001000693 ;; Defense => 89 (+16)695 ;; 00010000696 ;; HP => 203 (+16)697 ;; Attack => 125 (+2)699 ;; 00100000700 ;; Attack => 127 (+4)702 ;; 01000000703 ;; Attack -> 131 (+8)705 ;; 10000000706 ;; Attack -> 139 (+16)708 ;; 0xD186710 ;; 00000001711 ;; HP => 189 (+2)712 ;; Special => (+2)714 ;; 00000010715 ;; Special => 116 (+4)717 ;; 00000100718 ;; Special => 120 (+8)720 ;; 00001000721 ;; Special => 128 (+16)723 ;; 00010000724 ;; HP => 191 (+4)725 ;; Speed => 196 (+2)727 ;; 00100000728 ;; Speed => 198 (+4)730 ;; 01000000731 ;; Speed => 202 (+8)733 ;; 10000000734 ;; Speed => 210 (+16)736 (def pokemon-1-DV-start 0xD185)738 (defn pokemon-DV-start-point [poke-num]739 (+ (* poke-num pokemon-record-width)740 pokemon-1-DV-start))742 (def reverse-4-bit743 {0 0744 1 8745 2 4746 3 12747 5 10748 6 6749 7 14750 9 9751 15 15752 13 11754 8 1755 4 2756 12 3757 10 5758 11 13759 14 7 })761 (defn read-DV762 ([^SaveState state poke-num]763 (assert (<= 0 poke-num 5))764 (let [[raw-DV-1765 raw-DV-2]766 (subvec (vec (memory state))767 (pokemon-DV-start-point poke-num)768 (+ 2 (pokemon-DV-start-point poke-num)))769 defense-DV (bit-and raw-DV-1 0x0F)770 attack-DV (bit-shift-right771 (bit-and raw-DV-1 0xF0)772 4)773 special-DV (bit-and raw-DV-2 0x0F)774 speed-DV (bit-shift-right775 (bit-and raw-DV-2 0xF0)776 4)777 HP-DV778 (+779 (if (bit-test special-DV 0) 1 0)780 (if (bit-test speed-DV 0) 2 0)781 (if (bit-test defense-DV 0) 4 0)782 (if (bit-test attack-DV 0) 8 0))]783 {:attack attack-DV784 :defense defense-DV785 :speed speed-DV786 :special special-DV787 :hp HP-DV}))788 ([poke-num]789 (read-DV @current-state poke-num)))792 (defn give-DV793 ([^SaveState state poke-num dv-values]795 (assert (<= 0 poke-num 5))796 (map #(assert (<= 0 % 15)) (vals dv-values))797 (let [raw-dv-1*798 (+ (:defense dv-values)799 (bit-shift-left (:attack dv-values) 4))800 raw-dv-2*801 (+ (:special dv-values)802 (bit-shift-left (:speed dv-values) 4))803 hp-dv (:hp dv-values)804 hp-masks-1805 [[0 (bit-test hp-dv 2)]806 [4 (bit-test hp-dv 3)]]807 hp-masks-2808 [[0 (bit-test hp-dv 0)]809 [4 (bit-test hp-dv 1)]]810 set-hp-bits811 (fn [init [index hp?]]812 (if hp?813 (bit-set init index)814 (bit-clear init index)))816 raw-dv-1 (reduce set-hp-bits raw-dv-1*817 hp-masks-1)819 raw-dv-2 (reduce set-hp-bits raw-dv-2*820 hp-masks-2)822 dv-start (pokemon-DV-start-point poke-num)]824 (if (or (not= raw-dv-1* raw-dv-1)825 (not= raw-dv-2* raw-dv-2))826 (println "Warning: inconsistent DV-values."827 "Using HP settings."))829 (set-memory830 (set-memory state dv-start raw-dv-1)831 (inc dv-start) raw-dv-2)))832 ([poke-num dv-values]833 (give-DV @current-state poke-num dv-values)))835 (def good-DVs836 {:attack 15837 :defense 15838 :speed 15839 :special 15840 :hp 15})842 (def bad-DVs843 {:attack 0844 :defense 0845 :speed 0846 :special 0847 :hp 0})