diff clojure/com/aurellem/gb/vbm.clj @ 145:412ca096a9ba

major refactoring complete.
author Robert McIntyre <rlm@mit.edu>
date Mon, 19 Mar 2012 21:23:46 -0500
parents
children b7f682bb3090
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/clojure/com/aurellem/gb/vbm.clj	Mon Mar 19 21:23:46 2012 -0500
     1.3 @@ -0,0 +1,127 @@
     1.4 +(ns com.aurellem.gb.vbm
     1.5 +  (:import java.io.File)
     1.6 +  (:import org.apache.commons.io.FileUtils)
     1.7 +  (:use com.aurellem.gb.gb-driver))
     1.8 +
     1.9 +;;;;;;;;;;;;; read vbm file 
    1.10 +
    1.11 +(def ^:dynamic *moves-cache*
    1.12 +     (File. user-home "proj/pokemon-escape/moves/"))
    1.13 +
    1.14 +(defn buttons [mask]
    1.15 +  (loop [buttons []
    1.16 +         masks (seq (dissoc button-code :listen))]
    1.17 +    (if (empty? masks) buttons
    1.18 +        (let [[button value] (first masks)]
    1.19 +          (if (not= 0x0000 (bit-and value mask))
    1.20 +            (recur (conj buttons button) (rest masks))
    1.21 +            (recur buttons (rest masks)))))))
    1.22 +
    1.23 +(defn vbm-bytes [#^File vbm]
    1.24 +  (let [bytes (FileUtils/readFileToByteArray vbm)
    1.25 +        ints (int-array (count bytes))]
    1.26 +    (areduce bytes idx _ nil
    1.27 +             (aset ints idx
    1.28 +                   (bit-and 0xFF (aget bytes idx))))
    1.29 +    ints))
    1.30 +
    1.31 +(def vbm-header-length 255)
    1.32 +
    1.33 +(defn repair-vbm
    1.34 +  "Two 0's must be inserted after every reset."
    1.35 +  [vbm-masks]
    1.36 +  (loop [fixed []
    1.37 +         pending vbm-masks]
    1.38 +    (if (empty? pending) fixed
    1.39 +        (let [mask (first pending)]
    1.40 +          (if (not= 0x0000 (bit-and mask (button-code :restart)))
    1.41 +            (recur (conj fixed mask 0x0000 0x0000) (next pending))
    1.42 +            (recur (conj fixed mask) (next pending)))))))
    1.43 +
    1.44 +(defn vbm-masks [#^File vbm]
    1.45 +  (repair-vbm
    1.46 +   (map (fn [[a b]]
    1.47 +          (+ (bit-shift-left a 8) b))
    1.48 +        (partition
    1.49 +         2 (drop vbm-header-length (vbm-bytes vbm))))))
    1.50 +
    1.51 +(defn vbm-buttons [#^File vbm]
    1.52 +  (map buttons (vbm-masks vbm)))
    1.53 +
    1.54 +(defn convert-buttons
    1.55 +  "To write a vbm file, we must remove the last two buttons after any
    1.56 +   reset event."
    1.57 +  [buttons]
    1.58 +  (loop [fixed []
    1.59 +         pending buttons]
    1.60 +    (if (empty? pending) fixed
    1.61 +        (let [mask (first pending)]
    1.62 +          (if (contains? (set (first pending)) :reset)
    1.63 +            (recur (conj fixed mask) (drop 3 pending))
    1.64 +            (recur (conj fixed mask) (next pending)))))))
    1.65 +
    1.66 +(defn moves->filename [frame]
    1.67 +  (File. *moves-cache* (format "%07d.vbm" frame)))
    1.68 +
    1.69 +(defn read-moves [frame]
    1.70 +  (let [target (moves->filename frame)]
    1.71 +    (if (.exists target)
    1.72 +      (vbm-buttons target))))
    1.73 +;;;;;;;;;;;;;; write moves to vbm file
    1.74 +
    1.75 +
    1.76 +(def vbm-header
    1.77 +  (byte-array
    1.78 +   (map
    1.79 +    byte
    1.80 +    [86 66 77 26 1 0 0 0 105 74 88 79 89 1 0 0 0 0 0 0 0 1 2 112 0 0 0
    1.81 +     0 0 0 0 0 1 0 0 0 80 79 75 69 77 79 78 32 89 69 76 76 1 -105 124 4
    1.82 +     3 0 0 0 0 0 0 0 0 1 0 0 95 95 95 95 95 95 95 95 95 95 95 95 95 95
    1.83 +     95 95 82 111 98 101 114 116 32 32 77 99 73 110 116 121 114 101 95
    1.84 +     95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95
    1.85 +     95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95
    1.86 +     95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95
    1.87 +     95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95
    1.88 +     95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95
    1.89 +     95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95
    1.90 +     95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95
    1.91 +     95 95 95 95])))
    1.92 +
    1.93 +(def vbm-trailer
    1.94 +  (byte-array
    1.95 +   (map byte [0])))
    1.96 +
    1.97 +(defn buttons->vbm-bytes [buttons]
    1.98 +  (let [bytes-in-ints
    1.99 +        (map button-mask (convert-buttons buttons))
   1.100 +        high-bits (map #(bit-shift-right (bit-and 0xFF00 %) 8)
   1.101 +                       bytes-in-ints)
   1.102 +        low-bits (map #(bit-and 0xFF %) bytes-in-ints)
   1.103 +        convert-byte (fn [i] (byte (if (>= i 128) (- i 256) i)))
   1.104 +        contents
   1.105 +        (byte-array
   1.106 +         (concat
   1.107 +          vbm-header
   1.108 +          (map convert-byte (interleave high-bits low-bits))
   1.109 +          vbm-trailer))]
   1.110 +    contents))
   1.111 +        
   1.112 +(defn write-moves! [moves]
   1.113 +  (let [target (moves->filename (count moves))]
   1.114 +    (clojure.java.io/copy (buttons->vbm-bytes moves) target)
   1.115 +    target))
   1.116 +
   1.117 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.118 +
   1.119 +(use 'clojure.java.shell)
   1.120 +
   1.121 +(def vba-linux (File. user-home "bin/vba-linux"))
   1.122 +
   1.123 +(defn play-vbm [#^File vbm]
   1.124 +  (.delete yellow-save-file)
   1.125 +  (if (.exists vbm)
   1.126 +    (sh (.getCanonicalPath vba-linux)
   1.127 +        (str "--playmovie=" (.getCanonicalPath vbm))
   1.128 +        (.getCanonicalPath yellow-rom-image)))
   1.129 +  nil)
   1.130 +