ocsenave@347: rlm@218: (ns com.aurellem.gb.hxc ocsenave@308: (:use (com.aurellem.gb assembly characters gb-driver util mem-util ocsenave@281: constants species)) rlm@218: (:import [com.aurellem.gb.gb_driver SaveState])) rlm@218: ocsenave@249: ; ************* HANDWRITTEN CONSTANTS ocsenave@249: ocsenave@243: (def pkmn-types ocsenave@272: [:normal ;;0 ocsenave@272: :fighting ;;1 ocsenave@272: :flying ;;2 ocsenave@272: :poison ;;3 ocsenave@272: :ground ;;4 ocsenave@272: :rock ;;5 ocsenave@272: :bird ;;6 ocsenave@272: :bug ;;7 ocsenave@272: :ghost ;;8 ocsenave@244: :A ocsenave@244: :B ocsenave@244: :C ocsenave@244: :D ocsenave@244: :E ocsenave@244: :F ocsenave@244: :G ocsenave@244: :H ocsenave@244: :I ocsenave@244: :J ocsenave@244: :K ocsenave@272: :fire ;;20 (0x14) ocsenave@272: :water ;;21 (0x15) ocsenave@272: :grass ;;22 (0x16) ocsenave@272: :electric ;;23 (0x17) ocsenave@272: :psychic ;;24 (0x18) ocsenave@272: :ice ;;25 (0x19) ocsenave@272: :dragon ;;26 (0x1A) ocsenave@244: ]) ocsenave@243: ocsenave@243: ocsenave@246: ;; question: when status effects claim to take ocsenave@246: ;; their accuracy from the move accuracy, does ocsenave@246: ;; this mean that the move always "hits" but the ocsenave@246: ;; status effect may not? ocsenave@246: ocsenave@246: (def move-effects ocsenave@246: ["normal damage" ocsenave@246: "no damage, just opponent sleep" ;; how many turns? is atk power ignored? ocsenave@246: "0x4C chance of poison" ocsenave@246: "leech half of inflicted damage" ocsenave@246: "0x19 chance of burn" ocsenave@246: "0x19 chance of freeze" ocsenave@246: "0x19 chance of paralyze" ocsenave@259: "user faints; opponent defense halved during attack." ocsenave@246: "leech half of inflicted damage ONLY if sleeping opponent." ocsenave@246: "imitate last attack" ocsenave@246: "user atk +1" ocsenave@246: "user def +1" ocsenave@246: "user spd +1" ocsenave@246: "user spc +1" ocsenave@246: "user acr +1" ;; unused?! ocsenave@246: "user evd +1" ocsenave@246: "get post-battle $ = 2*level*uses" ocsenave@246: "0xFE acr, no matter what." ocsenave@246: "opponent atk -1" ;; acr taken from move acr? ocsenave@246: "opponent def -1" ;; ocsenave@246: "opponent spd -1" ;; ocsenave@246: "opponent spc -1" ;; ocsenave@246: "opponent acr -1";; ocsenave@246: "opponent evd -1" ocsenave@246: "converts user's type to opponent's." ocsenave@246: "(haze)" ocsenave@246: "(bide)" ocsenave@246: "(thrash)" ocsenave@246: "(teleport)" ocsenave@246: "(fury swipes)" ocsenave@246: "attacks 2-5 turns" ;; unused? like rollout? ocsenave@246: "0x19 chance of flinch" ocsenave@246: "opponent sleep for 1-7 turns" ocsenave@246: "0x66 chance of poison" ocsenave@246: "0x4D chance of burn" ocsenave@246: "0x4D chance of freeze" ocsenave@246: "0x4D chance of paralyze" ocsenave@246: "0x4D chance of flinch" ocsenave@246: "one-hit KO" ocsenave@246: "charge one turn, atk next." ocsenave@246: "fixed damage, leaves 1HP." ;; how is dmg determined? ocsenave@246: "fixed damage." ;; cf seismic toss, dragon rage, psywave. ocsenave@246: "atk 2-5 turns; opponent can't attack" ;; unnormalized? (0 0x60 0x60 0x20 0x20) ocsenave@246: "charge one turn, atk next. (can't be hit when charging)" ocsenave@246: "atk hits twice." ocsenave@246: "user takes 1 damage if misses." ocsenave@246: "evade status-lowering effects" ;;caused by you or also your opponent? ocsenave@246: "(broken) if user is slower than opponent, makes critical hit impossible, otherwise has no effect" ocsenave@246: "atk causes recoil dmg = 1/4 dmg dealt" ocsenave@246: "confuses opponent" ;; acr taken from move acr ocsenave@246: "user atk +2" ocsenave@246: "user def +2" ocsenave@246: "user spd +2" ocsenave@246: "user spc +2" ocsenave@246: "user acr +2" ;; unused! ocsenave@246: "user evd +2" ;; unused! ocsenave@246: "restores up to half of user's max hp." ;; broken: fails if the difference ocsenave@246: ;; b/w max and current hp is one less than a multiple of 256. ocsenave@246: "(transform)" ocsenave@246: "opponent atk -2" ocsenave@246: "opponent def -2" ocsenave@246: "opponent spd -2" ocsenave@246: "opponent spc -2" ocsenave@246: "opponent acr -2" ocsenave@246: "opponent evd -2" ocsenave@246: "doubles user spc when attacked" ocsenave@246: "doubles user def when attacked" ocsenave@249: "just poisons opponent" ;;acr taken from move acr ocsenave@249: "just paralyzes opponent" ;; ocsenave@246: "0x19 chance opponent atk -1" ocsenave@246: "0x19 chance opponent def -1" ocsenave@246: "0x19 chance opponent spd -1" ocsenave@246: "0x4C chance opponent spc -1" ;; context suggest chance is 0x19 ocsenave@246: "0x19 chance opponent acr -1" ocsenave@246: "0x19 chance opponent evd -1" ocsenave@246: "???" ;; unused? no effect? ocsenave@246: "???" ;; unused? no effect? ocsenave@246: "0x19 chance opponent confused" ocsenave@246: "atk hits twice. 0x33 chance opponent poisioned." ocsenave@246: "broken. crash the game after attack." ocsenave@246: "(substitute)" ocsenave@246: "unless opponent faints, user must recharge after atk. some ocsenave@246: exceptions apply." ocsenave@246: "(rage)" ocsenave@246: "(mimic)" ocsenave@246: "(metronome)" ocsenave@246: "(leech seed)" ocsenave@246: "does nothing (splash)" ocsenave@246: "(disable)" ocsenave@246: ]) ocsenave@246: ocsenave@249: ;; ************** HARDCODED DATA ocsenave@246: ocsenave@249: (defn hxc-thunk ocsenave@259: "Creates a thunk (nullary fn) that grabs data in a certain region of rom and ocsenave@249: splits it into a collection by 0x50. If rom is not supplied, uses the ocsenave@249: original rom data." ocsenave@249: [start length] ocsenave@249: (fn self ocsenave@249: ([rom] ocsenave@249: (take-nth 2 ocsenave@249: (partition-by #(= % 0x50) ocsenave@249: (take length ocsenave@249: (drop start rom))))) ocsenave@249: ([] ocsenave@249: (self com.aurellem.gb.gb-driver/original-rom)))) ocsenave@246: ocsenave@249: (def hxc-thunk-words ocsenave@249: "Same as hxc-thunk, except it interprets the rom data as characters, ocsenave@249: returning a collection of strings." ocsenave@249: (comp ocsenave@249: (partial comp (partial map character-codes->str)) ocsenave@249: hxc-thunk)) ocsenave@249: ocsenave@249: ;; -------------------------------------------------- ocsenave@246: ocsenave@288: ocsenave@288: (defn hxc-pokenames-raw ocsenave@288: "The hardcoded names of the 190 species in memory. List begins at ocsenave@288: ROM@E8000. Although names in memory are padded with 0x50 to be 10 characters ocsenave@288: long, these names are stripped of padding. See also, hxc-pokedex-names" ocsenave@288: ([] ocsenave@288: (hxc-pokenames-raw com.aurellem.gb.gb-driver/original-rom)) ocsenave@288: ([rom] ocsenave@288: (let [count-species 190 ocsenave@288: name-length 10] ocsenave@288: (map character-codes->str ocsenave@288: (partition name-length ocsenave@288: (map #(if (= 0x50 %) 0x00 %) ocsenave@288: (take (* count-species name-length) ocsenave@288: (drop 0xE8000 ocsenave@288: rom)))))))) ocsenave@288: (def hxc-pokenames ocsenave@288: (comp ocsenave@288: (partial map format-name) ocsenave@288: hxc-pokenames-raw)) ocsenave@288: ocsenave@288: ocsenave@288: ocsenave@288: ocsenave@288: (defn hxc-pokedex-names ocsenave@420: "The names of the pokemon in hardcoded pokedex order. List of the ocsenave@420: pokedex numbers of each pokemon (in internal order) begins at ocsenave@288: ROM@410B1. See also, hxc-pokenames." ocsenave@288: ([] (hxc-pokedex-names ocsenave@288: com.aurellem.gb.gb-driver/original-rom)) ocsenave@288: ([rom] ocsenave@288: (let [names (hxc-pokenames rom)] ocsenave@288: (#(mapv % ocsenave@288: ((comp range count keys) %)) ocsenave@288: (zipmap ocsenave@288: (take (count names) ocsenave@288: (drop 0x410b1 rom)) ocsenave@288: ocsenave@288: names))))) ocsenave@288: ocsenave@348: (def hxc-types ocsenave@348: "The hardcoded type names in memory. List begins at ROM@27D99, ocsenave@348: shortly before hxc-titles." ocsenave@348: (hxc-thunk-words 0x27D99 102)) ocsenave@288: ocsenave@288: ocsenave@306: ;; http://hax.iimarck.us/topic/581/ ocsenave@307: (defn hxc-cry ocsenave@307: "The pokemon cry data in internal order. List begins at ROM@39462" ocsenave@308: ([](hxc-cry com.aurellem.gb.gb-driver/original-rom)) ocsenave@307: ([rom] ocsenave@307: (zipmap ocsenave@307: (hxc-pokenames rom) ocsenave@307: (map ocsenave@307: (fn [[cry-id pitch length]] ocsenave@307: {:cry-id cry-id ocsenave@307: :pitch pitch ocsenave@307: :length length} ocsenave@307: ) ocsenave@307: (partition 3 ocsenave@308: (drop 0x39462 rom)))))) ocsenave@306: ocsenave@307: (defn hxc-cry-groups ocsenave@308: ([] (hxc-cry-groups com.aurellem.gb.gb-driver/original-rom)) ocsenave@307: ([rom] ocsenave@307: (map #(mapv first ocsenave@307: (filter ocsenave@307: (fn [[k v]] ocsenave@307: (= % (:cry-id v))) ocsenave@308: (hxc-cry))) ocsenave@307: ((comp ocsenave@307: range ocsenave@307: count ocsenave@307: set ocsenave@307: (partial map :cry-id) ocsenave@307: vals ocsenave@307: hxc-cry) ocsenave@307: rom)))) ocsenave@306: ocsenave@288: ocsenave@307: (defn cry-conversion! ocsenave@307: "Convert Porygon's cry in ROM to be the cry of the given pokemon." ocsenave@307: [pkmn] ocsenave@307: (write-rom! ocsenave@307: (rewrite-memory ocsenave@307: (vec(rom)) ocsenave@307: 0x3965D ocsenave@307: (map second ocsenave@307: ((hxc-cry) pkmn))))) ocsenave@307: ocsenave@348: ocsenave@348: ocsenave@348: ocsenave@288: (def hxc-items-raw ocsenave@249: "The hardcoded names of the items in memory. List begins at ocsenave@249: ROM@045B7" ocsenave@249: (hxc-thunk-words 0x45B7 870)) ocsenave@246: ocsenave@348: (def hxc-items ocsenave@348: "The hardcoded names of the items in memory, presented as ocsenave@348: keywords. List begins at ROM@045B7. See also, hxc-items-raw." ocsenave@348: (comp (partial map format-name) hxc-items-raw)) ocsenave@348: ocsenave@348: ocsenave@246: ocsenave@246: (def hxc-titles ocsenave@246: "The hardcoded names of the trainer titles in memory. List begins at ocsenave@246: ROM@27E77" ocsenave@249: (hxc-thunk-words 0x27E77 196)) ocsenave@246: ocsenave@259: ocsenave@288: (def hxc-pokedex-text-raw ocsenave@259: "The hardcoded pokedex entries in memory. List begins at ocsenave@259: ROM@B8000, shortly before move names." ocsenave@259: (hxc-thunk-words 0xB8000 14754)) ocsenave@259: ocsenave@288: ocsenave@288: ocsenave@288: ocsenave@285: (defn hxc-pokedex-text ocsenave@285: "The hardcoded pokedex entries in memory, presented as an ocsenave@285: associative hash map. List begins at ROM@B8000." ocsenave@285: ([] (hxc-pokedex-text com.aurellem.gb.gb-driver/original-rom)) ocsenave@285: ([rom] ocsenave@285: (zipmap ocsenave@285: (hxc-pokedex-names rom) ocsenave@285: (cons nil ;; for missingno. ocsenave@288: (hxc-pokedex-text-raw rom))))) ocsenave@259: ocsenave@272: ;; In red/blue, pokedex stats are in internal order. ocsenave@272: ;; In yellow, pokedex stats are in pokedex order. ocsenave@259: (defn hxc-pokedex-stats ocsenave@272: "The hardcoded pokedex stats (species height weight) in memory. List ocsenave@272: begins at ROM@40687" ocsenave@259: ([] (hxc-pokedex-stats com.aurellem.gb.gb-driver/original-rom)) ocsenave@259: ([rom] ocsenave@288: (let [pokedex-names (zipmap (range) (hxc-pokedex-names rom)) ocsenave@288: pkmn-count (count pokedex-names) ocsenave@259: ] ocsenave@259: ((fn capture-stats ocsenave@259: [n stats data] ocsenave@259: (if (zero? n) stats ocsenave@259: (let [[species ocsenave@259: [_ ocsenave@259: height-ft ocsenave@259: height-in ocsenave@259: weight-1 ocsenave@259: weight-2 ocsenave@259: _ ocsenave@259: dex-ptr-1 ocsenave@259: dex-ptr-2 ocsenave@259: dex-bank ocsenave@259: _ ocsenave@259: & data]] ocsenave@259: (split-with (partial not= 0x50) data)] ocsenave@259: (recur (dec n) ocsenave@259: (assoc stats ocsenave@285: (pokedex-names (- pkmn-count (dec n))) ocsenave@259: {:species ocsenave@285: (format-name (character-codes->str species)) ocsenave@259: :height-ft ocsenave@259: height-ft ocsenave@259: :height-in ocsenave@259: height-in ocsenave@259: :weight ocsenave@259: (/ (low-high weight-1 weight-2) 10.) ocsenave@259: ocsenave@259: ;; :text ocsenave@259: ;; (character-codes->str ocsenave@259: ;; (take-while ocsenave@259: ;; (partial not= 0x50) ocsenave@259: ;; (drop ocsenave@259: ;; (+ 0xB8000 ocsenave@259: ;; -0x4000 ocsenave@259: ;; (low-high dex-ptr-1 dex-ptr-2)) ocsenave@259: ;; rom))) ocsenave@259: }) ocsenave@259: ocsenave@259: data) ocsenave@259: ocsenave@259: ocsenave@259: ))) ocsenave@259: ocsenave@259: pkmn-count ocsenave@259: {} ocsenave@259: (drop 0x40687 rom))) )) ocsenave@259: ocsenave@259: ocsenave@259: ocsenave@259: ocsenave@246: (def hxc-places ocsenave@246: "The hardcoded place names in memory. List begins at ocsenave@420: ROM@71500. [Cinnabar/Celadon] Mansion seems to be dynamically calculated." ocsenave@249: (hxc-thunk-words 0x71500 560)) ocsenave@246: ocsenave@249: (defn hxc-dialog ocsenave@249: "The hardcoded dialogue in memory, including in-game alerts. Dialog ocsenave@249: seems to be separated by 0x57 instead of 0x50 (END). Begins at ROM@98000." ocsenave@249: ([rom] ocsenave@249: (map character-codes->str ocsenave@249: (take-nth 2 ocsenave@249: (partition-by #(= % 0x57) ocsenave@249: (take 0x0F728 ocsenave@249: (drop 0x98000 rom)))))) ocsenave@249: ([] ocsenave@249: (hxc-dialog com.aurellem.gb.gb-driver/original-rom))) ocsenave@249: ocsenave@246: ocsenave@246: (def hxc-move-names ocsenave@246: "The hardcoded move names in memory. List begins at ROM@BC000" ocsenave@249: (hxc-thunk-words 0xBC000 1551)) ocsenave@249: (defn hxc-move-data ocsenave@246: "The hardcoded (basic (move effects)) in memory. List begins at ocsenave@249: 0x38000. Returns a map of {:name :power :accuracy :pp :fx-id ocsenave@249: :fx-txt}. The move descriptions are handwritten, not hardcoded." ocsenave@249: ([] ocsenave@249: (hxc-move-data com.aurellem.gb.gb-driver/original-rom)) ocsenave@249: ([rom] ocsenave@249: (let [names (vec (hxc-move-names rom)) ocsenave@249: move-count (count names) ocsenave@281: move-size 6 ocsenave@281: types pkmn-types ;;; !! hardcoded types ocsenave@281: ] ocsenave@249: (zipmap (map format-name names) ocsenave@249: (map ocsenave@281: (fn [[idx effect power type-id accuracy pp]] ocsenave@249: {:name (names (dec idx)) ocsenave@249: :power power ocsenave@249: :accuracy accuracy ocsenave@249: :pp pp ocsenave@281: :type (types type-id) ocsenave@249: :fx-id effect ocsenave@249: :fx-txt (get move-effects effect) ocsenave@249: } ocsenave@249: ) ocsenave@249: ocsenave@249: (partition move-size ocsenave@249: (take (* move-size move-count) ocsenave@249: (drop 0x38000 rom)))))))) ocsenave@246: ocsenave@246: ocsenave@246: ocsenave@249: (defn hxc-move-data* ocsenave@249: "Like hxc-move-data, but reports numbers as hexadecimal symbols instead." ocsenave@249: ([] ocsenave@249: (hxc-move-data* com.aurellem.gb.gb-driver/original-rom)) ocsenave@249: ([rom] ocsenave@249: (let [names (vec (hxc-move-names rom)) ocsenave@249: move-count (count names) ocsenave@249: move-size 6 ocsenave@249: format-name (fn [s] ocsenave@249: (keyword (.toLowerCase ocsenave@249: (apply str ocsenave@249: (map #(if (= % \space) "-" %) s))))) ocsenave@249: ] ocsenave@249: (zipmap (map format-name names) ocsenave@249: (map ocsenave@249: (fn [[idx effect power type accuracy pp]] ocsenave@249: {:name (names (dec idx)) ocsenave@249: :power power ocsenave@249: :accuracy (hex accuracy) ocsenave@249: :pp pp ocsenave@249: :fx-id (hex effect) ocsenave@249: :fx-txt (get move-effects effect) ocsenave@249: } ocsenave@249: ) ocsenave@249: ocsenave@249: (partition move-size ocsenave@249: (take (* move-size move-count) ocsenave@249: (drop 0x38000 rom)))))))) ocsenave@243: ocsenave@243: ocsenave@283: (defn hxc-machines ocsenave@312: "The hardcoded moves taught by TMs and HMs. List begins at ROM@1232D." ocsenave@283: ([] (hxc-machines ocsenave@283: com.aurellem.gb.gb-driver/original-rom)) ocsenave@283: ([rom] ocsenave@283: (let [moves (hxc-move-names rom)] ocsenave@283: (zipmap ocsenave@283: (range) ocsenave@283: (take-while ocsenave@283: (comp not nil?) ocsenave@283: (map (comp ocsenave@283: format-name ocsenave@283: (zipmap ocsenave@283: (range) ocsenave@283: moves) ocsenave@283: dec) ocsenave@283: (take 100 ocsenave@283: (drop 0x1232D rom)))))))) ocsenave@285: ocsenave@285: ocsenave@259: ocsenave@348: ocsenave@259: (defn internal-id ocsenave@259: ([rom] ocsenave@259: (zipmap ocsenave@288: (hxc-pokenames rom) ocsenave@259: (range))) ocsenave@259: ([] ocsenave@259: (internal-id com.aurellem.gb.gb-driver/original-rom))) ocsenave@285: ocsenave@285: ocsenave@285: ocsenave@259: ocsenave@259: ocsenave@263: ;; nidoran gender change upon levelup ocsenave@263: ;; (-> ocsenave@263: ;; @current-state ocsenave@263: ;; rom ocsenave@263: ;; vec ocsenave@263: ;; (rewrite-memory ocsenave@263: ;; (nth (hxc-ptrs-evolve) ((internal-id) :nidoran♂)) ocsenave@263: ;; [1 1 15]) ocsenave@263: ;; (rewrite-memory ocsenave@263: ;; (nth (hxc-ptrs-evolve) ((internal-id) :nidoran♀)) ocsenave@263: ;; [1 1 3]) ocsenave@263: ;; (write-rom!) ocsenave@263: ocsenave@263: ;; ) ocsenave@263: ocsenave@259: ocsenave@259: ocsenave@370: (defn hxc-advantage ocsenave@370: ;; in-game multipliers are stored as 10x their effective value ocsenave@370: ;; to allow for fractional multipliers like 1/2 ocsenave@370: ocsenave@370: "The hardcoded type advantages in memory, returned as tuples of ocsenave@370: atk-type def-type multiplier. By default (i.e. if not listed here), ocsenave@370: the multiplier is 1. List begins at 0x3E62D." ocsenave@370: ([] (hxc-advantage com.aurellem.gb.gb-driver/original-rom)) ocsenave@370: ([rom] ocsenave@370: (map ocsenave@370: (fn [[atk def mult]] [(get pkmn-types atk (hex atk)) ocsenave@370: (get pkmn-types def (hex def)) ocsenave@370: (/ mult 10)]) ocsenave@370: (partition 3 ocsenave@370: (take-while (partial not= 0xFF) ocsenave@370: (drop 0x3E62D rom)))))) ocsenave@243: ocsenave@243: ocsenave@281: ocsenave@263: (defn format-evo ocsenave@347: "Parse a sequence of evolution data, returning a map. First is the ocsenave@347: method: 0 = end-evolution-data. 1 = level-up, 2 = item, 3 = trade. Next is an item id, if the ocsenave@347: method of evolution is by item (only stones will actually make pokemon ocsenave@347: evolve, for some auxillary reason.) Finally, the minimum level for ocsenave@347: evolution to occur (level 1 means no limit, which is used for trade ocsenave@347: and item evolutions), followed by the internal id of the pokemon ocsenave@347: into which to evolve. Hence, level up and trade evolutions are ocsenave@347: described with 3 ocsenave@347: bytes; item evolutions with four." ocsenave@263: [coll] ocsenave@263: (let [method (first coll)] ocsenave@263: (cond (empty? coll) [] ocsenave@263: (= 0 method) [] ;; just in case ocsenave@263: (= 1 method) ;; level-up evolution ocsenave@263: (conj (format-evo (drop 3 coll)) ocsenave@263: {:method :level-up ocsenave@263: :min-level (nth coll 1) ocsenave@263: :into (dec (nth coll 2))}) ocsenave@263: ocsenave@263: (= 2 method) ;; item evolution ocsenave@263: (conj (format-evo (drop 4 coll)) ocsenave@263: {:method :item ocsenave@263: :item (dec (nth coll 1)) ocsenave@263: :min-level (nth coll 2) ocsenave@263: :into (dec (nth coll 3))}) ocsenave@243: ocsenave@263: (= 3 method) ;; trade evolution ocsenave@263: (conj (format-evo (drop 3 coll)) ocsenave@263: {:method :trade ocsenave@263: :min-level (nth coll 1) ;; always 1 for trade. ocsenave@263: :into (dec (nth coll 2))})))) ocsenave@243: ocsenave@243: ocsenave@263: (defn hxc-ptrs-evolve ocsenave@267: "A hardcoded collection of 190 pointers to alternating evolution/learnset data, ocsenave@263: in internal order." ocsenave@263: ([] ocsenave@263: (hxc-ptrs-evolve com.aurellem.gb.gb-driver/original-rom)) ocsenave@259: ([rom] ocsenave@288: (let [ ocsenave@288: pkmn-count (count (hxc-pokenames-raw)) ;; 190 ocsenave@259: ptrs ocsenave@263: (map (fn [[a b]] (low-high a b)) ocsenave@259: (partition 2 ocsenave@259: (take (* 2 pkmn-count) ocsenave@263: (drop 0x3b1e5 rom))))] ocsenave@263: (map (partial + 0x34000) ptrs) ocsenave@263: ocsenave@263: ))) ocsenave@263: ocsenave@370: (defn hxc-evolution ocsenave@370: "Hardcoded evolution data in memory. The data exists at ROM@34000, ocsenave@370: sorted by internal order. Pointers to the data exist at ROM@3B1E5; see also, hxc-ptrs-evolve." ocsenave@370: ([] (hxc-evolution com.aurellem.gb.gb-driver/original-rom)) ocsenave@370: ([rom] ocsenave@370: (apply assoc {} ocsenave@370: (interleave ocsenave@370: (hxc-pokenames rom) ocsenave@370: (map ocsenave@370: (comp ocsenave@370: format-evo ocsenave@370: (partial take-while (comp not zero?)) ocsenave@370: #(drop % rom)) ocsenave@370: (hxc-ptrs-evolve rom) ocsenave@370: ))))) ocsenave@370: ocsenave@370: (defn hxc-evolution-pretty ocsenave@370: "Like hxc-evolution, except it uses the names of items and pokemon ocsenave@370: --- grabbed from ROM --- rather than their numerical identifiers." ocsenave@370: ([] (hxc-evolution-pretty com.aurellem.gb.gb-driver/original-rom)) ocsenave@370: ([rom] ocsenave@370: (let ocsenave@370: [poke-names (vec (hxc-pokenames rom)) ocsenave@370: item-names (vec (hxc-items rom)) ocsenave@370: use-names ocsenave@370: (fn [m] ocsenave@370: (loop [ks (keys m) new-map m] ocsenave@370: (let [k (first ks)] ocsenave@370: (cond (nil? ks) new-map ocsenave@370: (= k :into) ocsenave@370: (recur ocsenave@370: (next ks) ocsenave@370: (assoc new-map ocsenave@370: :into ocsenave@370: (poke-names ocsenave@370: (:into ocsenave@370: new-map)))) ocsenave@370: (= k :item) ocsenave@370: (recur ocsenave@370: (next ks) ocsenave@370: (assoc new-map ocsenave@370: :item ocsenave@370: (item-names ocsenave@370: (:item new-map)))) ocsenave@370: :else ocsenave@370: (recur ocsenave@370: (next ks) ocsenave@370: new-map) ocsenave@370: ))))] ocsenave@370: ocsenave@370: (into {} ocsenave@370: (map (fn [[pkmn evo-coll]] ocsenave@370: [pkmn (map use-names evo-coll)]) ocsenave@370: (hxc-evolution rom)))))) ocsenave@370: ocsenave@370: ocsenave@370: ocsenave@267: ocsenave@267: (defn hxc-learnsets ocsenave@267: "Hardcoded map associating pokemon names to lists of pairs [lvl ocsenave@267: move] of abilities they learn as they level up. The data ocsenave@347: exists at ROM@34000, sorted by internal order. Pointers to the data ocsenave@267: exist at ROM@3B1E5; see also, hxc-ptrs-evolve" ocsenave@267: ([] (hxc-learnsets com.aurellem.gb.gb-driver/original-rom)) ocsenave@267: ([rom] ocsenave@267: (apply assoc ocsenave@267: {} ocsenave@267: (interleave ocsenave@288: (hxc-pokenames rom) ocsenave@267: (map (comp ocsenave@268: (partial map ocsenave@268: (fn [[lvl mv]] [lvl (dec mv)])) ocsenave@267: (partial partition 2) ocsenave@267: ;; keep the learnset data ocsenave@267: (partial take-while (comp not zero?)) ocsenave@267: ;; skip the evolution data ocsenave@267: rest ocsenave@267: (partial drop-while (comp not zero?))) ocsenave@267: (map #(drop % rom) ocsenave@267: (hxc-ptrs-evolve rom))))))) ocsenave@267: ocsenave@267: (defn hxc-learnsets-pretty ocsenave@267: "Live hxc-learnsets except it reports the name of each move --- as ocsenave@267: it appears in rom --- rather than the move index." ocsenave@267: ([] (hxc-learnsets-pretty com.aurellem.gb.gb-driver/original-rom)) ocsenave@267: ([rom] ocsenave@267: (let [moves (vec(map format-name (hxc-move-names)))] ocsenave@267: (into {} ocsenave@267: (map (fn [[pkmn learnset]] ocsenave@268: [pkmn (map (fn [[lvl mv]] [lvl (moves mv)]) ocsenave@267: learnset)]) ocsenave@267: (hxc-learnsets rom)))))) ocsenave@267: ocsenave@267: ocsenave@267: ocsenave@273: (defn hxc-pokemon-base ocsenave@273: ([] (hxc-pokemon-base com.aurellem.gb.gb-driver/original-rom)) ocsenave@273: ([rom] ocsenave@273: (let [entry-size 28 ocsenave@371: ocsenave@285: pokemon (rest (hxc-pokedex-names)) ocsenave@371: pkmn-count (inc(count pokemon)) ocsenave@273: types (apply assoc {} ocsenave@273: (interleave ocsenave@273: (range) ocsenave@273: pkmn-types)) ;;!! softcoded ocsenave@273: moves (apply assoc {} ocsenave@273: (interleave ocsenave@273: (range) ocsenave@273: (map format-name ocsenave@273: (hxc-move-names rom)))) ocsenave@288: machines (hxc-machines) ocsenave@273: ] ocsenave@285: (zipmap ocsenave@285: pokemon ocsenave@285: (map ocsenave@285: (fn [[n ocsenave@285: rating-hp ocsenave@285: rating-atk ocsenave@285: rating-def ocsenave@285: rating-speed ocsenave@285: rating-special ocsenave@285: type-1 ocsenave@285: type-2 ocsenave@285: rarity ocsenave@285: rating-xp ocsenave@285: pic-dimensions ;; tile_width|tile_height (8px/tile) ocsenave@285: ptr-pic-obverse-1 ocsenave@285: ptr-pic-obverse-2 ocsenave@285: ptr-pic-reverse-1 ocsenave@285: ptr-pic-reverse-2 ocsenave@285: move-1 ocsenave@285: move-2 ocsenave@285: move-3 ocsenave@285: move-4 ocsenave@285: growth-rate ocsenave@285: & ocsenave@285: TMs|HMs]] ocsenave@285: (let ocsenave@285: [base-moves ocsenave@285: (mapv moves ocsenave@285: ((comp ocsenave@285: ;; since the game uses zero as a delimiter, ocsenave@285: ;; it must also increment all move indices by 1. ocsenave@285: ;; heren we decrement to correct this. ocsenave@285: (partial map dec) ocsenave@285: (partial take-while (comp not zero?))) ocsenave@285: [move-1 move-2 move-3 move-4])) ocsenave@285: ocsenave@285: types ocsenave@285: (set (list (types type-1) ocsenave@285: (types type-2))) ocsenave@285: TMs|HMs ocsenave@285: (map ocsenave@285: (comp ocsenave@285: (partial map first) ocsenave@285: (partial remove (comp zero? second))) ocsenave@285: (split-at ocsenave@285: 50 ocsenave@285: (map vector ocsenave@285: (rest(range)) ocsenave@285: (reduce concat ocsenave@285: (map ocsenave@285: #(take 8 ocsenave@285: (concat (bit-list %) ocsenave@285: (repeat 0))) ocsenave@285: ocsenave@273: TMs|HMs))))) ocsenave@285: ocsenave@285: TMs (vec (first TMs|HMs)) ocsenave@285: HMs (take 5 (map (partial + -50) (vec (second TMs|HMs)))) ocsenave@285: ocsenave@285: ocsenave@285: ] ocsenave@285: ocsenave@285: ocsenave@285: {:dex# n ocsenave@285: :base-moves base-moves ocsenave@285: :types types ocsenave@285: :TMs TMs ocsenave@285: :HMs HMs ocsenave@285: :base-hp rating-hp ocsenave@285: :base-atk rating-atk ocsenave@285: :base-def rating-def ocsenave@285: :base-speed rating-speed ocsenave@285: :base-special rating-special ocsenave@310: :o0 pic-dimensions ocsenave@310: :o1 ptr-pic-obverse-1 ocsenave@310: :o2 ptr-pic-obverse-2 ocsenave@285: })) ocsenave@285: ocsenave@285: (partition entry-size ocsenave@285: (take (* entry-size pkmn-count) ocsenave@285: (drop 0x383DE ocsenave@285: rom)))))))) ocsenave@348: ocsenave@285: ocsenave@285: ocsenave@310: (defn hxc-intro-pkmn ocsenave@310: "The hardcoded pokemon to display in Prof. Oak's introduction; the pokemon's ocsenave@310: internal id is stored at ROM@5EDB." ocsenave@310: ([] (hxc-intro-pkmn ocsenave@310: com.aurellem.gb.gb-driver/original-rom)) ocsenave@310: ([rom] ocsenave@310: (nth (hxc-pokenames rom) (nth rom 0x5EDB)))) ocsenave@310: ocsenave@310: (defn sxc-intro-pkmn! ocsenave@310: "Set the hardcoded pokemon to display in Prof. Oak's introduction." ocsenave@310: [pokemon] ocsenave@310: (write-rom! ocsenave@310: (rewrite-rom 0x5EDB ocsenave@310: [ ocsenave@310: (inc ocsenave@310: ((zipmap ocsenave@310: (hxc-pokenames) ocsenave@310: (range)) ocsenave@310: pokemon))]))) ocsenave@285: ocsenave@310: ocsenave@282: (defn hxc-item-prices ocsenave@282: "The hardcoded list of item prices in memory. List begins at ROM@4495" ocsenave@282: ([] (hxc-item-prices com.aurellem.gb.gb-driver/original-rom)) ocsenave@282: ([rom] ocsenave@288: (let [items (hxc-items rom) ocsenave@282: price-size 3] ocsenave@282: (zipmap items ocsenave@282: (map (comp ocsenave@282: ;; zero-cost items are "priceless" ocsenave@282: #(if (zero? %) :priceless %) ocsenave@282: decode-bcd butlast) ocsenave@282: (partition price-size ocsenave@282: (take (* price-size (count items)) ocsenave@282: (drop 0x4495 rom)))))))) ocsenave@273: ocsenave@281: (defn hxc-shops ocsenave@281: ([] (hxc-shops com.aurellem.gb.gb-driver/original-rom)) ocsenave@281: ([rom] ocsenave@288: (let [items (zipmap (range) (hxc-items rom)) ocsenave@281: ocsenave@281: ;; temporarily softcode the TM items ocsenave@281: items (into ocsenave@281: items ocsenave@281: (map (juxt identity ocsenave@281: (comp keyword ocsenave@281: (partial str "tm-") ocsenave@281: (partial + 1 -200) ocsenave@281: )) ocsenave@281: (take 200 (drop 200 (range))))) ocsenave@282: ocsenave@281: ] ocsenave@281: ocsenave@281: ((fn parse-shop [coll [num-items & items-etc]] ocsenave@282: (let [inventory (take-while ocsenave@282: (partial not= 0xFF) ocsenave@282: items-etc) ocsenave@281: [separator & items-etc] (drop num-items (rest items-etc))] ocsenave@281: (if (= separator 0x50) ocsenave@281: (map (partial mapv (comp items dec)) (conj coll inventory)) ocsenave@281: (recur (conj coll inventory) items-etc) ocsenave@281: ) ocsenave@281: )) ocsenave@281: ocsenave@281: '() ocsenave@282: (drop 0x233C rom)) ocsenave@281: ocsenave@281: ocsenave@281: ))) ocsenave@281: ocsenave@281: ocsenave@273: ocsenave@292: ocsenave@292: (defn hxc-ptrs-wild ocsenave@292: "A list of the hardcoded wild encounter data in memory. Pointers ocsenave@292: begin at ROM@0CB95; data begins at ROM@0x04D89" ocsenave@292: ([] (hxc-ptrs-wild com.aurellem.gb.gb-driver/original-rom)) ocsenave@292: ([rom] ocsenave@292: (let [ptrs ocsenave@292: (map (fn [[a b]] (+ a (* 0x100 b))) ocsenave@292: (take-while (partial not= (list 0xFF 0xFF)) ocsenave@292: (partition 2 (drop 0xCB95 rom))))] ocsenave@292: ptrs))) ocsenave@292: ocsenave@292: ocsenave@292: ocsenave@292: (defn hxc-wilds ocsenave@292: "A list of the hardcoded wild encounter data in memory. Pointers ocsenave@292: begin at ROM@0CB95; data begins at ROM@0x04D89" ocsenave@292: ([] (hxc-wilds com.aurellem.gb.gb-driver/original-rom)) ocsenave@292: ([rom] ocsenave@292: (let [pokenames (zipmap (range) (hxc-pokenames rom))] ocsenave@292: (map ocsenave@292: (partial map (fn [[a b]] {:species (pokenames (dec b)) :level ocsenave@292: a})) ocsenave@292: (partition 10 ocsenave@292: ocsenave@292: (take-while (comp (partial not= 1) ocsenave@292: first) ocsenave@292: (partition 2 ocsenave@292: (drop 0xCD8C rom)) ocsenave@292: ocsenave@292: )))))) ocsenave@292: ocsenave@292: ocsenave@292: ocsenave@249: ;; ********************** MANIPULATION FNS ocsenave@249: ocsenave@249: ocsenave@285: (defn same-type ocsenave@285: ([pkmn move] ocsenave@288: (same-type ocsenave@285: com.aurellem.gb.gb-driver/original-rom pkmn move)) ocsenave@285: ([rom pkmn move] ocsenave@285: (((comp :types (hxc-pokemon-base rom)) pkmn) ocsenave@285: ((comp :type (hxc-move-data rom)) move)))) ocsenave@285: ocsenave@285: ocsenave@249: ocsenave@249: ocsenave@249: (defn submap? ocsenave@249: "Compares the two maps. Returns true if map-big has the same associations as map-small, otherwise false." ocsenave@249: [map-small map-big] ocsenave@249: (cond (empty? map-small) true ocsenave@249: (and ocsenave@249: (contains? map-big (ffirst map-small)) ocsenave@249: (= (get map-big (ffirst map-small)) ocsenave@249: (second (first map-small)))) ocsenave@249: (recur (next map-small) map-big) ocsenave@249: ocsenave@249: :else false)) ocsenave@249: ocsenave@249: ocsenave@249: (defn search-map [proto-map maps] ocsenave@249: "Returns all the maps that make the same associations as proto-map." ocsenave@249: (some (partial submap? proto-map) maps)) ocsenave@249: rlm@252: (defn filter-vals rlm@252: "Returns a map consisting of all the pairs [key val] for rlm@252: which (pred key) returns true." rlm@252: [pred map] rlm@252: (reduce (partial apply assoc) {} rlm@252: (filter (fn [[k v]] (pred v)) map))) ocsenave@249: ocsenave@249: ocsenave@249: (defn search-moves rlm@252: "Returns a subcollection of all hardcoded moves with the rlm@252: given attributes. Attributes consist of :name :power rlm@252: :accuracy :pp :fx-id rlm@252: (and also :fx-txt, but it contains the same information rlm@252: as :fx-id)" ocsenave@249: ([attribute-map] rlm@252: (search-moves rlm@252: com.aurellem.gb.gb-driver/original-rom attribute-map)) ocsenave@249: ([rom attribute-map] rlm@252: (filter-vals (partial submap? attribute-map) rlm@252: (hxc-move-data rom)))) ocsenave@249: ocsenave@249: ocsenave@249: ocsenave@249: ocsenave@243: ocsenave@283: ;; note: 0x2f31 contains the names "TM" "HM"? ocsenave@283: ocsenave@246: ;; note for later: credits start at F1290 ocsenave@243: ocsenave@346: ;; note: DADB hyper-potion-hp _ _ _ super-potion-hp _ _ _ potion-hp ?? ocsenave@243: ocsenave@346: ;; note: DD4D spells out pokemon vital stat names ("speed", etc.) ocsenave@346: ocsenave@346: ;; note: 1195C-6A says ABLE#NOT ABLE#, but so does 119C0-119CE. ocsenave@346: ;; The first instance is for Machines; the second, for stones. ocsenave@243: ocsenave@420: ;; note: according to ocsenave@420: ;; http://www.upokecenter.com/games/rby/guides/rgbtrainers.php ocsenave@420: ;; the amount of money given by a trainer is equal to the ocsenave@420: ;; base money times the level of the last Pokemon on that trainer's ocsenave@420: ;; list. Other sources say it's the the level of the last pokemon ocsenave@420: ;; /defeated/. ocsenave@420: ocsenave@420: ;; todo: find base money. ocsenave@420: ocsenave@420: ocsenave@420: ;; note: 0xDFEA (in indexable mem) is the dex# of the currently-viewed Pokemon in ocsenave@420: ;; in the pokedex. It's used for other purposes if there is none. ocsenave@420: ocsenave@420: ;; note: 0x9D35 (index.) switches from 0xFF to 0x00 temporarily when ocsenave@420: ;; you walk between areas. ocsenave@420: ocsenave@420: ;; note: 0xD059 (index.) is the special battle type of your next battle: ocsenave@420: ;; - 00 is a usual battle ocsenave@420: ;; - 01 is a pre-scripted OLD MAN battle which always fails to catch the ocsenave@420: ;; target Pokemon. ocsenave@420: ;; - 02 is a safari zone battle ocsenave@420: ;; - 03 obligates you to run away. (unused) ocsenave@420: ;; - 04 is a pre-scripted OAK battle, which (temporarily) causes the ocsenave@420: ;; enemy Pokemon to cry PIKAAA, and which always catches the target ocsenave@420: ;; Pokemon. The target Pokemon is erased after the battle. ocsenave@420: ;; - 05+ are glitch states in which you are sort of the Pokemon. ocsenave@420: ocsenave@420: ocsenave@420: ;; note: 0x251A (in indexable mem): image decompression routine seems to begin here. ocsenave@420: ocsenave@420: ;; note: 0x4845 (index): vending inventory is loaded here. possibly ocsenave@420: ;; other things, too. ocsenave@420: (comment ocsenave@420: ;; temporarily intercept/adjust what pops out of the vending ocsenave@420: ;; machine. ocsenave@420: ;; (and how much it costs) ocsenave@420: ocsenave@420: ;; located at 0x4845 ocsenave@420: ;; not to be confused with shop inventory, 0xCF7B ocsenave@420: (do ocsenave@420: (step (read-state "vend-menu")) ocsenave@420: (write-memory! (rewrite-memory (vec(memory)) 0x4845 [2 0 1 0])) ocsenave@420: (step @current-state [:a]) ocsenave@420: (step @current-state []) ocsenave@420: (nstep @current-state 200) )) ocsenave@347: ocsenave@347: rlm@376: ;; Note: There are two tile tables, one from 8000-8FFF, the other from rlm@376: ;; 8800-97FF. The latter contains symbols, possibly map tiles(?), with some japanese chars and stuff at the end. rlm@376: (defn print-pixel-letters! rlm@376: "The pixel tiles representing letters. Neat!" ocsenave@420: ([] (print-pixel-letters! (read-state "oak-speaks"))) ocsenave@420: ([state] ocsenave@420: (map ocsenave@420: (comp ocsenave@420: println ocsenave@420: (partial map #(if (zero? %) \space 0)) ocsenave@420: #(if (< (count %) 8) ocsenave@420: (recur (cons 0 %)) ocsenave@420: %) ocsenave@420: reverse bit-list) ocsenave@420: ocsenave@420: (take 0xFFF (drop 0x8800 (memory state)))))) ocsenave@420: ocsenave@420: ocsenave@420: ;; (defn test-2 [] ocsenave@420: ;; (loop [n 0 ocsenave@420: ;; pc-1 (pc-trail (-> state-defend (tick) (step [:a]) (step [:a]) (step []) (nstep 100)) 100000) ocsenave@420: ;; pc-2 (pc-trail (-> state-speed (tick) (step [:a]) (step [:a]) ocsenave@420: ;; (step []) (nstep 100)) 100000)] ocsenave@420: ;; (cond (empty? (drop n pc-1)) [pc-1 n] ocsenave@420: ;; (not= (take 10 (drop n pc-1)) (take 10 pc-2)) ocsenave@420: ;; (recur pc-1 pc-2 (inc n)) ocsenave@420: ;; :else ocsenave@420: ;; [(take 1000 pc-2) n]))) ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: (defn test-3 ocsenave@420: "Explore trainer data" ocsenave@420: ([] (test-3 0x3A289)) ocsenave@420: ([start] ocsenave@420: (let [pokenames (vec(hxc-pokenames-raw))] ocsenave@420: (println ocsenave@420: (reduce ocsenave@420: str ocsenave@420: (map ocsenave@420: (fn [[adr lvl pkmn]] ocsenave@420: (str (format "%-11s %4d %02X %02X \t %05X\n" ocsenave@420: ocsenave@420: (cond ocsenave@420: (zero? lvl) "+" ocsenave@420: (nil? (get pokenames (dec pkmn))) ocsenave@420: "-" ocsenave@420: :else ocsenave@420: (get pokenames (dec pkmn))) ocsenave@420: lvl ocsenave@420: pkmn ocsenave@420: lvl ocsenave@420: adr ocsenave@420: ))) ocsenave@420: (map cons ocsenave@420: (take-nth 2 (drop start (range))) ocsenave@420: (partition 2 ocsenave@420: (take 400;;703 ocsenave@420: (drop ocsenave@420: start ocsenave@420: ;; 0x3A75D ocsenave@420: (rom))))))))))) ocsenave@420: ocsenave@420: (defn search-memory* [mem codes k] ocsenave@420: (loop [index 0 ocsenave@420: index-next 1 ocsenave@420: start-match 0 ocsenave@420: to-match codes ocsenave@420: matches []] ocsenave@420: (cond ocsenave@420: (>= index (count mem)) matches ocsenave@420: ocsenave@420: (empty? to-match) ocsenave@420: (recur ocsenave@420: index-next ocsenave@420: (inc index-next) ocsenave@420: index-next ocsenave@420: codes ocsenave@420: (conj matches ocsenave@420: [(hex start-match) (take k (drop start-match mem))]) ocsenave@420: ) ocsenave@420: ocsenave@420: (or (= (first to-match) \_) ;; wildcard ocsenave@420: (= (first to-match) (nth mem index))) ocsenave@420: (recur ocsenave@420: (inc index) ocsenave@420: index-next ocsenave@420: start-match ocsenave@420: (rest to-match) ocsenave@420: matches) ocsenave@420: ocsenave@420: :else ocsenave@420: (recur ocsenave@420: index-next ocsenave@420: (inc index-next) ocsenave@420: index-next ocsenave@420: codes ocsenave@420: matches)))) rlm@376: ocsenave@420: ocsenave@420: (defn search-pattern [ptn coll] ocsenave@420: (loop ocsenave@420: [index 0 ocsenave@420: to-match ptn ocsenave@420: binds {} ocsenave@420: ocsenave@420: next-index 1 ocsenave@420: match-start 0 ocsenave@420: matches []] ocsenave@420: ocsenave@420: (cond ocsenave@420: (>= index (count coll)) matches ocsenave@420: (empty? to-match) ocsenave@420: (recur ocsenave@420: next-index ocsenave@420: ptn ocsenave@420: {} ocsenave@420: (inc next-index) ocsenave@420: next-index ocsenave@420: (conj match-start ocsenave@420: [(hex match-start) binds])) ocsenave@420: ocsenave@420: :else ocsenave@420: (let [k (first to-match) ocsenave@420: v (nth coll index)] ocsenave@420: (cond ocsenave@420: (= k \_) ;; wildcard ocsenave@420: (recur ocsenave@420: (inc index) ocsenave@420: (rest to-match) ocsenave@420: binds ocsenave@420: ocsenave@420: next-index ocsenave@420: match-start ocsenave@420: matches) ocsenave@420: ocsenave@420: (keyword? k) ocsenave@420: (if (binds k) ocsenave@420: (if (= (binds k) v) ocsenave@420: ocsenave@420: ;; consistent bindings ocsenave@420: (recur ocsenave@420: (inc index) ocsenave@420: (rest to-match) ocsenave@420: binds ocsenave@420: ocsenave@420: next-index ocsenave@420: match-start ocsenave@420: matches) ocsenave@420: ocsenave@420: ;; inconsistent bindings ocsenave@420: (recur ocsenave@420: next-index ocsenave@420: ptn ocsenave@420: {} ocsenave@420: (inc next-index) ocsenave@420: next-index ocsenave@420: matches)) ocsenave@420: ocsenave@420: (if ((set (vals binds)) v) ocsenave@420: ;; bindings are not unique ocsenave@420: (recur ocsenave@420: next-index ocsenave@420: ptn ocsenave@420: {} ocsenave@420: (inc next-index) ocsenave@420: next-index ocsenave@420: matches) ocsenave@420: ocsenave@420: ;; bindings are unique ocsenave@420: (recur ocsenave@420: (inc index) ocsenave@420: (rest to-match) ocsenave@420: (assoc binds k v) ocsenave@420: ocsenave@420: next-index ocsenave@420: match-start ocsenave@420: matches))) ocsenave@420: ocsenave@420: :else ;; k is just a number ocsenave@420: (if (= k v) ocsenave@420: (recur ocsenave@420: (inc index) ocsenave@420: (rest to-match) ocsenave@420: binds ocsenave@420: ocsenave@420: next-index ocsenave@420: match-start ocsenave@420: matches) ocsenave@420: ocsenave@420: (recur ocsenave@420: next-index ocsenave@420: ptn ocsenave@420: {} ocsenave@420: (inc next-index) ocsenave@420: next-index ocsenave@420: matches))))))) ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: (defn search-pattern* [ptn coll] ocsenave@420: (loop ocsenave@420: [ ocsenave@420: binds {} ocsenave@420: index 0 ocsenave@420: index-next 1 ocsenave@420: start-match 0 ocsenave@420: to-match ptn ocsenave@420: matches []] ocsenave@420: ocsenave@420: (cond ocsenave@420: (>= index (count coll)) matches ocsenave@420: (empty? to-match) ocsenave@420: (recur ocsenave@420: {} ocsenave@420: index-next ocsenave@420: (inc index-next) ocsenave@420: index-next ocsenave@420: ptn ocsenave@420: (conj matches ocsenave@420: [(hex start-match) binds])) ocsenave@420: ocsenave@420: :else ocsenave@420: (let [k (first to-match) ocsenave@420: v (nth coll index)] ocsenave@420: (cond ocsenave@420: (= k \_) ;; wildcard ocsenave@420: (recur ocsenave@420: binds ocsenave@420: (inc index) ocsenave@420: index-next ocsenave@420: start-match ocsenave@420: (rest to-match) ocsenave@420: matches) ocsenave@420: ocsenave@420: (keyword? k) ocsenave@420: (if (binds k) ocsenave@420: (if (= (binds k) v) ocsenave@420: (recur ocsenave@420: binds ocsenave@420: (inc index) ocsenave@420: index-next ocsenave@420: start-match ocsenave@420: (rest to-match) ocsenave@420: matches) ocsenave@420: (recur ocsenave@420: {} ocsenave@420: index-next ocsenave@420: (inc index-next) ocsenave@420: index-next ocsenave@420: ptn ocsenave@420: matches)) ocsenave@420: (if ocsenave@420: ;; every symbol must be bound to a different thing. ocsenave@420: ((set (vals binds)) v) ocsenave@420: (recur ocsenave@420: {} ocsenave@420: index-next ocsenave@420: (inc index-next) ocsenave@420: index-next ocsenave@420: ptn ocsenave@420: matches) ocsenave@420: (recur ocsenave@420: (assoc binds k v) ocsenave@420: (inc index) ocsenave@420: index-next ocsenave@420: start-match ocsenave@420: (rest to-match) ocsenave@420: matches)))))))) ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: ocsenave@420: ;; look for the rainbow badge in memory ocsenave@420: (println (reduce str (map #(str (first %) "\t" (vec(second %)) "\n") (search-memory (rom) [221] 10)))) rlm@376: rlm@376: ocsenave@246: (comment ocsenave@243: rlm@218: (def hxc-later rlm@218: "Running this code produces, e.g. hardcoded names NPCs give rlm@218: their pokemon. Will sort through it later." rlm@218: (print (character-codes->str(take 10000 rlm@218: (drop 0x71597 rlm@218: (rom (root))))))) rlm@218: rlm@218: (let [dex rlm@218: (partition-by #(= 0x50 %) rlm@218: (take 2540 rlm@218: (drop 0x40687 rlm@218: (rom (root)))))] rlm@218: (def dex dex) rlm@218: (def hxc-species rlm@218: (map character-codes->str rlm@218: (take-nth 4 dex)))) ocsenave@259: )