diff --git a/src/server/MapBuilder.luau b/src/server/MapBuilder.luau index 6827d66..1eb40c9 100644 --- a/src/server/MapBuilder.luau +++ b/src/server/MapBuilder.luau @@ -1222,33 +1222,19 @@ local function buildPA(map: Folder) local segCF = CFrame.lookAt(segMid, p1, UP) deck("PARing", Vector3.new(RING_W, 2, segLen), segCF) - -- Ring edge treatment. + -- Ring edge: NO barrier on the circulation road any more. -- + -- CHANGE (2026-08-02, user call, third pass): the edge used to be + -- emitted here, per ring-road arc segment, so it inherited the ring's + -- CIRCLE -- radius ~412 about the PA centre. But the parking area is a + -- SQUARE 828 x 828 apron (real Daikoku Futo is 181 m x 174 m, see the + -- layout note above). A circle inscribed in that square bulges past + -- the apron at the four corners and cuts INSIDE it at the four edge + -- midpoints, so the barrier visibly sliced across the lot instead of + -- following its perimeter -- read as a second ring. -- - -- CHANGE (2026-08-02, user call, second pass): first pass only swapped - -- the outer parapet+rail for a low edge and KEPT the inner kerb, which - -- left two concentric barriers (69 outer + 64 inner) still ringing the - -- lot -- visibly the same "ring barrier" from the driver's seat. The - -- ask was a single barrier on the edge of the parking area, so the - -- inner edge is now nothing at all: the lot and its circulation road - -- are the same continuous surface, which is how the real PA reads. - -- Only the outer edge gets a barrier, because behind it is a drop off - -- the structure. - local fwd = (p1 - p0).Unit - local outN = (segMid - Vector3.new(c.X, ringY, c.Z)).Unit - local ePos = segMid + outN * (RING_W / 2) - if not nearJunction(ePos, GATE_OUT) then - local eCF = CFrame.lookAt(ePos, ePos + fwd, UP) - local EDGE_H = 3.0 - local edge = part({ - Name = "PARingEdge", - 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 + -- The perimeter barrier is now built ONCE, after this loop, as four + -- straight runs along the apron edge. Nothing is emitted per-arc. -- No pillars under the ring any more. The ring is now a GROUND-LEVEL -- circulation road sharing the apron slab (Circuit.PA_LIFT raises the @@ -1258,6 +1244,72 @@ local function buildPA(map: Folder) -- Mainline pillars are built in buildRoad; see PA_LIFT. end + -- PERIMETER BARRIER ------------------------------------------------------- + -- A single simple barrier following the EDGE OF THE PARKING AREA, which is + -- a square apron (APRON half-extent), not the circular ring road. Built as + -- four straight runs of short segments so gaps can be opened wherever a + -- ramp crosses the boundary -- otherwise the barrier would seal the PA and + -- trap the player. Segment length is kept modest so a gap lands cleanly. + do + local PERIM_H = 3.0 + local PERIM_T = 1.6 + local SEG = 40 + -- Sit the barrier just inside the slab edge so it reads as the lot's + -- own kerb line rather than floating off the asphalt. + local half = APRON - PERIM_T / 2 - 1 + local baseY = DECK_Y + 1 + PERIM_H / 2 + + -- Ramps tee in at the ring; open the perimeter where a ramp's centre + -- line crosses the square, plus clearance for the full ramp width. + local GATE = 90 + local function blocked(x, z) + for _, jn in ipairs(junctions) do + -- Project the junction outward onto the square boundary and + -- compare against this segment's centre. + local d = Vector3.new(x - jn.ringPt.X, 0, z - jn.ringPt.Z) + if d.Magnitude <= GATE then + return true + end + end + return false + end + + local n = 0 + for _, side in ipairs({ "N", "S", "E", "W" }) do + local along = -half + while along < half do + local segLen = math.min(SEG, half - along) + local mid = along + segLen / 2 + local x, z, sizeV + if side == "N" then + x, z = c.X + mid, c.Z - half + sizeV = Vector3.new(segLen + 0.5, PERIM_H, PERIM_T) + elseif side == "S" then + x, z = c.X + mid, c.Z + half + sizeV = Vector3.new(segLen + 0.5, PERIM_H, PERIM_T) + elseif side == "W" then + x, z = c.X - half, c.Z + mid + sizeV = Vector3.new(PERIM_T, PERIM_H, segLen + 0.5) + else + x, z = c.X + half, c.Z + mid + sizeV = Vector3.new(PERIM_T, PERIM_H, segLen + 0.5) + end + if not blocked(x, z) then + local seg = part({ + Name = "PAPerimeter", + Size = sizeV, + CFrame = CFrame.new(x, baseY, z), + Color = C_PARAPET, + Material = Enum.Material.Concrete, + }) + seg.Parent = pa + n = n + 1 + end + along = along + segLen + end + end + end + -- Two ramps: mainline -> ring (entry) and ring -> mainline (exit). -- `junctions` was resolved above (the ring wall needed it to place gates); -- reuse it so the ramp deck and the wall opening can never disagree.