rlm@170: (ns com.aurellem.exp.item-bridge rlm@179: (:use (com.aurellem.gb saves util constants gb-driver vbm items assembly)) rlm@170: (:use (com.aurellem.run title save-corruption)) rlm@179: ;;(:use (com.aurellem.exp pokemon)) rlm@154: (:import [com.aurellem.gb.gb_driver SaveState])) rlm@130: rlm@131: (defn corrupt-item-state [] rlm@131: (second (destroy-item-end-of-list-marker))) rlm@131: rlm@131: (defn corrupt-item-state [] rlm@131: (read-state "corrupt-items")) rlm@131: rlm@133: (defn view-memory-range [state start end] rlm@133: (dorun rlm@133: (map (fn [loc val] rlm@133: (println (format "%04X : %02X" loc val))) rlm@133: (range start end) (subvec (vec (memory state)) start end))) rlm@133: state) rlm@131: rlm@133: (defn almost-broken rlm@133: "if one more memory location is turned into 0x03, the game crashes." rlm@133: [n] rlm@133: (view-memory-range rlm@133: (set-inv-mem (mid-game) rlm@133: (concat [0xFF] (repeat 64 0x03) rlm@133: (subvec (vec (memory (mid-game))) rlm@133: (+ item-list-start 65) rlm@133: (+ item-list-start 65 n)) rlm@170: (repeat (- 255 65 n) 0x03))) rlm@133: item-list-start (+ item-list-start 255))) rlm@131: rlm@133: (defn actually-broken rlm@170: "if this memory location is turned into 0x03, the game crashes." rlm@133: [] rlm@133: (set-memory (mid-game) 0xD35D 0x03)) rlm@131: rlm@131: rlm@133: ;; (almost-broken 20) more or less works rlm@133: rlm@133: (defn capture-program-counter rlm@133: "records the program counter for each tick" rlm@133: [^SaveState state ticks] rlm@133: (let [i (atom 0)] rlm@133: (reduce (fn [[program-counters state] _] rlm@133: (println (swap! i inc)) rlm@133: [(conj program-counters (PC state)) rlm@133: (tick state)]) rlm@133: [[] state] rlm@133: (range ticks)))) rlm@133: rlm@133: rlm@133: (defn capture-program-counter rlm@133: [^SaveState state ticks] rlm@176: (tick state) rlm@176: rlm@133: (loop [i 0 rlm@133: pcs []] rlm@133: (if (= i ticks) rlm@179: (filter (partial < 0x2000)(sort (set pcs))) rlm@133: (do rlm@133: (com.aurellem.gb.Gb/tick) rlm@133: (recur (inc i) rlm@133: (conj pcs (first (registers)))))))) rlm@170: rlm@170: (defn loop-program [] rlm@174: [0x00 ;0xD31D ;; disable-interrupts rlm@170: rlm@170: 0xC3 ;; loop forever rlm@170: 0x1D rlm@170: 0xD3]) rlm@170: rlm@170: (def map-function-address-start 0xD36D) rlm@170: rlm@170: (defn test-loop [] rlm@174: (continue! rlm@170: (-> (mid-game) rlm@170: (set-memory-range 0xD31D (loop-program)) rlm@170: (set-memory-range rlm@170: map-function-address-start rlm@174: [0xD3 0x1D])))) rlm@174: rlm@174: rlm@170: rlm@170: rlm@170: (defn-memo corrupt-moves [] rlm@170: (concat rlm@170: (first rlm@170: (->> rlm@170: [[] (mid-game)] rlm@170: (advance [:b] [:b :start]) rlm@170: (advance [] [:d]) rlm@170: (play-moves [[] [] [] [:d] [] [] [] [:d] [] [] [:a]]) rlm@170: scroll-text rlm@170: (play-moves rlm@170: ;; this section is copied from speedrun-2942 rlm@170: ;; and corrupts the save so that the end-of-list marker rlm@170: ;; for the pokemon roster is destroyed, but the save is still rlm@170: ;; playable. rlm@170: [[] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] rlm@170: [] [] [] [] [] [] [] [] [] [] [:select] [:restart]]) rlm@170: (play-moves rlm@170: (first (title))) rlm@170: (advance [] [:start]) rlm@170: (advance [] [:a]) rlm@170: (advance [:a] [:a :start]))) rlm@170: [[]])) rlm@170: rlm@170: rlm@170: rlm@170: (defn corrupt rlm@170: "enter the codes to destroy the rlm@170: pokemon list using save corruption" rlm@170: ([^SaveState state] rlm@170: (run-moves rlm@170: state rlm@170: (corrupt-moves))) rlm@171: ([] (corrupt @current-state))) rlm@173: rlm@173: (defn mid-game-corrupt [] rlm@173: (read-state "corrupt-mid-game")) rlm@170: rlm@212: rlm@187: rlm@170: rlm@170: rlm@212: rlm@187: (defn test-memory-fun [n] rlm@187: (capture-program-counter rlm@187: (set-memory-range rlm@187: (tick (mid-game)) rlm@187: 0xD36D rlm@187: [0 0]) rlm@187: n)) rlm@170: rlm@187: ;;(def good (test-memory-fun 17000)) rlm@187: rlm@187: ;;(def bad (test-memory-fun 18000)) rlm@187: rlm@187: rlm@212: rlm@212: (defn menu-open-state [] rlm@212: (read-state "menu-open")) rlm@212: rlm@212: (defn prepare-memory rlm@212: ([^SaveState state] rlm@212: (-> state rlm@212: (set-memory-range 0xD31D (loop-program)) rlm@212: (set-memory-range 0xD36D [0x1D 0xD3]))) rlm@212: ([] (prepare-memory @current-state))) rlm@212: rlm@233: (def memory-function-address-start 0xD36D) rlm@233: rlm@233: (defn read-map-function-address rlm@233: ([^SaveState state] rlm@233: (let [mem (memory state)] rlm@233: [(aget mem memory-function-address-start) rlm@233: (aget mem (inc memory-function-address-start))])) rlm@233: ([] (read-map-function-address @current-state))) rlm@212: rlm@212: (defn succesful-PC-capture rlm@212: "This function demonstrates successful PC capturing by rlm@212: setting 0xD36D to the value of the start location of rlm@212: a specially prepared program. rlm@212: rlm@212: You must run the function and then exit the open menu rlm@212: to see the effect." rlm@212: [] rlm@212: (dorun rlm@212: (map #(println (Integer/toHexString %)) rlm@212: (capture-program-counter rlm@212: (prepare-memory (menu-open-state)) rlm@212: 9000000)))) rlm@233: rlm@233: (defn trampoline-assembly [^SaveState state] rlm@233: (flatten rlm@233: [0x3E ;; rlm@233: 0x3E ;; load lemonade into A rlm@233: rlm@233: 0xEA rlm@233: 0x1D rlm@233: 0xD3 ;; set first item to lemonade rlm@233: rlm@233: 0xC3 ;; return control to the game via absolute junp. rlm@233: (read-map-function-address state) rlm@233: ])) rlm@233: rlm@233: (defn test-trampoline rlm@233: "Demonstrates item-program execution via the map-function that rlm@233: returns control to the main pokemon game after one loop." rlm@233: [] rlm@233: (let [insertion-address 0xD33D rlm@233: insertion-address-bits [0x3D 0xD3]] rlm@233: (-> rlm@233: (menu-open-state) rlm@233: (set-memory-range rlm@233: insertion-address rlm@233: (trampoline-assembly (menu-open-state))) rlm@233: (set-memory-range rlm@233: memory-function-address-start rlm@233: insertion-address-bits))))