From fdf69b8b11cd6ae0a01c38bbd2425b887154eeac Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Sat, 24 Apr 2021 23:39:50 -0400 Subject: [PATCH] Fix codegen, implement 8bitsy dialog editor --- 8Bitsy.dsk | Bin 143360 -> 143360 bytes asm/asm.fnl | 3 +- editor/8bitsy.fnl | 29 ++++++++++++++++ editor/actions.fnl | 7 ++++ editor/init.fnl | 2 ++ editor/mapedit.fnl | 3 +- game/content.fnl | 7 +--- game/defs.fnl | 24 +++++++++---- game/entity.fnl | 8 ++--- game/files.fnl | 24 +++++++++++-- game/game.json | 2 +- game/init.fnl | 3 +- game/tiles.fnl | 51 ++++++---------------------- lib/fennel.lua | 82 ++++++++++++++++++++++----------------------- 14 files changed, 139 insertions(+), 106 deletions(-) create mode 100644 editor/8bitsy.fnl diff --git a/8Bitsy.dsk b/8Bitsy.dsk index 4b8f8c73839df89a02f62522a3068f558c1d97ce..06c53d67e5b919e5df27af14e35ff37f7bef9503 100644 GIT binary patch delta 627 zcmZp8z|ru4W5Y2H#_yYtbL{kD^qbrmY{uxfc}K7Z6QlQL#<1Uvj0}_ihJR%A+5A2t zk6GZmfC(>yg9&e-ppak`kI&`JxiL(Pj{nYBhonTg8=3uMGp*)tEHvq2d&Rt|@x8(M zm&*gBwV7_3xpD1`U%4!E%_OchLK{EJ^_xyV;UyQie2qlaeku0~rp+5-r!ZPNI503U zT)Fb*&6_I?Ko$cN6C)$zs#V*zZCeHAGcb5)0D*@FND>TKSb>0rbuuH9*yiB)T*gI- z9QAzcSpgtP7WU;}numD}nC52Q2&TE1w}EM1=G|bLkNE(Y_Eh&(aP(7f3<&UX)dLw2 z91`T{=kBVb5a}PP;N$P_t>EM7?W*9Y;OrOzR-mB4BkE_uYZ0L5WWwtfUD9EK5tD}8PJ*tWGYDVC|K~U;0Ff2 ze}muAfbG0*10d|bye59zc^?ME@_6cA;CL6jkEu5Z7#yOLMYDg^H+XhCg6-H3w3opP ziPHe#oaAL-0J_7`&qQFQ+YKkM+NT2ge&2aaco`WO`1Jiac~81c7ia@H6{YHl>-Y}O8Q;!dr5K&zFz|4=t*pGP3k74w zV7CqO!M=x2lG?~X(~aHo>Y3;DTieI44Rua$GMjpT!_D05)3FO3r|R0feq0*bUY)Jq zzds+S-N`*&_ErVoGP7S2M~qC*BdB+9rG|cS5Kfj2L(fz%9S^%eAfkm?US^e0izxG< zPF7V&wbQ58v$7KQi?YCKs;^n(gRI{d^0@$8i)e|%D@v31jW>_h4-usv)T%5bpddi$ zyQ9&xI@(JhTZLFRdR0nJloL{~8lS@t)IZ4{=A=11toEQ`hxyE5ejO93+!nhw-Jdx& z=rEHGGv%z@C^2*N1~PM0dfy$*Hl|SaY|5GCQ}(Qovb&2xbp2>u=@doAGAo~$9c&Fo zoetAgV!DtSojNh0EzMM#;z^>TEya@|XOUL{pi!|GUA7{k7Ohx9acaKqDCD>horNgY zNG#7b^WnT76~qO%<${2$hD;n4h?lLR<_AKEygaR%(Ao%%!+lB%F;9piFIy0^n?rigC7elDUUSt3d81-Es67-;xsKdH}i! eXAX}@7N?dBE;7Y9DUktVV&J;%PV8k2zW)twa{WO7 diff --git a/asm/asm.fnl b/asm/asm.fnl index 1dc4595..cddd9f8 100644 --- a/asm/asm.fnl +++ b/asm/asm.fnl @@ -179,7 +179,7 @@ (fn process-pdat [pdat process default ...] (fn complain [ok ...] (if ok (values ...) - (do (pp pdat) (error (.. process " failed in " pdat.type " near " (or pdat.nearest-symbol "") " @" (or pdat.addr "") " - " ...))))) + (do (error (.. process " failed in " pdat.type " near " (or pdat.nearest-symbol "") " @" (or pdat.addr "") " - " ...))))) (local processor (. pdat-processor pdat.type process)) (if processor (complain (pcall #(processor pdat $...) ...)) default)) @@ -256,7 +256,6 @@ (local block-env (make-env block env)) (var bytes "") (each [_ pdat (ipairs block.pdats)] - (print pdat.type pdat.addr pdat.nearest-symbol) (process-pdat pdat :generate nil block-env) (local pdatbytes (process-pdat pdat :bytes pdat.bytes block-env)) (assert (= (type pdatbytes) :string) (.. "failed to generate bytes: " (fv pdat))) diff --git a/editor/8bitsy.fnl b/editor/8bitsy.fnl new file mode 100644 index 0000000..57449ce --- /dev/null +++ b/editor/8bitsy.fnl @@ -0,0 +1,29 @@ +(local util (require :lib.util)) +(local actions (require :editor.actions)) +(local {: textbox : dropdown } (util.require :editor.imstate)) +(local files (require :game.files)) +(local lume (require :lib.lume)) +(local style (require :core.style)) + +(actions.register :say + (fn [action view x y w i] + (let [characters (lume.map files.game.portraits #$1.label) + character (or action.character (. characters 1)) + lines (or action.lines []) + (character y) (dropdown view [:say :char i] character characters x (+ y style.padding.y) 300) + (line1 y) (textbox view [:say :line1 i] (. lines 1) x (+ y style.padding.y) 300) + (line2 y) (textbox view [:say :line2 i] (. lines 2) x y 300) + (line3 y) (textbox view [:say :line3 i] (. lines 3) x y 300) + (line4 y) (textbox view [:say :line4 i] (. lines 4) x y 300) + ] + (set action.character character) + (util.nested-tset action [:lines 1] line1) + (util.nested-tset action [:lines 2] line2) + (util.nested-tset action [:lines 3] line3) + (util.nested-tset action [:lines 4] line4) + y)) + (fn [action vm] + (local {: say} (require :game.defs)) + (say action.character (table.unpack (lume.map action.lines #($1:upper)))))) + +{} diff --git a/editor/actions.fnl b/editor/actions.fnl index 1878648..f8a174e 100644 --- a/editor/actions.fnl +++ b/editor/actions.fnl @@ -9,4 +9,11 @@ (defmethod actions.edit :default (fn [action view x y w i] y)) +(fn actions.register [key edit generate] + (when (= actions.actionlist nil) + (set actions.actionlist [])) + (table.insert actions.actionlist key) + (defmethod actions.edit key edit) + (defmethod actions.generate key generate)) + actions.hot diff --git a/editor/init.fnl b/editor/init.fnl index 6af9d3c..f4dc184 100644 --- a/editor/init.fnl +++ b/editor/init.fnl @@ -9,6 +9,8 @@ (local keymap (require :core.keymap)) (local common (require :core.common)) +(require :editor.8bitsy) + (let [commands {}] (each [_ name (ipairs [:tile :portrait :font :brush :map])] (local cls (require (.. "editor." name "edit"))) diff --git a/editor/mapedit.fnl b/editor/mapedit.fnl index 1a4fe79..814c058 100644 --- a/editor/mapedit.fnl +++ b/editor/mapedit.fnl @@ -104,6 +104,7 @@ (fn MapEditView.draw-map-editor [self x y] (love.graphics.setColor 1 1 1 1) + (local button-state self.imstate.left) (activate self :map x y (* tilew mapw) (* tileh maph)) (var iobject-over nil) (for [my 1 maph] @@ -130,7 +131,7 @@ (when (and self.itile (active? self :map) (mouse-inside tilex tiley tilew tileh) (not= itile self.itile)) (self:set-tile mx my self.itile)) (when (and (= self.itile nil) (active? self :map) (mouse-inside tilex tiley tilew tileh)) - (match self.imstate.left + (match button-state :pressed (set self.iobject-linking iobject) :released (if (and (not= iobject nil) (= self.iobject-linking iobject)) diff --git a/game/content.fnl b/game/content.fnl index 6423d69..fc08522 100644 --- a/game/content.fnl +++ b/game/content.fnl @@ -1,9 +1,4 @@ ; TODO: Generate from data? (local {: vm : say : deflevel} (require :game.defs)) -(deflevel "game/map1.json" :map1) -(vm:word :cat (say :cat "I'M A CAT")) -(vm:word :fish (say :angryfish "I'M AN ANGRY FISH" "GRRRR")) -(vm:word :pot (say :player "IT'S A POT.") (say :player "NOTHING UNUSUAL ABOUT IT.") (say :player "JUST AN ORDINARY POT.")) -(vm:word :suspiciouspot (say :player "IT'S A POT.") (say :player "NOTHING UNUSUAL ABOUT IT.") (say :player "JUST AN ORDINARY POT.") (say :player "YEP, NOTHING SPECIAL HERE.")) - +(deflevel 1 :map1) diff --git a/game/defs.fnl b/game/defs.fnl index 6f0d78c..f14e790 100644 --- a/game/defs.fnl +++ b/game/defs.fnl @@ -4,7 +4,9 @@ (local asm (require :asm.asm)) (local VM (require :asm.vm)) (local tiles (require :game.tiles)) +(local files (require :game.files)) (local Prodos (require :asm.prodos)) +(local actions (require :editor.actions)) (local prg (asm.new)) (local vm (VM.new prg {:org 0xc00})) @@ -123,7 +125,7 @@ (fn append-map [map org label] (org:append [:align 0x100] label - [:bytes (map.map:fromhex)] + [:bytes map.map] [:db (length map.objects)] [:dw (tiles.encode-yx map.player)] [:jmp (if (= (or map.tickword "") "") :next map.tickword)] @@ -138,18 +140,27 @@ (vm:word :map-specific-move :map 246 :+ :execute) (vm:word :map-specific-load :map 249 :+ :execute) -(fn deflevel [mapfile label] +(fn generate-entity-code [level vm prefix] + (each [ientity entity (ipairs level.objects)] + (when (not entity.advanced) + (let [code []] + (each [iaction action (ipairs (or entity.steps []))] + (lume.push code (actions.generate action vm iaction))) + (vm:word (.. prefix ientity) (table.unpack code)))))) + +(fn deflevel [ilevel label] (local level prg) ; todo: (asm.new prg) - if we want to load levels as an overlay (local org level.vm.code) ; (level:org org.level.org) - if we want to give level data a stable loxation - (local map (readjson mapfile)) + (local map (. files.game.levels ilevel)) (local entity (require :game.entity)) (append-map map org label) (entity.append-from-map map org label) (set level.vm.code org) + (generate-entity-code map level.vm (.. label "-entity-word-")) level) (fn say-runon [portrait ...] - (local result [:vm (.. :draw-p portrait)]) + (local result [:vm (.. :draw-portrait- portrait)]) (local lines [...]) (local ilineOffset (if (< (length lines) 4) 1 0)) (each [iline line (ipairs lines)] @@ -161,10 +172,9 @@ (table.insert result :dismiss-dialog) result) -(local tilelist (tiles.loadgfx tiles.fn-tiles)) -(fn itile [label] (tiles.find-itile tilelist label)) +(fn itile [label] (tiles.find-itile files.game.tiles label)) (set vm.code org.code) -{: vm : prg : mapw : maph : mon : org : achar : astr : style : rot8l : deflevel : say : say-runon : itile : tilelist} +{: vm : prg : mapw : maph : mon : org : achar : astr : style : rot8l : deflevel : say : say-runon : itile} diff --git a/game/entity.fnl b/game/entity.fnl index 364771f..d4da123 100644 --- a/game/entity.fnl +++ b/game/entity.fnl @@ -100,10 +100,10 @@ (entity-org:append (.. prefix "-entity-" ientity) [:db (- entity.x 1)] [:db (- entity.y 1)] - [:ref entity.func] - (if (and entity.linkword (> (length entity.linkword) 0)) [:ref entity.linkword] [:dw 0]) - (if entity.link [:ref (.. prefix "-entity-" entity.link)] - entity.linkentity [:ref entity.linkentity] + [:ref (if entity.advanced entity.func (.. prefix "-entity-word-" ientity))] + (if (and entity.advanced entity.linkword (> (length entity.linkword) 0)) [:ref entity.linkword] [:dw 0]) + (if entity.link [:ref (.. prefix "-entity-" entity.link)] + (and entity.advanced entity.linkentity) [:ref entity.linkentity] [:dw 0])))) {: ev : append-from-map} diff --git a/game/files.fnl b/game/files.fnl index 9c40a4b..a07dc4c 100644 --- a/game/files.fnl +++ b/game/files.fnl @@ -1,21 +1,39 @@ (local util (require :lib.util)) (local lume (require :lib.lume)) -(local tile (require :game.tiles)) (local tiledraw (require :editor.tiledraw)) (local files (util.hot-table ...)) (local filename "game/game.json") + +(local encoded-tile-fields [:gfx :mask]) +(fn convert [tile field method] + (local oldval (. tile field)) + (when oldval + (tset tile field (: oldval method))) + tile) +(fn convert-all [tile method] + (each [_ field (ipairs encoded-tile-fields)] + (convert tile field method)) + tile) + +(fn tile-deserialize [tile] + (match (type tile) + :string {:gfx (tile:fromhex) :flags {}} + :table (convert-all tile :fromhex))) + +(fn tile-serialize [tile] (convert-all (lume.clone tile) :tohex)) + (fn deserialize [key value] (match key - (where (or :tiles :portraits :font)) (tile.deserialize value) + (where (or :tiles :portraits :font)) (tile-deserialize value) :levels (do (set value.map (value.map:fromhex)) value) _ value)) (fn serialize [key value] (match key - (where (or :tiles :portraits :font)) (tile.serialize value) + (where (or :tiles :portraits :font)) (tile-serialize value) :levels (do (set value.map (value.map:tohex)) value) _ value)) diff --git a/game/game.json b/game/game.json index 343751c..b24f435 100644 --- a/game/game.json +++ b/game/game.json @@ -1 +1 @@ -{"tiles":[{"gfx":"8080808080808080808080808080808080808080808080808080808080808080","word":"","label":"","flags":{"walkable":true}},{"gfx":"8080C0C0C0C0E0F0F8FCE6E6E0B0B0B0808183838383878F9FBFE7E7868C8C8C","word":"","label":"player-frame1","flags":[]},{"gfx":"8080808084CCFCFCFCFCFCF8F0B0B0B080808080E1E1E1F1B99F9F8F8F8C8C8C","word":"","label":"","flags":[]},{"gfx":"D5D5D5858585A5A5A5A5858585D5D5D5AAAAAAA8A8A8A9A9A9A9A8A8A8AAAAAA","word":"","label":"","flags":[]},{"gfx":"8080D4D0D0D0D4D45454D4D4D4D0808080808A8282828A8A8A0A0A8A8A828080","word":"pot","label":"","flags":[]},{"gfx":"8080808080D490948484A48494D080808080808080AA88A8A0A5A5A0A88A8080","word":"","label":"","flags":[]},{"gfx":"8080D4D0D0D0D4D45454D4D4D4D0808080808A8282828A8A8A0A0A8A8A828080","word":"","label":"","flags":[]},{"gfx":"000000A0908884827E0A0A0A0000000000000000201008040785858500000000","word":"","label":"","flags":[]},{"gfx":"000014040414500000000000A888A8800000282020280A010101010195919580","word":"","label":"","flags":[]},{"gfx":"00008C92921C60105010781C0E070300000098A4A41C030504050F1C38706000","word":"","label":"","flags":[]},{"gfx":"000000004040000000D4D4ECECECD480000000000202010101AAAAB6B6B6AA80","word":"","label":"","flags":[]},{"gfx":"0000000000004828282828482800000000000000000004050505050405000000","word":"","label":"","flags":[]}],"levels":[{"loadword":"","map":"000000000000000000000000000000000000000000606060606060606060606060606060606060000060000000000000000000000000000000006000006000000000000000000000000000000000600000600000A00000000000000000004000000060000060000000000000000000000000000000006000006000000000000000000000000000000000600000600000000000000000000000000000000060000060000000000000000080808080800000006000006000000000000000000000000000000000600000606060606060606060606060606060606060000000000000000000000000000000000000000000","player":{"y":4,"x":5},"tickword":"","moveword":"","objects":[{"x":15,"linkentity":"","func":"cat","y":8,"linkword":"","name":""},{"x":5,"linkentity":"","func":"fish","linkword":"","name":"","y":8},{"x":13,"linkentity":"","func":"pot","linkword":"","name":"","y":4},{"x":12,"linkentity":"","func":"suspiciouspot","name":"","linkword":"","y":4},{"x":11,"linkentity":"","func":"pot","name":"","linkword":"","y":4},{"x":14,"linkentity":"","func":"pot","name":"","linkword":"","y":4},{"x":15,"linkentity":"","func":"pot","name":"","linkword":"","y":4}]}],"portraits":[{"gfx":"000000000000000000000000000000000000007C7C7E7E7E7E7E7E7E7E7E7E7E00000000707F7F7F7F7F7F7F7F7F7F7F7E7E7E7E7F7F7F7F7F7F7F7F7F7F7F7F0000000F0F1F1F1F1F1F1F1F1F1F1F1F000000000000000000000000000000001F1F1F1F7F7F7F7F7F7F7F7F7F7F7F7F00000000077F7F7F7F7F7F7F7F7F7F7F","label":"pplayer","flags":[]},{"gfx":"00000000004040606060707070707070000000000000010103037F7F7F7F7F7F707060604000000000000000000000007F7F7F7F7F7F7800004040406060606000000000001018383C3C7F7F7F7F7F7F000000000000000000000000000000007F7F7F3F0F67717C7F7F7F7F7F7F7F7F00007C7E7F7F7F7F7F7F7F7F7F7F7F7F","label":"pcat","flags":[]},{"gfx":"80808080808080808080D5818181858480808080808080808080AA80808080808484848484A4848484A48484848494D0809090D0D4F5D5D5D5D5D480808080AA80808080808080808080D5808080808080808080808080808080AAA0A0A0A888808080808AA8AAAAAA828080808080D588888888888889898888888888888A82","label":"pangryfish","flags":[]}],"font":[{"flags":[],"gfx":"0000000000000000"},{"flags":[],"gfx":"081C1C1C08000800"},{"flags":[],"gfx":"3636241200000000"},{"flags":[],"gfx":"123F1212123F1200"},{"flags":[],"gfx":"083C0A1C281E0800"},{"flags":[],"gfx":"0026160834320000"},{"flags":[],"gfx":"0E1B1B062F1B3600"},{"flags":[],"gfx":"0C0C080400000000"},{"flags":[],"gfx":"180C0606060C1800"},{"flags":[],"gfx":"0C18303030180C00"},{"flags":[],"gfx":"082A1C081C2A0800"},{"flags":[],"gfx":"000C0C3F3F0C0C00"},{"flags":[],"gfx":"000000000C0C0804"},{"flags":[],"gfx":"0000001E1E000000"},{"flags":[],"gfx":"00000000000C0C00"},{"flags":[],"gfx":"002030180C060200"},{"flags":[],"gfx":"1C26263E26261C00"},{"flags":[],"gfx":"181C181818183C00"},{"flags":[],"gfx":"1C2620180C063E00"},{"flags":[],"gfx":"1C26201820261C00"},{"flags":[],"gfx":"2626263C30303000"},{"flags":[],"gfx":"3E061E2020201E00"},{"flags":[],"gfx":"1C26061E26261C00"},{"flags":[],"gfx":"3E2630180C0C0C00"},{"flags":[],"gfx":"1C26261C26261C00"},{"flags":[],"gfx":"1C26263C20201C00"},{"flags":[],"gfx":"000C0C000C0C0000"},{"flags":[],"gfx":"000C0C000C0C0804"},{"flags":[],"gfx":"30180C060C183000"},{"flags":[],"gfx":"00003E003E000000"},{"flags":[],"gfx":"060C1830180C0600"},{"flags":[],"gfx":"1C3630180C000C00"},{"flags":[],"gfx":"1E33212D3D011E00"},{"flags":[],"gfx":"1C3E26263E262600"},{"flags":[],"gfx":"1E26261E26261E00"},{"flags":[],"gfx":"1C26060606261C00"},{"flags":[],"gfx":"1E26262626261E00"},{"flags":[],"gfx":"3E06061E06063E00"},{"flags":[],"gfx":"3E06061E06060600"},{"flags":[],"gfx":"1C26063626263C00"},{"flags":[],"gfx":"2626263E26262600"},{"flags":[],"gfx":"3C18181818183C00"},{"flags":[],"gfx":"3C30303036361C00"},{"flags":[],"gfx":"2626261E26262600"},{"flags":[],"gfx":"0606060606063E00"},{"flags":[],"gfx":"373F2B2B23232300"},{"flags":[],"gfx":"26262E3626262600"},{"flags":[],"gfx":"1C26262626261C00"},{"flags":[],"gfx":"1E26261E06060600"},{"flags":[],"gfx":"1C26262626363C00"},{"flags":[],"gfx":"1E26261E26262600"},{"flags":[],"gfx":"3C26061C20221E00"},{"flags":[],"gfx":"3F0C0C0C0C0C0C00"},{"flags":[],"gfx":"2626262626261C00"},{"flags":[],"gfx":"2626261C1C1C0800"},{"flags":[],"gfx":"2323232B2B2A3600"},{"flags":[],"gfx":"2626261C26262600"},{"flags":[],"gfx":"2626261C18181800"},{"flags":[],"gfx":"3E3E30180C063E00"},{"flags":[],"gfx":"1C0C0C0C0C0C1C00"},{"flags":[],"gfx":"0002060C18302000"},{"flags":[],"gfx":"1C18181818181C00"},{"flags":[],"gfx":"081C260000000000"},{"flags":[],"gfx":"0000000000003E00"},{"flags":[],"gfx":"0C0C100000000000"}]} \ No newline at end of file +{"tiles":[{"gfx":"8080808080808080808080808080808080808080808080808080808080808080","word":"","label":"","flags":{"walkable":true}},{"gfx":"8080C0C0C0C0E0F0F8FCE6E6E0B0B0B0808183838383878F9FBFE7E7868C8C8C","word":"","label":"player-frame1","flags":[]},{"gfx":"8080808084CCFCFCFCFCFCF8F0B0B0B080808080E1E1E1F1B99F9F8F8F8C8C8C","word":"","label":"","flags":[]},{"gfx":"D5D5D5858585A5A5A5A5858585D5D5D5AAAAAAA8A8A8A9A9A9A9A8A8A8AAAAAA","word":"","label":"","flags":[]},{"gfx":"8080D4D0D0D0D4D45454D4D4D4D0808080808A8282828A8A8A0A0A8A8A828080","word":"pot","label":"","flags":[]},{"gfx":"8080808080D490948484A48494D080808080808080AA88A8A0A5A5A0A88A8080","word":"","label":"","flags":[]},{"gfx":"8080D4D0D0D0D4D45454D4D4D4D0808080808A8282828A8A8A0A0A8A8A828080","word":"","label":"","flags":[]},{"gfx":"000000A0908884827E0A0A0A0000000000000000201008040785858500000000","word":"","label":"","flags":[]},{"gfx":"000014040414500000000000A888A8800000282020280A010101010195919580","word":"","label":"","flags":[]},{"gfx":"00008C92921C60105010781C0E070300000098A4A41C030504050F1C38706000","word":"","label":"","flags":[]},{"gfx":"000000004040000000D4D4ECECECD480000000000202010101AAAAB6B6B6AA80","word":"","label":"","flags":[]},{"gfx":"0000000000004828282828482800000000000000000004050505050405000000","word":"","label":"","flags":[]}],"font":[{"flags":[],"gfx":"0000000000000000"},{"flags":[],"gfx":"081C1C1C08000800"},{"flags":[],"gfx":"3636241200000000"},{"flags":[],"gfx":"123F1212123F1200"},{"flags":[],"gfx":"083C0A1C281E0800"},{"flags":[],"gfx":"0026160834320000"},{"flags":[],"gfx":"0E1B1B062F1B3600"},{"flags":[],"gfx":"0C0C080400000000"},{"flags":[],"gfx":"180C0606060C1800"},{"flags":[],"gfx":"0C18303030180C00"},{"flags":[],"gfx":"082A1C081C2A0800"},{"flags":[],"gfx":"000C0C3F3F0C0C00"},{"flags":[],"gfx":"000000000C0C0804"},{"flags":[],"gfx":"0000001E1E000000"},{"flags":[],"gfx":"00000000000C0C00"},{"flags":[],"gfx":"002030180C060200"},{"flags":[],"gfx":"1C26263E26261C00"},{"flags":[],"gfx":"181C181818183C00"},{"flags":[],"gfx":"1C2620180C063E00"},{"flags":[],"gfx":"1C26201820261C00"},{"flags":[],"gfx":"2626263C30303000"},{"flags":[],"gfx":"3E061E2020201E00"},{"flags":[],"gfx":"1C26061E26261C00"},{"flags":[],"gfx":"3E2630180C0C0C00"},{"flags":[],"gfx":"1C26261C26261C00"},{"flags":[],"gfx":"1C26263C20201C00"},{"flags":[],"gfx":"000C0C000C0C0000"},{"flags":[],"gfx":"000C0C000C0C0804"},{"flags":[],"gfx":"30180C060C183000"},{"flags":[],"gfx":"00003E003E000000"},{"flags":[],"gfx":"060C1830180C0600"},{"flags":[],"gfx":"1C3630180C000C00"},{"flags":[],"gfx":"1E33212D3D011E00"},{"flags":[],"gfx":"1C3E26263E262600"},{"flags":[],"gfx":"1E26261E26261E00"},{"flags":[],"gfx":"1C26060606261C00"},{"flags":[],"gfx":"1E26262626261E00"},{"flags":[],"gfx":"3E06061E06063E00"},{"flags":[],"gfx":"3E06061E06060600"},{"flags":[],"gfx":"1C26063626263C00"},{"flags":[],"gfx":"2626263E26262600"},{"flags":[],"gfx":"3C18181818183C00"},{"flags":[],"gfx":"3C30303036361C00"},{"flags":[],"gfx":"2626261E26262600"},{"flags":[],"gfx":"0606060606063E00"},{"flags":[],"gfx":"373F2B2B23232300"},{"flags":[],"gfx":"26262E3626262600"},{"flags":[],"gfx":"1C26262626261C00"},{"flags":[],"gfx":"1E26261E06060600"},{"flags":[],"gfx":"1C26262626363C00"},{"flags":[],"gfx":"1E26261E26262600"},{"flags":[],"gfx":"3C26061C20221E00"},{"flags":[],"gfx":"3F0C0C0C0C0C0C00"},{"flags":[],"gfx":"2626262626261C00"},{"flags":[],"gfx":"2626261C1C1C0800"},{"flags":[],"gfx":"2323232B2B2A3600"},{"flags":[],"gfx":"2626261C26262600"},{"flags":[],"gfx":"2626261C18181800"},{"flags":[],"gfx":"3E3E30180C063E00"},{"flags":[],"gfx":"1C0C0C0C0C0C1C00"},{"flags":[],"gfx":"0002060C18302000"},{"flags":[],"gfx":"1C18181818181C00"},{"flags":[],"gfx":"081C260000000000"},{"flags":[],"gfx":"0000000000003E00"},{"flags":[],"gfx":"0C0C100000000000"}],"levels":[{"loadword":"","map":"000000000000000000000000000000000000000000606060606060606060606060606060606060000060000000000000000000000000000000006000006000000000000000000000000000000000600000600000A00000000000000000004000000060000060000000000000000000000000000000006000006000000000000000000000000000000000600000600000000000000000000000000000000060000060000000000000000080808080800000006000006000000000000000000000000000000000600000606060606060606060606060606060606060000000000000000000000000000000000000000000","player":{"y":4,"x":5},"tickword":"","moveword":"","objects":[{"x":15,"linkword":"","linkentity":"","func":"cat","y":8,"name":"","steps":[{"character":"cat","lines":["I'm an apple.","","",""],"action":"say"},{"character":"player","lines":["Strange, you look like a cat.","","",""],"action":"say"}]},{"x":5,"linkentity":"","func":"fish","name":"","linkword":"","y":8},{"x":13,"linkentity":"","func":"pot","name":"","linkword":"","y":4},{"x":12,"linkentity":"","func":"suspiciouspot","linkword":"","name":"","y":4},{"x":11,"linkentity":"","func":"pot","linkword":"","name":"","y":4},{"x":14,"linkentity":"","func":"pot","linkword":"","name":"","y":4},{"x":15,"linkentity":"","func":"pot","linkword":"","name":"","y":4}]}],"portraits":[{"gfx":"000000000000000000000000000000000000007C7C7E7E7E7E7E7E7E7E7E7E7E00000000707F7F7F7F7F7F7F7F7F7F7F7E7E7E7E7F7F7F7F7F7F7F7F7F7F7F7F0000000F0F1F1F1F1F1F1F1F1F1F1F1F000000000000000000000000000000001F1F1F1F7F7F7F7F7F7F7F7F7F7F7F7F00000000077F7F7F7F7F7F7F7F7F7F7F","label":"player","flags":[]},{"gfx":"00000000004040606060707070707070000000000000010103037F7F7F7F7F7F707060604000000000000000000000007F7F7F7F7F7F7800004040406060606000000000001018383C3C7F7F7F7F7F7F000000000000000000000000000000007F7F7F3F0F67717C7F7F7F7F7F7F7F7F00007C7E7F7F7F7F7F7F7F7F7F7F7F7F","label":"cat","flags":[]},{"gfx":"80808080808080808080D5818181858480808080808080808080AA80808080808484848484A4848484A48484848494D0809090D0D4F5D5D5D5D5D480808080AA80808080808080808080D5808080808080808080808080808080AAA0A0A0A888808080808AA8AAAAAA828080808080D588888888888889898888888888888A82","label":"angryfish","flags":[]}]} \ No newline at end of file diff --git a/game/init.fnl b/game/init.fnl index 827c7a3..2acb7bb 100644 --- a/game/init.fnl +++ b/game/init.fnl @@ -2,6 +2,7 @@ (local {: lo : hi : readjson} util) (local tile (util.reload :game.tiles)) (local {: prg : vm : org} (util.reload :game.defs)) +(local files (require :game.files)) (local disk (util.reload :game.disk)) @@ -14,7 +15,7 @@ (tile.appendtiles org.code) (org.code:append [:align 0x100] :font) -(tile.appendgfx org.code (tile.loadgfx tile.fn-font)) +(tile.appendgfx org.code files.game.font) (tile.append-portraitwords vm) (vm:var :tick-count) diff --git a/game/tiles.fnl b/game/tiles.fnl index 9c97975..b9709d1 100644 --- a/game/tiles.fnl +++ b/game/tiles.fnl @@ -1,50 +1,21 @@ (local util (require :lib.util)) (local lume (require :lib.lume)) - +(local files (require :game.files)) (local flags [:walkable]) (local flag-to-bit {}) (each [iflag flag (ipairs flags)] (tset flag-to-bit flag (bit.lshift 1 (- iflag 1)))) -(local encoded-tile-fields [:gfx :mask]) -(fn convert [tile field method] - (local oldval (. tile field)) - (when oldval - (tset tile field (: oldval method))) - tile) -(fn convert-all [tile method] - (each [_ field (ipairs encoded-tile-fields)] - (convert tile field method)) - tile) - -(fn deserialize [tile] - (match (type tile) - :string {:gfx (tile:fromhex) :flags {}} - :table (convert-all tile :fromhex))) - -(fn serialize [tile] (convert-all (lume.clone tile) :tohex)) - -(local fn-tiles "game/tiles.json") -(local fn-portraits "game/portraits.json") -(local fn-font "game/font.json") - -(fn loadgfx [filename] - (if (util.file-exists filename) - (lume.map (util.readjson filename) deserialize) - [])) - -(fn savegfx [filename gfx] (util.writejson filename (lume.map gfx serialize))) - -(fn appendgfx [org gfx ?key ?ignore-labels] +(fn appendgfx [org gfx ?key ?label-prefix] (each [_ g (ipairs gfx)] - (when (and g.label (not ?ignore-labels)) (org:append g.label)) + (when g.label (org:append (.. (or ?label-prefix "") g.label))) (org:append [:bytes (. g (or ?key :gfx))]))) (fn appendtiles [org] - (local tiles (loadgfx fn-tiles)) + (local tiles files.game.tiles) (org:append [:align 0x100] :tileset) (appendgfx org tiles) - (appendgfx org (loadgfx fn-portraits)) + (appendgfx org files.game.portraits nil :portrait-) (org:append :tileflags) (each [_ tile (ipairs tiles)] (var flags 0) @@ -54,11 +25,11 @@ (fn append-portraitwords [vm ?overrides] (local overrides (or ?overrides {})) - (each [_ p (ipairs (loadgfx fn-portraits))] - (let [wordname (.. :draw- p.label) + (each [_ p (ipairs files.game.portraits)] + (let [wordname (.. :draw-portrait- p.label) override (. overrides p.label)] - (vm:word (.. :draw- p.label) :show-footer - (if override (override p.label) [:vm :lit p.label]) + (vm:word wordname :show-footer + (if override (override p.label) [:vm :lit (.. :portrait- p.label)]) :draw-portrait)))) (fn encode-yx [xy] @@ -81,6 +52,6 @@ (if (= tile.label label) (encode-itile itile) (find-itile tiles label (+ itile 1)))) -{: loadgfx : savegfx : appendtiles : appendgfx : append-portraitwords : flags : flag-to-bit : find-itile - : fn-tiles : fn-portraits : fn-font : encode-yx : encode-itile : decode-itile : serialize : deserialize} +{: appendtiles : appendgfx : append-portraitwords : flags : flag-to-bit : find-itile + : encode-yx : encode-itile : decode-itile} diff --git a/lib/fennel.lua b/lib/fennel.lua index 4646342..1185044 100644 --- a/lib/fennel.lua +++ b/lib/fennel.lua @@ -2223,8 +2223,8 @@ package.preload["fennel.compiler"] = package.preload["fennel.compiler"] or funct return table.concat(utils.map(exprs, 1), ", ") end local function disambiguate_parens(code, chunk) - if ((code:byte() == 40) and (1 < #chunk)) then - return ("; " .. code) + if (code:byte() == 40) then + return ("do end " .. code) else return code end @@ -3712,13 +3712,13 @@ do local builtin_macros = [===[;; This module contains all the built-in Fennel macros. Unlike all the other ;; modules that are loaded by the old bootstrap compiler, this runs in the ;; compiler scope of the version of the compiler being defined. - + ;; The code for these macros is somewhat idiosyncratic because it cannot use any ;; macros which have not yet been defined. - + ;; TODO: some of these macros modify their arguments; we should stop doing that, ;; but in a way that preserves file/line metadata. - + (fn ->* [val ...] "Thread-first macro. Take the first value and splice it into the second form as its first argument. @@ -3729,7 +3729,7 @@ do (table.insert elt 2 x) (set x elt))) x) - + (fn ->>* [val ...] "Thread-last macro. Same as ->, except splices the value into the last position of each form @@ -3740,7 +3740,7 @@ do (table.insert elt x) (set x elt))) x) - + (fn -?>* [val ...] "Nil-safe thread-first macro. Same as -> except will short-circuit with nil when it encounters a nil value." @@ -3755,7 +3755,7 @@ do (if ,tmp (-?> ,el ,(unpack els)) ,tmp))))) - + (fn -?>>* [val ...] "Nil-safe thread-last macro. Same as ->> except will short-circuit with nil when it encounters a nil value." @@ -3770,14 +3770,14 @@ do (if ,tmp (-?>> ,el ,(unpack els)) ,tmp))))) - + (fn ?dot [tbl k ...] "Nil-safe table look up. Same as . (dot), except will short-circuit with nil when it encounters a nil value in any of subsequent keys." (if (= nil k) tbl `(let [res# (. ,tbl ,k)] (and res# (?. res# ,...))))) - + (fn doto* [val ...] "Evaluates val and splices it into the first argument of subsequent forms." (let [name (gensym) @@ -3787,7 +3787,7 @@ do (table.insert form elt)) (table.insert form name) form)) - + (fn when* [condition body1 ...] "Evaluate body for side-effects only when condition is truthy." (assert body1 "expected body") @@ -3795,7 +3795,7 @@ do (do ,body1 ,...))) - + (fn with-open* [closable-bindings ...] "Like `let`, but invokes (v:close) on each binding after evaluating the body. The body is evaluated inside `xpcall` so that bound values will be closed upon @@ -3812,13 +3812,13 @@ do `(let ,closable-bindings ,closer (close-handlers# (xpcall ,bodyfn ,traceback))))) - + (fn collect* [iter-tbl key-value-expr ...] "Returns a table made by running an iterator and evaluating an expression that returns key-value pairs to be inserted sequentially into the table. This can be thought of as a \"table comprehension\". The provided key-value expression must return either 2 values, or nil. - + For example, (collect [k v (pairs {:apple \"red\" :orange \"orange\"})] (values v k)) @@ -3834,12 +3834,12 @@ do (match ,key-value-expr (k# v#) (tset tbl# k# v#))) tbl#)) - + (fn icollect* [iter-tbl value-expr ...] "Returns a sequential table made by running an iterator and evaluating an expression that returns values to be inserted sequentially into the table. This can be thought of as a \"list comprehension\". - + For example, (icollect [_ v (ipairs [1 2 3 4 5])] (when (> v 2) (* v v))) returns @@ -3853,7 +3853,7 @@ do (each ,iter-tbl (tset tbl# (+ (length tbl#) 1) ,value-expr)) tbl#)) - + (fn partial* [f ...] "Returns a function with all arguments partially applied to f." (assert f "expected a function to partially apply") @@ -3861,10 +3861,10 @@ do (table.insert body _VARARG) `(fn [,_VARARG] ,body))) - + (fn pick-args* [n f] "Creates a function of arity n that applies its arguments to f. - + For example, (pick-args 2 func) expands to @@ -3876,10 +3876,10 @@ do (tset bindings i (gensym))) `(fn ,bindings (,f ,(unpack bindings))))) - + (fn pick-values* [n ...] "Like the `values` special, but emits exactly n values. - + For example, (pick-values 2 ...) expands to @@ -3894,7 +3894,7 @@ do (if (= n 0) `(values) `(let [,let-syms ,let-values] (values ,(unpack let-syms)))))) - + (fn lambda* [...] "Function literal with arity checking. Will throw an exception if a declared argument is passed in as nil, unless @@ -3921,26 +3921,26 @@ do ,(tostring a) ,(or a.filename :unknown) ,(or a.line "?")))))) - + (assert (= :table (type arglist)) "expected arg list") (each [_ a (ipairs arglist)] (check! a)) (if empty-body? (table.insert args (sym :nil))) `(fn ,(unpack args)))) - + (fn macro* [name ...] "Define a single macro." (assert (sym? name) "expected symbol for macro name") (local args [...]) `(macros {,(tostring name) (fn ,(unpack args))})) - + (fn macrodebug* [form return?] "Print the resulting form after performing macroexpansion. With a second argument, returns expanded form as a string instead of printing." (let [handle (if return? `do `print)] `(,handle ,(view (macroexpand form _SCOPE))))) - + (fn import-macros* [binding1 module-name1 ...] "Binds a table of macros from each macro module according to a binding form. Each binding form can be either a symbol or a k/v destructuring table. @@ -3971,9 +3971,9 @@ do (tostring modname))) (tset scope.macros import-key (. subscope.macros macro-name)))))) nil) - + ;;; Pattern matching - + (fn match-values [vals pattern unifications match-pattern] (let [condition `(and) bindings []] @@ -3984,7 +3984,7 @@ do (each [_ b (ipairs subbindings)] (table.insert bindings b)))) (values condition bindings))) - + (fn match-table [val pattern unifications match-pattern] (let [condition `(and (= (type ,val) :table)) bindings []] @@ -4016,7 +4016,7 @@ do (each [_ b (ipairs subbindings)] (table.insert bindings b))))) (values condition bindings))) - + (fn match-pattern [vals pattern unifications] "Takes the AST of values and a single pattern and returns a condition to determine if it matches as well as a list of bindings to @@ -4056,7 +4056,7 @@ do (match-table val pattern unifications match-pattern) ;; literal value (values `(= ,val ,pattern) [])))) - + (fn match-condition [vals clauses] "Construct the actual `if` AST for the given match values and clauses." (if (not= 0 (% (length clauses) 2)) ; treat odd final clause as default @@ -4070,7 +4070,7 @@ do (table.insert out `(let ,bindings ,body)))) out)) - + (fn match-val-syms [clauses] "How many multi-valued clauses are there? return a list of that many gensyms." (let [syms (list (gensym))] @@ -4080,7 +4080,7 @@ do (if (not (. syms valnum)) (tset syms valnum (gensym)))))) syms)) - + (fn match* [val ...] ;; Old implementation of match macro, which doesn't directly support ;; `where' and `or'. New syntax is implemented in `match-where', @@ -4090,9 +4090,9 @@ do ;; protect against multiple evaluation of the value, bind against as ;; many values as we ever match against in the clauses. (list `let [vals val] (match-condition vals clauses)))) - + ;; Construction of old match syntax from new syntax - + (fn partition-2 [seq] ;; Partition `seq` by 2. ;; If `seq` has odd amount of elements, the last one is dropped. @@ -4112,7 +4112,7 @@ do (if (not= nil v2) (table.insert res [v1 v2])))) res)) - + (fn transform-or [[_ & pats] guards] ;; Transforms `(or pat pats*)` lists into match `guard` patterns. ;; @@ -4121,7 +4121,7 @@ do (each [_ pat (ipairs pats)] (table.insert res (list pat `? (unpack guards)))) res)) - + (fn transform-cond [cond] ;; Transforms `where` cond into sequence of `match` guards. ;; @@ -4136,12 +4136,12 @@ do [(list second `? (unpack cond 3))])) :else [cond])) - + (fn match-where [val ...] "Perform pattern matching on val. See reference for details. - + Syntax: - + (match data-expression pattern body (where pattern guard guards*) body @@ -4157,7 +4157,7 @@ do (if else-branch (table.insert match-body else-branch)) (match* val (unpack match-body)))) - + {:-> ->* :->> ->>* :-?> -?>*