Multiple tile-style support, layered maps
This commit is contained in:
parent
fe00a91064
commit
18f62e89b9
|
@ -12,14 +12,19 @@
|
|||
|
||||
(fn GraphicsEditView.new [self]
|
||||
(GraphicsEditView.super.new self)
|
||||
(set self.tilecache (files.cache (self:resource-key)))
|
||||
(set self.itile 1)
|
||||
(self:set-style (self:initial-style))
|
||||
(set self.scrollheight math.huge)
|
||||
(set self.scrollable true)
|
||||
(attach-imstate self))
|
||||
(fn GraphicsEditView.get_scrollable_size [self] self.scrollheight)
|
||||
(fn GraphicsEditView.resource-key [self] :tiles)
|
||||
(fn GraphicsEditView.tilesize [self] (values 16 16))
|
||||
(fn GraphicsEditView.initial-style [self] :tiles)
|
||||
(fn GraphicsEditView.tilesize [self]
|
||||
(let [style (tiles.style self.style)]
|
||||
(values (or style.editw style.tilew) (or style.edith style.tileh))))
|
||||
(fn GraphicsEditView.set-style [self key]
|
||||
(set self.style key)
|
||||
(set self.tilecache (files.cache key))
|
||||
(set self.itile 1))
|
||||
(fn GraphicsEditView.reload [self] (files.reload))
|
||||
(fn GraphicsEditView.save [self] (files.save))
|
||||
|
||||
|
|
|
@ -5,48 +5,56 @@
|
|||
(local files (require :game.files))
|
||||
(local {: mouse-inside : activate : active? : checkbox : textfield : textbutton : textbox : dropdown} (util.require :editor.imstate))
|
||||
(local {: tilestrip-to-sprite} (util.require :editor.tiledraw))
|
||||
(local {: encode-yx : encode-itile : decode-itile} (util.require :game.tiles))
|
||||
(local {: encode-yx : encode-itile : decode-itile : dimensions} (util.require :game.tiles))
|
||||
(local actions (require :editor.actions))
|
||||
|
||||
(local MapEditView (GraphicsEditView:extend))
|
||||
(local sprite-scale 3)
|
||||
|
||||
(local platforms {
|
||||
:ii {:mapw 20 :maph 12 :tilew 14 :tileh 16}
|
||||
:iigs {:mapw 20 :maph 12 :tilew 16 :tileh 16}
|
||||
})
|
||||
(fn platform [?key] (let [p (dimensions)] (if ?key (. p ?key) p)))
|
||||
(fn MapEditView.layer-type [self ?ilayer] (or (?. (platform :layers) (or ?ilayer self.ilayer)) :tiles))
|
||||
(fn MapEditView.dimensions [self ?ilayer] (or (platform (self:layer-type)) (platform)))
|
||||
|
||||
(local platform (. platforms (files.platform)))
|
||||
(local {: mapw : maph} platform)
|
||||
(local tilew (* sprite-scale platform.tilew))
|
||||
(local tileh (* sprite-scale platform.tileh))
|
||||
(fn MapEditView.mapw [self ?ilayer] (. (self:dimensions ?ilayer) :mapw))
|
||||
(fn MapEditView.maph [self ?ilayer] (. (self:dimensions ?ilayer) :maph))
|
||||
(fn MapEditView.tilew [self ?ilayer] (* sprite-scale (. (self:dimensions ?ilayer) :tilew)))
|
||||
(fn MapEditView.tileh [self ?ilayer] (* sprite-scale (. (self:dimensions ?ilayer) :tileh)))
|
||||
|
||||
(fn MapEditView.empty-map [self] (string.rep "\0" (* (self:mapw) (self:maph))))
|
||||
|
||||
(fn MapEditView.new [self]
|
||||
(MapEditView.super.new self)
|
||||
(set self.sprite-scale sprite-scale)
|
||||
(set self.stripcache {})
|
||||
(set self.ilevel 1)
|
||||
(self:set-ilayer 1)
|
||||
(self:reload))
|
||||
|
||||
; map is stored bottom-to-top
|
||||
(fn imap-from-xy [mx my]
|
||||
(+ mx -1 (* mapw (- maph my))))
|
||||
(fn MapEditView.imap-from-xy [self mx my]
|
||||
(+ mx -1 (* (self:mapw) (- (self:maph) my))))
|
||||
|
||||
(fn update-map [map mx my itile]
|
||||
(local imap (imap-from-xy mx my))
|
||||
(fn MapEditView.update-map [self map mx my itile]
|
||||
(local imap (self:imap-from-xy mx my))
|
||||
(local enctile (encode-itile itile))
|
||||
(..
|
||||
(map:sub 1 imap)
|
||||
(string.char enctile)
|
||||
(map:sub (+ imap 2))))
|
||||
|
||||
(fn MapEditView.map [self]
|
||||
(if (platform :layers) (or (?. self.level.layers self.ilayer) (self:empty-map))
|
||||
self.level.map))
|
||||
|
||||
(fn MapEditView.itile-from-xy [self mx my]
|
||||
(local imap (+ (imap-from-xy mx my) 1))
|
||||
(local enctile (string.byte (self.level.map:sub imap imap)))
|
||||
(local imap (+ (self:imap-from-xy mx my) 1))
|
||||
(local enctile (string.byte (string.sub (self:map) imap imap)))
|
||||
(decode-itile enctile))
|
||||
|
||||
(fn MapEditView.set-tile [self mx my itile]
|
||||
(set self.level.map (update-map self.level.map mx my itile)))
|
||||
(let [updated-map (self:update-map (self:map) mx my itile)]
|
||||
(if (platform :layers) (util.nested-tset self.level [:layers self.ilayer] updated-map)
|
||||
(set self.level.map updated-map))))
|
||||
|
||||
(fn MapEditView.iobject-from-xy [self mx my ?iobj]
|
||||
(local iobj (or ?iobj 1))
|
||||
|
@ -83,11 +91,25 @@
|
|||
(self:load-level))
|
||||
(- yNext y)))
|
||||
|
||||
(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)
|
||||
(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))]
|
||||
(when (not= self.ilayer selection.ilayer)
|
||||
(self:set-ilayer selection.ilayer))
|
||||
(- yNext y)))
|
||||
|
||||
(fn MapEditView.linking-obj [self] (. self.level.objects self.iobject-linking))
|
||||
(fn MapEditView.draw-link-line [self x y iobjectSrc color toMouse?]
|
||||
(local objectSrc (. self.level.objects iobjectSrc))
|
||||
(local objectDest (. self.level.objects objectSrc.link))
|
||||
(local coord (fn [c m d] (+ c (* (- m 1) d) (/ d 2))))
|
||||
(local [tilew tileh] [(self:tilew) (self:tileh)])
|
||||
(local xStart (coord x objectSrc.x tilew))
|
||||
(local yStart (coord y objectSrc.y tileh))
|
||||
(when (or toMouse? objectDest)
|
||||
|
@ -102,7 +124,7 @@
|
|||
; stripcache leaks but honestly who cares
|
||||
(local tilestrip [])
|
||||
(var stripid "")
|
||||
(for [mx 1 mapw]
|
||||
(for [mx 1 (self:mapw)]
|
||||
(local itile (self:itile-from-xy mx my))
|
||||
(local tile (?. self.tilecache.tiles itile :gfx))
|
||||
(table.insert tilestrip tile)
|
||||
|
@ -116,6 +138,7 @@
|
|||
(fn MapEditView.draw-map-editor [self x y]
|
||||
(love.graphics.setColor 1 1 1 1)
|
||||
(local button-state self.imstate.left)
|
||||
(local [mapw maph tilew tileh] [(self:mapw) (self:maph) (self:tilew) (self:tileh)])
|
||||
(activate self :map x y (* tilew mapw) (* tileh maph))
|
||||
(var iobject-over nil)
|
||||
(for [my 1 maph]
|
||||
|
@ -234,7 +257,7 @@
|
|||
(fn MapEditView.load-level [self]
|
||||
(set self.stripcache {})
|
||||
(when (= (. (self:levels) self.ilevel) nil)
|
||||
(tset (self:levels) self.ilevel {:map (string.rep "\0" (* mapw maph)) :objects []}))
|
||||
(tset (self:levels) self.ilevel {:map (self:empty-map) :objects []}))
|
||||
(set self.level (. (self:levels) self.ilevel))
|
||||
(set self.iobject nil))
|
||||
|
||||
|
@ -247,9 +270,12 @@
|
|||
(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:mapw) (self:maph) (self:tilew) (self:tileh)])
|
||||
(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))
|
||||
|
||||
(self:draw-map-editor x y)
|
||||
(set y (+ y (* tileh maph) style.padding.y))
|
||||
(set y (+ y (self:draw-tile-selector x y (if editor-on-side (* tilew mapw)
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
(local {: putpixel : make-canvas} (require :editor.tiledraw))
|
||||
(local tiles (require :game.tiles))
|
||||
|
||||
; converted from http://pixeljoint.com/forum/forum_posts.asp?TID=12795 (db16)
|
||||
; maybe check out https://lospec.com/palette-list ?
|
||||
(local pal [[1 0 1] [4 2 3] [3 3 6] [4 4 4] [8 4 3] [3 6 2] [13 4 4] [7 7 6]
|
||||
[5 7 12] [13 7 2] [8 9 10] [6 10 2] [13 10 9] [6 12 12] [13 13 5] [13 14 13]])
|
||||
(fn gs-to-rgb [color] (icollect [_ v (ipairs color)] (* v 0x11)))
|
||||
(fn gs-to-rgb [color] (icollect [_ v (ipairs (or color [0 0 0]))] (* v 0x11)))
|
||||
|
||||
(fn tile-to-sprite [tile]
|
||||
(if tile (make-canvas 16 16 (fn [canvas]
|
||||
(love.graphics.clear 0 0 0 0)
|
||||
(for [y 0 15]
|
||||
(for [x 0 15]
|
||||
(let [ibyte (+ (* y 16) x 1)
|
||||
byte (string.byte (tile:sub ibyte ibyte))
|
||||
mask (bit.band (bit.rshift byte 4) 0xf)
|
||||
color (bit.band byte 0xf)
|
||||
rgb (if (= mask 0) (gs-to-rgb (. pal (+ color 1))) [255 0 255])]
|
||||
(when (= mask 0) (putpixel x y rgb)))))))))
|
||||
(fn spritegen-for-size [w h]
|
||||
(fn [tile]
|
||||
(when tile (make-canvas w h (fn [canvas]
|
||||
(love.graphics.clear 0 0 0 0)
|
||||
(for [y 0 (- h 1)]
|
||||
(for [x 0 (- w 1)]
|
||||
(let [ibyte (+ (* y w) x 1)
|
||||
byte (string.byte (tile:sub ibyte ibyte))
|
||||
mask (bit.band (bit.rshift byte 4) 0xf)
|
||||
color (bit.band byte 0xf)
|
||||
rgb (if (= mask 0) (gs-to-rgb (. pal (+ color 1))) [255 0 255])]
|
||||
(when (= mask 0) (putpixel x y rgb))))))))))
|
||||
|
||||
{: tile-to-sprite : pal : gs-to-rgb}
|
||||
(local tile-to-sprite (spritegen-for-size 16 16))
|
||||
|
||||
(fn spritegen-for-style [name]
|
||||
(let [{: tilew : tileh} (tiles.style name)]
|
||||
(spritegen-for-size tilew tileh)))
|
||||
|
||||
{: tile-to-sprite : spritegen-for-size : spritegen-for-style : pal : gs-to-rgb}
|
||||
|
|
|
@ -31,6 +31,14 @@
|
|||
#(each [isprite sprite (ipairs sprites)]
|
||||
(love.graphics.draw sprite (* (sprite:getWidth) (- isprite 1)) 0))))))
|
||||
|
||||
(files.default-platform-method TileDraw :editor.tiledraw :spritegen-for-style
|
||||
(fn [style]
|
||||
(match style
|
||||
:font TileDraw.char-to-sprite
|
||||
:brushes TileDraw.char-to-sprite
|
||||
:portraits TileDraw.portrait-to-sprite
|
||||
_ TileDraw.tile-to-sprite)))
|
||||
|
||||
(fn TileDraw.TileCache [tiles ?spritegen]
|
||||
{: tiles
|
||||
:spritegen (or ?spritegen TileDraw.tile-to-sprite)
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
(local {: pal : gs-to-rgb} (require :editor.tiledraw.iigs))
|
||||
(local lume (require :lib.lume))
|
||||
|
||||
{:map-bitxy (fn [self x y] (values (+ (* y 16) x) 0 0xff))
|
||||
{:map-bitxy (fn [self x y w h] (values (+ (* y w) x) 0 0xff))
|
||||
:pixel-color (fn [self b] (match b 0xf0 (values [128 128 128] [64 64 64])
|
||||
_ (gs-to-rgb (. pal (+ b 1)))))
|
||||
:draw-bits #(if (= $1.icolor 17) 0xf0 (- $1.icolor 1))
|
||||
:palette #(lume.concat (icollect [_ color (ipairs pal)] (gs-to-rgb color)) [[255 0 255]])
|
||||
:pixel-storage-divisor #1
|
||||
:preview-locations #[[8 0] [0 5] [16 5] [8 10]]
|
||||
:blank-tile-byte #"\xf0"
|
||||
:preview-locations (fn [self]
|
||||
(match self.style
|
||||
:iso [[12 0] [0 6] [24 6] [12 12]]
|
||||
_ [[0 0] [12 0] [0 12] [12 12]]))
|
||||
}
|
||||
|
||||
|
|
|
@ -3,14 +3,13 @@
|
|||
(local tiles (require :game.tiles))
|
||||
(local files (require :game.files))
|
||||
(local util (require :lib.util))
|
||||
(local {: mouse-inside : activate : active? : checkbox : textfield : button} (util.require :editor.imstate))
|
||||
(local {: mouse-inside : activate : active? : checkbox : textfield : button : dropdown} (util.require :editor.imstate))
|
||||
|
||||
(local TileView (GraphicsEditView:extend))
|
||||
|
||||
(set TileView.pixel-size 24)
|
||||
(local pixel-size TileView.pixel-size)
|
||||
|
||||
(fn TileView.tilesize [self] (values 16 16))
|
||||
(fn TileView.tilekeys [self]
|
||||
(if files.game.tilesets (icollect [_ key (pairs files.game.tilesets)] key)
|
||||
[:gfx]))
|
||||
|
@ -37,10 +36,12 @@
|
|||
(files.default-platform-method TileView :editor.tileedit :preview-locations
|
||||
(fn [self] (let [(w h) (self:tilesize)] [[0 0] [w 0] [0 h] [w h]])))
|
||||
|
||||
(files.default-platform-method TileView :editor.tileedit :blank-tile-byte #"\0")
|
||||
|
||||
(fn TileView.tile [self]
|
||||
(local (w h) (self:tilesize))
|
||||
(or (-?> self.tilecache.tiles (. self.itile) (. (or self.tilekey :gfx)))
|
||||
(string.rep "\0" (/ (* w h) (self:pixel-storage-divisor)))))
|
||||
(string.rep (self:blank-tile-byte) (/ (* w h) (self:pixel-storage-divisor)))))
|
||||
|
||||
(fn TileView.draw-pixel [self x y colorbg ?colorfg]
|
||||
(renderer.draw_rect x y pixel-size pixel-size colorbg)
|
||||
|
@ -53,7 +54,7 @@
|
|||
(local editor-h (* (+ pixel-size 1) h))
|
||||
(activate self :tile x y editor-w editor-h)
|
||||
(for [bitx 0 (- w 1)] (for [bity 0 (- h 1)]
|
||||
(local (ibyte ibit mask) (self:map-bitxy bitx bity))
|
||||
(local (ibyte ibit mask) (self:map-bitxy bitx bity w h))
|
||||
(local b (get-bits tile ibyte ibit mask))
|
||||
(local (px py) (values (+ x (* bitx (+ pixel-size 1))) (+ y (* bity (+ pixel-size 1)))))
|
||||
(local (colorbg colorfg) (self:pixel-color b ibyte ibit))
|
||||
|
@ -107,7 +108,14 @@
|
|||
0))
|
||||
|
||||
(fn TileView.update-tile [self newtile]
|
||||
(self.tilecache:update-tile self.itile newtile self.tilekey))
|
||||
(self.tilecache:update-tile self.itile newtile self.tilekey))
|
||||
|
||||
(fn TileView.draw-style-selector [self x y]
|
||||
(renderer.draw_text style.font "Style" x (+ y (/ style.padding.y 2)) style.text)
|
||||
(let [(selection yNext) (dropdown self :layer-selector self.style (tiles.tile-styles) (+ x (* 50 SCALE)) y (* 100 SCALE)) ]
|
||||
(when (not= self.style selection)
|
||||
(self:set-style selection))
|
||||
(- yNext y)))
|
||||
|
||||
(fn TileView.draw [self]
|
||||
(self:draw_background style.background)
|
||||
|
@ -119,12 +127,14 @@
|
|||
(self:draw-tile-preview (+ x editor-w pixel-size) (+ preview-y style.padding.y))
|
||||
(var selector-y (+ y editor-h pixel-size))
|
||||
(set selector-y (+ selector-y (self:draw-tile-palette x selector-y (- self.size.x 20))))
|
||||
(when (> (length (tiles.tile-styles)) 1)
|
||||
(set selector-y (+ selector-y (self:draw-style-selector x selector-y) style.padding.y)))
|
||||
(each [_ key (ipairs (self:tilekeys))]
|
||||
(local selector-h (self:draw-tile-selector x selector-y (- self.size.x 20) key))
|
||||
(set selector-y (+ selector-y selector-h pixel-size)))
|
||||
(set self.scrollheight (- selector-y y)))
|
||||
|
||||
(fn TileView.resource-key [self] :tiles)
|
||||
(fn TileView.initial-style [self] :tiles)
|
||||
(fn TileView.get_name [self] "Tile Editor")
|
||||
|
||||
TileView
|
||||
|
|
|
@ -29,13 +29,17 @@
|
|||
(fn deserialize [key value root]
|
||||
(match key
|
||||
(where (or :tiles :portraits :font :brushes)) (tile-deserialize value root)
|
||||
:levels (do (set value.map (value.map:fromhex)) value)
|
||||
:levels (do (set value.map (value.map:fromhex))
|
||||
(set value.layers (icollect [_ layer (ipairs (or value.layers []))] (layer:fromhex)))
|
||||
value)
|
||||
_ value))
|
||||
|
||||
(fn serialize [key value root]
|
||||
(match key
|
||||
(where (or :tiles :portraits :font :brushes)) (tile-serialize value root)
|
||||
:levels (do (set value.map (value.map:tohex)) value)
|
||||
:levels (do (set value.map (value.map:tohex))
|
||||
(set value.layers (icollect [_ layer (ipairs (or value.layers []))] (layer:tohex)))
|
||||
value)
|
||||
_ value))
|
||||
|
||||
(fn clone [v]
|
||||
|
@ -65,11 +69,8 @@
|
|||
|
||||
(fn new-cache [game key]
|
||||
(let [tiledraw (require :editor.tiledraw)
|
||||
spritegen (match key
|
||||
:font tiledraw.char-to-sprite
|
||||
:brushes tiledraw.char-to-sprite
|
||||
:portraits tiledraw.portrait-to-sprite
|
||||
_ tiledraw.tile-to-sprite)
|
||||
tiles (require :game.tiles)
|
||||
spritegen (tiledraw.spritegen-for-style key)
|
||||
gfx (. game key)]
|
||||
(tiledraw.TileCache gfx spritegen)))
|
||||
|
||||
|
|
|
@ -2,6 +2,29 @@
|
|||
(local lume (require :lib.lume))
|
||||
(local files (require :game.files))
|
||||
|
||||
(local platforms {
|
||||
:ii {:mapw 20 :maph 12 :tilew 14 :tileh 16 :editw 16
|
||||
:font {:tilew 7 :editw 8 :tileh 8}
|
||||
:brushes {:tilew 7 :editw 8 :tileh 8}
|
||||
:portraits {:tilew 28 :editw 32 :tileh 32}}
|
||||
:iigs {:mapw 26 :maph 16 :tilew 12 :tileh 12
|
||||
:layers [:tiles :iso :iso]
|
||||
:yoffsets [0 6 0]
|
||||
:iso {:mapw 13 :maph 16 :tilew 24 :tileh 32 :stagger 12}
|
||||
:font {:tilew 8 :tileh 8}
|
||||
:brushes {:tilew 8 :tileh 8}
|
||||
:portraits {:tilew 32 :tileh 32}}
|
||||
})
|
||||
|
||||
(fn dimensions [] (. platforms (files.platform)))
|
||||
(fn style [name] (or (. (dimensions) name) (dimensions)))
|
||||
(fn tile-styles [include-details]
|
||||
(let [dim (dimensions)
|
||||
styles {:tiles dim}]
|
||||
(each [_ layer (ipairs (or dim.layers []))]
|
||||
(when (not= layer :tiles) (tset styles layer (. dim layer))))
|
||||
(if include-details styles (lume.keys styles))))
|
||||
|
||||
(fn flags [] (or files.game.tileflags [:walkable]))
|
||||
(fn flag-to-bit []
|
||||
(collect [iflag flag (ipairs (flags))] (values flag (bit.lshift 1 (- iflag 1)))))
|
||||
|
@ -55,5 +78,5 @@
|
|||
(find-itile tiles label (+ itile 1))))
|
||||
|
||||
{: appendtiles : appendgfx : append-portraitwords : flags : flag-to-bit : find-itile
|
||||
: encode-yx : encode-itile : decode-itile}
|
||||
: encode-yx : encode-itile : decode-itile : dimensions : tile-styles : style}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue