changeset 419:4901ba2d3860

Figured out how NPC Pokemon teams are encoded.
author Dylan Holmes <ocsenave@gmail.com>
date Sat, 14 Apr 2012 05:20:28 -0500
parents 21b8b3350b20
children acc3d1ad24e8
files org/rom.org
diffstat 1 files changed, 162 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/org/rom.org	Sat Apr 14 05:41:55 2012 -0500
     1.2 +++ b/org/rom.org	Sat Apr 14 05:20:28 2012 -0500
     1.3 @@ -1,8 +1,8 @@
     1.4  #+title: Notes on Deconstructing Pokemon Yellow
     1.5  #+author: Dylan Holmes
     1.6  #+email: rlm@mit.edu
     1.7 -#+description:
     1.8 -#+keywords:
     1.9 +#+description: A detailed explication of Pok\eacute{}mon Yellow, helped by Clojure.
    1.10 +#+keywords: pokemon, pokemon yellow, rom, gameboy, assembly, hex, pointers, clojure
    1.11  #+SETUPFILE: ../../aurellem/org/setup.org
    1.12  #+INCLUDE: ../../aurellem/org/level-0.org
    1.13  #+BABEL: :exports both :noweb yes :cache no :mkdirp yes
    1.14 @@ -12,7 +12,6 @@
    1.15  # pokedollar: U+20B1
    1.16  * Introduction
    1.17  
    1.18 -
    1.19  ** COMMENT Getting linguistic data: names, words, etc.
    1.20  
    1.21  Some of the simplest data 
    1.22 @@ -1011,6 +1010,83 @@
    1.23  
    1.24  ** COMMENT Status ailments
    1.25  
    1.26 +
    1.27 +* NPC Trainers
    1.28 +
    1.29 +** Trainer Pok\eacute{}mon
    1.30 +# http://hax.iimarck.us/topic/103/
    1.31 +There are two formats for specifying lists of NPC PPok\eacute{}mon:
    1.32 +- If all the Pok\eacute{}mon will have the same level, the format is
    1.33 +  - Level (used for all the Pok\eacute{}mon)
    1.34 +  - Any number of Pok\eacute{}mon internal ids.
    1.35 +  - 0x00, to indicate end-of-list.
    1.36 +- Otherwise, all the Pok\eacute{}mon will have their level
    1.37 +  specified. The format is
    1.38 +  - 0xFF, to indicate that we will be specifying the levels individually[fn::Because 0xFF is a
    1.39 +    forbidden level within the usual gameplay discipline, the game
    1.40 +    makers could safely use 0xFF as a mode indicator.].
    1.41 +  - Any number of alternating Level/Pokemon pairs
    1.42 +  - 0x00, to indicate end-of-list.
    1.43 +
    1.44 +*** Get the pointers
    1.45 +*** See the data
    1.46 +#+begin_src clojure :exports both :results output 
    1.47 +(ns com.aurellem.gb.hxc
    1.48 +  (:use (com.aurellem.gb assembly characters gb-driver util mem-util
    1.49 +                         constants))
    1.50 +  (:import [com.aurellem.gb.gb_driver SaveState]))
    1.51 +
    1.52 +(->>
    1.53 + (rom)
    1.54 + (drop 0x39E2F)
    1.55 + (take 21)
    1.56 + (println))
    1.57 +
    1.58 +
    1.59 +(->>
    1.60 + (rom)
    1.61 + (drop 0x39E2F)
    1.62 + (take 21)
    1.63 + (partition-by zero?)
    1.64 + (take-nth 2)
    1.65 + (println))
    1.66 +
    1.67 +
    1.68 +
    1.69 +(let
    1.70 +    [pokenames
    1.71 +     (zipmap
    1.72 +      (rest (range))
    1.73 +      (hxc-pokenames-raw))]
    1.74 +
    1.75 +  (->>
    1.76 +   (rom)
    1.77 +   (drop 0x39E2F)
    1.78 +   (take 21)   ;; (1922 in all)
    1.79 +   (partition-by zero?)
    1.80 +   (take-nth 2)
    1.81 +   (map
    1.82 +    (fn parse-team [[mode & team]]
    1.83 +      (if (not= 0xFF mode)
    1.84 +        (mapv
    1.85 +         #(hash-map :level mode :species (pokenames %))
    1.86 +         team)
    1.87 +        
    1.88 +        (mapv
    1.89 +         (fn [[lvl id]] (hash-map :level lvl :species (pokenames id)))
    1.90 +         (partition 2 team)))))
    1.91 +
    1.92 +   (println)))
    1.93 +
    1.94 +
    1.95 +
    1.96 +#+end_src
    1.97 +
    1.98 +#+results:
    1.99 +: (11 165 108 0 14 5 0 10 165 165 107 0 14 165 108 107 0 15 165 5 0)
   1.100 +: ((11 165 108) (14 5) (10 165 165 107) (14 165 108 107) (15 165 5))
   1.101 +: ([{:species RATTATA, :level 11} {:species EKANS, :level 11}] [{:species SPEAROW, :level 14}] [{:species RATTATA, :level 10} {:species RATTATA, :level 10} {:species ZUBAT, :level 10}] [{:species RATTATA, :level 14} {:species EKANS, :level 14} {:species ZUBAT, :level 14}] [{:species RATTATA, :level 15} {:species SPEAROW, :level 15}])
   1.102 +
   1.103  * Places
   1.104  ** Names of places
   1.105  
   1.106 @@ -1018,11 +1094,18 @@
   1.107  #+begin_src clojure
   1.108  (def hxc-places
   1.109    "The hardcoded place names in memory. List begins at
   1.110 -ROM@71500. [Cinnabar] Mansion seems to be dynamically calculated."
   1.111 +ROM@71500. [Cinnabar/Cerulean] Mansion seems to be dynamically calculated."
   1.112    (hxc-thunk-words 0x71500 560))
   1.113 +#+end_src
   1.114  
   1.115 +*** See it work
   1.116 +#+begin_src clojure :exports both :results output 
   1.117 +(println (hxc-places))
   1.118  #+end_src
   1.119  
   1.120 +#+results:
   1.121 +: (PALLET TOWN VIRIDIAN CITY PEWTER CITY CERULEAN CITY LAVENDER TOWN VERMILION CITY CELADON CITY FUCHSIA CITY CINNABAR ISLAND INDIGO PLATEAU SAFFRON CITY ROUTE 1 ROUTE 2 ROUTE 3 ROUTE 4 ROUTE 5 ROUTE 6 ROUTE 7 ROUTE 8 ROUTE 9 ROUTE 10  ROUTE 11 ROUTE 12 ROUTE 13 ROUTE 14 ROUTE 15 ROUTE 16 ROUTE 17 ROUTE 18 SEA ROUTE 19 SEA ROUTE 20  SEA ROUTE 21 ROUTE 22 ROUTE 23 ROUTE 24 ROUTE 25 VIRIDIAN FOREST MT.MOON ROCK TUNNEL SEA COTTAGE S.S.ANNE [POKE]MON LEAGUE UNDERGROUND PATH [POKE]MON TOWER SEAFOAM ISLANDS VICTORY ROAD DIGLETT's CAVE ROCKET HQ SILPH CO. [0x4A] MANSION SAFARI ZONE)
   1.122 +
   1.123  ** Wild Pok\eacute{}mon demographics
   1.124  #+name: wilds
   1.125  #+begin_src clojure
   1.126 @@ -1067,9 +1150,6 @@
   1.127  
   1.128  
   1.129  * Appendices
   1.130 -
   1.131 -
   1.132 -
   1.133  ** Mapping the ROM
   1.134  
   1.135  | ROM address (hex)     | Description     | Format          | Example         |
   1.136 @@ -1118,8 +1198,8 @@
   1.137  |-----------------------+-----------------+-----------------+-----------------|
   1.138  | 3997D-39B05           | Trainer titles (extended; see 27E77). This list includes strictly more trainers, seemingly at random inserted into the list from 27E77.[fn::The names added are in bold: YOUNGSTER, BUG CATCHER, LASS, *SAILOR*, JR TRAINER(m), JR TRAINER(f), POK\eacute{}MANIAC, SUPER NERD, *HIKER*, *BIKER*, BURGLAR, ENGINEER, JUGGLER, *FISHERMAN*, SWIMMER, *CUE BALL*, *GAMBLER*, BEAUTY,  *PSYCHIC*, ROCKER, JUGGLER (again), *TAMER*, *BIRDKEEPER*, BLACKBELT, *RIVAL1*, PROF OAK, CHIEF, SCIENTIST, *GIOVANNI*, ROCKET, COOLTRAINER(m), COOLTRAINER(f), *BRUNO*, *BROCK*, *MISTY*, *LT. SURGE*, *ERIKA*, *KOGA*, *BLAINE*, *SABRINA*, *GENTLEMAN*, *RIVAL2*, *RIVAL3*, *LORELEI*, *CHANNELER*, *AGATHA*, *LANCE*.] |                 |                 |
   1.139  | 39B05-39DD0.          | unknown         |                 |                 |
   1.140 -| 39DD1-                | (?) Pointers to trainer Pok\eacute{}mon |                 |                 |
   1.141 -| 3A289-3A540 (approx)  | Trainer Pok\eacute{}mon | Consecutive level/internal-id pairs (as with wild Pok\eacute{}mon; see 04D89) with irregular spacing \mdash{} the separators seem to have some metadata purpose. | The first entry is 0x05 0x66, representing level 5 Eevee (from your first battle in the game[fn::Incidentally, to change your rival's starter Pok\eacute{}mon, it's enough just to change its species in all of your battles with him.].) |
   1.142 +| 39DD1-39E2E           | Pointers to trainer Pok\eacute{}mon | Pairs of low-high bits. | The first pair is 0x2F 0x5E, which corresponds to memory location 5E2F relative to this 38000-3C000 bank, i.e.[fn::For details about how relative bank pointers work, see the relevant Appendix.] position 39E2F overall. |
   1.143 +| 39E2F-3A5B2           | Trainer Pok\eacute{}mon | Specially-formatted lists of various length, separated by 0x00. If the list starts with 0xFF, the rest of the list will alternate between levels and internal-ids. Otherwise, start of the list is the level of the whole team, and the rest of the list is internal-ids. | The first entry is (11 165 108 0), which means a level 11 team consisting of Rattata and Ekans. The entry for MISTY is (255 18 27 21 152 0), which means a team of various levels consisting of level 18 Staryu and level 21 Starmie. [fn::Incidentally, if you want to change your rival's starter Pok\eacute{}mon, it's enough just to change its species in all of your battles with him.].) |
   1.144  | 3B1E5-3B361           | Pointers to evolution/learnset data. | One high-low byte pair for each of the 190 Pok\eacute{}mon in internal order. |                 |
   1.145  |-----------------------+-----------------+-----------------+-----------------|
   1.146  | 3B361-3BBAA           | Evolution and learnset data. [fn::Evolution data consists of how to make Pok\eacute{}mon evolve, and what they evolve into. Learnset data consists of the moves that Pok\eacute{}mon learn as they level up.] | Variable-length evolution information (see below), followed by a list of level/move-id learnset pairs. |                 |
   1.147 @@ -1143,15 +1223,61 @@
   1.148  | 71C1E-71CAA (approx.) | Tradeable NPC Pok\eacute{}mon. | Internal ID, followed by nickname (11 chars; extra space padded by 0x50). Some of the Pokemon have unknown extra data around the id. | The first entry is [0x76] "GURIO######", corresponding to a Dugtrio named "GURIO". |
   1.149  | 7C249-7C2??           | Pointers to background music, pt II. |                 |                 |
   1.150  |-----------------------+-----------------+-----------------+-----------------|
   1.151 -| 98000-B8000           | Dialogue and other messsages. | Variable-length strings. |                 |
   1.152 +| 98000-B7190           | Dialogue and other messsages. | Variable-length strings. |                 |
   1.153 +| B7190-B8000           | (empty space)   |                 | 0 0 0 0 0 ...   |
   1.154  | B8000-BC000           | The text of each Pok\eacute{}mon's Pok\eacute{}dex entry. | Variable-length descriptions (strings) in Pok\eacute{}dex order, separated by 0x50. These entries use the special characters *0x49* (new page), *0x4E* (new line), and *0x5F* (end entry). | The first entry (Bulbasaur's) is: "It can go for days [0x4E] without eating a [0x4E] single morsel. [0x49] In the bulb on [0x4E] its back,  it [0x4E] stores energy [0x5F] [0x50]." |
   1.155 -| BC000-BC60E           | Move names.     | Variable-length move names, separated by 0x50. The moves are in internal order. | POUND#KARATE CHOP#DOUBLESLAP#COMET PUNCH#... |
   1.156 +| BC000-BC60F           | Move names.     | Variable-length move names, separated by 0x50. The moves are in internal order. | POUND#KARATE CHOP#DOUBLESLAP#COMET PUNCH#... |
   1.157 +| BC610-BD000           | (empty space)   |                 | 0 0 0 0 0 ...   |
   1.158  | E8000-E876C           | Names of the \ldquo{}190\rdquo{} species of Pok\eacute{}mon in memory. | Fixed length (10-letter) Pok\eacute{}mon names. Any extra space is padded with the character 0x50. The names are in \ldquo{}internal order\rdquo{}. | RHYDON####KANGASKHANNIDORAN♂#... |
   1.159  |-----------------------+-----------------+-----------------+-----------------|
   1.160  | E9BD5-                | The text PLAY TIME (see above, 70442) |                 |                 |
   1.161     #+TBLFM: 
   1.162  
   1.163  
   1.164 +** Understanding  memory banks and pointers
   1.165 +#+begin_src clojure
   1.166 +
   1.167 +(defn endian-flip
   1.168 +  "Flip the bytes of the two-byte number."
   1.169 +  [n]
   1.170 +  (assert (< n 0xFFFF))
   1.171 +  (+ (* 0x100 (rem n 0x100))
   1.172 +        (int (/ n 0x100))))
   1.173 +
   1.174 +
   1.175 +(defn offset->ptr
   1.176 +  "Convert an offset into a little-endian pointer."
   1.177 +  [n]
   1.178 +  (->
   1.179 +   n
   1.180 +   (rem 0x10000) ;; take last four bytes
   1.181 +   (rem 0x4000)   ;; get relative offset from the start of the bank
   1.182 +   (+ 0x4000)
   1.183 +   endian-flip))
   1.184 +
   1.185 +(defn offset->bank
   1.186 +  "Get the bank of the offset."
   1.187 +  [n]
   1.188 +  (int (/ n 0x4000)))
   1.189 +
   1.190 +(defn ptr->offset
   1.191 +  "Convert a two-byte little-endian pointer into an offset."
   1.192 +  [bank ptr]
   1.193 +  (->
   1.194 +   ptr
   1.195 +   endian-flip
   1.196 +   (- 0x4000)
   1.197 +   (+ (* 0x4000 bank))
   1.198 +   ))
   1.199 +
   1.200 +(defn same-bank-offset
   1.201 +  "Convert a ptr into an absolute offset by using the bank of the reference."
   1.202 +  [reference ptr]
   1.203 +  (ptr->offset
   1.204 +   (offset->bank reference)
   1.205 +   ptr))
   1.206 +#+end_src
   1.207 +
   1.208  
   1.209  ** Internal Pok\eacute{}mon IDs
   1.210  ** Type IDs
   1.211 @@ -1663,30 +1789,32 @@
   1.212      (take 0xFFF (drop 0x8800 (memory state))))))
   1.213  
   1.214  
   1.215 -(defn test-2 []
   1.216 -  (loop [n 0
   1.217 -         pc-1 (pc-trail (-> state-defend (tick) (step [:a]) (step [:a]) (step []) (nstep 100)) 100000)
   1.218 -         pc-2 (pc-trail (-> state-speed (tick) (step [:a]) (step [:a])
   1.219 -  (step []) (nstep 100)) 100000)]
   1.220 -    (cond (empty? (drop n pc-1)) [pc-1 n]
   1.221 -          (not= (take 10 (drop n pc-1)) (take 10 pc-2))
   1.222 -          (recur  pc-1 pc-2 (inc n))
   1.223 -          :else
   1.224 -          [(take 1000 pc-2) n])))
   1.225 +;; (defn test-2 []
   1.226 +;;   (loop [n 0
   1.227 +;;          pc-1 (pc-trail (-> state-defend (tick) (step [:a]) (step [:a]) (step []) (nstep 100)) 100000)
   1.228 +;;          pc-2 (pc-trail (-> state-speed (tick) (step [:a]) (step [:a])
   1.229 +;;   (step []) (nstep 100)) 100000)]
   1.230 +;;     (cond (empty? (drop n pc-1)) [pc-1 n]
   1.231 +;;           (not= (take 10 (drop n pc-1)) (take 10 pc-2))
   1.232 +;;           (recur  pc-1 pc-2 (inc n))
   1.233 +;;           :else
   1.234 +;;           [(take 1000 pc-2) n])))
   1.235  
   1.236  
   1.237  
   1.238  
   1.239  (defn test-3 
   1.240    "Explore trainer data"
   1.241 -  []
   1.242 +  ([] (test-3 0x3A289))
   1.243 +  ([start]
   1.244    (let [pokenames (vec(hxc-pokenames-raw))]
   1.245      (println 
   1.246       (reduce
   1.247        str
   1.248        (map
   1.249 -       (fn [[lvl pkmn]]
   1.250 -         (str (format "%-11s %4d       %02X %02X"
   1.251 +       (fn [[adr lvl pkmn]]
   1.252 +         (str (format "%-11s %4d       %02X %02X \t %05X\n"
   1.253 +                      
   1.254                        (cond
   1.255                          (zero? lvl) "+"
   1.256                          (nil? (get pokenames (dec pkmn)))
   1.257 @@ -1696,14 +1824,16 @@
   1.258                        lvl
   1.259                        pkmn
   1.260                        lvl
   1.261 -                      ) "\n"))
   1.262 -       
   1.263 -       (partition 2
   1.264 -                  (take 100;;703
   1.265 -                        (drop
   1.266 -                         0x3A281
   1.267 -                        ;; 0x3A75D
   1.268 -                         (rom)))))))))
   1.269 +                      adr
   1.270 +                      )))
   1.271 +       (map cons
   1.272 +            (take-nth 2 (drop start (range)))
   1.273 +            (partition 2
   1.274 +                       (take 400;;703
   1.275 +                             (drop
   1.276 +                              start
   1.277 +                              ;; 0x3A75D
   1.278 +                              (rom)))))))))))
   1.279    
   1.280  (defn search-memory* [mem codes k]
   1.281    (loop [index 0