add flags to tile editor, objects to map editor, textbox to imgui

This commit is contained in:
Jeremy Penner 2020-10-28 22:59:47 -04:00
parent dbc618acaa
commit eb1ca6078b
12 changed files with 277 additions and 104 deletions

View file

@ -117,15 +117,13 @@
(fn parse-dats [block dats] (fn parse-dats [block dats]
(each [_ dat (ipairs dats)] (each [_ dat (ipairs dats)]
(if (= (type dat) "string") (if (= (type dat) "string")
(do (do (tset block.symbols dat (+ (length block.pdats) 1))
(tset block.symbols dat (+ (length block.pdats) 1))
(when (= (dat:sub 1 2) "G-") (when (= (dat:sub 1 2) "G-")
(tset block.globals dat true))) (tset block.globals dat true)))
(let [opcode (. dat 1) (let [opcode (. dat 1)
parser (. dat-parser opcode) parser (. dat-parser opcode)
pdat pdat
(if (if parser (parser dat block)
parser (parser dat block)
(. opcodes opcode) (dat-parser.op dat) (. opcodes opcode) (dat-parser.op dat)
(error (.. "Unrecognized opcode " (fv opcode))))] (error (.. "Unrecognized opcode " (fv opcode))))]
(table.insert block.pdats pdat) (table.insert block.pdats pdat)

View file

@ -15,21 +15,25 @@
(set self.itile 1) (set self.itile 1)
(attach-imstate self)) (attach-imstate self))
(fn GraphicsEditView.reload [self]
(self.tilecache:load (tiles.loadtiles)))
(fn GraphicsEditView.select-rel [self ditile] (fn GraphicsEditView.select-rel [self ditile]
(when self.itile
(local itile (+ self.itile ditile)) (local itile (+ self.itile ditile))
(when (>= itile 1) (set self.itile itile))) (when (>= itile 1) (set self.itile itile))))
(fn GraphicsEditView.draw-sprite [self x y itile] (fn GraphicsEditView.draw-sprite [self x y itile]
(love.graphics.draw (self.tilecache:sprite itile) x y 0 sprite-scale sprite-scale)) (love.graphics.draw (self.tilecache:sprite itile) x y 0 self.sprite-scale self.sprite-scale))
(fn GraphicsEditView.draw-tile-selector [self x y w] (fn GraphicsEditView.draw-tile-selector [self x y w]
(var tilex x) (var tilex x)
(var tiley y) (var tiley y)
(local tile-size (* 16 sprite-scale)) (local tile-size (* 16 self.sprite-scale))
(for [itile 1 (length self.tilecache.tiles)] (for [itile 1 (length self.tilecache.tiles)]
(self:draw-sprite tilex tiley itile) (self:draw-sprite tilex tiley itile)
(when (= itile self.itile) (when (= itile self.itile)
(love.graphics.rectangle :line (- tilex 2) (- tiley 2) (+ (* 14 sprite-scale) 4) (+ tile-size 4))) (love.graphics.rectangle :line (- tilex 2) (- tiley 2) (+ (* 14 self.sprite-scale) 4) (+ tile-size 4)))
(when (button self [:tile itile] tilex tiley tile-size tile-size) (when (button self [:tile itile] tilex tiley tile-size tile-size)
(set self.itile itile)) (set self.itile itile))
(set tilex (+ tilex tile-size)) (set tilex (+ tilex tile-size))

View file

@ -1,3 +1,9 @@
(local core (require :core))
(local command (require :core.command))
(local keymap (require :core.keymap))
(local style (require :core.style))
(local lume (require :lib.lume))
(fn attach-imstate [view] (fn attach-imstate [view]
(set view.imstate {}) (set view.imstate {})
(fn view.on_mouse_pressed [self button x y clicks] (fn view.on_mouse_pressed [self button x y clicks]
@ -6,8 +12,19 @@
(fn view.on_mouse_released [self button x y] (fn view.on_mouse_released [self button x y]
(tset self.imstate button :released) (tset self.imstate button :released)
(self.__index.on_mouse_released self button x y)) (self.__index.on_mouse_released self button x y))
(fn view.on_key_pressed [self key]
(when (= self.imstate.keys nil)
(set self.imstate.keys []))
(table.insert self.imstate.keys key))
(fn view.on_text_input [self text]
(set self.imstate.text (.. (or self.imstate.text "") text))
(self.__index.on_text_input self text))
(fn view.draw [self] (fn view.draw [self]
(set self.cursor nil)
(self.__index.draw self) (self.__index.draw self)
(when (= self.cursor nil) (set self.cursor :arrow))
(set self.imstate.keys nil)
(set self.imstate.text nil)
(when (= self.imstate.left :released) (when (= self.imstate.left :released)
(set self.imstate.active nil)) (set self.imstate.active nil))
(each [_ button (pairs [:left :middle :right])] (each [_ button (pairs [:left :middle :right])]
@ -17,6 +34,27 @@
:down :down :down :down
:released nil))))) :released nil)))))
(fn register-keys [keys]
(local commands {})
(local keymaps {})
(each [_ key (ipairs keys)]
(local command-name (.. "imstate:" key))
(tset commands command-name #(core.active_view:on_key_pressed key))
(tset keymaps key command-name))
(command.add #(not= (-?> core.active_view.imstate (. :focus)) nil) commands)
(keymap.add keymaps))
(register-keys [:backspace :delete :left :right :shift+left :shift+right :home :end :shift+home :shift+end])
(fn cmd-predicate [p]
(var p-fn p)
(when (= (type p-fn) :string) (set p-fn (require p-fn)))
(when (= (type p-fn) :table)
(local cls p-fn)
(set p-fn (fn [] (core.active_view:is cls))))
(fn [] (when (= (-?> core.active_view.imstate (. :focus)) nil)
(p-fn))))
(fn make-tag [tag] (fn make-tag [tag]
(match (type tag) (match (type tag)
:string tag :string tag
@ -36,4 +74,113 @@
(activate view tag x y w h) (activate view tag x y w h)
(and (active? view tag) (= view.imstate.left :released) (mouse-inside x y w h))) (and (active? view tag) (= view.imstate.left :released) (mouse-inside x y w h)))
{: attach-imstate : mouse-inside : activate : active? : button} (fn checkbox [view name isset x y ?tag]
(love.graphics.rectangle (if isset :fill :line) x y 12 12)
(local xEnd (renderer.draw_text style.font name (+ x 16) y style.text))
(love.graphics.setColor 1 1 1 1)
(button view (or ?tag name) x y (- xEnd x) 12))
(fn focused? [view tag] (= tag (-?> view.imstate.focus (. :tag))))
(fn focus [view tag x y w h opts]
(if (activate view tag x y w h)
(set view.imstate.focus
(doto (lume.clone (or opts {}))
(tset :tag tag)))
(and (= view.imstate.left :released) (focused? view tag) (not (active? view tag)))
(set view.imstate.focus nil))
(focused? view tag))
(local blink_period 0.8)
(fn x-from-i [s i xLeft font]
(if (or (<= i 1) (= s "")) xLeft
(x-from-i (s:sub 2) (- i 1) (+ xLeft (font:get_width (s:sub 1 1))) font)))
(fn i-from-x [s x xLeft font ?i]
(local i (or ?i 1))
(local w (font:get_width (s:sub 1 1)))
(local xMid (+ xLeft (/ w 2)))
(if (or (<= x xMid) (= s "")) i
(i-from-x (s:sub 2) x (+ xLeft w) font (+ i 1))))
(fn textnav [key i text]
(local imax (+ (length text) 1))
(match key
:left (math.max 1 (- i 1))
:right (math.min imax (+ i 1))
:home 1
:end imax))
(fn selection-span [view]
(let [f view.imstate.focus
iStart (math.min f.i f.iAnchor)
iLim (math.max f.i f.iAnchor)]
(values iStart iLim)))
(fn replace-selection [view s replacement ?iStart ?iLim]
(local (iStart iLim) (if ?iLim (values ?iStart ?iLim) (selection-span view)))
(local text
(.. (s:sub 1 (- iStart 1))
replacement
(s:sub iLim)))
(local iNew (+ iStart (length replacement)))
(set view.imstate.focus.i iNew)
(set view.imstate.focus.iAnchor iNew)
text)
(fn textbox [view tag text x y w]
(var textNew text)
(local (h hText xText yText) (values 20 16 (+ x 2) (+ y 2)))
; handle key events
(when (focus view tag x y w h {:i 1 :iAnchor 1 :blink (love.timer.getTime)})
(local f view.imstate.focus)
(when view.imstate.text
(set textNew (replace-selection view textNew view.imstate.text)))
(each [_ key (ipairs (or view.imstate.keys []))]
(set view.imstate.focus.blink (love.timer.getTime))
(if (= (key:sub 1 6) "shift+")
(set f.i (or (textnav (key:sub 7) f.i textNew) f.i))
(let [iNav (textnav key f.i textNew)]
(when iNav
(set f.i iNav)
(set f.iAnchor iNav))
(if (= f.i f.iAnchor)
(set textNew
(match key
:delete (replace-selection view textNew "" f.i (+ f.i 1))
(:backspace ? (> f.i 1)) (replace-selection view textNew "" (- f.i 1) f.i)
_ textNew))
(when (or (= key :delete) (= key :backspace))
(set textNew (replace-selection view textNew ""))))))))
; handle mouse events
(when (mouse-inside x y w h) (set view.cursor :ibeam))
(when (and (focused? view tag) (active? view tag) (mouse-inside x y w h))
(local mouse-i (i-from-x textNew (love.mouse.getX) x style.font))
(when (= view.imstate.left :pressed)
(set view.imstate.focus.iAnchor mouse-i))
(set view.imstate.focus.i mouse-i))
; draw box
(love.graphics.setLineWidth 1)
(love.graphics.rectangle :line x y w h)
(if (focused? view tag)
; draw text with selection + caret
(let [(iStart iLim) (selection-span view)
xSelect (renderer.draw_text style.font (textNew:sub 1 (- iStart 1)) xText yText style.text)
sSelect (textNew:sub iStart (- iLim 1))
wSelect (style.font:get_width sSelect)
xTail (+ xSelect wSelect)]
(when (> wSelect 0)
(renderer.draw_rect xSelect yText wSelect hText style.selection)
(renderer.draw_text style.font sSelect xSelect yText style.text))
(renderer.draw_text style.font (textNew:sub iLim) xTail yText style.text)
(when (or (active? view tag)
(< (% (- (love.timer.getTime) view.imstate.focus.blink) (* blink_period 2)) blink_period))
(renderer.draw_rect (x-from-i textNew view.imstate.focus.i xText style.font) yText style.caret_width hText style.caret)))
; just draw the text
(renderer.draw_text style.font textNew xText yText style.text))
(love.graphics.setColor 1 1 1)
textNew)
{: attach-imstate : cmd-predicate : mouse-inside : activate : active? : button : checkbox : textbox}

View file

@ -1,6 +1,8 @@
(require :editor.lite) (require :editor.lite)
(local util (require :lib.util))
(local TileView (require :editor.tileedit)) (local TileView (require :editor.tileedit))
(local MapEditView (require :editor.mapedit)) (local MapEditView (require :editor.mapedit))
(local {: cmd-predicate} (util.require :editor.imstate))
(local core (require :core)) (local core (require :core))
(local command (require :core.command)) (local command (require :core.command))
(local keymap (require :core.keymap)) (local keymap (require :core.keymap))
@ -15,31 +17,25 @@
) )
}) })
(command.add :editor.tileedit { (command.add (cmd-predicate :editor.gfxedit) {
"tileedit:save" (fn [] (core.active_view:save) (core.log "Saved tiles")) "graphics-editor:save" (fn [] (core.active_view:save) (core.log "Saved"))
"tileedit:next-tile" #(core.active_view:select-rel 1) "graphics-editor:reload" (fn [] (core.active_view:reload) (core.log "Reloaded"))
"tileedit:previous-tile" #(core.active_view:select-rel -1) "graphics-editor:next-tile" #(core.active_view:select-rel 1)
"tileedit:copy" #(system.set_clipboard (: (core.active_view:tile) :tohex)) "graphics-editor:previous-tile" #(core.active_view:select-rel -1)
})
(command.add (cmd-predicate :editor.tileedit) {
"tileedit:copy"
#(system.set_clipboard (: (core.active_view:tile) :tohex))
"tileedit:paste" "tileedit:paste"
#(when (= (length (system.get_clipboard)) 64) #(when (= (length (system.get_clipboard)) 64)
(core.active_view:update-tile (: (system.get_clipboard) :fromhex))) (core.active_view:update-tile (: (system.get_clipboard) :fromhex)))
}) })
(keymap.add { (keymap.add {
"ctrl+s" "tileedit:save" "ctrl+s" "graphics-editor:save"
"left" "tileedit:previous-tile" "alt+r" "graphics-editor:reload"
"right" "tileedit:next-tile" "left" "graphics-editor:previous-tile"
"right" "graphics-editor:next-tile"
"ctrl+c" "tileedit:copy" "ctrl+c" "tileedit:copy"
"ctrl+v" "tileedit:paste" "ctrl+v" "tileedit:paste"
}) })
(command.add :editor.mapedit {
"mapedit:next-tile" #(core.active_view:select-rel 1)
"mapedit:previous-tile" #(core.active_view:select-rel -1)
"mapedit:save" (fn [] (core.active_view:save) (core.log "Saved map"))
})
(keymap.add {
"ctrl+s" "mapedit:save"
"left" "mapedit:previous-tile"
"right" "mapedit:next-tile"
})

View file

@ -1,18 +1,21 @@
(local GraphicsEditView (require :editor.gfxedit)) (local GraphicsEditView (require :editor.gfxedit))
(local style (require :core.style)) (local style (require :core.style))
(local util (require :lib.util)) (local util (require :lib.util))
(local {: mouse-inside : activate : active?} (util.require :editor.imstate)) (local lume (require :lib.lume))
(local {: mouse-inside : activate : active? : checkbox : textbox} (util.require :editor.imstate))
(local MapEditView (GraphicsEditView:extend)) (local MapEditView (GraphicsEditView:extend))
(local sprite-scale 3)
(local mapw 20) (local mapw 20)
(local maph 12) (local maph 12)
(local tilew (* GraphicsEditView.sprite-scale 14)) (local tilew (* sprite-scale 14))
(local tileh (* GraphicsEditView.sprite-scale 16)) (local tileh (* sprite-scale 16))
(fn MapEditView.new [self] (fn MapEditView.new [self]
(MapEditView.super.new self) (MapEditView.super.new self)
(set self.map (string.rep "\0" (* mapw maph)))) (set self.sprite-scale sprite-scale)
(set self.testtext "Hello")
(self:reload))
; map is stored bottom-to-top ; map is stored bottom-to-top
(fn imap-from-xy [mx my] (fn imap-from-xy [mx my]
@ -31,13 +34,21 @@
(fn MapEditView.itile-from-xy [self mx my] (fn MapEditView.itile-from-xy [self mx my]
(local imap (+ (imap-from-xy mx my) 1)) (local imap (+ (imap-from-xy mx my) 1))
(local enctile (string.byte (self.map:sub imap imap))) (local enctile (string.byte (self.level.map:sub imap imap)))
(+ 1 (bit.bor (+ 1 (bit.bor
(bit.lshift (bit.band enctile 0x1f) 3) (bit.lshift (bit.band enctile 0x1f) 3)
(bit.rshift (bit.band enctile 0xe0) 5)))) (bit.rshift (bit.band enctile 0xe0) 5))))
(fn MapEditView.set-tile [self mx my itile] (fn MapEditView.set-tile [self mx my itile]
(set self.map (update-map self.map mx my itile))) (set self.level.map (update-map self.level.map mx my itile)))
(fn MapEditView.iobject-from-xy [self mx my ?iobj]
(local iobj (or ?iobj 1))
(local obj (. self.level.objects iobj))
(when obj
(if (and (= obj.x mx) (= obj.y my))
iobj
(self:iobject-from-xy mx my (+ iobj 1)))))
(fn MapEditView.draw-map-editor [self x y] (fn MapEditView.draw-map-editor [self x y]
(activate self :map x y (* tilew mapw) (* tileh maph)) (activate self :map x y (* tilew mapw) (* tileh maph))
@ -45,20 +56,44 @@
(local tilex (+ x (* (- mx 1) tilew))) (local tilex (+ x (* (- mx 1) tilew)))
(local tiley (+ y (* (- my 1) tileh))) (local tiley (+ y (* (- my 1) tileh)))
(local itile (self:itile-from-xy mx my)) (local itile (self:itile-from-xy mx my))
(local iobject (self:iobject-from-xy mx my))
(self:draw-sprite tilex tiley itile) (self:draw-sprite tilex tiley itile)
(when (and (active? self :map) (mouse-inside tilex tiley tilew tileh) (not= itile self.itile)) (when (not= iobject nil)
(self:set-tile mx my self.itile))))) (love.graphics.setColor 1 0 (if (and (= self.itile nil) (= iobject self.iobject)) 1 0))
(love.graphics.setLineWidth 3)
(love.graphics.rectangle :line tilex tiley tilew tileh)
(love.graphics.setColor 1 1 1))
(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) (= self.imstate.left :released))
(if (= iobject nil)
(do (table.insert self.level.objects {:x mx :y my :func ""})
(set self.iobject (length self.level.objects)))
(set self.iobject iobject))))))
(fn MapEditView.reload [self]
(MapEditView.super.reload self)
(local level (util.readjson "game/map00001.json"))
(set self.level
(match (type level)
:string {:map (level:fromhex) :objects []}
:table (doto level (tset :map (level.map:fromhex))))))
(fn MapEditView.save [self] (fn MapEditView.save [self]
(util.writejson "game/map00001.json" (self.map:tohex))) (util.writejson "game/map00001.json"
(doto (lume.clone self.level)
(tset :map (self.level.map:tohex)))))
(fn MapEditView.draw [self] (fn MapEditView.draw [self]
(self:draw_background style.background) (self:draw_background style.background)
(love.graphics.setColor 1 1 1 1) (love.graphics.setColor 1 1 1 1)
(self:draw-map-editor (+ self.position.x 10) (+ self.position.y 10)) (self:draw-map-editor (+ self.position.x 10) (+ self.position.y 10))
(when (checkbox self "Edit objects" (= self.itile nil) (+ self.position.x 10) (+ self.position.y 20 (* tileh maph)))
(set self.itile nil))
(set self.testtext (textbox self :test self.testtext (+ self.position.x 10) (+ self.position.y 40 (* tileh maph)) 200))
(self:draw-tile-selector (self:draw-tile-selector
(+ self.position.x 10) (+ self.position.x 10)
(+ self.position.y 20 (* tileh maph)) (+ self.position.y 65 (* tileh maph))
(- self.size.x 20))) (- self.size.x 20)))
(fn MapEditView.get_name [self] "Map Editor") (fn MapEditView.get_name [self] "Map Editor")

