(local lume (require :lib.lume)) (local map (require :game.tilemap)) (local tileset (require :game.tiles)) (local state (require :game.state)) (local helpers (require :game.helpers)) (local Rules {}) (local tetrominoes {:O [["##" "##"]] :L [["###" "# "] ["# " "# " "##"] [" #" "###"] ["##" " #" " #"]] :J [["###" " #"] ["##" "# " "# "] ["# " "###"] [" #" " #" "##"]] :I [["####"] ["#" "#" "#" "#"]] :S [[" ##" "## "] ["# " "##" " #"]] :Z [["## " " ##"] [" #" "##" "# "]] :T [["###" " # "] ["# " "##" "# "] [" # " "###"] [" #" "##" " #"]]}) (fn Rules.choose-random-tetromino [] (let [possible-values (icollect [k (pairs state.tetrominoes)] k) ivalue (love.math.random (length possible-values))] (. possible-values ivalue))) (fn Rules.tetromino [k irotation] (let [rotations (or (. state.tetrominoes k) []) irotation (+ (% (- irotation 1) (length rotations)) 1)] (. rotations irotation))) (fn Rules.reset-game [] (set state.tetrominoes tetrominoes) (set state.well (map.new-tilemap 12 21)) (for [y 0 19] (map.set-itile-at 0 y state.well "X") (map.set-itile-at 11 y state.well "X")) (for [x 0 11] (map.set-itile-at x 20 state.well "X")) (set state.drop-speed-ms 750) (Rules.play-next-piece)) (fn Rules.play-next-piece [] (let [piece (or state.next-piece (Rules.choose-random-tetromino)) x (math.floor (/ (- (length (. state.well 1)) 2) 2))] (set state.current {: piece : x :y 0 :irotation 1}) (set state.next-piece (Rules.choose-random-tetromino)))) (fn Rules.current-tetromino [] (when state.current (Rules.tetromino state.current.piece state.current.irotation))) (fn solid-positions [tetromino ?x ?y] (let [h (length tetromino) w (length (. tetromino 1)) x (or ?x 0) y (or ?y 0)] (icollect [tx ty (helpers.all-coordinates w h)] (let [itile (map.itile-at tx ty tetromino)] (when (not= itile " ") [(+ x tx) (+ y ty) itile]))))) (fn Rules.collides? [tetromino x y] (var collides false) (when tetromino (each [_ [wx wy] (ipairs (solid-positions tetromino x y)) :until collides] (set collides (not= (map.itile-at wx wy state.well) " ")))) collides) (fn Rules.place-piece [tetromino x y] (each [_ [wx wy itile] (ipairs (solid-positions tetromino x y))] (map.set-itile-at wx wy state.well itile))) (fn Rules.try-move-piece [dx dy] (when state.current (let [tetromino (Rules.current-tetromino) x (+ state.current.x dx) y (+ state.current.y dy) stopped (Rules.collides? tetromino x y)] (if (and stopped (not= dy 0)) ; dropping (do (Rules.place-piece tetromino state.current.x state.current.y) (Rules.play-next-piece)) (not stopped) (do (set state.current.x x) (set state.current.y y)))))) (fn Rules.rotate [di] (when state.current (set state.current.irotation (+ state.current.irotation di)))) (set Rules.commands {:move Rules.try-move-piece :rotate Rules.rotate :reset Rules.reset-game}) (set Rules.keymap {:left [:move -1 0] :right [:move 1 0] :down [:move 0 1] :up [:rotate 1] :z [:rotate -1] :x [:rotate 1] :r [:reset]}) (fn Rules.run-command [cmd] (when cmd (let [[command & args] cmd f (. Rules.commands command)] (when f (f (table.unpack args)))))) (fn Rules.keypressed [key] (Rules.run-command (. Rules.keymap key))) (fn Rules.update [dt] (let [drop-ms (- (or state.drop-ms state.drop-speed-ms) (* dt 1000))] (if (<= drop-ms 0) (do (set state.drop-ms nil) (Rules.try-move-piece 0 1)) (set state.drop-ms drop-ms)))) Rules