class_name UrbanFloors extends RefCounted # One definition supplies both visible geometry and authoritative collision. # Each house has ground -> upper -> roof internal stairs and an exterior escape stair. const LEVEL := 3.7 const ROOF := 7.4 const FRAME := Color("343b3d") const TRIM := Color("92938a") const WARNING := Color("c7aa64") var arena: Node3D var origin: Vector3 var accent: Color var outward: float var batch: UrbanMeshBatch static func build(target: Node3D, x: float, z: float, _tint: Color) -> void: var floors := UrbanFloors.new() floors.arena = target floors.origin = Vector3(x, 0, z) # Restrained factory sheet metal replaces the former pastel residential walls. floors.accent = Color("929b94") if x < 0 else Color("a39f91") floors.outward = signf(x) if DisplayServer.get_name() != "headless": floors.batch = UrbanMeshBatch.new() floors._build() func part(at: Vector3, size: Vector3, kind: String, tint: Color, solid: bool = true) -> void: if solid: arena.box(origin + at, size, tint).visible = false if batch: batch.bevel_box(origin + at, size, kind, tint, minf(0.025, size.y * 0.15)) func _slab(height: float, left: float, right: float, near: float, far: float) -> void: # Rectangle around a real stairwell opening; no invisible ceiling over stairs. part(Vector3((-4.9 + left) / 2, height - 0.15, 0), Vector3(left + 4.9, 0.3, 11.8), "floor", TRIM) part(Vector3((right + 4.9) / 2, height - 0.15, 0), Vector3(4.9 - right, 0.3, 11.8), "floor", TRIM) part(Vector3((left + right) / 2, height - 0.15, (-5.9 + near) / 2), Vector3(right - left, 0.3, near + 5.9), "floor", TRIM) part(Vector3((left + right) / 2, height - 0.15, (far + 5.9) / 2), Vector3(right - left, 0.3, 5.9 - far), "floor", TRIM) func _wall_box(axis: int, fixed: float, along: float, y: float, length: float, height: float, kind: String, tint: Color, solid: bool = true) -> void: var pos := Vector3(along, y, fixed) if axis == 0 else Vector3(fixed, y, along) var size := Vector3(length, height, 0.35) if axis == 0 else Vector3(0.35, height, length) part(pos, size, kind, tint, solid) func _wall(axis: int, fixed: float, width: float, openings: Array[Vector4]) -> void: var cursor := -width / 2 for gap in openings: if gap.x > cursor: _wall_box(axis, fixed, (cursor + gap.x) / 2, LEVEL + 1.7, gap.x - cursor, 3.4, "corrugated", accent) _column(axis, fixed, (cursor + gap.x) / 2) if gap.z > 0: _wall_box(axis, fixed, (gap.x + gap.y) / 2, LEVEL + gap.z / 2, gap.y - gap.x, gap.z, "corrugated", accent) _wall_box(axis, fixed, (gap.x + gap.y) / 2, LEVEL + (gap.w + 3.4) / 2, gap.y - gap.x, 3.4 - gap.w, "corrugated", accent) # Real empty opening: frames only, no glass panel or hidden collision face. for edge in [gap.x, gap.y]: _wall_box(axis, fixed, edge, LEVEL + (gap.z + gap.w) / 2, 0.07, gap.w - gap.z, "metal", FRAME, false) for y in [gap.z, gap.w]: _wall_box(axis, fixed, (gap.x + gap.y) / 2, LEVEL + y, gap.y - gap.x + 0.1, 0.07, "metal", TRIM, false) cursor = gap.y if cursor < width / 2: _wall_box(axis, fixed, (cursor + width / 2) / 2, LEVEL + 1.7, width / 2 - cursor, 3.4, "corrugated", accent) _column(axis, fixed, (cursor + width / 2) / 2) _wall_box(axis, fixed + signf(fixed) * 0.055, 0, LEVEL + 3.32, width + 0.12, 0.14, "metal", FRAME, false) _wall_box(axis, fixed + signf(fixed) * 0.055, 0, LEVEL - 0.17, width + 0.12, 0.18, "metal", FRAME, false) func _column(axis: int, fixed: float, along: float) -> void: # Sheet-metal support posts remain on solid wall spans, never in a window gap. _wall_box(axis, fixed + signf(fixed) * 0.05, along, LEVEL + 1.68, 0.12, 3.36, "metal", FRAME, false) _wall_box(axis, fixed + signf(fixed) * 0.075, along, LEVEL + 0.1, 0.23, 0.17, "metal", TRIM, false) func _flight(x: float, first_z: float, direction: float, bottom: float, exterior: bool) -> void: for i in 19: var height := (i + 1) * LEVEL / 19.0 var z := first_z + direction * i * 0.4 # Folded steel treads, return lip and anti-slip ribs. Physics stays on the ramp. part(Vector3(x, bottom + height - 0.025, z), Vector3(1.8, 0.05, 0.4), "metal", Color("888d88"), false) part(Vector3(x, bottom + height - 0.09, z - direction * 0.185), Vector3(1.8, 0.15, 0.03), "metal", FRAME, false) for rib in 4: part(Vector3(x, bottom + height + 0.004, z - 0.14 + rib * 0.085), Vector3(1.68, 0.008, 0.014), "metal", TRIM, false) if batch: for side in [-1,1]: batch.cylinder(origin+Vector3(x+side*0.83,bottom+height+0.007,z),0.018,0.012,"metal",FRAME) if batch: for side in [-1,1]: var start := origin+Vector3(x+side*0.88,bottom-0.09,first_z-0.2*direction) var end := origin+Vector3(x+side*0.88,bottom+LEVEL-0.12,first_z+7.4*direction) var angle := Vector3(-atan2(end.y-start.y,absf(end.z-start.z))*direction,0,0) batch.box((start+end)*0.5,Vector3(0.065,0.19,start.distance_to(end)),"metal",FRAME,angle) StairFlight.build(arena, origin + Vector3(x, bottom, first_z), direction, LEVEL, exterior, batch) func _build() -> void: _slab(LEVEL, 0.95, 3.05, -3.6, 4.4) _slab(ROOF, -3.45, -1.35, -4.4, 3.6) for end in [-1, 1]: _wall(0, end * 5.5, 9, [Vector4(-3.2, -1.0, 0.85, 2.45), Vector4(1.0, 3.2, 0.85, 2.45)]) for side in [-1, 1]: var gaps: Array[Vector4] = [Vector4(-3.4, -1, 0.85, 2.45), Vector4(0, 2.4, 0.85, 2.45)] if side == outward: gaps.append(Vector4(3.15, 5.3, 0, 2.8)) _wall(1, side * 4.5, 11, gaps) # Parallel internal flights leave a full-height landing at each end. _flight(2.0, 3.8, -1, 0, false) _flight(-2.4, -3.8, 1, LEVEL, false) # Guard the long sides of the upper stairwell. Ends remain open for walking. for x in [0.9, 3.1]: part(Vector3(x, LEVEL + 0.46, 0.4), Vector3(0.1, 0.92, 7.7), "metal", FRAME) for x in [-3.5, -1.3]: part(Vector3(x, ROOF + 0.46, -0.4), Vector3(0.1, 0.92, 7.7), "metal", FRAME) # Exterior switchback: ground -> upper door -> roof, an independent counter-route. _flight(outward * 6.0, -3.8, 1, 0, true) _flight(outward * 8.3, 3.8, -1, LEVEL, true) part(Vector3(outward * 6.4, LEVEL - 0.15, 4.6), Vector3(5.0, 0.3, 2.0), "floor", TRIM) part(Vector3(outward * 6.4, ROOF - 0.15, -4.6), Vector3(5.0, 0.3, 2.0), "floor", TRIM) for y in [LEVEL, ROOF]: var z := 5.58 if y == LEVEL else -5.58 part(Vector3(outward * 6.4, y + 0.48, z), Vector3(5.0, 0.96, 0.13), "metal", FRAME) part(Vector3(outward * 8.9, y + 0.48, z - signf(z) * 0.85), Vector3(0.13, 0.96, 1.8), "metal", FRAME) # Solid parapets protect crouched players; the rear screen limits spawn views. for side in [-1, 1]: if side == outward: part(Vector3(side * 4.6, ROOF + 0.5, 1), Vector3(0.25, 1, 9), "concrete", Color("bab8aa")) else: part(Vector3(side * 4.6, ROOF + 0.5, 0), Vector3(0.25, 1, 11.3), "concrete", Color("bab8aa")) var height := 2.2 if side == signf(origin.z) else 1.0 part(Vector3(0, ROOF + height / 2, side * 5.6), Vector3(9.4, height, 0.25), "concrete", Color("bab8aa")) part(Vector3(0, ROOF + height + 0.035, side * 5.6), Vector3(9.5, 0.07, 0.34), "metal", FRAME, false) # Central roof machinery interrupts diagonal roof-to-roof sightlines. part(Vector3(1, ROOF + 0.65, 0.3), Vector3(2.3, 1.3, 2.3), "corrugated", Color("a1aaa2")) if batch: for x in [0.45, 1.55]: batch.cylinder(origin + Vector3(x, ROOF + 1.33, 0.3), 0.42, 0.06, "metal", FRAME) for i in 8: part(Vector3(1, ROOF + 0.2 + i * 0.12, 1.46), Vector3(2.05, 0.025, 0.035), "metal", FRAME, false) for x in [-0.08, 2.08]: part(Vector3(x, ROOF + 0.66, 0.3), Vector3(0.055, 1.26, 2.28), "metal", FRAME, false) # Ceiling flanges stay away from the roof stairwell at x=-2.4. for x in [0.0, 3.8]: part(Vector3(x, ROOF - 0.38, 0), Vector3(0.23, 0.11, 10.8), "metal", FRAME, false) # Flush warehouse wayfinding and fixtures sit on solid upper-wall panels. part(Vector3(-0.03, LEVEL + 2.87, -5.28), Vector3(0.85, 0.18, 0.025), "paint", FRAME, false) part(Vector3(-0.03, LEVEL + 2.87, -5.255), Vector3(0.7, 0.075, 0.02), "paint", Color("dee8df"), false) var model := Node3D.new() model.name = "UpperFloors_%s_%s" % [int(origin.x), int(origin.z)] arena.add_child(model) batch.finish(model, "FloorDetail") var light := OmniLight3D.new() light.position = origin + Vector3(-0.4, LEVEL + 2.8, 0) light.name = "WarehouseUpperBounce" light.light_color = Color("c9dfe1") light.light_energy = 0.32 light.omni_range = 7 arena.add_child(light) arena.sign_text("01 / OPERATIONS", origin + Vector3(0, LEVEL + 2.6, -5.28), 0, TRIM, 30) arena.sign_text("ROOF ACCESS →", origin + Vector3(-0.15, LEVEL + 2.2, -5.28), 0, WARNING, 23)