update voxelizations of celadon diner stools and tables. Update square table voxelization in celadon mansion. Update mansion computer desks

This commit is contained in:
DramaticShape
2026-08-06 17:52:59 -04:00
parent 442e9d26d5
commit 91d9a37e8f
4 changed files with 559 additions and 29 deletions
+208 -2
View File
@@ -680,6 +680,23 @@ TEMPLATES = {
roof_rows=28, roof_back=24, roof_front=0, roof_cycle=(2, 23),
slab=3, front_eave=0, ledge=None, tileset="mansion",
),
# F07b: the SQUARE table of CELADON_MANSION_1F cells (0,6):(1,7)
# (1 placement) -- the long table (F07) at two cells wide, the same
# drawing to the tile everywhere but the interior column count, and
# the same read to the row: 0-23 the tabletop seen from above, 24-26
# the slab's black/#555/black front edge, 27 the #555 shadow that
# closes it (slab = 3, folded into the band), 28-30 the base with the
# legs stopping one row short of the grid. Family numbers unchanged.
"mansion_square_table": dict(
tiles=[
[38, 39, 39, 41],
[54, 55, 55, 57],
[54, 55, 55, 57],
[60, 58, 58, 59],
],
roof_rows=28, roof_back=24, roof_front=0, roof_cycle=(2, 23),
slab=3, front_eave=0, ledge=None, tileset="mansion",
),
# F08: the dining table of the generic town house -- 18 placements,
# every home's cells (3,3):(4,4) -- the chief's long table (F07) at
# two cells wide. The same read to the row: 0-23 the rounded
@@ -853,6 +870,79 @@ TEMPLATES = {
z=3, depth=11, stretch=True), # the stool
],
),
# F09 on the lobby atlas: the Celadon department store's stools --
# the diner's chairs, the roof terrace's, the Game Corner's six
# rows and the four on 1F (58 placements). A DIFFERENT drawing from
# the house stool -- it sits one row HIGHER in the tile (seat top
# rows 4-9 over front edge 10 and legs 11-14, with a clear floor
# row below) and its leg detail differs -- but the same object band
# for band, so it takes the same part table with the bands shifted
# up one row. The measured ground line (15 here, 16 in the house)
# shifts with them, so the stand is the same 5 voxels.
"diner_stool": dict(
tiles=[
[7, 8],
[23, 24],
],
roof_rows=0, roof_back=0, roof_front=0, roof_cycle=(0, 0),
slab=0, front_eave=0, ledge=None, tileset="lobby",
panes=False,
parts=[
dict(kind="upright", x=(2, 13), top=(4, 9), facade=(10, 14),
z=3, depth=11, stretch=True), # the stool
],
),
# F11: the ROUND TABLE of the Celadon diner and the roof terrace --
# 4 placements, all on the lobby atlas (CELADON_DINER cells (0,2)
# and (0,5), CELADON_MART_ROOF (4,2) and (8,4); scan
# "9,39,39,25;54,55,55,57;70,55,55,71;85,86,87,55", no matches on
# any other atlas). The drawing packs three facings no band split
# can reach: rows 0-23 are the OCTAGONAL top seen from above (24
# top-view rows = 24 depth rows, the same 1:1 every tabletop is
# drawn with -- so the plan is the silhouette itself, 32 wide by 24
# deep), rows 24-25 the slab's own fascia (#555 over black, folded
# down the rim under the band's drawn outline -> slab 3), and rows
# 26-31 the PEDESTAL seen under the front edge: the base's top
# surface with the dark column rising from its middle (26-27), its
# lit south half (28-29), and its front arc curving to the floor
# (30-31). The flattened arcs are horizontal CIRCLES seen from
# above -- depth, not narrowing -- so the pedestal is two discs:
# base diameter 16 (drawn cols 8-23), column diameter 6 (the dark
# blob's cols 13-18), both centred on the drawn centre x=16, plan
# centre z=12. MEASURED: plan, diameters, centre, slab 3. AUTHORED:
# tabletop plane 8 -- counter height, developer-tuned (the first
# cut stood it at the flat compromise's 16px and it read too tall)
# -- plus base height 2 and the 3-voxel column between (the
# projection cannot state either; the drawn base arc suggests a
# low disc). depth 3 keeps the plot to the drawn plan's 24 rows;
# the grid's 4th tile row is the pedestal's own drawing and the
# floor tile at its southeast corner, which the claim paints as
# ground. `scrub` repoints the top's interior field -- the four
# $37 tiles, which are ALSO the checkerboard floor's light half
# and carry the floor's palette in a colorized atlas -- at the
# same grey sourced from the rim's own field, so the whole top
# wears the table's palette (the drawn field there is uniform
# grey; nothing drawn is lost).
"diner_round_table": dict(
tiles=[
[9, 39, 39, 25],
[54, 55, 55, 57],
[70, 55, 55, 71],
[85, 86, 87, 55],
],
roof_rows=0, roof_back=0, roof_front=0, roof_cycle=(0, 0),
slab=0, front_eave=0, ledge=None, tileset="lobby", depth=3,
panes=False, scrub=[(8, 8, 23, 23)],
parts=[
dict(kind="disc", cx2=32, cz2=24, r=8, rise=0, h=2,
side=dict(rows=(30, 31), x=(13, 18)),
cap=dict(rows=(26, 29), x=(9, 22))), # the base
dict(kind="disc", cx2=32, cz2=24, r=3, rise=2, h=3,
side=dict(rows=(26, 27), x=(14, 17))), # the column
dict(kind="plan", x=(0, 31), rows=(0, 23),
fascia=(24, 25), fascia_x=(8, 23), rise=5), # the top
],
),
# F04: the Pokemon Center's PC -- every Center's northeast corner
# (11 placements) plus the Indigo Plateau lobby, whose MART tileset
# shares this atlas. The lab desk-set read again: a
@@ -1333,7 +1423,7 @@ def build_desk_set(sp, pr, t):
def build_parts(plane):
for p in t["parts"]:
x0, x1 = p["x"]
x0, x1 = p.get("x", (0, W - 1))
if p["kind"] == "flat":
r0, r1 = p["rows"]
# `at` names the sheet's own height when it does not lie
@@ -1445,6 +1535,91 @@ def build_desk_set(sp, pr, t):
if pr0 <= sy <= pr1 and inside(sx, sy):
put(sx, plane + y, z, sx, sy)
continue
if p["kind"] == "plan":
# A PLAN part is a slab whose plan IS the drawn top view:
# the band's silhouette becomes the footprint pixel for
# pixel (drawn row = depth row, the same 1:1 every
# tabletop is drawn with), so an octagonal top stands as
# an octagon rather than the box no rectangular band can
# escape. The top layer wears the band itself, outline
# and all; the rim layers below wear the drawn fascia
# rows folded down the edge (x clamped into the drawn
# fascia's span), and the slab's unseen interior the
# field's dark texel.
r0, r1 = p["rows"]
f0, f1 = p["fascia"]
fx0, fx1 = p["fascia_x"]
rise = p.get("rise", 0)
h = (f1 - f0 + 1) + 1
dark = shade_px.get(DARK) or shade_px[BLACK]
def drawn(sx, z):
return (x0 <= sx <= x1 and 0 <= z <= r1 - r0
and inside(sx, r0 + z))
for z in range(r1 - r0 + 1):
if not 0 <= z < D:
continue
sy = r0 + z
for sx in range(x0, x1 + 1):
if not inside(sx, sy):
continue
put(sx, rise + h - 1, z, sx, sy)
edge = not (drawn(sx - 1, z) and drawn(sx + 1, z)
and drawn(sx, z - 1) and drawn(sx, z + 1))
for y in range(rise, rise + h - 1):
if edge:
put(sx, y, z, max(fx0, min(fx1, sx)),
f0 + (rise + h - 2 - y))
else:
put(sx, y, z, dark[0], dark[1])
continue
if p["kind"] == "disc":
# A DISC part is ROUND IN PLAN -- the pedestal column
# and base the projection can only draw from the front.
# Centre and radius are measured off the drawn widths
# (a flattened arc is a horizontal circle seen from
# above); the circular footprint is synthesized like any
# continued geometry, and every voxel still wears the
# drawing: the side folds the drawn face-on rows around
# the hull (x clamped into the drawn span, rows
# repeating up the height), and `cap` lays the drawn
# top-view rows over the top layer's interior, drawn
# north rows to the plan's north. `cx2`/`cz2` are
# DOUBLED plan centres, so an even diameter keeps its
# centre between two voxels instead of limping one off.
r, rise, h = p["r"], p.get("rise", 0), p["h"]
s0, s1 = p["side"]["rows"]
sa0, sa1 = p["side"]["x"]
sn = s1 - s0 + 1
cap = p.get("cap")
def in_disc(x, z):
dx = 2 * x + 1 - p["cx2"]
dz = 2 * z + 1 - p["cz2"]
return dx * dx + dz * dz <= 4 * r * r
zlo = (p["cz2"] - 2 * r) // 2
for x in range((p["cx2"] - 2 * r) // 2,
(p["cx2"] + 2 * r) // 2 + 1):
for z in range(max(0, zlo),
min(D - 1, (p["cz2"] + 2 * r) // 2) + 1):
if not in_disc(x, z):
continue
edge = not (in_disc(x - 1, z) and in_disc(x + 1, z)
and in_disc(x, z - 1)
and in_disc(x, z + 1))
for y in range(rise, rise + h):
if cap and y == rise + h - 1 and not edge:
c0, c1 = cap["rows"]
sy = min(c1, c0 + ((z - zlo)
* (c1 - c0 + 1)) // (2 * r))
sx = max(cap["x"][0], min(cap["x"][1], x))
else:
sy = s0 + (rise + h - 1 - y) % sn
sx = max(sa0, min(sa1, x))
put(x, y, z, sx, sy)
continue
tr0, tr1 = p["top"]
fr0, fr1 = p["facade"]
pd = p["depth"]
@@ -1933,7 +2108,7 @@ def verify_desk_set(vox, pr, t):
# sink) -- and nothing stands anywhere else
tops = {}
for p in t["parts"]:
x0, x1 = p["x"]
x0, x1 = p.get("x", (0, W - 1))
if p["kind"] == "flat":
r0, r1 = p["rows"]
z0 = p.get("z", r0)
@@ -1979,6 +2154,37 @@ def verify_desk_set(vox, pr, t):
for y in range(plane, plane + h + 1):
assert (x, y, z) in vox, \
f"iso box hole at {x},{y},{z}"
elif p["kind"] == "plan":
# its one geometric intent: the plan IS the drawn band's
# silhouette -- a solid slab column wherever the band draws
r0, r1 = p["rows"]
h = (p["fascia"][1] - p["fascia"][0] + 1) + 1
rise = p.get("rise", 0)
for x in range(x0, x1 + 1):
for z in range(min(r1 - r0 + 1, D)):
if not pr["inside"](x, r0 + z):
continue
tops[(x, z)] = max(tops.get((x, z), 0), rise + h - 1)
for y in range(rise, rise + h):
assert (x, y, z) in vox, \
f"plan slab hole at {x},{y},{z}"
elif p["kind"] == "disc":
# its one geometric intent: a solid circle in plan at every
# layer, symmetric about the authored centre
r, rise, h = p["r"], p.get("rise", 0), p["h"]
in_disc = lambda x, z: ((2 * x + 1 - p["cx2"]) ** 2
+ (2 * z + 1 - p["cz2"]) ** 2
<= 4 * r * r)
for x in range((p["cx2"] - 2 * r) // 2,
(p["cx2"] + 2 * r) // 2 + 1):
for z in range(D):
if not in_disc(x, z):
continue
assert in_disc(p["cx2"] - 1 - x, z), \
f"disc asymmetric at {x},{z}"
tops[(x, z)] = max(tops.get((x, z), 0), rise + h - 1)
for y in range(rise, rise + h):
assert (x, y, z) in vox, f"disc hole at {x},{y},{z}"
else:
fr0, fr1 = p["facade"]
ytp = plane + p.get("rise", 0) + (fr1 - fr0)