diff --git a/data/voxel_heights.lua b/data/voxel_heights.lua index e1aed77..2154f88 100644 --- a/data/voxel_heights.lua +++ b/data/voxel_heights.lua @@ -735,14 +735,21 @@ return { -- floor the artist had already drawn. So the couch keeps its -- polygonal box and he stands on top of it, at NPC scale. -- - -- The mask keeps the couch's east rule (column 7) wherever it is - -- drawn dark, because that is where his hair crosses the tile seam - -- -- without it the overhang would float free of his head. The - -- cushion wedge under his legs and the two floor pixels above his - -- head are the only interior pixels it gives back. + -- The mask keeps ALL of column 7, the couch's east edge. Where that + -- column is drawn dark it is the couch's own rule -- but it is also + -- where his hair crosses the tile seam, so dropping it floats the + -- overhang free of his head. And where it is drawn WHITE it is the + -- right side of his face, so dropping it opens a slit down his cheek + -- (rows 5-8, which is exactly what the first cut did). Keeping the + -- rule twice costs nothing: tile 39 redraws it on the couch beneath + -- him either way. The background corners around his head and the + -- cushion wedge under his legs are the only pixels given back. figures = { { - class = "billboard", + -- the `cutout` pool: one voxel, a flat card -- the same thing + -- the walking NPCs are, so the man reads as a person and not + -- as a ten-voxel wedge of furniture + class = "cutout", w = 2, tiles = { 37, 57, 53, 60 }, @@ -754,10 +761,10 @@ return { "XXXXXXXXX.......", "XXXXXXXXXX......", "XXXXXXXXXX......", - "XXXXXXX.X.......", - "XXXXXXX.X.......", - "XXXXXXX.X.......", - "XXXXXXX.X.......", + "XXXXXXXXX.......", + "XXXXXXXXX.......", + "XXXXXXXXX.......", + "XXXXXXXXX.......", "XXXXXXXX........", "XXXXXXXX........", "XXXXXXXX........", diff --git a/lib/Structures.lua b/lib/Structures.lua index 5045e77..bcd6d3f 100644 --- a/lib/Structures.lua +++ b/lib/Structures.lua @@ -2165,9 +2165,14 @@ local function buildFigure(S, map, fig, tx, ty, perRow) baseY, support = bs.h, bs end + -- He stands in the depth band of the tile row he is DRAWN in, centred. + -- No south shift: buildObject nudges a supported prop one row back + -- because a monitor is drawn in the rows ABOVE the desk it stands on, + -- so its drawn row is not its standing row. A figure's mask already + -- says exactly which row is his -- shifting it walked him off his own + -- cell and onto the couch's southern half. local depth = PINNED_DEPTH[fig.class] or PINNED_DEPTH.billboard - local z0 = ty * 8 + math.floor(lowY / 8) * 8 - + (support and 8 or 0) + (8 - depth) / 2 + local z0 = ty * 8 + math.floor(lowY / 8) * 8 + (8 - depth) / 2 local z1 = z0 + depth -- ONE object by construction: the figure keeps its drawn proportions @@ -2234,8 +2239,6 @@ end -- own tiles, so a match can never fire twice on the same drawing. function Structures.buildFigures(S, map, x0, x1, y0, y1) local figures = TileShape.figures(map.tileset.id) - print("[fig] map", map.id, "tileset", map.tileset.id, "figures", - figures and #figures or "nil") if not figures then return end local perRow = map.tileset.tilesPerRow or 16 for _, fig in ipairs(figures) do @@ -2250,10 +2253,7 @@ function Structures.buildFigures(S, map, x0, x1, y0, y1) break end end - if hit then - print("[fig] MATCH at", tx, ty) - buildFigure(S, map, fig, tx, ty, perRow) - end + if hit then buildFigure(S, map, fig, tx, ty, perRow) end end end end diff --git a/tests/voxel_figure_test.lua b/tests/voxel_figure_test.lua index c60f052..dff4a00 100644 --- a/tests/voxel_figure_test.lua +++ b/tests/voxel_figure_test.lua @@ -57,7 +57,14 @@ T.check(type(figs) == "table" and #figs == 1, local fig = figs[1] T.eq(fig.w, 2, "the figure is two tiles across") T.eq(fig.h, 2, "the figure is two tiles tall") -T.eq(fig.n, 124, "the mask claims 124 pixels of the 256 it spans") +T.eq(fig.n, 128, "the mask claims 128 pixels of the 256 it spans") + +-- no holes in him: his tiles' column 7 is the couch's east rule AND the +-- right side of his face, and masking it out by shade slit his cheek open +for ly = 5, 8 do + T.check(fig.mask[ly * (fig.w * 8) + 7] == true, + "his cheek is solid at row " .. ly .. " (the column-7 slit)") +end T.eq(fig.tiles[1], 37, "it starts at the tile his head is drawn in") T.eq(fig.under[1], 39, "which wears the couch's own cushion once he is off") T.eq(fig.under[2], 1, "and the floor tiles wear the clean art (57 -> 1)") @@ -160,7 +167,13 @@ T.eq(minY, 8, "his feet are on the couch's top face, not the floor") T.eq(maxY, 24, "and he stands his drawn 16px tall from there") T.eq(minX, 8, "he starts at the tile column he is drawn in") T.eq(maxX, 18, "and reaches his hair's overhang, two pixels east of it") -T.eq(maxZ - minZ, 10, "a billboard-pool standee, ten voxels of body") +T.eq(maxZ - minZ, 1, "a flat card, one voxel deep, like the walking NPCs") + +-- and he stands in the depth band of the row he is DRAWN in -- the couch's +-- northern cell (tile row 9 spans z 72..80), not shifted onto its southern +-- half the way a supported prop is +T.check(minZ >= 72 and maxZ <= 80, + "he stands on his own cell, not the couch's southern half") -- the cushion wedge under his legs stayed with the couch: his lowest row -- is his foot alone, not the whole tile width