View file

@ -60,14 +60,24 @@
(fn TileCache [tiles] (fn TileCache [tiles]
{: tiles {: tiles
:tilesprites [] :tilesprites []
:tile (fn [self itile] (or (. self.tiles itile) {:flags {}}))
:update-tile :update-tile
(fn [self itile tile] (fn [self itile tile]
(tset self.tiles itile tile) (tset self.tiles itile
(-> (self:tile itile)
(doto (tset :gfx tile))))
(tset self.tilesprites itile nil)) (tset self.tilesprites itile nil))
:set-flag
(fn [self itile flag clear]
(tset (. self.tiles itile :flags) flag (if clear nil true)))
:load
(fn [self tiles]
(set self.tiles tiles)
(set self.tilesprites []))
:sprite :sprite
(fn [self itile] (fn [self itile]
(when (and (= nil (. self.tilesprites itile)) (not= nil (. self.tiles itile))) (when (and (= nil (. self.tilesprites itile)) (not= nil (. self.tiles itile)))
(tset self.tilesprites itile (tile-to-sprite (. self.tiles itile)))) (tset self.tilesprites itile (tile-to-sprite (. self.tiles itile :gfx))))
(. self.tilesprites itile))}) (. self.tilesprites itile))})
{: tile-to-sprite : pal-from-bit : pal-from-byte : TileCache} {: tile-to-sprite : pal-from-bit : pal-from-byte : TileCache}

