rlm@60: (ns com.aurellem.gb-driver rlm@60: (:import com.aurellem.gb.Gb) rlm@65: (:import java.io.File) rlm@60: (:import (java.nio IntBuffer ByteOrder))) rlm@48: rlm@66: (Gb/loadVBA) rlm@65: rlm@65: (def yellow-rom-image rlm@65: (File. "/home/r/proj/pokemon-escape/roms/yellow.gbc")) rlm@65: rlm@67: (def yellow-save-file rlm@67: (File. "/home/r/proj/pokemon-escape/roms/yellow.sav")) rlm@67: rlm@73: (def current-frame (atom 0)) rlm@73: rlm@62: (defn vba-init [] rlm@73: (reset! current-frame 0) rlm@67: (.delete yellow-save-file) rlm@70: (Gb/startEmulator (.getCanonicalPath yellow-rom-image))) rlm@60: rlm@71: (defn shutdown [] (Gb/shutdown)) rlm@71: rlm@71: (defn reset [] (shutdown) (vba-init)) rlm@71: rlm@64: (defn cpu-data [size arr-fn] rlm@64: (let [store (int-array size)] rlm@64: (fn [] rlm@64: (arr-fn store) rlm@64: store))) rlm@60: rlm@64: (def ram rlm@64: (cpu-data (Gb/getRAMSize) #(Gb/getRAM %))) rlm@61: rlm@64: (def rom rlm@64: (cpu-data (Gb/getROMSize) #(Gb/getROM %))) rlm@61: rlm@64: (def working-ram rlm@64: (cpu-data Gb/WRAM_SIZE #(Gb/getWRAM %))) rlm@62: rlm@64: (def video-ram rlm@64: (cpu-data Gb/VRAM_SIZE #(Gb/getVRAM %))) rlm@64: rlm@64: (def registers rlm@64: (cpu-data Gb/NUM_REGISTERS #(Gb/getRegisters %))) rlm@64: rlm@71: (def button-code rlm@71: {;; main buttons rlm@71: :a 0x0001 rlm@71: :b 0x0002 rlm@71: rlm@71: ;; directional pad rlm@71: :r 0x0010 rlm@71: :l 0x0020 rlm@71: :u 0x0040 rlm@71: :d 0x0080 rlm@71: rlm@71: ;; meta buttons rlm@71: :select 0x0004 rlm@71: :start 0x0008 rlm@71: rlm@71: ;; hard reset -- not really a button rlm@71: :reset 0x0800}) rlm@71: rlm@71: (defn button-mask [buttons] rlm@71: (reduce bit-or 0x0000 (map button-code buttons))) rlm@71: rlm@71: (defn buttons [mask] rlm@71: (loop [buttons [] rlm@71: masks (seq button-code)] rlm@71: (if (empty? masks) buttons rlm@71: (let [[button value] (first masks)] rlm@71: (if (not= 0x0000 (bit-and value mask)) rlm@71: (recur (conj buttons button) (rest masks)) rlm@71: (recur buttons (rest masks))))))) rlm@71: rlm@73: rlm@73: (defn save-state [] (Gb/saveState)) rlm@73: rlm@73: (def history (atom {})) rlm@73: rlm@73: (defn goto [frame] rlm@73: (let [save (@history frame)] rlm@73: (if (not (nil? save)) rlm@73: (do rlm@73: (reset! current-frame frame) rlm@73: (Gb/loadState save)) rlm@73: (println "no backup state")))) rlm@73: rlm@73: (defn clear-history [] (reset! history {})) rlm@73: rlm@74: (defn rewind rlm@74: ([n] (goto (- @current-frame n))) rlm@74: ([] (rewind 1))) rlm@73: rlm@73: (defn backup-state [frame] rlm@73: (swap! history #(assoc % frame (save-state)))) rlm@73: rlm@73: (def ^:dynamic *save-history* true) rlm@73: rlm@73: (defn advance [] rlm@75: (swap! current-frame inc) rlm@75: (if *save-history* rlm@75: (let [save (save-state)] rlm@75: (backup-state @current-frame)))) rlm@73: rlm@65: (defn step rlm@73: ([] (advance) (Gb/step)) rlm@71: ([mask-or-buttons] rlm@73: (advance) rlm@71: (if (number? mask-or-buttons) rlm@71: (Gb/step mask-or-buttons) rlm@71: (Gb/step (button-mask mask-or-buttons))))) rlm@73: rlm@75: (defn step! [& args] rlm@75: (binding [*save-history* false] rlm@75: (apply step args))) rlm@75: rlm@73: (defn frame [] @current-frame) rlm@73: rlm@73: