diff --git a/game/mode.fnl b/game/mode.fnl index 6841292..1609a2f 100644 --- a/game/mode.fnl +++ b/game/mode.fnl @@ -6,18 +6,18 @@ (local dim (require :game.dim)) (local {: draw : update} (util.require :game.entity)) -(fn game-update [dt]) - -(fn exception-update [dt] +(fn exception-update [] (when (love.keyboard.isDown :f2) (set state.update-exception nil))) -(fn update [dt] +(fn wrap-call [thunk] (if state.update-exception - (exception-update dt) - (xpcall #(game-update dt) (fn [msg] + (exception-update) + (xpcall thunk (fn [msg] (set state.update-exception (.. msg "\n" (debug.traceback))))))) +(fn update [dt] (wrap-call #(rules.update dt))) + (fn game-draw [] (let [xnext (/ dim.tilesize 2) xwell (* dim.tilesize 5) @@ -37,5 +37,10 @@ (exception-draw) (game-draw))) -{: update : draw} +(fn handler [ev ...] + (let [f (. rules ev) + args [...]] + (when f (wrap-call #(f (table.unpack args)))))) + +{: update : draw : handler} diff --git a/game/rules.fnl b/game/rules.fnl index 1057074..76fe437 100644 --- a/game/rules.fnl +++ b/game/rules.fnl @@ -2,6 +2,7 @@ (local map (require :game.tilemap)) (local tileset (require :game.tiles)) (local state (require :game.state)) +(local helpers (require :game.helpers)) (local Rules {}) @@ -78,7 +79,7 @@ (. possible-values ivalue))) (fn Rules.tetromino [k irotation] - (let [rotations (or (. state.tetrominoes k) [["##" "##"]]) + (let [rotations (or (. state.tetrominoes k) []) irotation (+ (% (- irotation 1) (length rotations)) 1)] (. rotations irotation))) @@ -90,12 +91,12 @@ (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-ms 750) + (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 (/ (- (length (. state.well 1)) 2) 2)] + 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)))) @@ -103,5 +104,73 @@ (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 diff --git a/lib/lume.lua b/lib/lume.lua index 2157891..48c7a68 100644 --- a/lib/lume.lua +++ b/lib/lume.lua @@ -689,7 +689,7 @@ function lume.hotswap(modname) local oldglobal = lume.clone(_G) local updated = {} local function update(old, new) - if updated[old] then return end + if old == nil or updated[old] then return end updated[old] = true local oldmt, newmt = getmetatable(old), getmetatable(new) if oldmt and newmt then update(oldmt, newmt) end