View file

@ -3,7 +3,7 @@
(local tiles (require :game.tiles)) (local tiles (require :game.tiles))
(local tiledraw (require :editor.tiledraw)) (local tiledraw (require :editor.tiledraw))
(local util (require :lib.util)) (local util (require :lib.util))
(local {: mouse-inside : activate : active?} (util.require :editor.imstate)) (local {: mouse-inside : activate : active? : checkbox} (util.require :editor.imstate))
(local TileView (GraphicsEditView:extend)) (local TileView (GraphicsEditView:extend))
@ -42,12 +42,14 @@
(fn draw-bit [bit x y even] (fn draw-bit [bit x y even]
(renderer.draw_rect x y pixel-size pixel-size (if bit [255 255 255] [0 0 0]))) (renderer.draw_rect x y pixel-size pixel-size (if bit [255 255 255] [0 0 0])))
(fn TileView.tile [self] (or (. self.tilecache.tiles self.itile) (string.rep "\0" 32))) (fn TileView.tile [self]
(or (-?> self.tilecache.tiles (. self.itile) (. :gfx)) (string.rep "\0" 32)))
(fn TileView.draw-tile-editor [self tile x y] (fn TileView.draw-tile-editor [self tile x y]
(when (not (active? self :tile)) (when (not (active? self :tile))
(set self.bit nil)) (set self.bit nil))
(activate self :tile x y (* (+ pixel-size 1) 16) (* (+ pixel-size 1) 16)) (local editor-size (* (+ pixel-size 1) 16))
(activate self :tile x y editor-size editor-size)
(for [bitx 0 15] (for [bity 0 15] (for [bitx 0 15] (for [bity 0 15]
(local (ibyte ibit) (map-bitxy bitx bity)) (local (ibyte ibit) (map-bitxy bitx bity))
(local bit (get-bit tile ibyte ibit)) (local bit (get-bit tile ibyte ibit))
@ -59,7 +61,18 @@
(when (= self.bit nil) (set self.bit (not bit))) (when (= self.bit nil) (set self.bit (not bit)))
(when (not= self.bit bit) (when (not= self.bit bit)
(self:update-tile (set-tile-bit tile ibyte ibit self.bit)))))) (self:update-tile (set-tile-bit tile ibyte ibit self.bit))))))
(love.graphics.setColor 1 1 1 1)) (love.graphics.setColor 1 1 1 1)
editor-size)
(fn TileView.draw-tile-flag [self flagname x y]
(local flags (-?> self.tilecache.tiles (. self.itile) (. :flags)))
(local flagset (if flags (. flags flagname) false))
(when (checkbox self flagname flagset x y)
(tset flags flagname (if flagset nil true))))
(fn TileView.draw-tile-flags [self x y]
(each [iflag flagname (ipairs tiles.flags)]
(self:draw-tile-flag flagname x (+ y (* (- iflag 1) (+ pixel-size 4))))))
(fn TileView.update-tile [self newtile] (fn TileView.update-tile [self newtile]
(self.tilecache:update-tile self.itile newtile)) (self.tilecache:update-tile self.itile newtile))
@ -69,7 +82,8 @@
(fn TileView.draw [self] (fn TileView.draw [self]
(self:draw_background style.background) (self:draw_background style.background)
(local (x y) (values (+ self.position.x 10) (+ self.position.y 10))) (local (x y) (values (+ self.position.x 10) (+ self.position.y 10)))
(self:draw-tile-editor (self:tile) x y) (local editor-size (self:draw-tile-editor (self:tile) x y))
(self:draw-tile-flags (+ x editor-size pixel-size) y)
(self:draw-tile-selector x (+ y (* 18 (+ pixel-size 1))) (- self.size.x 20))) (self:draw-tile-selector x (+ y (* 18 (+ pixel-size 1))) (- self.size.x 20)))
(fn TileView.get_name [self] "Tile Editor") (fn TileView.get_name [self] "Tile Editor")

