mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 16:41:13 +02:00
pokecenter machines, water occlusion
This commit is contained in:
+255
-82
@@ -842,12 +842,12 @@ return {
|
||||
-- console face (76/77) and button panel (6/22) are ALSO wall:
|
||||
-- drawn 16px tall against the band, so wall height is their drawn
|
||||
-- height and they read as equipment jutting from it. (The
|
||||
-- `center_heal_machine` template below claims those four tiles at
|
||||
-- every placement and models the console properly; these pins are
|
||||
-- the degradation path when the profile is absent.) The
|
||||
-- near-black screen tiles must be pinned or the void rule flattens
|
||||
-- them. What is NOT wall is the machines' two flanks -- see
|
||||
-- `prop` below.
|
||||
-- `center_heal_machine_w`/`_e` templates below claim the full
|
||||
-- 4x4 machine grids at every placement and model the console
|
||||
-- properly; these pins are the degradation path when the profile
|
||||
-- is absent.) The near-black screen tiles must be pinned or the
|
||||
-- void rule flattens them. What is NOT wall is the machines'
|
||||
-- two flanks -- see `prop` below.
|
||||
wall = { 2, 3, 4, 5, 6, 16, 18, 19, 20, 21, 22, 40, 41,
|
||||
76, 77, 92, 93, 94, 95 },
|
||||
-- the counters, half a cell high: top band (8) with the nurse's
|
||||
@@ -899,7 +899,10 @@ return {
|
||||
-- game -- 12 maps, the same two cells in each -- so this pin cannot
|
||||
-- reach anything but the machines. 72 is still the $48
|
||||
-- water-fallback trap and still has to carry SOME pin; it just
|
||||
-- wanted the thin one, not the wall.
|
||||
-- wanted the thin one, not the wall. (The machine templates now
|
||||
-- claim the flank tiles too and model the hoses and keyboard as
|
||||
-- attached 3D equipment; these standee pins are the degradation
|
||||
-- path when the profile is absent.)
|
||||
prop = { 7, 13, 72, 73,
|
||||
-- ...and the potted plants -- see THE POTTED PLANTS below
|
||||
32, 33, 34, 35, 48, 49, 50, 51 },
|
||||
@@ -1968,13 +1971,24 @@ return {
|
||||
-- on (see `buildings` below). The pin is only the degradation
|
||||
-- path here -- the template claims both placements -- but the two
|
||||
-- must not disagree about where the desk's top is.
|
||||
heights = { table = 8 },
|
||||
--
|
||||
-- `stool` is 5 for the same reason: that is the drawn elevation of
|
||||
-- BOTH seats in this tileset -- rows 11-15, the seat's front edge
|
||||
-- over its legs -- and the height the `club_stool` template stands
|
||||
-- them. Bill's chair and the Fan Club's are different drawings
|
||||
-- above the seat but share tiles 59/60 below it, so they are drawn
|
||||
-- at the same height pixel for pixel; the class default of 8 was
|
||||
-- three voxels over both. Every one of these cells is WALKABLE,
|
||||
-- so this is also where a character sitting on one ends up.
|
||||
heights = { table = 8, stool = 5 },
|
||||
-- the seats: Bill's desk stool (43/44 over 59/60) and the Fan
|
||||
-- Club's four members' chairs (61/62 over 59/60), a whole cell
|
||||
-- each. All of them sit in WALKABLE cells, so they were flat
|
||||
-- floor until pinned; the 8px standee pool puts them at seat
|
||||
-- height, which is also where a character standing on the cell
|
||||
-- ends up.
|
||||
-- floor until pinned; the standee pool puts them at seat height,
|
||||
-- which is also where a character standing on the cell ends up.
|
||||
-- The Fan Club's four are modelled in full by `club_stool` below
|
||||
-- and these pins are their degradation path; Bill's chair stays a
|
||||
-- standee, stood up as a part of `bills_desk`.
|
||||
stool = { 43, 44, 59, 60, 61, 62 },
|
||||
-- flat, and pinned flat on purpose. 31 is the rooms' floor tile
|
||||
-- and needs no pin for its 980 walkable placements -- but the
|
||||
@@ -3737,82 +3751,154 @@ return {
|
||||
z = 13 }, -- keyboard
|
||||
},
|
||||
},
|
||||
-- F05: the healing machine behind the counter -- the pair in every
|
||||
-- Center (cells (1,0):(2,1) and (6,0):(7,1)), 22 placements, plus
|
||||
-- the Indigo Plateau lobby's pair under MART below (scan
|
||||
-- "58,59;74,75;76,77;6,22").
|
||||
-- F05: the healing machine behind the counter -- two 4x4-tile
|
||||
-- variants, 24 placements between them (a pair in every Center,
|
||||
-- cells (1,0):(2,1) and (6,0):(7,1), plus the Indigo Plateau
|
||||
-- lobby's pair under MART below). The variants differ only in
|
||||
-- the east flank: the west machine has the control keyboard
|
||||
-- there (7/13, scan "40,58,59,40;40,74,75,40;72,76,77,7;
|
||||
-- 72,6,22,13" -- 12 placements), the east machine mirrored
|
||||
-- hoses (73, scan "...;72,76,77,73;72,6,22,73" -- 12).
|
||||
--
|
||||
-- The drawing is 4x4 tiles but only its middle COLUMN is this
|
||||
-- template's. The corners are the striped wall band (40), and
|
||||
-- the outer tile columns are the flanking EQUIPMENT -- the hoses
|
||||
-- (72 west, 73 east) and the control keyboard (7/13) -- which are
|
||||
-- separate thin objects, not part of this console: they are
|
||||
-- pinned into the THIN standee pool above and stay out of this
|
||||
-- grid. What no class can split is the middle -- a wall-height
|
||||
-- The FULL drawing is claimed now: the corners are the striped
|
||||
-- wall band (40), the flanks the machine's own equipment --
|
||||
-- hoses and a keyboard ATTACHED to the cabinet, not furniture
|
||||
-- standing free (their standee pins above stay as the
|
||||
-- degradation path). What no class can split is a wall-height
|
||||
-- cabinet with a monitor perched on its front top edge, drawn
|
||||
-- across two map rows because it towers over the 16px band
|
||||
-- behind it, which the volume path can only read as more wall.
|
||||
--
|
||||
-- Read off the pixels (local x, the whole drawing's x8..x23):
|
||||
-- rows 15-31 the CABINET's front face, 16 wide, 17 tall:
|
||||
-- black front-top edge with vent notches (15),
|
||||
-- white top rail (16), black panel in a white
|
||||
-- frame (17-28), white rail / light plinth / black
|
||||
-- ground line (29-31).
|
||||
-- rows 6-14 the cabinet's TOP FACE seen from above -- not a
|
||||
-- second-story facade: a white expanse with a lit
|
||||
-- west strip (x1 white) and a shaded east strip
|
||||
-- (x14 #555) wrapping the monitor, full-width in
|
||||
-- front of it (13-14), strips beside it (7-12).
|
||||
-- Its 9 rows plus the front edge row 15 ARE the
|
||||
-- cabinet's depth: 10. `desk.top` lays the band
|
||||
-- flat as the lid; where the monitor's drawing
|
||||
-- occludes it, the lid continues the nearest strip
|
||||
-- (the drawing's own pixels).
|
||||
-- rows 1-13 the MONITOR, x2..x13: black back rim (1) and
|
||||
-- white cap (2-3) seen from above -- 3 rows plus
|
||||
-- the front edge, depth 4 -- then bezel, screen
|
||||
-- and control strip (4-13) face-on, 10 tall,
|
||||
-- standing on the cabinet top at its front: the
|
||||
-- drawn base edge (13) is one band row up from the
|
||||
-- front strip (14), so its front plane is one
|
||||
-- voxel back from the cabinet's -- z 20..23. The
|
||||
-- screen interior (x5..x10, rows 6-8) is sealed
|
||||
-- behind its own black frame and sinks one voxel
|
||||
-- Read off the pixels (absolute grid x0..x31):
|
||||
-- rows 15-31, x8..x23 the CABINET's front face, 16 wide, 17
|
||||
-- tall: black front-top edge with vent notches
|
||||
-- (15), white top rail (16), black panel in a
|
||||
-- white frame (17-28), white rail / light plinth /
|
||||
-- black ground line (29-31). `desk.x` bounds the
|
||||
-- desk to the middle columns.
|
||||
-- rows 6-14, x8..x23 the cabinet's TOP FACE seen from above
|
||||
-- -- not a second-story facade: a white expanse
|
||||
-- with a lit west strip (x9) and a shaded east
|
||||
-- strip (x22) wrapping the monitor. Its 9 rows
|
||||
-- plus the front edge row 15 ARE the cabinet's
|
||||
-- depth: 10, z 16..25 against the wall.
|
||||
-- `desk.top` lays the band flat as the lid; where
|
||||
-- the monitor's drawing occludes it, the lid
|
||||
-- continues the nearest strip (the drawing's own
|
||||
-- pixels).
|
||||
-- rows 1-13, x10..x21 the MONITOR: black back rim (1) and
|
||||
-- white cap (2-3) seen from above -- depth 4 --
|
||||
-- then bezel, screen and control strip (4-13)
|
||||
-- face-on, 10 tall, at the cabinet top's front
|
||||
-- (the drawn base edge 13 is one band row up from
|
||||
-- the front strip 14): z 20..23. The screen
|
||||
-- interior (x13..x18, rows 6-8) sinks one voxel
|
||||
-- via `inset` -- the pane rule applied by hand,
|
||||
-- because `panes = false` blocks the global pass.
|
||||
-- rows 0-5 at the flanks: wall stripes and the machine's
|
||||
-- cast shadow on the wall east of it -- BACKGROUND,
|
||||
-- the same standing as the potted plants' floor.
|
||||
-- The `wall` element keeps the band solid over the
|
||||
-- back map row: a 16-tall, 16-deep block cycling
|
||||
-- the drawing's own stripe unit (x0, rows 0-3),
|
||||
-- what the neighbouring cells' wall pins render.
|
||||
-- rows 16-31, x0..x7 the HOSES (tile 72 stacked): one 8-row
|
||||
-- motif per map row, and the two stacked motifs
|
||||
-- are two hoses in DEPTH -- the drawn row band is
|
||||
-- the depth band, and each motif's own rows are
|
||||
-- its elevation WITHIN that band, exactly the
|
||||
-- potted plants' stacked-cell rule. So both
|
||||
-- hoses hug the floor: a horizontal run off the
|
||||
-- cabinet's side (rows 24-26, x3..x7 -> heights
|
||||
-- 5..7) over a shaded drop landing ON the floor
|
||||
-- (rows 27-31, x2..x7 -> heights 0..4) -- all
|
||||
-- measured, the drawn extent maps 1:1 with no
|
||||
-- continuation. `box` parts at z 18 and z 24, 3
|
||||
-- deep; both wear the LOWER motif's rows (the one
|
||||
-- drawn at its true elevation; the upper motif is
|
||||
-- the same atlas tile, pixel-identical).
|
||||
-- rows 16-31, x24..x31 west variant: the KEYBOARD (7/13), a
|
||||
-- key grid with its cable at the north end and a
|
||||
-- bar down the east edge -- TOP-VIEW art, 16 rows
|
||||
-- = 16 depth rows. A `flat` part mounted on the
|
||||
-- cabinet's side at COUNTER level (`at` 8, the
|
||||
-- counters' own 8px band -- the one number
|
||||
-- top-view art cannot state, pinned to the room's
|
||||
-- work surface), 3 thick, top face wearing the
|
||||
-- drawn art. The dark dashes east of it (x30-31)
|
||||
-- are its cast shadow on the floor: background.
|
||||
-- East variant: mirrored hoses (runs x24..x28,
|
||||
-- drops x24..x29), same rows and z slots.
|
||||
-- rows 0-15 elsewhere wall stripes and the machine's cast
|
||||
-- shadow -- BACKGROUND, the same standing as the
|
||||
-- potted plants' floor. The `wall` element keeps
|
||||
-- the band solid over the back map row, full grid
|
||||
-- width: a 16-tall, 16-deep block cycling the
|
||||
-- drawing's own stripe unit (x0, rows 0-3), what
|
||||
-- the neighbouring cells' wall pins render.
|
||||
--
|
||||
-- `depth = 4` is BOTH map rows: the back row is the wall's plot,
|
||||
-- the front row the machine's own, and the cabinet leans against
|
||||
-- the wall at z 16..25. `panes = false`: the front panel seals
|
||||
-- DARK behind LIGHT (a black panel in a white frame), the
|
||||
-- opposite polarity to the pane rule, so the global recess pass
|
||||
-- would sink the frame and leave the panel proud.
|
||||
-- the front row the machine's own. `panes = false`: the front
|
||||
-- panel seals DARK behind LIGHT (a black panel in a white
|
||||
-- frame), the opposite polarity to the pane rule, so the global
|
||||
-- recess pass would sink the frame and leave the panel proud.
|
||||
{
|
||||
id = "center_heal_machine",
|
||||
id = "center_heal_machine_w",
|
||||
tiles = {
|
||||
{ 58, 59 },
|
||||
{ 74, 75 },
|
||||
{ 76, 77 },
|
||||
{ 6, 22 },
|
||||
{ 40, 58, 59, 40 },
|
||||
{ 40, 74, 75, 40 },
|
||||
{ 72, 76, 77, 7 },
|
||||
{ 72, 6, 22, 13 },
|
||||
},
|
||||
roofRows = 0, roofBack = 0, roofFront = 0, roofCycle = { 0, 0 },
|
||||
slab = 0, frontEave = 0, ledge = nil, depth = 4,
|
||||
panes = false,
|
||||
wall = { h = 16, depthPx = 16, x = 0, cycle = { 0, 3 } },
|
||||
desk = { fascia = { 15, 16 }, base = { 17, 31 }, z = 16,
|
||||
depthPx = 10, top = { 6, 14 } },
|
||||
desk = { x = { 8, 23 }, fascia = { 15, 16 }, base = { 17, 31 },
|
||||
z = 16, depthPx = 10, top = { 6, 14 } },
|
||||
parts = {
|
||||
{ kind = "upright", x = { 2, 13 }, top = { 1, 3 },
|
||||
{ kind = "upright", x = { 10, 21 }, top = { 1, 3 },
|
||||
facade = { 4, 13 }, z = 20, depth = 4,
|
||||
inset = { x = { 5, 10 }, rows = { 6, 8 } } }, -- the monitor
|
||||
inset = { x = { 13, 18 }, rows = { 6, 8 } } }, -- the monitor
|
||||
{ kind = "box", x = { 3, 7 }, rows = { 24, 26 },
|
||||
z = 18, depth = 3 }, -- N hose run
|
||||
{ kind = "box", x = { 2, 7 }, rows = { 27, 31 },
|
||||
z = 18, depth = 3 }, -- N hose drop
|
||||
{ kind = "box", x = { 3, 7 }, rows = { 24, 26 },
|
||||
z = 24, depth = 3 }, -- S hose run
|
||||
{ kind = "box", x = { 2, 7 }, rows = { 27, 31 },
|
||||
z = 24, depth = 3 }, -- S hose drop
|
||||
{ kind = "flat", x = { 24, 29 }, rows = { 16, 31 },
|
||||
z = 16, at = 8, thick = 3 }, -- keyboard shelf
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "center_heal_machine_e",
|
||||
tiles = {
|
||||
{ 40, 58, 59, 40 },
|
||||
{ 40, 74, 75, 40 },
|
||||
{ 72, 76, 77, 73 },
|
||||
{ 72, 6, 22, 73 },
|
||||
},
|
||||
roofRows = 0, roofBack = 0, roofFront = 0, roofCycle = { 0, 0 },
|
||||
slab = 0, frontEave = 0, ledge = nil, depth = 4,
|
||||
panes = false,
|
||||
wall = { h = 16, depthPx = 16, x = 0, cycle = { 0, 3 } },
|
||||
desk = { x = { 8, 23 }, fascia = { 15, 16 }, base = { 17, 31 },
|
||||
z = 16, depthPx = 10, top = { 6, 14 } },
|
||||
parts = {
|
||||
{ kind = "upright", x = { 10, 21 }, top = { 1, 3 },
|
||||
facade = { 4, 13 }, z = 20, depth = 4,
|
||||
inset = { x = { 13, 18 }, rows = { 6, 8 } } }, -- the monitor
|
||||
{ kind = "box", x = { 3, 7 }, rows = { 24, 26 },
|
||||
z = 18, depth = 3 }, -- NW hose run
|
||||
{ kind = "box", x = { 2, 7 }, rows = { 27, 31 },
|
||||
z = 18, depth = 3 }, -- NW hose drop
|
||||
{ kind = "box", x = { 3, 7 }, rows = { 24, 26 },
|
||||
z = 24, depth = 3 }, -- SW hose run
|
||||
{ kind = "box", x = { 2, 7 }, rows = { 27, 31 },
|
||||
z = 24, depth = 3 }, -- SW hose drop
|
||||
{ kind = "box", x = { 24, 28 }, rows = { 24, 26 },
|
||||
z = 18, depth = 3 }, -- NE hose run
|
||||
{ kind = "box", x = { 24, 29 }, rows = { 27, 31 },
|
||||
z = 18, depth = 3 }, -- NE hose drop
|
||||
{ kind = "box", x = { 24, 28 }, rows = { 24, 26 },
|
||||
z = 24, depth = 3 }, -- SE hose run
|
||||
{ kind = "box", x = { 24, 29 }, rows = { 27, 31 },
|
||||
z = 24, depth = 3 }, -- SE hose drop
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -3840,28 +3926,75 @@ return {
|
||||
},
|
||||
},
|
||||
-- F05 again: the Indigo Plateau lobby has the Centers' healing
|
||||
-- machine pair too (cells (5,4):(6,5) and (10,4):(11,5)), and its
|
||||
-- MART tileset shares the POKECENTER atlas, so this is the same
|
||||
-- drawing tile for tile. Same part table as the POKECENTER entry
|
||||
-- above.
|
||||
-- machine pair too -- the west-variant grid at (5,4):(6,5) and
|
||||
-- the east at (10,4):(11,5), verified by region dump -- and its
|
||||
-- MART tileset shares the POKECENTER atlas, so these are the
|
||||
-- same drawings tile for tile. Same part tables as the
|
||||
-- POKECENTER entries above.
|
||||
{
|
||||
id = "center_heal_machine",
|
||||
id = "center_heal_machine_w",
|
||||
tiles = {
|
||||
{ 58, 59 },
|
||||
{ 74, 75 },
|
||||
{ 76, 77 },
|
||||
{ 6, 22 },
|
||||
{ 40, 58, 59, 40 },
|
||||
{ 40, 74, 75, 40 },
|
||||
{ 72, 76, 77, 7 },
|
||||
{ 72, 6, 22, 13 },
|
||||
},
|
||||
roofRows = 0, roofBack = 0, roofFront = 0, roofCycle = { 0, 0 },
|
||||
slab = 0, frontEave = 0, ledge = nil, depth = 4,
|
||||
panes = false,
|
||||
wall = { h = 16, depthPx = 16, x = 0, cycle = { 0, 3 } },
|
||||
desk = { fascia = { 15, 16 }, base = { 17, 31 }, z = 16,
|
||||
depthPx = 10, top = { 6, 14 } },
|
||||
desk = { x = { 8, 23 }, fascia = { 15, 16 }, base = { 17, 31 },
|
||||
z = 16, depthPx = 10, top = { 6, 14 } },
|
||||
parts = {
|
||||
{ kind = "upright", x = { 2, 13 }, top = { 1, 3 },
|
||||
{ kind = "upright", x = { 10, 21 }, top = { 1, 3 },
|
||||
facade = { 4, 13 }, z = 20, depth = 4,
|
||||
inset = { x = { 5, 10 }, rows = { 6, 8 } } }, -- the monitor
|
||||
inset = { x = { 13, 18 }, rows = { 6, 8 } } }, -- the monitor
|
||||
{ kind = "box", x = { 3, 7 }, rows = { 24, 26 },
|
||||
z = 18, depth = 3 }, -- N hose run
|
||||
{ kind = "box", x = { 2, 7 }, rows = { 27, 31 },
|
||||
z = 18, depth = 3 }, -- N hose drop
|
||||
{ kind = "box", x = { 3, 7 }, rows = { 24, 26 },
|
||||
z = 24, depth = 3 }, -- S hose run
|
||||
{ kind = "box", x = { 2, 7 }, rows = { 27, 31 },
|
||||
z = 24, depth = 3 }, -- S hose drop
|
||||
{ kind = "flat", x = { 24, 29 }, rows = { 16, 31 },
|
||||
z = 16, at = 8, thick = 3 }, -- keyboard shelf
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "center_heal_machine_e",
|
||||
tiles = {
|
||||
{ 40, 58, 59, 40 },
|
||||
{ 40, 74, 75, 40 },
|
||||
{ 72, 76, 77, 73 },
|
||||
{ 72, 6, 22, 73 },
|
||||
},
|
||||
roofRows = 0, roofBack = 0, roofFront = 0, roofCycle = { 0, 0 },
|
||||
slab = 0, frontEave = 0, ledge = nil, depth = 4,
|
||||
panes = false,
|
||||
wall = { h = 16, depthPx = 16, x = 0, cycle = { 0, 3 } },
|
||||
desk = { x = { 8, 23 }, fascia = { 15, 16 }, base = { 17, 31 },
|
||||
z = 16, depthPx = 10, top = { 6, 14 } },
|
||||
parts = {
|
||||
{ kind = "upright", x = { 10, 21 }, top = { 1, 3 },
|
||||
facade = { 4, 13 }, z = 20, depth = 4,
|
||||
inset = { x = { 13, 18 }, rows = { 6, 8 } } }, -- the monitor
|
||||
{ kind = "box", x = { 3, 7 }, rows = { 24, 26 },
|
||||
z = 18, depth = 3 }, -- NW hose run
|
||||
{ kind = "box", x = { 2, 7 }, rows = { 27, 31 },
|
||||
z = 18, depth = 3 }, -- NW hose drop
|
||||
{ kind = "box", x = { 3, 7 }, rows = { 24, 26 },
|
||||
z = 24, depth = 3 }, -- SW hose run
|
||||
{ kind = "box", x = { 2, 7 }, rows = { 27, 31 },
|
||||
z = 24, depth = 3 }, -- SW hose drop
|
||||
{ kind = "box", x = { 24, 28 }, rows = { 24, 26 },
|
||||
z = 18, depth = 3 }, -- NE hose run
|
||||
{ kind = "box", x = { 24, 29 }, rows = { 27, 31 },
|
||||
z = 18, depth = 3 }, -- NE hose drop
|
||||
{ kind = "box", x = { 24, 28 }, rows = { 24, 26 },
|
||||
z = 24, depth = 3 }, -- SE hose run
|
||||
{ kind = "box", x = { 24, 29 }, rows = { 27, 31 },
|
||||
z = 24, depth = 3 }, -- SE hose drop
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4236,6 +4369,46 @@ return {
|
||||
facade = { 22, 31 }, rise = -8, z = 22, depth = 10 },
|
||||
},
|
||||
},
|
||||
-- F09 once more: the Pokemon Fan Club's four members' chairs,
|
||||
-- drawn round the boardroom table -- POKEMON_FAN_CLUB cells (1,3),
|
||||
-- (1,4), (6,3) and (6,4), and nowhere else in the game.
|
||||
--
|
||||
-- A DIFFERENT drawing from the house stool -- its seat field
|
||||
-- carries a one-pixel white margin where the house's carries two
|
||||
-- -- but the same object band for band: rows 5-10 the seat seen
|
||||
-- from above (its lid), row 11 the seat's own front edge, 12-15
|
||||
-- the legs with the floor showing between them. Its elevation
|
||||
-- rows are PIXEL-IDENTICAL to the house drawing's, so it takes
|
||||
-- that part table unchanged, growth and all: z 3..13, `stretch`
|
||||
-- mapping the seat band over the deeper lid, `panes = false` so
|
||||
-- the pane rule does not sink the legs' lit faces.
|
||||
--
|
||||
-- Rows 11-15 come from tiles 59/60, which this drawing SHARES
|
||||
-- with Bill's chair (43/44 over 59/60, modelled as a part of
|
||||
-- `bills_desk` above). That is why the tileset's `stool = 5`
|
||||
-- height override is right for both seats rather than a special
|
||||
-- case for this one: they are drawn at the same height because
|
||||
-- they are drawn with the same pixels.
|
||||
--
|
||||
-- Listed after `bills_desk` although neither grid is a subgrid of
|
||||
-- the other (that grid has 43/44 over 59/60, this one 61/62), so
|
||||
-- the order is free and the bigger, more specific grid keeps
|
||||
-- first claim.
|
||||
{
|
||||
id = "club_stool",
|
||||
tiles = {
|
||||
{ 61, 62 },
|
||||
{ 59, 60 },
|
||||
},
|
||||
roofRows = 0, roofBack = 0, roofFront = 0, roofCycle = { 0, 0 },
|
||||
slab = 0, frontEave = 0, ledge = nil,
|
||||
panes = false,
|
||||
parts = {
|
||||
{ kind = "upright", x = { 2, 13 }, top = { 5, 10 },
|
||||
facade = { 11, 15 }, z = 3, depth = 11,
|
||||
stretch = true }, -- the stool
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
+73
-13
@@ -440,14 +440,68 @@ local function deskSetModel(sp, pr, t)
|
||||
if p.kind == "flat" then
|
||||
-- drawn row = depth row by default; `z` renames the origin when
|
||||
-- the flat sits below the desk's own drawn top span (the Center
|
||||
-- PC's keyboard)
|
||||
-- PC's keyboard). `at` names the sheet's own height when it does
|
||||
-- not lie on the desk plane (the healing machine's keyboard is a
|
||||
-- shelf mounted on the cabinet's side); `thick` gives it a body
|
||||
-- -- layers below the sheet repeating each column's own texel,
|
||||
-- the same continuation rule every synthesized surface follows.
|
||||
local r0 = p.rows[1]
|
||||
local z0 = p.z or r0
|
||||
local atY = p.at or plane
|
||||
local thick = p.thick or 1
|
||||
if atY > ytop then ytop = atY end
|
||||
for sy = r0, p.rows[2] do
|
||||
local z = z0 + (sy - r0)
|
||||
if z >= 0 and z < D then
|
||||
for sx = x0, x1 do
|
||||
if inside[sy * W + sx] then put(sx, plane, z, sy * W + sx) end
|
||||
if inside[sy * W + sx] then
|
||||
for y = math.max(0, atY - thick + 1), atY do
|
||||
put(sx, y, z, sy * W + sx)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif p.kind == "box" then
|
||||
-- A BOX part is a drawn rect standing at its own drawn
|
||||
-- elevation -- equipment attached to the machine rather than an
|
||||
-- object on the desk plane. The rows are face-on art: the top
|
||||
-- row's drawn height IS the box's top (ground - 1 - r0,
|
||||
-- measured), and the box runs down to `base` (default the drawn
|
||||
-- extent; 0 continues it to the floor, the legs-continue rule).
|
||||
-- Height beyond the drawn rows fills the way a roof band does:
|
||||
-- rows before `cycle` map 1:1 from the top, rows after it 1:1
|
||||
-- from the bottom -- the healing machine hoses' foot lands ON
|
||||
-- the floor -- and the cycle window repeats between.
|
||||
local r0, r1 = p.rows[1], p.rows[2]
|
||||
local c0 = p.cycle and p.cycle[1] or r1
|
||||
local c1 = p.cycle and p.cycle[2] or r1
|
||||
local pz = p.z or 0
|
||||
local pd = p.depth
|
||||
local top = pr.ground - 1 - r0
|
||||
local bot = p.base or (pr.ground - 1 - r1)
|
||||
local nTop, nBot = c0 - r0, r1 - c1
|
||||
if top > ytop then ytop = top end
|
||||
for y = bot, top do
|
||||
local k, j = top - y, y - bot
|
||||
local sy
|
||||
if k < nTop then
|
||||
sy = r0 + k
|
||||
elseif j < nBot then
|
||||
sy = r1 - j
|
||||
else
|
||||
sy = c0 + (k - nTop) % (c1 - c0 + 1)
|
||||
end
|
||||
for sx = x0, x1 do
|
||||
local i = sy * W + sx
|
||||
if inside[i] then
|
||||
local ix = interiorAt(sx, sy, x0, x1)
|
||||
for z = pz, pz + pd - 1 do
|
||||
if z >= 0 and z < D then
|
||||
local px = (z == pz or z == pz + pd - 1) and sx or ix
|
||||
put(sx, y, z, sy * W + px)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -700,6 +754,11 @@ local function deskSetModel(sp, pr, t)
|
||||
local dz0 = t.desk.z or 0
|
||||
local dz1 = dz0 + deskD - 1
|
||||
local deskG = b1 + 1
|
||||
-- ...and the desk's COLUMNS (`x`), when the grid is wider than the
|
||||
-- desk: the healing machine's grid carries its flanking hoses and
|
||||
-- keyboard, and the cabinet is only the middle 16 columns.
|
||||
local dx0 = t.desk.x and t.desk.x[1] or 0
|
||||
local dx1 = t.desk.x and t.desk.x[2] or W - 1
|
||||
|
||||
-- The WALL element: the band the machine backs onto, whose tiles this
|
||||
-- grid claims. The drawing shows it only as the stripe background
|
||||
@@ -727,9 +786,9 @@ local function deskSetModel(sp, pr, t)
|
||||
for sy = b0, b1 do
|
||||
Budget.tick()
|
||||
local y = deskG - 1 - sy
|
||||
for sx = 0, W - 1 do
|
||||
for sx = dx0, dx1 do
|
||||
if inside[sy * W + sx] then
|
||||
local ix = interiorAt(sx, sy, 0, W - 1)
|
||||
local ix = interiorAt(sx, sy, dx0, dx1)
|
||||
for z = dz0, dz1 do
|
||||
local px = (z == dz0 or z == dz1) and sx or ix
|
||||
put(sx, y, z, sy * W + px)
|
||||
@@ -739,8 +798,9 @@ local function deskSetModel(sp, pr, t)
|
||||
end
|
||||
for i in pairs(pr.recess) do
|
||||
local sy = math.floor(i / W)
|
||||
if sy >= b0 and sy <= b1 then
|
||||
vox[key(i % W, deskG - 1 - sy, dz1)] = nil
|
||||
local sx = i % W
|
||||
if sy >= b0 and sy <= b1 and sx >= dx0 and sx <= dx1 then
|
||||
vox[key(sx, deskG - 1 - sy, dz1)] = nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -748,7 +808,7 @@ local function deskSetModel(sp, pr, t)
|
||||
for sy = f0, f1 do
|
||||
Budget.tick()
|
||||
local y = plane - 1 - (sy - f0)
|
||||
for sx = 0, W - 1 do
|
||||
for sx = dx0, dx1 do
|
||||
for z = dz0, dz1 do put(sx, y, z, sy * W + sx) end
|
||||
end
|
||||
end
|
||||
@@ -767,19 +827,19 @@ local function deskSetModel(sp, pr, t)
|
||||
for z = dz0, dz1 do
|
||||
Budget.tick()
|
||||
local sy = z == dz1 and f0 or math.min(tr0 + (z - dz0), tr1)
|
||||
for sx = 0, W - 1 do
|
||||
for sx = dx0, dx1 do
|
||||
local px = sx
|
||||
for _, p in ipairs(t.parts) do
|
||||
local px0, px1 = p.x[1], p.x[2]
|
||||
local r0, r1
|
||||
if p.kind == "flat" or p.kind == "iso" then
|
||||
if p.kind == "flat" or p.kind == "iso" or p.kind == "box" then
|
||||
r0, r1 = p.rows[1], p.rows[2]
|
||||
else
|
||||
r0, r1 = p.top[1], p.facade[2]
|
||||
end
|
||||
if sx >= px0 and sx <= px1 and sy >= r0 and sy <= r1 then
|
||||
px = (sx - px0 < px1 - sx) and (px0 - 1) or (px1 + 1)
|
||||
px = math.max(0, math.min(W - 1, px))
|
||||
px = math.max(dx0, math.min(dx1, px))
|
||||
break
|
||||
end
|
||||
end
|
||||
@@ -790,12 +850,12 @@ local function deskSetModel(sp, pr, t)
|
||||
-- the lid continues the sibling tables' top -- black rim, white
|
||||
-- highlight courses along the north and west, grey field
|
||||
local field = t.desk.lid == "white" and WHITE or GREY
|
||||
for sx = 0, W - 1 do
|
||||
for sx = dx0, dx1 do
|
||||
for z = dz0, dz1 do
|
||||
local shade = field
|
||||
if sx == 0 or sx == W - 1 or z == dz0 or z == dz1 then
|
||||
if sx == dx0 or sx == dx1 or z == dz0 or z == dz1 then
|
||||
shade = BLACK
|
||||
elseif sx == 1 or z == dz0 + 1 then
|
||||
elseif sx == dx0 + 1 or z == dz0 + 1 then
|
||||
shade = WHITE
|
||||
end
|
||||
put(sx, plane - 1, z, pr.shadeTexel[shade])
|
||||
|
||||
+36
-9
@@ -583,8 +583,40 @@ end
|
||||
-- The overworld's alone: the staged battle draws its water plain, always --
|
||||
-- its placed camera reads this pass wrong, and a stage set wants painted
|
||||
-- water anyway (see BattleScene, where the choice is argued).
|
||||
-- ------- and why the flat draw happens FIRST, every time
|
||||
--
|
||||
-- The reflective pass writes no depth -- it cannot, the depth canvas is
|
||||
-- detached for the length of it so the shader can READ it -- and it does its
|
||||
-- own depth test against that texture instead. That test asks whether
|
||||
-- something opaque is in front, and it answers correctly for every case but
|
||||
-- one: WATER IN FRONT OF WATER. Nothing puts water in the depth buffer, so
|
||||
-- no lake can hide another, and the pass simply paints them in mesh order.
|
||||
--
|
||||
-- On flat water that never mattered, because every surface lies in the one
|
||||
-- plane at its own recessed height and a farther sheet always lands farther
|
||||
-- down the screen. THE WORLD CURVE ENDS THAT. The bend drops the world by
|
||||
-- the square of its distance, so the far side of the map swings down and
|
||||
-- back up into the near field of view -- and a sheet of sea a hundred and
|
||||
-- fifty tiles away, drawn later in the same mesh, paints straight over the
|
||||
-- pond at the player's feet. That is the tall grass and the water "from the
|
||||
-- other side of the map": not a reflection of them, THEM, rasterised on top
|
||||
-- of the water in front of you.
|
||||
--
|
||||
-- So the meshes go down flat first, through the ordinary scene shader with
|
||||
-- depth writes on, and the reflective pass draws over the top of what
|
||||
-- survived. Three things fall out of it and all three are wanted: the depth
|
||||
-- buffer now holds the water surface, so the pass's own test throws the far
|
||||
-- sheet away; the reflection COPY holds it too, so a ray grazing another
|
||||
-- part of the lake reads water rather than the void behind it; and the flat
|
||||
-- draw is the same fallback this function already ended with, so a frame
|
||||
-- that cannot run the reflective pass is unchanged.
|
||||
--
|
||||
-- It costs one more rasterisation of the water meshes. Water is a small
|
||||
-- share of a frame's triangles and this is the cheapest shader in the mode.
|
||||
function VoxelScene.drawWater(draws, cast)
|
||||
local plain = true
|
||||
for _, d in ipairs(draws) do
|
||||
Voxel3D.draw(d[1], d[2], d[3])
|
||||
end
|
||||
if Water.enabled() and Voxel3D.depthReadable() then
|
||||
local mirror, depth = Voxel3D.beginWater(cast)
|
||||
local w, h = Voxel3D.size()
|
||||
@@ -602,20 +634,15 @@ function VoxelScene.drawWater(draws, cast)
|
||||
Water.draw(d[1], d[2], d[3])
|
||||
end
|
||||
Water.finish()
|
||||
plain = false
|
||||
end
|
||||
-- Unconditionally, and OUTSIDE the success branch: beginWater unbinds
|
||||
-- the shader and the depth mode BEFORE it can discover it cannot go on,
|
||||
-- so a frame that bails halfway through has to be put back together
|
||||
-- exactly like one that succeeded -- otherwise the plain draw below (and
|
||||
-- every pass after it) runs with no shader and no depth test.
|
||||
-- exactly like one that succeeded -- otherwise every pass after it runs
|
||||
-- with no shader and no depth test. (What a bail leaves on screen is the
|
||||
-- flat draw above, which is where this function used to end anyway.)
|
||||
Voxel3D.endWater()
|
||||
end
|
||||
if plain then
|
||||
for _, d in ipairs(draws) do
|
||||
Voxel3D.draw(d[1], d[2], d[3])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- A stamp of everything the sun pass depends on. Nothing in it moving
|
||||
|
||||
+8
-1
@@ -956,8 +956,15 @@ vec4 effect(mediump vec4 color, Image tex, mediump vec2 tc, mediump vec2 sc) {
|
||||
// the bound canvas's own pixel size, the same units sc is measured in, on
|
||||
// every display. (`screen` stays in units: skyPos reads it against cell
|
||||
// and skyEdge, which are unit-measured with it.)
|
||||
//
|
||||
// The buffer now holds THIS SURFACE too (VoxelScene draws the water flat
|
||||
// before the pass that reflects it), which is what makes one lake able to
|
||||
// hide another -- and it means every fragment here is testing against its
|
||||
// own depth. The two draws reach it through different shader programs, so
|
||||
// ask for a hair of slack rather than bit-equality: far less than the gap
|
||||
// to anything genuinely in front, far more than two compilers disagree by.
|
||||
vec2 uv = sc / love_ScreenSize.xy;
|
||||
if (gl_FragCoord.z > Texel(depthTex, uv).r) discard;
|
||||
if (gl_FragCoord.z > Texel(depthTex, uv).r + 1e-5) discard;
|
||||
|
||||
// THE COLUMN THIS FRAGMENT IS LOOKING AT. Every water pixel is a bar of
|
||||
// its own standing a whole number of pixels tall, and the ray decides
|
||||
|
||||
@@ -1915,6 +1915,19 @@ T.check(plain:find("sc / love_ScreenSize.xy", 1, true) ~= nil,
|
||||
.. "size -- `screen` counts canvas UNITS, and on a highdpi phone the two "
|
||||
.. "differ by the density, which clamped the lookup and cut the water "
|
||||
.. "into blocks")
|
||||
-- ...and it tests against a buffer that now holds the water surface too,
|
||||
-- because VoxelScene lays the meshes down flat before the reflective pass
|
||||
-- runs over them. Nothing else can make one lake hide another: the pass
|
||||
-- writes no depth (the buffer is detached so it can be READ), so before this
|
||||
-- the sheets were simply painted in mesh order. Flat water never showed it --
|
||||
-- one plane, and a farther sheet always lands farther down the screen -- but
|
||||
-- the world curve drops the far side of the map into the near field of view,
|
||||
-- and a sea a hundred and fifty tiles away came out rasterised on top of the
|
||||
-- pond at the player's feet, tall grass and all.
|
||||
T.check(plain:find("Texel(depthTex, uv).r + 1e-5", 1, true) ~= nil,
|
||||
"with a hair of slack, because every water fragment is now testing "
|
||||
.. "against its own depth through a second shader program")
|
||||
T.check(VoxelScene.drawWater ~= nil, "and the flat draw that puts it there")
|
||||
|
||||
-- ------- the lift itself
|
||||
--
|
||||
|
||||
+69
-38
@@ -765,6 +765,35 @@ TEMPLATES = {
|
||||
z=3, depth=11, stretch=True), # the stool
|
||||
],
|
||||
),
|
||||
# F09 once more, on the interior atlas: the Pokemon Fan Club's four
|
||||
# members' chairs, drawn round the boardroom table -- 4 placements
|
||||
# (cells (1,3), (1,4), (6,3), (6,4)) and nowhere else in the game.
|
||||
# A DIFFERENT drawing from the house stool -- its seat field carries
|
||||
# a one-pixel white margin where the house's carries two -- but the
|
||||
# same object band for band, and its elevation rows (11-15: the
|
||||
# seat's front edge, then the legs) are pixel-identical to the house
|
||||
# drawing's. So it takes the same part table unchanged, including
|
||||
# the two-voxel growth north and south.
|
||||
#
|
||||
# Those elevation rows come from tiles 59/60, which this drawing
|
||||
# SHARES with Bill's chair (43/44 over 59/60, modelled as a part of
|
||||
# `bills_desk`) -- which is why one `stool = 5` height override in
|
||||
# the tileset entry is right for both seats rather than a special
|
||||
# case: they are drawn at the same height because they are drawn
|
||||
# with the same pixels.
|
||||
"club_stool": dict(
|
||||
tiles=[
|
||||
[61, 62],
|
||||
[59, 60],
|
||||
],
|
||||
roof_rows=0, roof_back=0, roof_front=0, roof_cycle=(0, 0),
|
||||
slab=0, front_eave=0, ledge=None, tileset="interior",
|
||||
panes=False,
|
||||
parts=[
|
||||
dict(kind="upright", x=(2, 13), top=(5, 10), facade=(11, 15),
|
||||
z=3, depth=11, stretch=True), # the stool
|
||||
],
|
||||
),
|
||||
# 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
|
||||
@@ -829,29 +858,31 @@ TEMPLATES = {
|
||||
# voxel via `inset` -- the pane rule by hand, since
|
||||
# `panes=False` blocks the global pass.
|
||||
# rows 16-31, x0..x7 the HOSES (tile 72 twice): one 8-row
|
||||
# motif per map row -- a horizontal run high on the
|
||||
# cabinet's side (16-18, x3..x7 -> heights 13..15,
|
||||
# measured off the drawn rows) and a shaded drop
|
||||
# (19-23, x2..x7) that bends down INTO THE FLOOR.
|
||||
# The two stacked motifs are two hoses in DEPTH (the
|
||||
# drawn row band is the depth band): `box` parts at
|
||||
# z 18 and z 24, 3 deep, the drop cycling its two
|
||||
# shading rows (19-20) down to the floor with the
|
||||
# drawn foot rows (21-23) landing at the bottom --
|
||||
# the roof-rim rule turned vertical. The second
|
||||
# hose re-wears the first motif's rows: the atlas
|
||||
# tile is the same, so the pixels are identical.
|
||||
# motif per map row, and the two stacked motifs are
|
||||
# two hoses in DEPTH -- the drawn row band is the
|
||||
# depth band, and each motif's own rows are its
|
||||
# elevation WITHIN that band, exactly the potted
|
||||
# plants' stacked-cell rule. So both hoses hug the
|
||||
# floor: a horizontal run off the cabinet's side
|
||||
# (rows 24-26, x3..x7 -> heights 5..7) over a shaded
|
||||
# drop landing ON the floor (rows 27-31, x2..x7 ->
|
||||
# heights 0..4) -- all measured, the drawn extent
|
||||
# maps 1:1 with no continuation. `box` parts at z 18
|
||||
# and z 24, 3 deep; both wear the LOWER motif's rows
|
||||
# (the one drawn at its true elevation; the upper
|
||||
# motif is the same atlas tile, pixel-identical).
|
||||
# rows 16-31, x24..x31 west variant: the KEYBOARD (7/13), a
|
||||
# key grid with its cable at the north end and a bar
|
||||
# down the east edge -- TOP-VIEW art, 16 rows = 16
|
||||
# depth rows. A `flat` part mounted on the cabinet's
|
||||
# side at working height (`at` 11, authored -- the
|
||||
# one number top-view art cannot state), 3 thick,
|
||||
# top face wearing the drawn art. The stray dark
|
||||
# dashes east of it (x30-31) are its cast shadow on
|
||||
# the floor: background. East variant: mirrored
|
||||
# hoses (runs 16-18 x24..x28, drops 19-23 x24..x29),
|
||||
# same z slots.
|
||||
# side at COUNTER level (`at` 8, the counters' own
|
||||
# 8px band -- the one number top-view art cannot
|
||||
# state, pinned to the room's work surface), 3
|
||||
# thick, top face wearing the drawn art. The stray
|
||||
# dark dashes east of it (x30-31) are its cast
|
||||
# shadow on the floor: background. East variant:
|
||||
# mirrored hoses (runs x24..x28, drops x24..x29),
|
||||
# same rows and z slots.
|
||||
# rows 0-15 elsewhere wall stripes and cast shadow: BACKGROUND.
|
||||
# The `wall` element keeps the band solid over the
|
||||
# back map row, full grid width -- a 16-tall,
|
||||
@@ -878,16 +909,16 @@ TEMPLATES = {
|
||||
dict(kind="upright", x=(10, 21), top=(1, 3), facade=(4, 13),
|
||||
z=20, depth=4,
|
||||
inset=dict(x=(13, 18), rows=(6, 8))), # the monitor
|
||||
dict(kind="box", x=(3, 7), rows=(16, 18),
|
||||
dict(kind="box", x=(3, 7), rows=(24, 26),
|
||||
z=18, depth=3), # north hose run
|
||||
dict(kind="box", x=(2, 7), rows=(19, 23), cycle=(19, 20),
|
||||
base=0, z=18, depth=3), # north hose drop
|
||||
dict(kind="box", x=(3, 7), rows=(16, 18),
|
||||
dict(kind="box", x=(2, 7), rows=(27, 31),
|
||||
z=18, depth=3), # north hose drop
|
||||
dict(kind="box", x=(3, 7), rows=(24, 26),
|
||||
z=24, depth=3), # south hose run
|
||||
dict(kind="box", x=(2, 7), rows=(19, 23), cycle=(19, 20),
|
||||
base=0, z=24, depth=3), # south hose drop
|
||||
dict(kind="box", x=(2, 7), rows=(27, 31),
|
||||
z=24, depth=3), # south hose drop
|
||||
dict(kind="flat", x=(24, 29), rows=(16, 31),
|
||||
z=16, at=11, thick=3), # keyboard shelf
|
||||
z=16, at=8, thick=3), # keyboard shelf
|
||||
],
|
||||
),
|
||||
"center_heal_machine_e": dict(
|
||||
@@ -907,22 +938,22 @@ TEMPLATES = {
|
||||
dict(kind="upright", x=(10, 21), top=(1, 3), facade=(4, 13),
|
||||
z=20, depth=4,
|
||||
inset=dict(x=(13, 18), rows=(6, 8))), # the monitor
|
||||
dict(kind="box", x=(3, 7), rows=(16, 18),
|
||||
dict(kind="box", x=(3, 7), rows=(24, 26),
|
||||
z=18, depth=3), # NW hose run
|
||||
dict(kind="box", x=(2, 7), rows=(19, 23), cycle=(19, 20),
|
||||
base=0, z=18, depth=3), # NW hose drop
|
||||
dict(kind="box", x=(3, 7), rows=(16, 18),
|
||||
dict(kind="box", x=(2, 7), rows=(27, 31),
|
||||
z=18, depth=3), # NW hose drop
|
||||
dict(kind="box", x=(3, 7), rows=(24, 26),
|
||||
z=24, depth=3), # SW hose run
|
||||
dict(kind="box", x=(2, 7), rows=(19, 23), cycle=(19, 20),
|
||||
base=0, z=24, depth=3), # SW hose drop
|
||||
dict(kind="box", x=(24, 28), rows=(16, 18),
|
||||
dict(kind="box", x=(2, 7), rows=(27, 31),
|
||||
z=24, depth=3), # SW hose drop
|
||||
dict(kind="box", x=(24, 28), rows=(24, 26),
|
||||
z=18, depth=3), # NE hose run
|
||||
dict(kind="box", x=(24, 29), rows=(19, 23), cycle=(19, 20),
|
||||
base=0, z=18, depth=3), # NE hose drop
|
||||
dict(kind="box", x=(24, 28), rows=(16, 18),
|
||||
dict(kind="box", x=(24, 29), rows=(27, 31),
|
||||
z=18, depth=3), # NE hose drop
|
||||
dict(kind="box", x=(24, 28), rows=(24, 26),
|
||||
z=24, depth=3), # SE hose run
|
||||
dict(kind="box", x=(24, 29), rows=(19, 23), cycle=(19, 20),
|
||||
base=0, z=24, depth=3), # SE hose drop
|
||||
dict(kind="box", x=(24, 29), rows=(27, 31),
|
||||
z=24, depth=3), # SE hose drop
|
||||
],
|
||||
),
|
||||
# F06: the Bike Shop's toolbox -- 2 placements, cells (6,6) and (7,7)
|
||||
|
||||
Reference in New Issue
Block a user