First cut at updating mapedit

This commit is contained in:
Jeremy Penner 2021-12-21 21:04:43 -06:00
parent b9ec214b46
commit 939cfc6065
4 changed files with 156 additions and 141 deletions

View file

@ -3,7 +3,7 @@
(local tiledraw (require :editor.tiledraw))
(local util (require :lib.util))
(local files (require :game.files))
(local {: attach-imstate : button : vert : horiz-wrapper} (util.require :editor.imgui))
(local {: attach-imstate : button : vert : horiz-wrapper : begin-group} (util.require :editor.imgui))
(local GraphicsEditView (View:extend))
@ -42,16 +42,18 @@
(fn tile-selector [{: view &as form} selected-itile ?key]
(var selected-itile selected-itile)
(let [wrap (horiz-wrapper form)]
(let [g (begin-group)
wrap (horiz-wrapper form)]
(for [itile 1 (length view.tilecache.tiles)]
(let [{: x : y} form
(w h) (view:draw-sprite x y itile ?key)]
(when (and w h)
(when (= itile selected-itile)
(love.graphics.rectangle :line (- x 2) (- y 2) (+ w 4) (+ h 4)))
(when (wrap button {:tag [:tile itile] : w : h})
(set selected-itile itile))))))
selected-itile)
(when (g wrap form button {:tag [:tile itile] : w : h})
(set selected-itile itile)))))
(g form)
selected-itile))
(fn GraphicsEditView.draw-tile-selector [self form ?key]
(match (vert form tile-selector {:scale self.sprite-scale :w form.w} (when (= self.tilekey ?key) self.itile) ?key)

View file

@ -23,6 +23,7 @@
(fn view.form [self ?overrides]
(lume.merge {:x (+ self.position.x style.padding.x (- self.scroll.x))
:y (+ self.position.y style.padding.y (- self.scroll.y))
:w (- self.size.x (* style.padding.x 2))
:view self}
(or ?overrides {})))
(fn view.end-scroll [self {: y : h}]
@ -280,7 +281,8 @@
(fn dropdown [form selection options]
(let [{: x : y : w :h row-h : font : color : bg : xpad : ypad : view : tag}
(with-style form :h #(+ ($1.font:get_height) $1.ypad)
(with-style form :w (* 150 SCALE)
:h #(+ ($1.font:get_height) $1.ypad)
:bg style.selection)]
(var new-selection nil)
@ -303,6 +305,18 @@
(focus form)
(or new-selection selection)))
(fn labelled-dropdown [form label selection options]
(let [{: x : y : wlabel : wdropdown : font : color}
(with-style form :wlabel #(+ ($1.font:get_width label) $1.xpad)
:wdropdown (* 150 SCALE)
:w #(+ $1.wlabel $1.wdropdown)
:tag label)
form-dropdown (lume.merge form {:x (+ x wlabel) :w wdropdown})
_ (renderer.draw_text font label x y color)
selection (dropdown form-dropdown selection options)]
(set form.h form-dropdown.h)
selection))
(local form-preserved-keys (collect [_ key (ipairs [:view :x :y :font :color :xpad :ypad])] key true))
(fn prepare-form [form overrides]
(each [key (pairs form)]
@ -312,18 +326,18 @@
form)
(fn vert [form viewfn overrides ...]
(let [result [(viewfn (prepare-form form overrides) ...)]]
(let [result (if viewfn [(viewfn (prepare-form form overrides) ...)] [])]
(set form.y (+ form.y (or form.h 0) (or form.ypad 0)))
(table.unpack result)))
(fn horiz [form viewfn overrides ...]
(let [result [(viewfn (prepare-form form overrides) ...)]]
(let [result (if viewfn [(viewfn (prepare-form form overrides) ...)] [])]
(set form.x (+ form.x (or form.w 0) (or form.xpad 0)))
(table.unpack result)))
(fn horiz-wrapper [{: x : w &as form}]
(set form.w nil)
(fn [viewfn overrides ...]
(fn [form viewfn overrides ...]
(let [result [(viewfn (prepare-form form overrides) ...)]]
(set form.x (+ form.x (or form.w 0) (or form.xpad 0)))
(when (> (+ form.x (or form.w 0)) (+ x w))
@ -361,7 +375,7 @@
viewfn-or-form)))))
{: attach-imstate : cmd-predicate : postpone : mouse-inside : activate : active?
: button : checkbox : textbox : textfield : textbutton : dropdown
: button : checkbox : textbox : textfield : textbutton : dropdown : labelled-dropdown
: vert : horiz : horiz-wrapper : begin-group
: with-style : prepare-form : form-defaults}

View file

@ -1,9 +1,9 @@
(local GraphicsEditView (require :editor.gfxedit))
(local GraphicsEditView (require :editor.gfxedit2))
(local style (require :core.style))
(local util (require :lib.util))
(local lume (require :lib.lume))
(local files (require :game.files))
(local {: mouse-inside : activate : active? : checkbox : textfield : textbutton : textbox : dropdown} (util.require :editor.imstate))
(local {: mouse-inside : activate : active? : checkbox : textfield : textbutton : textbox : dropdown : labelled-dropdown : vert : horiz : begin-group} (util.require :editor.imgui))
(local {: tilestrip-to-sprite} (util.require :editor.tiledraw))
(local {: encode-yx : encode-itile : decode-itile : dimensions} (util.require :game.tiles))
(local actions (require :editor.actions))
@ -84,30 +84,24 @@
(set files.game.levels []))
files.game.levels)
(fn MapEditView.draw-map-selector [self x y]
(renderer.draw_text style.font "Map" x (+ y (/ style.padding.y 2)) style.text)
(let [options {}
level-count (length (self:levels))
_ (do (for [i 1 level-count] (tset options i i))
(table.insert options :New))
(ilevel yNext) (dropdown self :map-selector self.ilevel options (+ x (* 50 SCALE)) y (* 100 SCALE))]
(fn MapEditView.draw-map-selector [self {: x : y &as form}]
(let [level-count (length (self:levels))
options (icollect [i (util.countiter (+ level-count 1))] (if (<= i level-count) i :New))
ilevel (vert form labelled-dropdown {:tag :map-selector :wdropdown (* 100 SCALE)} "Map" self.ilevel options)]
(when (not= ilevel self.ilevel)
(set self.ilevel (if (= ilevel :New) (+ level-count 1) ilevel))
(self:load-level))
(- yNext y)))
(self:load-level))))
(fn MapEditView.set-ilayer [self ilayer]
(set self.ilayer ilayer)
(self:set-style (self:layer-type)))
(fn MapEditView.draw-layer-selector [self x y]
(renderer.draw_text style.font "Layer" x (+ y (/ style.padding.y 2)) style.text)
(fn MapEditView.draw-layer-selector [self {: x : y &as form}]
(let [mkopt (fn [ilayer] {: ilayer :label (.. ilayer " (" (self:layer-type ilayer) ")")})
options (icollect [ilayer (ipairs (platform :layers))] (mkopt ilayer))
(selection yNext) (dropdown self :layer-selector (mkopt self.ilayer) options (+ x (* 50 SCALE)) y (* 100 SCALE))]
selection (vert form labelled-dropdown {:wdropdown (* 100 SCALE) :tag :layer-selector} "Layer" (mkopt self.ilayer) options)]
(when (not= self.ilayer selection.ilayer)
(self:set-ilayer selection.ilayer))
(- yNext y)))
(self:set-ilayer selection.ilayer))))
(fn MapEditView.linking-obj [self] (. self.level.objects self.iobject-linking))
(fn MapEditView.draw-link-line [self x y iobjectSrc color toMouse?]
@ -125,6 +119,14 @@
(love.graphics.circle :line xEnd yEnd (/ tilew 5))
(love.graphics.setColor 1 1 1)))
(fn MapEditView.draw-link-lines [self {: x : y} iobject-over]
(for [iobject 1 (length self.level.objects)]
(self:draw-link-line x y iobject [0 0 1 0.3]))
(when (not= iobject-over nil) (self:draw-link-line x y iobject-over [0 0.5 1] false))
(when (not= self.iobject-linking nil)
(if (= self.imstate.left :released) (set self.iobject-linking nil)
(self:draw-link-line x y self.iobject-linking [0 1 0] true))))
(fn MapEditView.draw-tilestrip [self x y my ?ilayer]
; stripcache leaks but honestly who cares
(local tilestrip [])
@ -145,13 +147,55 @@
intileh (or ystagger tileh)]
[(+ (or xstagger 0) (* mapw tilew)) (+ tileh (* (- maph 1) intileh))]))
(fn MapEditView.draw-map-editor [self x y ilayer]
(fn MapEditView.draw-player [self mx my x y]
(each [_ player (ipairs (or files.game.players [:player]))]
(match (. self.level player)
{:x mx :y my} (renderer.draw_text style.font player x y style.text)))
(love.graphics.setColor 1 1 1))
(fn MapEditView.draw-object-box [self iobject x y w h]
(when (not= iobject nil)
(love.graphics.setColor 1 0 (if (and (= self.itile nil) (= iobject self.iobject)) 1 0))
(love.graphics.setLineWidth 3)
(love.graphics.rectangle :line x y w h)
(love.graphics.setColor 1 1 1)))
(fn MapEditView.handle-mouseedits-object [self mx my x y w h]
(when (and (active? self :map) (mouse-inside x y w h))
(let [iobject (self:iobject-from-xy mx my)]
(match self.imstate.left
:pressed (set self.iobject-linking iobject)
:released
(if (and (not= iobject nil) (= self.iobject-linking iobject))
(set self.iobject iobject)
(not= self.iobject-linking nil)
(tset (self:linking-obj) :link iobject)
(not= self.playerpos nil)
(do (tset self.level self.playerpos {:x mx :y my})
(set self.playerpos nil))
(= iobject nil)
(let [tile (self.tilecache:tile (self:itile-from-xy mx my))]
(table.insert self.level.objects {:x mx :y my :func (or tile.word "")})
(set self.iobject (length self.level.objects))))))))
(fn MapEditView.handle-mouseedits-tile [self mx my x y w h]
(when (and (active? self :map) (mouse-inside x y w h) (not= (self:itile-from-xy mx my) self.itile))
(self:set-tile mx my self.itile)))
(fn MapEditView.draw-tile-xy-label [self mx my x y h ystagger]
(local labely (math.floor (+ y (- (or ystagger 0)) (/ (- (if ystagger (* ystagger 2) h) (style.font:get_height)) 2))))
(renderer.draw_text style.font (string.format "%x" (encode-yx {:x mx :y my})) (+ x 20) labely style.text)
(love.graphics.setColor 1 1 1))
(fn MapEditView.draw-map-editor [self {: x : y &as form} ilayer]
(love.graphics.setColor 1 1 1 1)
(local button-state self.imstate.left)
(local {: mapw : maph : tilew : tileh : xstagger : ystagger} (self:scaled-dimensions ilayer))
(local intileh (or ystagger tileh))
(local [mappw mapph] (self:mapsize ilayer))
(activate self :map x y mappw mapph)
(let [[w h] (self:mapsize ilayer)] (lume.extend form {: w : h :tag :map}))
(activate form)
(var iobject-over nil)
(for [my 1 maph]
(local tiley (+ y (* (- my 1) (or ystagger tileh))))
@ -160,51 +204,18 @@
(self:draw-tilestrip (+ x xoff) tiley my ilayer)
(for [mx 1 mapw]
(local tilex (+ x (* (- mx 1) tilew) xoff))
(local itile (self:itile-from-xy mx my))
(local iobject (self:iobject-from-xy mx my))
(when (= self.itile nil)
(each [_ player (ipairs (or files.game.players [:player]))]
(match (. self.level player)
{:x mx :y my} (renderer.draw_text style.font player tilex intiley style.text)))
(love.graphics.setColor 1 1 1))
(when (and (not= iobject nil) (= self.itile nil))
(love.graphics.setColor 1 0 (if (and (= self.itile nil) (= iobject self.iobject)) 1 0))
(love.graphics.setLineWidth 3)
(love.graphics.rectangle :line tilex intiley tilew intileh)
(love.graphics.setColor 1 1 1))
(self:draw-player mx my tilex intiley)
(self:draw-object-box iobject tilex intiley tilew intileh))
(if self.itile
(self:handle-mouseedits-tile mx my tilex intiley tilew intileh)
(self:handle-mouseedits-object mx my tilex intiley tilew intileh))
(when (mouse-inside tilex intiley tilew intileh)
(when (not= iobject nil) (set iobject-over iobject))
(local labely (math.floor (+ intiley (- (or ystagger 0)) (/ (- (if ystagger (* ystagger 2) tileh) (style.font:get_height)) 2))))
(renderer.draw_text style.font (string.format "%x" (encode-yx {:x mx :y my})) (+ tilex 20) labely style.text)
(love.graphics.setColor 1 1 1))
(when (and self.itile (active? self :map) (mouse-inside tilex intiley tilew intileh) (not= itile self.itile))
(self:set-tile mx my self.itile))
(when (and (= self.itile nil) (active? self :map) (mouse-inside tilex intiley tilew intileh))
(match button-state
:pressed (set self.iobject-linking iobject)
:released
(if (and (not= iobject nil) (= self.iobject-linking iobject))
(set self.iobject iobject)
(not= self.iobject-linking nil)
(tset (self:linking-obj) :link iobject)
(not= self.playerpos nil)
(do (tset self.level self.playerpos {:x mx :y my})
(set self.playerpos nil))
(= iobject nil)
(let [tile (self.tilecache:tile itile)]
(table.insert self.level.objects {:x mx :y my :func (or tile.word "")})
(set self.iobject (length self.level.objects))))))))
(when (= self.itile nil)
(for [iobject 1 (length self.level.objects)]
(self:draw-link-line x y iobject [0 0 1 0.3]))
(when (not= iobject-over nil) (self:draw-link-line x y iobject-over [0 0.5 1] false))
(when (not= self.iobject-linking nil)
(if (= self.imstate.left :released) (set self.iobject-linking nil)
(self:draw-link-line x y self.iobject-linking [0 1 0] true))))
mapph)
(self:draw-tile-xy-label mx my tilex intiley tileh ystagger))))
(when (= self.itile nil) (self:draw-link-lines form iobject-over))
(vert form))
(fn condition-label [flag]
(if flag {:label flag : flag} {:label "<always>"}))
@ -215,23 +226,18 @@
(table.insert options (condition-label flag)))
options))
(fn MapEditView.draw-object-code-editor [self object x y]
(var y y)
(fn MapEditView.draw-object-code-editor [self form object]
(var istep-to-delete nil)
(when (not object.steps) (set object.steps []))
(each [istep step (ipairs object.steps)]
(when (textbutton self "X" (+ x (* 280 SCALE)) y)
(when (textbutton (lume.merge form {:x (+ form.x (* 280 SCALE))}) "X")
(set istep-to-delete istep))
(set step.condition (. (dropdown self [:code-condition istep] (condition-label step.condition) (condition-options)
(+ x (* 100 SCALE) style.padding.x) y (* 100 SCALE))
:flag))
(set (step.action y) (dropdown self [:code-action istep] (or step.action (. actions.actionlist 1)) actions.actionlist x y (* 100 SCALE)))
(set y (actions.edit step self x y (* 300 SCALE) istep))
(set y (+ y style.padding.y)))
(set step.condition (. (dropdown (lume.merge form {:x (+ form.x (* 100 SCALE)) :w (* 100 SCALE) :tag [:code-condition istep]}) (condition-label step.condition) (condition-options)) :flag))
(set step.action (vert form dropdown {:w (* 100 SCALE) :tag [:code-action istep]} (or step.action (. actions.actionlist 1)) actions.actionlist))
(vert form actions.edit {:w (* 300 SCALE)} istep))
(when istep-to-delete (table.remove object.steps istep-to-delete))
(let [(do-new y) (textbutton self "+ New Step" x (+ y style.padding.y))]
(when do-new (table.insert object.steps {}))
y))
(when (vert form textbutton {} "+ New Step")
(table.insert object.steps {})))
(fn advanced? [object]
(or object.advanced
@ -239,36 +245,36 @@
(not= object.func "")
(not= object.func nil))))
(fn MapEditView.draw-object-advanced-editor [self object x y]
(let [(func y) (textfield self "Word" object.func x y (* 100 SCALE) (* 200 SCALE))
(name y) (textfield self "Name" object.name x (+ y style.padding.y) (* 100 SCALE) (* 200 SCALE))
(linkword y) (textfield self "Link word" object.linkword x (+ y style.padding.y) (* 100 SCALE) (* 200 SCALE))
(do-unlink y) (if object.link (textbutton self "Unlink" x (+ y style.padding.y)) (values false y))
(linkentity y) (if object.link (values object.linkentity y) (textfield self "Link entity" object.linkentity x (+ y style.padding.y) (* 100 SCALE) (* 200 SCALE)))]
(lume.extend object {: func : name : linkword : linkentity})
(when do-unlink (set object.link nil))
y))
(fn MapEditView.draw-object-advanced-editor [self form object]
(let [fieldform {:wlabel (* 100 SCALE) :wtext (* 200 SCALE)}]
(set object.func (vert form textfield fieldform "Word" object.func))
(set object.name (vert form textfield fieldform "Name" object.name))
(set object.linkword (vert form textfield fieldform "Link word" object.linkword))
(if object.link
(when (vert form textbutton {} "Unlink")
(set object.link nil))
(set object.linkentity (vert form textfield fieldform "Link entity" object.linkentity)))))
(fn MapEditView.draw-object-editor [self x y]
(fn MapEditView.draw-object-editor [self form]
(let [object (self:object)
y (if (advanced? object)
(self:draw-object-advanced-editor object x y)
(self:draw-object-code-editor object x y))
new-flag-name (textbox self :new-flag-name self.new-flag-name x (+ y style.padding.y) (* 200 SCALE))
(mk-new-flag y) (textbutton self "+ New Flag" (+ x (* 200 SCALE) style.padding.x) (+ y style.padding.y))
do-delete (textbutton self "Delete" x (+ y (* style.padding.y 2)))
(do-advanced y) (textbutton self (if (advanced? object) "Simple" "Advanced") (+ x (* 150 SCALE)) (+ y (* style.padding.y 2)))]
(set self.new-flag-name new-flag-name)
(when mk-new-flag
footer (begin-group)]
(if (advanced? object)
(self:draw-object-advanced-editor form object)
(self:draw-object-code-editor form object))
(set self.new-flag-name (footer horiz form textbox {:tag :new-flag-name :w (* 200 SCALE)} self.new-flag-name))
(when (footer horiz form textbutton {} "+ New Flag")
(when (= files.game.flags nil)
(set files.game.flags []))
(table.insert files.game.flags new-flag-name)
(table.insert files.game.flags self.new-flag-name)
(set self.new-flag-name ""))
(when do-delete
(footer form)
(when (footer vert form textbutton {} "Delete")
(move-object self.level.objects (+ self.iobject 1) self.iobject)
(set self.iobject nil))
(when do-advanced (set object.advanced (not (advanced? object))))
y))
(when (footer textbutton (lume.merge form {:x (+ form.x (* 150 SCALE))}) (if (advanced? object) "Simple" "Advanced"))
(set object.advanced (not (advanced? object))))
(footer form)
(vert form)))
(fn MapEditView.load-level [self]
(set self.stripcache {})
@ -282,43 +288,36 @@
(self:load-level))
(fn MapEditView.draw [self]
(var x (+ self.position.x style.padding.x (- self.scroll.x)))
(var y (+ self.position.y style.padding.y (- self.scroll.y)))
(self:draw_background style.background)
(self:draw_scrollbar)
(local {: mapw : maph : tilew : tileh} (self:scaled-dimensions))
(local ytop y)
(local editor-on-side (> self.size.x (+ (* tilew mapw) (* 300 SCALE))))
(when (platform :layers) (self:draw-layer-selector (+ x (* 200 SCALE)) y))
(set y (+ y (self:draw-map-selector x y) style.padding.y))
(set y (+ y (self:draw-map-editor x y) style.padding.y))
(set y (+ y (self:draw-tile-selector x y (if editor-on-side (* tilew mapw)
(- self.size.x (* style.padding.x 2))))))
(set (self.level.tickword y) (textfield self "Tick word" self.level.tickword x (+ y style.padding.y) (* 100 SCALE) (* 200 SCALE)))
(set (self.level.moveword y) (textfield self "Move word" self.level.moveword x (+ y style.padding.y) (* 100 SCALE) (* 200 SCALE)))
(set (self.level.loadword y) (textfield self "Load word" self.level.loadword x (+ y style.padding.y) (* 100 SCALE) (* 200 SCALE)))
(let [(checked y-new) (checkbox self "Edit objects" (= self.itile nil) x (+ y style.padding.y))
_ (when checked
(set self.itile nil)
(set self.playerpos nil))]
(set y y-new)
(let [form (self:form)
form-editor (self:form)
header (begin-group)
_ (self:draw-map-selector form header)
_ (when (platform :layers) (self:draw-layer-selector form header))
_ (self:draw-map-editor form)
editor-on-side (> self.size.x (+ form.w (* 300 SCALE)))
fieldform {:wlabel (* 100 SCALE) :wtext (* 200 SCALE)}]
(when editor-on-side
(set form-editor.x (+ form.x form.w style.padding.x))
(set form-editor.w (- form-editor.w form.w style.padding.x)))
(self:draw-tile-selector (lume.extend form {:w (if editor-on-side form.w (- self.size.x (* style.padding.x 2)))}))
(set self.level.tickword (vert form textfield fieldform "Tick word" self.level.tickword))
(set self.level.moveword (vert form textfield fieldform "Move word" self.level.moveword))
(set self.level.loadword (vert form textfield fieldform "Load word" self.level.loadword))
(when (vert form checkbox {} "Edit objects" (= self.itile nil))
(set self.itile nil)
(set self.playerpos nil))
(each [_ player (ipairs (or files.game.players [:player]))]
(let [(checked y-new) (checkbox self (.. "Position " player) (and (= self.itile nil) (= self.playerpos player)) x (+ y style.padding.y))]
(when checked
(set self.itile nil)
(set self.playerpos player))
(set y y-new))))
(each [_ levelflag (ipairs (or files.game.levelflags []))]
(let [(checked y-new) (checkbox self levelflag (. self.level levelflag) x (+ y style.padding.y))]
(when checked (tset self.level levelflag (not (. self.level levelflag))))
(set y y-new)))
(when self.iobject
(set y (math.max y (if editor-on-side
(self:draw-object-editor (+ x (* tilew mapw) style.padding.x) ytop)
(self:draw-object-editor x (+ y style.padding.y))))))
(set self.scrollheight (+ y (- self.position.y) self.scroll.y style.padding.y)))
(when (vert form checkbox {} (.. "Position " player) (and (= self.itile nil) (= self.playerpos player)))
(set self.itile nil)
(set self.playerpos player)))
(each [_ levelflag (ipairs (or files.game.levelflags []))]
(when (vert form checkbox {} levelflag (. self.level levelflag))
(tset self.level levelflag (not (. self.level levelflag)))))
(when (not editor-on-side) (set form-editor.y (+ form.y form.h style.padding.y)))
(when self.iobject (self:draw-object-editor form-editor))
(self:end-scroll (if (> (+ form.y form.h) (+ form-editor.y (or form-editor.h 0))) form form-editor))))
(fn MapEditView.get_name [self] (.. "Map " self.ilevel))

View file

@ -102,7 +102,7 @@
(when (= icolor selected-color)
(love.graphics.setColor 1 1 1 1)
(love.graphics.rectangle :line (- form.x 2) (- form.y 2) (+ pixel-size 4) (+ pixel-size 4)))
(when (g wrap button {:tag [:pal icolor] :w pixel-size :h pixel-size})
(when (g wrap form button {:tag [:pal icolor] :w pixel-size :h pixel-size})
(set selected-color icolor)))
(g form)
selected-color))