fix victory road statues

This commit is contained in:
DramaticShape
2026-08-09 00:01:47 -04:00
parent 47369c24fe
commit 2af88d07cf
7 changed files with 501 additions and 44 deletions
+162 -10
View File
@@ -7020,10 +7020,21 @@ end)()
local Struct = run.loader.exports.DRAMATIC_SHAPE.lib.require("Structures")
local Shape = run.loader.exports.DRAMATIC_SHAPE.lib.require("TileShape")
T.eq(Shape.wallTop("HOUSE"), 0,
-- the blanket form: whatever a wall cell draws, it caps with the one
-- course the atlas's rooms are panelled in
T.eq(Shape.wallTop("HOUSE")(45), 0,
"the town house caps its walls with the blank course")
T.eq(Shape.wallTop("POKECENTER"), 40,
T.eq(Shape.wallTop("POKECENTER")(2), 40,
"and a Center with its striped panel -- the tile cell (9,0) draws")
T.eq(Shape.wallTop("REDS_HOUSE_2")(36), 0,
"Red's bedroom with its own blank panel, over the window")
T.eq(Shape.wallTop("REDS_HOUSE_1")(36), 0, "and so does the floor below")
-- the keyed form, for an atlas that dresses more than one kind of room
T.eq(Shape.wallTop("LOBBY")(40), 93,
"the Rocket lift's car door caps with the cabin frame")
T.eq(Shape.wallTop("LOBBY")(1), nil,
"but the department store's own panel is left exactly as it was -- "
.. "one atlas, several rooms, and only the lift is a lift")
T.eq(Shape.wallTop("DS_NO_SUCH_TILESET"), nil,
"a tileset that says nothing keeps the top it always had")
@@ -7061,7 +7072,11 @@ end)()
local ax = math.floor(math.min(a[4], b[4], c[4], d[4]) * 128 + 0.5)
local ay = math.floor(math.min(a[5], b[5], c[5], d[5]) * 48 + 0.5)
local tx = math.floor(math.min(a[1], b[1], c[1], d[1]) / 8)
out[tx] = out[tx] or (math.floor(ay / 8) * 16 + math.floor(ax / 8))
local ty = math.floor(math.min(a[3], b[3], c[3], d[3]) / 8)
-- keyed by the TILE ROW too: a wall band is two drawn rows deep
-- and they can wear different art
out[ty * 100 + tx] = out[ty * 100 + tx]
or (math.floor(ay / 8) * 16 + math.floor(ax / 8))
end
end
return out, verts
@@ -7073,9 +7088,12 @@ end)()
{ 0, 0, 45, 46, 36, 36, 0, 0 },
{ 0, 0, 61, 62, 52, 52, 0, 0 },
})
for tx = 0, 7 do
T.eq(houseTops[tx], 0,
("column %d of the house's back wall caps with the blank course"):format(tx))
for ty = 0, 1 do
for tx = 0, 7 do
T.eq(houseTops[ty * 100 + tx], 0,
("(%d,%d) of the house's back wall caps with the blank course")
:format(tx, ty))
end
end
-- and the FACE is untouched: the poster still hangs in the room, which is
@@ -7095,11 +7113,145 @@ end)()
{ 40, 40, 40, 2, 3, 40, 40, 40 },
{ 40, 40, 40, 18, 19, 40, 40, 40 },
})
for tx = 0, 7 do
T.eq(pcTops[tx], 40,
("column %d of the Center's back wall caps with the striped panel")
:format(tx))
for ty = 0, 1 do
for tx = 0, 7 do
T.eq(pcTops[ty * 100 + tx], 40,
("(%d,%d) of the Center's back wall caps with the striped panel")
:format(tx, ty))
end
end
-- ------- the Rocket lift's car doors
--
-- Detected rather than pinned -- the doors are a volume Structures finds
-- -- so the cap has to reach the RUN branch too, not only the pinned one.
local liftTops = topTiles("LOBBY", {
{ 92, 92, 92, 92, 92, 92, 92, 92 },
{ 93, 93, 93, 93, 93, 93, 93, 93 },
{ 1, 1, 40, 40, 40, 40, 1, 1 },
{ 33, 33, 56, 56, 56, 56, 33, 33 },
})
-- rows 2 and 3 are the doors' own band; the doors span columns 2-5
for ty = 2, 3 do
for tx = 2, 5 do
T.eq(liftTops[ty * 100 + tx], 93,
("(%d,%d) of the lift's door caps with the cabin frame"):format(tx, ty))
end
end
-- and the panelling either side of them is left alone, which is what the
-- keyed form buys: the same atlas panels the department store
T.eq(liftTops[2 * 100], 1, "the blank course beside the door is untouched")
T.eq(liftTops[3 * 100], 33, "and so is its skirting")
end)()
-- ------- Lance's room is furnished with the badge gyms' statue
--
-- The same drawing on a different atlas: one cell of bird over one cell of
-- plinth. Left derived the pair merged into one 32px volume wearing the
-- statue folded onto its face -- the extruded picture. The gyms' reading
-- (solid plinth, per-pixel standee on top) is the right one here too, and
-- these eight tiles draw nothing else anywhere in the game.
;(function()
local Shape = run.loader.exports.DRAMATIC_SHAPE.lib.require("TileShape")
local shapes = Shape.forMap({
tileset = { id = "DOJO", tilesPerRow = 16,
imageWidth = 128, imageHeight = 48, grassTile = -1 },
walkable = { [17] = true },
})
for _, t in ipairs({ 2, 18, 19, 56 }) do
T.eq(shapes[t].class, "prop",
("the statue's figure tile %d stands as a per-pixel cutout"):format(t))
T.eq(shapes[t].authored, true, "and it is an authored answer, not derived")
end
for _, t in ipairs({ 34, 35, 50, 51 }) do
T.eq(shapes[t].class, "wall",
("the plinth tile %d stays a solid 16px block"):format(t))
T.eq(shapes[t].authored, true,
"authored, which is what the standee's support rule tests -- and "
.. "what keeps tile 50 ($32) out of the water-fallback trap")
end
T.eq(shapes[13].class, "bookcase",
"and Oak's shelf ranks on the same atlas are untouched")
end)()
-- ------- a wall cut into a terrace inherits TERRACE, never a statue
--
-- `bookcase_backfill = "above"` hands a vacated row the cell above the run,
-- so masonry set into a hillside has more hillside behind it rather than a
-- trench. Indigo Plateau's avenue statues stand directly on the pilasters
-- that collapse this way, so what every one of them inherited was the BIRD:
-- the figure's shape and art copied onto two more rows down the shaft, and
-- the statue came out two deep behind itself. A standee above is an object
-- standing ON the terrace, not terrace -- so there is nothing to inherit.
;(function()
local Struct = run.loader.exports.DRAMATIC_SHAPE.lib.require("Structures")
-- the real west-edge statue of INDIGO_PLATEAU, tile for tile: the bird
-- (37/38 over 40/41) on the pilaster (cap 21/22, shaft 5/6 twice, foot
-- 21/22), standing on the plateau's paving (35)
local rows = {
{ 46, 47 }, { 46, 47 },
{ 37, 38 }, { 40, 41 },
{ 21, 22 }, { 5, 6 },
{ 5, 6 }, { 21, 22 },
{ 35, 35 }, { 35, 35 },
{ 35, 35 }, { 35, 35 },
}
local map = {
id = "DS_TEST_PLATEAU_STATUE",
tileset = { id = "PLATEAU", image = "gfx/tilesets/ds_test.png",
tilesPerRow = 16, imageWidth = 128, imageHeight = 40,
blocks = {}, grassTile = -1 },
def = { width = 1, height = 3, tileset = "PLATEAU" },
walkable = { [35] = true },
waterTiles = {},
doorTiles = {},
tileAt = function(_, tx, ty)
local r = rows[math.max(1, math.min(#rows, ty + 1))]
return r[(tx % 2) + 1]
end,
cellTile = function(self, cx, cy) return self:tileAt(cx * 2, cy * 2 + 1) end,
isWaterCell = function() return false end,
isWalkableCell = function(self, cx, cy)
return self:cellTile(cx, cy) == 35
end,
isDoorTileCell = function() return false end,
isGrassCell = function() return false end,
inBounds = function(_, cx, cy)
return cx >= 0 and cy >= 0 and cx < 2 and cy < 6
end,
}
Struct.invalidate(map.id)
local S = Struct.forMap(map)
local function keyOf(tx, ty) return (ty + 64) * 4096 + (tx + 64) end
-- the bird stands, once, where it is drawn
for _, ty in ipairs({ 2, 3 }) do
T.eq(S.shapeAt[keyOf(0, ty)].art, "billboard",
"the statue's own rows carry the standee")
end
-- and the pilaster rows it vacates carry NOTHING -- not a second bird
for _, ty in ipairs({ 4, 5, 6, 7 }) do
local s = S.shapeAt[keyOf(0, ty)]
T.check(s == nil or s.art ~= "billboard",
("pilaster row %d did not inherit the statue standing on it"):format(ty))
end
-- ...and the bird stands on the box rather than where it is DRAWN. The
-- collapse walks the whole four-row pilaster onto its southmost cell, so
-- a standee that trusted its own drawn position ended up a full cell
-- north of the pillar holding it up -- at the right height, over open
-- ground. Every row of the rank records where the box actually went.
for _, ty in ipairs({ 4, 5, 6, 7 }) do
T.eq(S.bookcaseBox[keyOf(0, ty)], 6,
("rank row %d knows the box stands on row 6"):format(ty))
end
local zlo = math.huge
for _, q in ipairs(S.objectQuads) do
for i = 1, 4 do zlo = math.min(zlo, q[i][3]) end
end
T.eq(math.floor(zlo / 8), 6,
"and the statue's own geometry starts on that row -- standing on the "
.. "pillar, not hanging in the air two cells in front of it")
end)()
Pipelines.reset()