View file

@ -154,7 +154,6 @@
; 20x12 means full map is 240 bytes - we have an extra 16 bytes at the end to mess with? ; 20x12 means full map is 240 bytes - we have an extra 16 bytes at the end to mess with?
(tile.appendmaps (prg:org 0x6800)) (tile.appendmaps (prg:org 0x6800))
; (: (prg:org 0x6800) :append :map [:bytes (string.rep "\0\032\064\096\128\160\192\224\001\033\065\097\129\161\193" 17)])
(code1:append :main (code1:append :main
[:jsr :reset] [:jsr :reset]

View file

@ -1 +1 @@
"2121212141212121212121212121412121212121610261616102616161026161616161026161612161C0C0C0C0C0C0C0C0C0C0C061C0C0C0C0C0612161C0C0C0C0C0C0C0C0C0C0C081C080C0C0C0024161C0C0C0C0C0C0C0C0C0C0C0C1C0C0C0E0C0612161C0C0C0C0C0C0C0C0C0C0C06161616161616121616161616161C1816161616161C0C0C0C0C0612161C0C0C0C0C0C0C0C0C0C0C061C0C0C0C0C0022161E0C0C0C0C0C0C0C0C0C0C081C0C0C0C0C0612161C0C0C0C0C0C0C0C0C0C0C061C0C0C0C0C0614161C0C0C0C0C0C0C0C0C0C0C061C0C0C0C0C061216161616161616161228161616161616161610221" {"map":"2121212141212121212121212121412121212121610261616102616161026161616161026161612161C0C0C0C0C0C0C0C0C0C0C061C0C0C0C0C0612161C0C0A282C0C0C0A2C0C0C081C080C0C0C2024161C0C0C0C0C0C0C0C0C2C0A2C1A2C0C0E082612161E2C08282C0C0C0C0A2C0C06161616161616121616161616161C1816161616161C0C0C0C0C0612161C0C0C0C0C0C0C0C0C0C0C061C0C0C0C0C0022161E08282A2C0C0C0C0C0C0C081C0C0C0C0C0612161C0C0C0C0C0C0C0C0C0C0C061C0C0C0C0C0614161C0C0C0C0C0C0C0C0C0C0C061C0C0C0C0C061216161616161616161228161616161616161610221","objects":[{"func":"","x":17,"y":8},{"func":"","x":13,"y":9},{"func":"","x":13,"y":8},{"func":"","x":13,"y":4},{"func":"","x":8,"y":6},{"func":"","x":7,"y":6},{"func":"","x":2,"y":4},{"func":"","x":9,"y":1},{"func":"","x":10,"y":1}]}

View file

@ -1,23 +1,25 @@
(local util (require :lib.util)) (local util (require :lib.util))
(local lume (require :lib.lume)) (local lume (require :lib.lume))
(fn loadtiles [] (local flags [:walkable :neutable :debris])
(lume.map
(util.readjson "game/tiles.json")
#($1:fromhex)))
(fn savetiles [tiles] (fn deserialize [tile]
(util.writejson (match (type tile)
"game/tiles.json" :string {:gfx (tile:fromhex) :flags {}}
(lume.map tiles #($1:tohex)))) :table (doto tile (tset :gfx (tile.gfx:fromhex)))))
(fn serialize [tile] (doto (lume.clone tile) (tset :gfx (tile.gfx:tohex))))
(fn loadtiles [] (lume.map (util.readjson "game/tiles.json") deserialize))
(fn savetiles [tiles] (util.writejson "game/tiles.json" (lume.map tiles serialize)))
(fn appendtiles [tiles org] (fn appendtiles [tiles org]
(each [_ tile (ipairs tiles)] (each [_ tile (ipairs tiles)]
(org:append [:bytes tile]))) (org:append [:bytes tile.gfx])))
(fn appendmaps [org] (fn appendmaps [org]
(local map (: (util.readjson "game/map00001.json") :fromhex)) (local map (: (util.readjson "game/map00001.json") :fromhex))
(org:append :map [:bytes map])) (org:append :map [:bytes map]))
{: loadtiles : savetiles : appendtiles : appendmaps} {: loadtiles : savetiles : appendtiles : appendmaps : flags}

View file

@ -1 +1 @@
["000000020A0820404A4020080A02000000010141511005025302051051410100","00000000020A0820404A4020080A020000000101415110050253020510514101","808080C0C0C0E0C0D0C8C04040404080808083858585828A9282820A08081980","8080C0A0A0A0C0C0D0C8C0501010188080808183838782828A8A920202020380","8080E0B0B0B098C0D0D0C840404060808080878D8D8D99828A8A920202020780","8080C0E0E0E0B0C0D0C8C040404060808080838787878D828A92820202020780","80808C8080808080B08080808C808080808C80808083B0808080808080868080","007C0C0C0C0C7C007C7E7EAA88888800001F181818181F001F0F979590909000","007C2C0C0C2C7C007C7E7EAA88888800001F18191C191F001F0F979590909000","D5D5D5D5D5D5D5D5D5D5D5D5D5D5D5D5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","D5D5D5D5D5F5F5FDDDD5D5D5D5D5D5D5AAAAAAAAAEAEBFBFBFABAAAAAAAAAAAA","FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF","FF8FA7B3B3B3B3B3B3B3B3B3B3B383FFFFF8F2E6E6E6E6E6E6E6E6E6E6E6E0FF","FF8F87838383838383838383838383FFFFF8F0E0E0E0E0E0E0E0E0E0E0E0E0FF","FFFFCFCFCFCF898183838787878FFFFFFFFCE4E4E4E4E0E0E0E0E0E0F0F8FFFF","FFFFCFCFCFCF898123232727878FFFFFFFFCE4E4E4E0E0616565656571F8FFFF","FFFF83D3D3D3D3D3D3D3D3D3D383FFFFFFFFC0CACACECACBCACACACACAC0FFFF","FFFFABFBFBFBFBBBBBFBFBFBFBABFFFFFFFFD5DFDFDFDFDDDDDFDFDFDFD5FFFF","FFFF2B7B7B7B2B6B6B2B7B7B7B2BFFFFFFFF555F5F5F555757555F5F5F55FFFF","FFF3C78FBFFCF98187BFFFFFBF9F9FC7FFCFE1F1FCFCF8FEFEFCF9F0E6CE8F9F"] [{"flags":[],"gfx":"000000020A0820406A4020080A02000000010141511005025702051051410100"},{"flags":[],"gfx":"00000000020A0820406A4020080A020000000101415110050257020510514101"},{"flags":[],"gfx":"808080C0C0C0E0C0D0C8C04040404080808083858585828A9282820A08081980"},{"flags":[],"gfx":"8080C0A0A0A0C0C0D0C8C0501010188080808183838782828A8A920202020380"},{"flags":[],"gfx":"8080E0B0B0B098C0D0D0C840404060808080878D8D8D99828A8A920202020780"},{"flags":[],"gfx":"8080C0E0E0E0B0C0D0C8C040404060808080838787878D828A92820202020780"},{"flags":[],"gfx":"80808C8080808080B08080808C808080808C80808083B0808080808080868080"},{"flags":[],"gfx":"007C0C0C0C0C7C007C7E7EAA88888800001F181818181F001F0F979584848400"},{"flags":{"neutable":true},"gfx":"007C2C0C0C2C7C007C7E7EAA88888800001F18191C191F001F0F979584848400"},{"flags":[],"gfx":"D5D5D5D5D5D5D5D5D5D5D5D5D5D5D5D5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},{"flags":[],"gfx":"D5D5D5D5D5F5F5FDDDD5D5D5D5D5D5D5AAAAAAAAAEAEBFBFBFABAAAAAAAAAAAA"},{"flags":{"neutable":true},"gfx":"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},{"flags":[],"gfx":"FF8FA7B3B3B3B3B3B3B3B3B3B3B383FFFFF8F2E6E6E6E6E6E6E6E6E6E6E6E0FF"},{"flags":{"walkable":true},"gfx":"FF8F87838383838383838383838383FFFFF8F0E0E0E0E0E0E0E0E0E0E0E0E0FF"},{"flags":{"neutable":true},"gfx":"FFFFCFCFCFCF898183838787878FFFFFFFFCE4E4E4E4E0E0E0E0E0E0F0F8FFFF"},{"flags":{"neutable":true},"gfx":"FFFFCFCFCFCF898123232727878FFFFFFFFCE4E4E4E0E0616565656571F8FFFF"},{"flags":[],"gfx":"FFFF83D3D3D3D3D3D3D3D3D3D383FFFFFFFFC0CACACECACBCACACACACAC0FFFF"},{"flags":{"neutable":true},"gfx":"FFFFAFEBFBFBFBBBBBFBFBFBEBAFFFFFFFFFF5D7DFDFDFDDDDDFDFDFD7F5FFFF"},{"flags":{"neutable":true},"gfx":"FFFF2F2B2B2B6B6B6B6B2B2B2B2FFFFFFFFF755555555757575755555575FFFF"},{"flags":[],"gfx":"FFF3C78FBFFCF98187BFFFFFBF9F9FC7FFCFE1F1FCFCF8FEFEFCF9F0E6CE8F9F"},{"flags":[],"gfx":"80808C80808080A8AAAAAAA888888880808C8080808380859595958584848480"},{"flags":{"debris":true},"gfx":"80808C8080A0A0A8AAAA8AA0A8808080808C8081919090848594959585858080"},{"flags":[],"gfx":"8080D0848484D0C0C0D0D4D49090B880808C8AA0A0A08A83838AAAAA88889C80"},{"flags":{"debris":true},"gfx":"808080809890D4D0C0E0E0908484D480808C808682828A8A81808288888A8280"}]

View file

@ -1,38 +1,6 @@
GOAL: Neut Tower runtime model:
live-program an emulator in assembly - before moving, see if an object exists at that location - if so, send it a message
- otherwise, see if the space is "empty" from the current player's perspective - if so, move them there
- a program is a graph that is flattened into a set of bytestreams. - lookup table for tiles? rol rol rol to get index, 8 bits of possible data
- first step: make the damn graph. - objects are kept in two parallel arrays, rather than a linked list
APPROACH:
- program is split into "ROM" and "RAM" - ROM is code that generally doesn't change while the program is running, RAM is program data
- a program is assembled from snippets that refer to other snippets by name
- a code snippet can be marked as a "loop point", a safe spot to pause and replace a running program's code
- this is also be a good spot to take snapshots of "RAM" which we could roll back to
- this assumes an empty stack + no code references in RAM - perhaps a special typed variable is needed for snippet pointers?
- for now, we will depend on gsplus' socket-based remote debugging capabilities to poke the program into emulated memory
WHAT IS A SNIPPET
- label + block
- block = bytestring, labels (offset into instruction list), fixups (label references)
- can concatenate blocks; snippets are stored "loose" - accessed by absolute JMP or JSR
- other compositional ideas:
- "scopes" - keep labels "alive" only for a short period, for autogenerated loops, if statements, etc
- could also just gensym
(lda 13) ; immediate
(lda (addr #x2000)) ; absolute
(lda (addr #x20)) ; zero-page
(lda (off-x (addr #x20))) ; zp,x
(lda (off-y (addr #x20))) ; zp,y
(lda (off-x@ (addr #x20))) ; (zp,x)
(lda (@off-y (addr #x20))) ; (zp),y
(lda (off-x (addr #x2000))) ; abs,x
(lda (off-y (addr #x2000))) ; abs,y
label = lazy address
maybe treat zero-page and absolute as different types? we will always plan what goes into zero-page. zp has addressing modes abs doesn't.
each opcode is a function that returns a block, usually 0-3 bytes with optionally associated labels + fixups
(fixup is a tuple: local offset, label reference, and whether we're expecting an absolute, zero-page, or relative address)