mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 07:00:51 +02:00
second pass at indigo plateau
This commit is contained in:
+69
-3
@@ -2344,15 +2344,81 @@ return {
|
||||
-- facade, the walls flanking the avenue and every badge-check gate
|
||||
-- down ROUTE_23), and $2E/$2F the white pillar shaft with $20/$21 its
|
||||
-- cap. These four groups are the enclosure.
|
||||
cliff = { 3,
|
||||
13, 14, 15,
|
||||
cliff = { 3, 13,
|
||||
32, 33, 46, 47 },
|
||||
-- THE GATE WALLS, stacked rather than laid out in depth. $0D/$0F/$0E
|
||||
-- (13/15/14 -- top band, face, base) draw the League's facade, the
|
||||
-- walls flanking the avenue and every badge-check gate down ROUTE_23,
|
||||
-- as FOUR tile rows: 13 / 15 / 15 / 14. That is 32px of artwork
|
||||
-- depicting one wall, and at one class per row it built four boxes
|
||||
-- marching north, so the wall was 32px DEEP -- you saw the southmost
|
||||
-- row's face and the rest hid behind it.
|
||||
--
|
||||
-- `bookcase` collapses the run onto a single one-cell-deep box at its
|
||||
-- full drawn height: bands from the south are base, face, face, top
|
||||
-- band, and the two rows behind are vacated. Same mechanism the
|
||||
-- Mart's back wall uses.
|
||||
-- ...and the PILASTER stacks with it. $05/$06 is its shaft, and it
|
||||
-- is drawn only ever inside a pilaster, so it needs no rule. Without
|
||||
-- this the pale columns stood 16px against a 32px brown wall and
|
||||
-- their top vertices sat a whole course below the wall's crown.
|
||||
bookcase = { 14, 15, 5, 6 },
|
||||
-- Tile 13 is DUAL-USE and needs resolving per position. It is the
|
||||
-- gate wall's TOP BAND (block $28's first row) and it is also the
|
||||
-- BASE COURSE under a column of rock face (blocks $18/$1A/$1B, last
|
||||
-- row). Pinned `bookcase` outright the second use became a one-row
|
||||
-- rank -- an 8px stub under the rock, 352 of them over both maps.
|
||||
--
|
||||
-- ABOVE cannot tell them apart, which is what `when_below` is for.
|
||||
-- Scanned over both maps through the engine's own tileAt, the tile
|
||||
-- above a 13 is the rock face $03 for 140 base courses AND for 64
|
||||
-- gate bands -- so a rule on `above` misfires on those 64 (it did:
|
||||
-- their runs came out 2 and 3 bands instead of 4). BELOW splits it
|
||||
-- exactly: the wall's own face $0F sits under the top band and under
|
||||
-- nothing else, 336 against 352. So 13 defaults to `cliff` and is
|
||||
-- promoted where the face is drawn beneath it.
|
||||
--
|
||||
-- 14 and 15 need no rule: 14 only ever sits under 15, 15 only ever
|
||||
-- under 13 or 15.
|
||||
when_below = {
|
||||
[13] = { { below = { 15 }, class = "bookcase" } },
|
||||
-- The pilaster's CAP ($15/$16) is the same stone as the statue's
|
||||
-- plinth top -- the artist drew it twice -- so it too resolves per
|
||||
-- position. Scanned over both maps: a cap with the shaft $05/$06
|
||||
-- beneath it is a pilaster (76 of them) and one with the plaque
|
||||
-- base $30/$31 beneath it is a statue's plinth (47). Default
|
||||
-- `wall`, promoted here, so the plinth keeps its single course and
|
||||
-- the statue standing on it still totals the 32px the wall is.
|
||||
[21] = { { below = { 5 }, class = "bookcase" } },
|
||||
[22] = { { below = { 6 }, class = "bookcase" } },
|
||||
},
|
||||
-- The other two ends of the same pair of drawings, keyed the other
|
||||
-- way round. A pilaster is capped at BOTH ends, so its lower cap has
|
||||
-- the shaft ABOVE it (8 placements); and the plaque base $30/$31 is a
|
||||
-- pilaster's foot when the shaft is above it (68) but a statue's
|
||||
-- plinth bottom when the cap $15/$16 is (47).
|
||||
when_above = {
|
||||
[21] = { { above = { 5 }, class = "bookcase" } },
|
||||
[22] = { { above = { 6 }, class = "bookcase" } },
|
||||
[48] = { { above = { 5 }, class = "bookcase" } },
|
||||
[49] = { { above = { 6 }, class = "bookcase" } },
|
||||
},
|
||||
-- The vacated rows behind a collapsed wall take the cell ABOVE the
|
||||
-- run rather than the default hidden floor: here that is more rock
|
||||
-- face on ROUTE_23 and the plateau's paving or grass on INDIGO_
|
||||
-- PLATEAU, so the wall reads as set INTO the terrace instead of
|
||||
-- standing in front of a trench of synthesized ground.
|
||||
bookcase_backfill = "above",
|
||||
-- ONE course, and it must stay one: $15/$16 + $05/$06 + $30/$31 is
|
||||
-- the pilaster -- cap, shaft, plaque base -- and $15/$16 over $30/$31
|
||||
-- IS the statue's plinth, the artist having drawn the same stone
|
||||
-- twice. Raising it would carry every statue standee up to 48px and
|
||||
-- break the very match the cliff height was chosen for.
|
||||
wall = { 21, 22, 48, 49, 5, 6 },
|
||||
-- $05/$06 is NOT here: it moved to `bookcase` above, and a tile
|
||||
-- listed in two groups resolves by whichever `pairs` order wins --
|
||||
-- half the pilasters kept the shaft as `wall`, which broke the run
|
||||
-- and left their caps as isolated 8px stubs. One group per tile.
|
||||
wall = { 21, 22, 48, 49 },
|
||||
-- The statues, and the same bird at the pillar feet. Black-outline
|
||||
-- segmented: the outline and everything it encloses stay, the sky
|
||||
-- and the paving around them flood away.
|
||||
|
||||
+26
-4
@@ -1222,6 +1222,9 @@ local function bookcaseRank(S, map, tx, northTy, frontTy, capTile)
|
||||
end
|
||||
|
||||
function Structures.buildBookcases(S, map, x0, x1, y0, y1)
|
||||
-- What to do with the rows a rank VACATES (see TileShape.bookcaseBackfill).
|
||||
-- Read once: it is a property of the tileset, not of the column.
|
||||
local backfill = TileShape.bookcaseBackfill(map.tileset.id)
|
||||
for tx = x0, x1 do
|
||||
local ty = y1
|
||||
while ty >= y0 do
|
||||
@@ -1249,10 +1252,24 @@ function Structures.buildBookcases(S, map, x0, x1, y0, y1)
|
||||
capTile = S.tileAt[ck]
|
||||
end
|
||||
end
|
||||
-- The box is one cell deep, so it covers only the run's southmost
|
||||
-- rows; everything north of that is vacated. By default a vacated
|
||||
-- row is skipped and painted with synthesized ground -- right for a
|
||||
-- shelf standing in a room. `bookcase_backfill = "above"` hands it
|
||||
-- the cell above the run instead, shape and art, so a wall cut into
|
||||
-- a terrace has more terrace behind it rather than a trench.
|
||||
local covered = math.min(2, front - top + 1)
|
||||
local srcK = keyOf(tx, top - 1)
|
||||
local src = backfill == "above" and S.shapeAt[srcK] or nil
|
||||
for cy = top, front do
|
||||
local tk = keyOf(tx, cy)
|
||||
S.skip[tk] = true
|
||||
S.ground[tk] = false
|
||||
if src and cy <= front - covered then
|
||||
S.shapeAt[tk] = src
|
||||
S.tileAt[tk] = S.tileAt[srcK]
|
||||
else
|
||||
S.skip[tk] = true
|
||||
S.ground[tk] = false
|
||||
end
|
||||
end
|
||||
bookcaseRank(S, map, tx, top, front, capTile)
|
||||
front = top - 1
|
||||
@@ -1977,8 +1994,13 @@ function Structures.buildObject(S, map, region, cluster,
|
||||
local bs = S.shapeAt[keyOf(cluster.minX, cluster.maxY + 1)]
|
||||
local blocked = not map:isWalkableCell(math.floor(cluster.minX / 2),
|
||||
math.floor(cluster.maxY / 2))
|
||||
if blocked and bs and bs.authored and bs.art == "upright"
|
||||
and (bs.h or 0) > 0 then
|
||||
-- `bookcase` supports as well as `upright`. A prop drawn above an
|
||||
-- authored box stands ON it whatever art the box renders with, and a
|
||||
-- stacked box is still a box: the Plateau's gate pilasters carry a
|
||||
-- statue on 48 of their tops, and collapsing the pilaster to a stacked
|
||||
-- run made every one of them fail this test and drop to ground level.
|
||||
if blocked and bs and bs.authored and (bs.h or 0) > 0
|
||||
and (bs.art == "upright" or bs.art == "bookcase") then
|
||||
baseY, support = bs.h, bs
|
||||
end
|
||||
end
|
||||
|
||||
+53
-17
@@ -233,29 +233,42 @@ end
|
||||
-- class = "..." } } }`, evaluated per POSITION in TileShape.at, where
|
||||
-- the map and coordinates are in hand. First match wins; no match keeps
|
||||
-- the tile's ordinary pin.
|
||||
-- `when_below` is the mirror, and it exists because ABOVE is not always the
|
||||
-- side that tells the two uses apart. The Plateau's $0D is the case: it is
|
||||
-- the gate wall's top band AND the base course under a column of rock face,
|
||||
-- and scanned over both maps the tile above is $03 for 64 of the first and
|
||||
-- 140 of the second -- no rule on `above` can split them. What is BELOW
|
||||
-- does, exactly: the wall's own face $0F sits under the top band and under
|
||||
-- nothing else (336 vs 352, clean).
|
||||
local function authoredConditions(tilesetId, heights)
|
||||
local s = load()
|
||||
local entry = s and s.tilesets and s.tilesets[tilesetId]
|
||||
local spec = entry and entry.when_above
|
||||
if type(spec) ~= "table" then return nil end
|
||||
if type(entry) ~= "table" then return nil end
|
||||
local out, any = {}, false
|
||||
for tile, rules in pairs(spec) do
|
||||
if type(tile) == "number" and type(rules) == "table" then
|
||||
local list = {}
|
||||
for _, rule in ipairs(rules) do
|
||||
if type(rule) == "table" and heights[rule.class]
|
||||
and type(rule.above) == "table" then
|
||||
local set = {}
|
||||
for _, t in ipairs(rule.above) do set[t] = true end
|
||||
list[#list + 1] = { above = set, class = rule.class }
|
||||
|
||||
local function collect(spec, side)
|
||||
if type(spec) ~= "table" then return end
|
||||
for tile, rules in pairs(spec) do
|
||||
if type(tile) == "number" and type(rules) == "table" then
|
||||
local list = out[tile] or {}
|
||||
for _, rule in ipairs(rules) do
|
||||
if type(rule) == "table" and heights[rule.class]
|
||||
and type(rule[side]) == "table" then
|
||||
local set = {}
|
||||
for _, t in ipairs(rule[side]) do set[t] = true end
|
||||
list[#list + 1] = { side = side, set = set, class = rule.class }
|
||||
end
|
||||
end
|
||||
if #list > 0 then
|
||||
out[tile] = list
|
||||
any = true
|
||||
end
|
||||
end
|
||||
if #list > 0 then
|
||||
out[tile] = list
|
||||
any = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
collect(entry.when_above, "above")
|
||||
collect(entry.when_below, "below")
|
||||
return any and out or nil
|
||||
end
|
||||
|
||||
@@ -357,9 +370,12 @@ function TileShape.at(map, shapes, tile, tx, ty)
|
||||
-- tile and the cell rules below (see authoredConditions)
|
||||
local rules = shapes.cond and shapes.cond[tile]
|
||||
if rules then
|
||||
local above = map:tileAt(tx, ty - 1)
|
||||
for _, rule in ipairs(rules) do
|
||||
if above and rule.above[above] then
|
||||
-- NOTE map:tileAt border-EXTENDS: one row off an edge answers the
|
||||
-- map's borderBlock, never nil. A rule listing whatever that block
|
||||
-- draws will fire along that whole edge (it did, on the Marts).
|
||||
local n = map:tileAt(tx, rule.side == "above" and ty - 1 or ty + 1)
|
||||
if n and rule.set[n] then
|
||||
-- shapes.condShape, NOT shapes.classes: the canonical class
|
||||
-- shapes are SHARED, and `wall` in particular is the very object
|
||||
-- rule 4 hands every unauthored solid tile. Marking that one
|
||||
@@ -503,6 +519,26 @@ function TileShape.propBg(tilesetId)
|
||||
return bgCache[tilesetId] or nil
|
||||
end
|
||||
|
||||
-- What a bookcase rank does with the rows it VACATES -- the ones behind the
|
||||
-- one-cell-deep box it collapses onto (a tileset entry's
|
||||
-- bookcase_backfill). Returns the mode name, or nil for the default.
|
||||
--
|
||||
-- "above" hand them the cell immediately above the run: its shape and
|
||||
-- its art. A wall set INTO a terrace wants this -- the ground
|
||||
-- behind it is more terrace, not a trench.
|
||||
-- nil skip them and paint the map's commonest ground underneath,
|
||||
-- which is right for a free-standing shelf against a wall.
|
||||
--
|
||||
-- Per tileset because it is a statement about what the drawing depicts, and
|
||||
-- the answer differs: the Mart's racks and Red's shelves stand in a room,
|
||||
-- the Plateau's gate walls are cut into a hillside.
|
||||
function TileShape.bookcaseBackfill(tilesetId)
|
||||
local s = load()
|
||||
local entry = s and s.tilesets and s.tilesets[tilesetId]
|
||||
local mode = entry and entry.bookcase_backfill
|
||||
return mode == "above" and mode or nil
|
||||
end
|
||||
|
||||
-- Drop the cache: a mod that shadows data/voxel_heights.lua or a tileset
|
||||
-- record needs the next lookup to re-resolve (hot reload, mod toggle).
|
||||
function TileShape.invalidate()
|
||||
|
||||
Reference in New Issue
Block a user