fix(pa): flush stall paint, drop ring parapet, complete ramp kerbs

Stall markings were 2.2-stud-tall slabs at DECK_Y+0.1, standing 1.2 studs
proud of the tarmac -- 434 concrete ridges across the parking rows. They
are paint, not kerbs: now 0.12 thick, sunk to sit 0.06 proud (verified
against PAFloor at y=47.0). Under tyre resolution.

Ring barrier: the outer edge was a 2.2-wide parapet + metal rail ringing
the whole lot. Replaced with a single 3.0-stud concrete edge (69 parts);
inner stays a 1.2 kerb. PARingWall/PARingRail are gone.

Ramp kerbs: the guard was still a height test (h > 2) after the earlier
h > 8 fix, and segment 0 of both ramps sits at h = 0.5..0.8 -- so the
barrier still began one segment up the ramp and visibly ended in mid-air
at the foot. Per-side probe confirmed seg0 had no kerb on EITHER side.
Height test removed entirely; only the merge mouth is now left open.

Verified in live Edit datamodel: PAOnRamp 13 segs / PAOffRamp 10 segs,
uncovered = merge segment only (seg12, seg9).
This commit is contained in:
2026-08-03 00:23:03 -04:00
parent 1e41de92fd
commit e997f0f73d
+44 -46
View File
@@ -1000,11 +1000,25 @@ local function buildPA(map: Folder)
local DECK_Y = c.Y + 1 -- top face of the apron slab
local C_PAINT = Color3.fromRGB(235, 235, 240)
-- Painted markings are PAINT, not kerbs. They must be flush with the apron.
--
-- BUG (2026-08-02, test drive): these were spawned 2.2 studs tall sitting
-- at DECK_Y + 0.1, so every stall divider stood ~1.2 studs PROUD of the
-- tarmac -- a kerb-height ridge exactly where you park. Driving the rows
-- meant bouncing over 300+ concrete strips ("like a whole foot out of the
-- ground" -- measured 1.2, and a stud is ~a foot, so: exactly right).
--
-- Fix: 0.12 studs thick, sunk so its TOP sits a hair above the deck. A
-- decal would be flatter still, but a thin slab keeps this buildable from
-- pure geometry with no asset IDs, and 0.06 studs proud is under tyre
-- resolution -- you cannot feel it.
local PAINT_T = 0.12
local function paint(name, size, x, z, colour)
local m = part({
Name = name,
Size = size,
CFrame = CFrame.new(x, DECK_Y + 0.1, z),
-- caller passes the old 2.2 in size.Y; ignore it and use PAINT_T
Size = Vector3.new(size.X, PAINT_T, size.Z),
CFrame = CFrame.new(x, DECK_Y + PAINT_T / 2 - 0.06, z),
Color = colour or C_PAINT,
Material = Enum.Material.SmoothPlastic,
})
@@ -1208,22 +1222,17 @@ local function buildPA(map: Folder)
local segCF = CFrame.lookAt(segMid, p1, UP)
deck("PARing", Vector3.new(RING_W, 2, segLen), segCF)
-- Ring edge treatment. The OUTER edge (sgn == 1, away from the apron)
-- keeps the full white parapet + dark railing, because behind it is a
-- drop off the structure -- that wall is the only thing stopping a car
-- leaving the world.
-- Ring edge treatment. BOTH edges are now a single low barrier.
--
-- The INNER edge (sgn == -1, facing the parking lot) is now a LOW KERB,
-- not a parapet. Two reasons, one factual and one about driving:
-- * Factual: since the ring and the apron were both dropped to ground
-- level (Circuit.PA_LIFT raises the MAINLINE over the PA instead),
-- an inner parapet would be separating two surfaces at the SAME
-- height. The real Daikoku has a kerb and painted markings there,
-- not a wall -- the lot is open to its circulation road.
-- * Driving: a 44-stud lane walled on both sides is a canyon with no
-- runoff. Clipping the inside of the loop stopped a car dead.
-- The kerb is 1.2 studs, well under the ~2-3 studs a car can climb, so
-- it reads as an edge without being a barrier.
-- CHANGE (2026-08-02, user call): the OUTER edge used to be a tall
-- white parapet + dark railing ringing the whole parking area. That
-- is the "ring barrier" -- it walled the lot in and, combined with the
-- inner kerb, made the circulation road a 44-stud canyon. Ditched in
-- favour of a plain single barrier on the edge of the parking area.
--
-- Outer keeps a slightly taller barrier than inner because behind the
-- outer edge is still a drop off the structure -- it has to stop a car
-- leaving the world, it just no longer needs to be a parapet+rail.
local fwd = (p1 - p0).Unit
local outN = (segMid - Vector3.new(c.X, ringY, c.Z)).Unit
for _, sgn in ipairs({ 1, -1 }) do
@@ -1233,34 +1242,15 @@ local function buildPA(map: Folder)
local gate = (sgn == 1) and GATE_OUT or GATE_IN
if not nearJunction(ePos, gate) then
local eCF = CFrame.lookAt(ePos, ePos + fwd, UP)
if sgn == 1 then
local lip = part({
Name = "PARingWall",
Size = Vector3.new(2.2, BARRIER_H, segLen + 1),
CFrame = eCF * CFrame.new(0, 1 + BARRIER_H / 2, 0),
Color = C_PARAPET,
Material = Enum.Material.Concrete,
})
lip.Parent = pa
local lr = part({
Name = "PARingRail",
Size = Vector3.new(0.6, RAIL_H, segLen + 1),
CFrame = eCF * CFrame.new(0, 1 + BARRIER_H + RAIL_H / 2, 0),
Color = C_RAIL,
Material = Enum.Material.Metal,
})
lr.Parent = pa
else
local KERB_H = 1.2
local kerb = part({
Name = "PARingKerb",
Size = Vector3.new(1.6, KERB_H, segLen + 1),
CFrame = eCF * CFrame.new(0, 1 + KERB_H / 2, 0),
Color = C_PARAPET,
Material = Enum.Material.Concrete,
})
kerb.Parent = pa
end
local EDGE_H = (sgn == 1) and 3.0 or 1.2
local edge = part({
Name = (sgn == 1) and "PARingEdge" or "PARingKerb",
Size = Vector3.new(1.6, EDGE_H, segLen + 1),
CFrame = eCF * CFrame.new(0, 1 + EDGE_H / 2, 0),
Color = C_PARAPET,
Material = Enum.Material.Concrete,
})
edge.Parent = pa
end
end
@@ -1338,8 +1328,16 @@ local function buildPA(map: Folder)
-- driving lane at the merge (measured: a 2.4-stud step 14 studs
-- right of the centreline, hit as Road_526 -> PARampKerb). A merge
-- has to be open, so the last segment carries no kerb.
-- Kerb EVERY segment except the merge mouth. The height test is
-- gone entirely: `h > 8` then `h > 2` both still failed on the
-- foot of the ramp (h = 0.5 .. 0.8 at apron level), which is
-- exactly where the barrier was seen "ending in mid-air" -- the
-- edge began one segment UP the ramp, leaving the first ~40 studs
-- of both ramps completely open on both sides. A ramp edge is
-- continuous in reality regardless of how high it happens to be,
-- so the only exclusion left is the merge, which must stay open.
local isMergeSeg = (s >= STEPS - 1)
if h > 2 and not isMergeSeg then
if not isMergeSeg then
local fwd2 = (b - a)
fwd2 = Vector3.new(fwd2.X, 0, fwd2.Z)
if fwd2.Magnitude > 0.01 then