# HG changeset patch # User Dylan Holmes # Date 1334413669 18000 # Node ID acc3d1ad24e86c2ba5b89464c3a226cb50ebdfc1 # Parent 4901ba2d3860622ee99a0b3c97c6cb9683ee826f Found HP restored by SODA POP, FRESH WATER, LEMONADE; also found number of steps for REPEL, SUPER REPEL, MAX REPEL. diff -r 4901ba2d3860 -r acc3d1ad24e8 clojure/com/aurellem/gb/hxc.clj --- a/clojure/com/aurellem/gb/hxc.clj Sat Apr 14 05:20:28 2012 -0500 +++ b/clojure/com/aurellem/gb/hxc.clj Sat Apr 14 09:27:49 2012 -0500 @@ -184,7 +184,8 @@ (defn hxc-pokedex-names - "The names of the pokemon in hardcoded pokedex order. List begins at + "The names of the pokemon in hardcoded pokedex order. List of the + pokedex numbers of each pokemon (in internal order) begins at ROM@410B1. See also, hxc-pokenames." ([] (hxc-pokedex-names com.aurellem.gb.gb-driver/original-rom)) @@ -350,10 +351,9 @@ (def hxc-places "The hardcoded place names in memory. List begins at -ROM@71500. [Cinnabar] Mansion seems to be dynamically calculated." +ROM@71500. [Cinnabar/Celadon] Mansion seems to be dynamically calculated." (hxc-thunk-words 0x71500 560)) - (defn hxc-dialog "The hardcoded dialogue in memory, including in-game alerts. Dialog seems to be separated by 0x57 instead of 0x50 (END). Begins at ROM@98000." @@ -923,25 +923,335 @@ ;; note: 1195C-6A says ABLE#NOT ABLE#, but so does 119C0-119CE. ;; The first instance is for Machines; the second, for stones. -;; 0x251A (in indexable mem): image decompression routine seems to begin here. +;; note: according to +;; http://www.upokecenter.com/games/rby/guides/rgbtrainers.php +;; the amount of money given by a trainer is equal to the +;; base money times the level of the last Pokemon on that trainer's +;; list. Other sources say it's the the level of the last pokemon +;; /defeated/. + +;; todo: find base money. + + +;; note: 0xDFEA (in indexable mem) is the dex# of the currently-viewed Pokemon in + ;; in the pokedex. It's used for other purposes if there is none. + +;; note: 0x9D35 (index.) switches from 0xFF to 0x00 temporarily when +;; you walk between areas. + +;; note: 0xD059 (index.) is the special battle type of your next battle: +;; - 00 is a usual battle +;; - 01 is a pre-scripted OLD MAN battle which always fails to catch the +;; target Pokemon. +;; - 02 is a safari zone battle +;; - 03 obligates you to run away. (unused) +;; - 04 is a pre-scripted OAK battle, which (temporarily) causes the +;; enemy Pokemon to cry PIKAAA, and which always catches the target +;; Pokemon. The target Pokemon is erased after the battle. +;; - 05+ are glitch states in which you are sort of the Pokemon. + + +;; note: 0x251A (in indexable mem): image decompression routine seems to begin here. + +;; note: 0x4845 (index): vending inventory is loaded here. possibly + ;; other things, too. +(comment + ;; temporarily intercept/adjust what pops out of the vending + ;; machine. + ;; (and how much it costs) + + ;; located at 0x4845 + ;; not to be confused with shop inventory, 0xCF7B + (do + (step (read-state "vend-menu")) + (write-memory! (rewrite-memory (vec(memory)) 0x4845 [2 0 1 0])) + (step @current-state [:a]) + (step @current-state []) + (nstep @current-state 200) )) ;; Note: There are two tile tables, one from 8000-8FFF, the other from ;; 8800-97FF. The latter contains symbols, possibly map tiles(?), with some japanese chars and stuff at the end. (defn print-pixel-letters! "The pixel tiles representing letters. Neat!" - ([] (print-pixel-letters! (read-state "oak-speaks"))) - ([state] - (map - (comp - println - (partial map #(if (zero? %) \space 0)) - #(if (< (count %) 8) - (recur (cons 0 %)) - %) - reverse bit-list) + ([] (print-pixel-letters! (read-state "oak-speaks"))) +([state] + (map + (comp + println + (partial map #(if (zero? %) \space 0)) + #(if (< (count %) 8) + (recur (cons 0 %)) + %) + reverse bit-list) + + (take 0xFFF (drop 0x8800 (memory state)))))) + + +;; (defn test-2 [] +;; (loop [n 0 +;; pc-1 (pc-trail (-> state-defend (tick) (step [:a]) (step [:a]) (step []) (nstep 100)) 100000) +;; pc-2 (pc-trail (-> state-speed (tick) (step [:a]) (step [:a]) +;; (step []) (nstep 100)) 100000)] +;; (cond (empty? (drop n pc-1)) [pc-1 n] +;; (not= (take 10 (drop n pc-1)) (take 10 pc-2)) +;; (recur pc-1 pc-2 (inc n)) +;; :else +;; [(take 1000 pc-2) n]))) + + + + +(defn test-3 + "Explore trainer data" + ([] (test-3 0x3A289)) + ([start] + (let [pokenames (vec(hxc-pokenames-raw))] + (println + (reduce + str + (map + (fn [[adr lvl pkmn]] + (str (format "%-11s %4d %02X %02X \t %05X\n" + + (cond + (zero? lvl) "+" + (nil? (get pokenames (dec pkmn))) + "-" + :else + (get pokenames (dec pkmn))) + lvl + pkmn + lvl + adr + ))) + (map cons + (take-nth 2 (drop start (range))) + (partition 2 + (take 400;;703 + (drop + start + ;; 0x3A75D + (rom))))))))))) + +(defn search-memory* [mem codes k] + (loop [index 0 + index-next 1 + start-match 0 + to-match codes + matches []] + (cond + (>= index (count mem)) matches + + (empty? to-match) + (recur + index-next + (inc index-next) + index-next + codes + (conj matches + [(hex start-match) (take k (drop start-match mem))]) + ) + + (or (= (first to-match) \_) ;; wildcard + (= (first to-match) (nth mem index))) + (recur + (inc index) + index-next + start-match + (rest to-match) + matches) + + :else + (recur + index-next + (inc index-next) + index-next + codes + matches)))) - (take 0xFFF (drop 0x88000 (memory state)))))) + +(defn search-pattern [ptn coll] + (loop + [index 0 + to-match ptn + binds {} + + next-index 1 + match-start 0 + matches []] + + (cond + (>= index (count coll)) matches + (empty? to-match) + (recur + next-index + ptn + {} + (inc next-index) + next-index + (conj match-start + [(hex match-start) binds])) + + :else + (let [k (first to-match) + v (nth coll index)] + (cond + (= k \_) ;; wildcard + (recur + (inc index) + (rest to-match) + binds + + next-index + match-start + matches) + + (keyword? k) + (if (binds k) + (if (= (binds k) v) + + ;; consistent bindings + (recur + (inc index) + (rest to-match) + binds + + next-index + match-start + matches) + + ;; inconsistent bindings + (recur + next-index + ptn + {} + (inc next-index) + next-index + matches)) + + (if ((set (vals binds)) v) + ;; bindings are not unique + (recur + next-index + ptn + {} + (inc next-index) + next-index + matches) + + ;; bindings are unique + (recur + (inc index) + (rest to-match) + (assoc binds k v) + + next-index + match-start + matches))) + + :else ;; k is just a number + (if (= k v) + (recur + (inc index) + (rest to-match) + binds + + next-index + match-start + matches) + + (recur + next-index + ptn + {} + (inc next-index) + next-index + matches))))))) + + + + + + + + + +(defn search-pattern* [ptn coll] + (loop + [ + binds {} + index 0 + index-next 1 + start-match 0 + to-match ptn + matches []] + + (cond + (>= index (count coll)) matches + (empty? to-match) + (recur + {} + index-next + (inc index-next) + index-next + ptn + (conj matches + [(hex start-match) binds])) + + :else + (let [k (first to-match) + v (nth coll index)] + (cond + (= k \_) ;; wildcard + (recur + binds + (inc index) + index-next + start-match + (rest to-match) + matches) + + (keyword? k) + (if (binds k) + (if (= (binds k) v) + (recur + binds + (inc index) + index-next + start-match + (rest to-match) + matches) + (recur + {} + index-next + (inc index-next) + index-next + ptn + matches)) + (if + ;; every symbol must be bound to a different thing. + ((set (vals binds)) v) + (recur + {} + index-next + (inc index-next) + index-next + ptn + matches) + (recur + (assoc binds k v) + (inc index) + index-next + start-match + (rest to-match) + matches)))))))) + + + + +;; look for the rainbow badge in memory +(println (reduce str (map #(str (first %) "\t" (vec(second %)) "\n") (search-memory (rom) [221] 10)))) (comment diff -r 4901ba2d3860 -r acc3d1ad24e8 org/rom.org --- a/org/rom.org Sat Apr 14 05:20:28 2012 -0500 +++ b/org/rom.org Sat Apr 14 09:27:49 2012 -0500 @@ -1094,7 +1094,7 @@ #+begin_src clojure (def hxc-places "The hardcoded place names in memory. List begins at -ROM@71500. [Cinnabar/Cerulean] Mansion seems to be dynamically calculated." +ROM@71500. [Cinnabar/Celadon] Mansion seems to be dynamically calculated." (hxc-thunk-words 0x71500 560)) #+end_src @@ -1148,9 +1148,111 @@ +** Map data + +# http://www.pokecommunity.com/showthread.php?t=235311 +# http://datacrystal.romhacking.net/wiki/Pokemon_Red/Blue:Notes + +#+name map +#+begin_src clojure :exports both :results output +(ns com.aurellem.gb.hxc + (:use (com.aurellem.gb assembly characters gb-driver util mem-util + constants)) + (:import [com.aurellem.gb.gb_driver SaveState])) + + +(defn parse-header-tileset + [[bank# ;; memory bank for blocks & tileset + + blocks-lo ;; structure + blocks-hi + + tileset-lo ;; style + tileset-hi + + collision-lo ;; collision info + collision-hi + + talk-here-1 ;; positions of up to three + talk-here-2 ;; talk-over-countertop tiles + talk-here-3 ;; --- 0xFF if unused. + + grass ;; grass tile --- 0xFF if unused + + animation-flags ;; settings for animation + & _]] + + [bank# + + blocks-lo ;; structure + blocks-hi + + tileset-lo ;; style + tileset-hi + + collision-lo ;; collision info + collision-hi + + talk-here-1 ;; positions of up to three + talk-here-2 ;; talk-over-countertop tiles + talk-here-3 ;; --- 0xFF if unused. + + grass ;; grass tile --- 0xFF if unused + + animation-flags ;; settings for animation + ]) + + + +(defn parse-header-map + [start] + + (let [connection-size 11 + + [tileset-index + map-height + map-width + layout-lo + layout-hi + text-lo + text-hi + script-lo + script-hi + adjacency-flags ;; x x x x N S W E + & etc] + (drop start (rom)) + + [east? west? south? north?] + (bit-list adjacency-flags) + + [connections object-data] + (split-at + (* connection-size (+ east? west? south? north?)) + etc) + + connections + (partition connection-size connections) + + + + + ] + (ptr->offset + 3 + (low-high layout-lo layout-hi)) + + + )) +#+end_src + +#+results: +: + + * Appendices ** Mapping the ROM +# D3AD: Script:Use Pokeball? | ROM address (hex) | Description | Format | Example | |-----------------------+-----------------+-----------------+-----------------| @@ -1174,11 +1276,19 @@ | 0822E-082F? | Pointers to background music, part I. | | | | 0CB95- | Pointers to lists of wild pokemon to encounter in each region. These lists begin at 04D89, see above. | Each pointer is a low-byte, high-byte pair. | The first entry is 0x89 0x4D, corresponding to the address 0x4D89, the location of the first list of wild Pok\eacute{}mon (see 04D89, above). | |-----------------------+-----------------+-----------------+-----------------| -| 0DADB. | Amount of HP restored by Hyper Potion. | The HP consists of a single byte. TODO: Discover what the surrounding data does, and find the data for the amount of HP restored by other items: Fresh Water (50HP), Soda (60HP), Lemonade(80HP). | 200 | +| 0DACB. | Amount of HP restored by Soda Pop | The HP consists of a single numerical byte. | 60 | +| 0DACF. | Amount of HP restored by Lemonade | " | 80 | +| 0DAD5. | Amount of HP restored by Fresh Water | " | 50 | +| 0DADB. | Amount of HP restored by Hyper Potion. | " | 200 | | 0DAE0. | Amount of HP restored by Super Potion. | " | 50 | | 0DAE3. | Amount of HP restored by Potion. | " | 20 | |-----------------------+-----------------+-----------------+-----------------| | 0DD4D-DD72 | Names of permanent stats. | Variable-length strings separated by 0x50. | #HEALTH#ATTACK#DEFENSE#SPEED#SPECIAL# | +|-----------------------+-----------------+-----------------+-----------------| +| 0DE2F. | Duration of Repel. | A single byte, representing the number of steps you can take before Super Repel wears off. | 100 | +| 0DF39. | Duration of Super Repel. | " | 200 | +| 0DF3E. | Duration of Max Repel. | " | 250 | +|-----------------------+-----------------+-----------------+-----------------| | 1164B- | Terminology for the Pok\eacute{}mon menu. | Contiguous, variable-length strings. | TYPE1[newline]TYPE2[newline] *№*,[newline]OT,[newline][0x50]STATUS,[0x50]OK | | 116DE- | Terminology for permanent stats in the Pok\eacute{}mon menu. | Contiguous, variable-length strings. | ATTACK[newline]DEFENSE[newline]SPEED[newline]SPECIAL[0x50] | | 11852- | Terminology for current stats in the Pok\eacute{}mon menu. | Contiguous, variable-length strings. | EXP POINTS[newline]LEVEL UP[0x50] | @@ -1214,6 +1324,9 @@ | 41072- | Pok\eacute{} placeholder species, "???" | | | |-----------------------+-----------------+-----------------+-----------------| | 410B1-4116F | A conversion table between internal order and Pokedex order. | 190 bytes, corresponding to the Pok\eacute{}dex numbers of the 190 Pok\eacute{}mon listed in internal order. All =MISSINGNO.= are assigned a Pok\eacute{}dex number of 0. | The first few entries are (112 115 32 35 21 100 34 80 2 ...), which are the Pok\eacute{}dex numbers of Rhydon, Kangaskhan, Nidoran(m), Clefairy, Spearow, Voltorb, Nidoking, Slobrow, and Ivysaur. | +|-----------------------+-----------------+-----------------+-----------------| +| 509B4-509E0 | Saffron City's adjacency info. | Four adjacency lists, each 11 bytes long. (For more info on adjacency lists a.k.a. connection data, see [[http://datacrystal.romhacking.net/wiki/Pokemon_Red/Blue:Notes][here]]) | The first adjacency list is (0x10 0x70 0x46 0xF0 0xC6 0x0A 0x0A 0x23 0xF6 0x09 0xC8) | +|-----------------------+-----------------+-----------------+-----------------| | 527BA-527DB | The costs and kinds of prizes from Celadon Game Corner. | The following pattern repeats three times, once per window[fn::For the first two prize lists, ids are interpreted as Pok\eacute{}mon ids. For the last prize list, ids are (somehow) interpreted as item ids.]: Internal ids / 0x50 / Prices (two bytes of BCD)/ 0x50. | (0x94 0x52 0x65 0x50) Abra Vulpix Wigglytuff (0x02 0x30 0x10 0x00 0x26 0x80) 230C, 1000C, 2680C | | 5DE10-5DE30 | Abbreviations for status ailments. | Fixed-length strings, probably[fn::Here's something strange: all of the status messages start with 0x7F and end with 0x4F \mdash{}except PAR, which ends with 0x50.]. The last entry is QUIT##. | [0x7F] *SLP* [0x4E][0x7F] *PSN* [0x4E][0x7F] *PAR* [0x50][0x7F]... | |-----------------------+-----------------+-----------------+-----------------| @@ -1770,6 +1883,22 @@ ;; note: 0x251A (in indexable mem): image decompression routine seems to begin here. +;; note: 0x4845 (index): vending inventory is loaded here. possibly + ;; other things, too. +(comment + ;; temporarily intercept/adjust what pops out of the vending + ;; machine. + ;; (and how much it costs) + + ;; located at 0x4845 + ;; not to be confused with shop inventory, 0xCF7B + (do + (step (read-state "vend-menu")) + (write-memory! (rewrite-memory (vec(memory)) 0x4845 [2 0 1 0])) + (step @current-state [:a]) + (step @current-state []) + (nstep @current-state 200) )) + ;; Note: There are two tile tables, one from 8000-8FFF, the other from ;; 8800-97FF. The latter contains symbols, possibly map tiles(?), with some japanese chars and stuff at the end. @@ -1870,8 +1999,218 @@ index-next codes matches)))) - - + + +(def script-use-ball + [0xFA ;; ld A, nn + \_ + \_ + 0xA7 ;; and A + 0xCA ;; JP Z + \_ + \_ + 0x3D ;; dec A + 0xC2 ;; JP NZ + \_ + \_ + 0xFA ;; LD A + \_ + \_ + ]) + + + +(defn search-pattern [ptn coll] + (loop + [index 0 + to-match ptn + binds {} + + next-index 1 + match-start 0 + matches []] + + (cond + (>= index (count coll)) matches + (empty? to-match) + (recur + next-index + ptn + {} + (inc next-index) + next-index + (conj match-start + [(hex match-start) binds])) + + :else + (let [k (first to-match) + v (nth coll index)] + (cond + (= k \_) ;; wildcard + (recur + (inc index) + (rest to-match) + binds + + next-index + match-start + matches) + + (keyword? k) + (if (binds k) + (if (= (binds k) v) + (recur + (inc index) + (rest to-match) + binds + next-index + match-start + matches) + + (recur + next-index + ptn + {} + (inc next-index) + next-index + matches)) + + ;; ;; consistent bindings + ;; (recur + ;; (inc index) + ;; (rest to-match) + ;; binds + + ;; next-index + ;; match-start + ;; matches) + + ;; ;; inconsistent bindings + ;; (recur + ;; next-index + ;; ptn + ;; {} + ;; (inc next-index) + ;; next-index + ;; matches)) + + (if ((set (vals binds)) v) + ;; bindings are not unique + (recur + next-index + ptn + {} + (inc next-index) + next-index + matches) + + ;; bindings are unique + (recur + (inc index) + (rest to-match) + (assoc binds k v) + + next-index + match-start + matches))) + + :else ;; k is just a number + (if (= k v) + (recur + (inc index) + (rest to-match) + binds + + next-index + match-start + matches) + + (recur + next-index + ptn + {} + (inc next-index) + next-index + matches))))))) + + + + + + + + + +(defn search-pattern* [ptn coll] + (loop + [ + binds {} + index 0 + index-next 1 + start-match 0 + to-match ptn + matches []] + + (cond + (>= index (count coll)) matches + (empty? to-match) + (recur + {} + index-next + (inc index-next) + index-next + ptn + (conj matches + [(hex start-match) binds])) + + :else + (let [k (first to-match) + v (nth coll index)] + (cond + (= k \_) ;; wildcard + (recur + binds + (inc index) + index-next + start-match + (rest to-match) + matches) + + (keyword? k) + (if (binds k) + (if (= (binds k) v) + (recur + binds + (inc index) + index-next + start-match + (rest to-match) + matches) + (recur + {} + index-next + (inc index-next) + index-next + ptn + matches)) + (if + ;; every symbol must be bound to a different thing. + ((set (vals binds)) v) + (recur + {} + index-next + (inc index-next) + index-next + ptn + matches) + (recur + (assoc binds k v) + (inc index) + index-next + start-match + (rest to-match) + matches)))))))) +