The only site whose contents are mostly SOFT, and that one material change rewrites the
level. `produce` is a new Smashable material that throws no shards at all — Splat.gd
bursts it instead: coloured pulp, a puddle that STAYS, a squelch, and litres counted,
because "how much juice did you make" is a far better score for a greengrocer than "how
many objects did you destroy".
Two knock-ons make the level play itself, both falling out of existing systems rather
than needing new ones:
* produce has a low brittle_speed, so anything heavy landing on it squashes it — which
means a pyramid crushes its OWN bottom layer as it collapses, with no special code.
Knock one off the top and the pile does the rest. Shove test: 257 items -> 45, and
42 litres of juice out of the collapse.
* puddles are slippery, cutting ACCELERATION rather than top speed so it reads as
sliding rather than as being slowed down. The more mess you make, the less the floor
cooperates.
Stacks are built bottom-up by Main._build_stack and nothing is glued or frozen — they
stand because they are stacked, so pulling one out of the bottom row does what you'd
hope. 258 produce items spawn and settle to 0.00 m/s with no spawn crush. The glass
bottles behind the juice bar are the deliberate exception: one shelf in the room that
still rewards a proper swing, and the contrast between litres and shards is the joke.
Round produce is authored CENTRED, not floor-centred like every other prop in this repo,
because a rolling body whose origin sits on the floor plane wobbles like a loaded die.
_glb_piece grew a `centred` flag for it.
REAL BUG FOUND, and it was costing hits in every level: _strike took the NEAREST collider
of any kind, so a static surface could eat a swing. Leaning over a display table, the
table edge is a few centimetres nearer than the fruit piled on it, so every swing hit the
table and nothing broke — 0/306 for the whole first take. It now prefers a Smashable and
only falls back to loose bodies if there isn't one. The offices were quietly losing hits
on desks and shelves the same way.
tools/gen_produce.py: apple, orange, tomato, watermelon, cabbage, banana hand, glass
juice bottle, display crate. The melon's stripes were radial boxes first time and it came
out looking like a sea mine; they're thin lenses through the middle now.
dev/probe_grocer.gd verifies stacks settle, that produce yields litres and NO debris,
that a collapse crushes, and that none of it leaks to the next site.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
680 lines
33 KiB
GDScript
680 lines
33 KiB
GDScript
extends RefCounted
|
|
class_name Levels
|
|
|
|
## The workplaces, as data. Each is a Floorplan spec (see Floorplan.gd for the schema).
|
|
##
|
|
## The point of these being data and not four subclasses: a new site is authorable in
|
|
## minutes, they can be diffed, and a generator can later emit the same structure.
|
|
##
|
|
## They are deliberately NOT reskins. Each differs in the three things a player actually
|
|
## reads — the palette, the light, and what the walls are made of:
|
|
##
|
|
## SCRANTON ..... magnolia, grey carpet, drop ceiling, fluorescent troffers, daylight
|
|
## down one glazed wall. The baseline office.
|
|
## PAWNEE ....... civic beige and blue-grey, low partitions everywhere, a public
|
|
## counter, pinboards. Municipal, over-partitioned, no privacy.
|
|
## THE HOUSE .... timber floor, white walls, 3 m ceiling, pendant lights, a glass wall
|
|
## onto a pool. Nobody here has an office; they work at a dining table.
|
|
## THE BASEMENT . concrete, no windows at all, exposed services, bare strip lights, a
|
|
## wall of server racks. The light is green and everything is junk.
|
|
##
|
|
## Godot 4.7 GDScript 2.0.
|
|
|
|
const ORDER := ["scranton", "pawnee", "house", "basement", "grocer", "backrooms"]
|
|
|
|
static func get_level(id: String) -> Dictionary:
|
|
match id:
|
|
"pawnee": return pawnee()
|
|
"house": return house()
|
|
"basement": return basement()
|
|
"backrooms": return backrooms()
|
|
"grocer": return grocer()
|
|
return scranton()
|
|
|
|
static func next_id(id: String) -> String:
|
|
var i := ORDER.find(id)
|
|
return ORDER[(i + 1) % ORDER.size()] if i >= 0 else ORDER[0]
|
|
|
|
# ================================================================ LEVEL 01
|
|
static func scranton() -> Dictionary:
|
|
return {
|
|
"name": "SCRANTON BRANCH",
|
|
"subtitle": "paper company · 2nd floor",
|
|
"bounds": {"x0": -11.0, "x1": 11.0, "z0": -8.0, "z1": 8.0, "h": 2.75},
|
|
"palette": {
|
|
"floor": Color(0.30, 0.30, 0.32), "wall": Color(0.80, 0.78, 0.72),
|
|
"ceiling": Color(0.88, 0.88, 0.86), "trim": Color(0.13, 0.12, 0.13),
|
|
"partition": Color(0.44, 0.44, 0.40), "wood": Color(0.42, 0.29, 0.17),
|
|
"accent": Color(0.36, 0.42, 0.50),
|
|
},
|
|
"floor_style": "carpet",
|
|
"ceiling": "tile",
|
|
"walls": [
|
|
# manager's office — half solid, half glass, so you can be watched through it
|
|
{"a": "x", "at": -4.4, "from": -11.0, "to": -6.6, "door": -9.2},
|
|
{"a": "z", "at": -6.6, "from": -8.0, "to": -4.4, "style": "glass_top"},
|
|
# conference room
|
|
{"a": "x", "at": -4.4, "from": -6.6, "to": -0.4, "door": -3.4},
|
|
{"a": "z", "at": -0.4, "from": -8.0, "to": -4.4},
|
|
# break room
|
|
{"a": "z", "at": 5.4, "from": -1.2, "to": 8.0, "door": 2.2},
|
|
{"a": "x", "at": -1.2, "from": 5.4, "to": 11.0},
|
|
# copier alcove
|
|
{"a": "z", "at": 3.6, "from": -1.6, "to": 1.0},
|
|
# reception screen
|
|
{"a": "z", "at": -6.9, "from": 4.6, "to": 8.0, "door": 6.8},
|
|
],
|
|
"windows": [{"a": "z", "at": 11.0, "from": -8.0, "to": 8.0,
|
|
"y0": 0.85, "y1": 2.35, "blinds": true}],
|
|
"lights": {"xs": [-8.5, -4.6, -0.7, 3.2, 7.1], "zs": [-6.2, -2.6, 1.0, 4.6],
|
|
"color": Color(1.0, 0.98, 0.93), "energy": 1.9, "style": "troffer"},
|
|
"sun": {"color": Color(0.82, 0.88, 1.0), "energy": 0.7,
|
|
"rot": Vector3(-30, -104, 0)},
|
|
"env": {"bg": Color(0.55, 0.62, 0.72), "ambient": Color(0.50, 0.50, 0.50),
|
|
"ambient_energy": 0.5},
|
|
"clusters": [Vector2(-4.6, -2.0), Vector2(-4.6, 2.8),
|
|
Vector2(-0.4, -2.0), Vector2(-0.4, 2.8)],
|
|
"cluster_gap": 0.78,
|
|
"slabs": [
|
|
# reception counter
|
|
{"size": Vector3(0.70, 1.10, 3.0), "at": Vector3(-9.9, 0.55, 5.6), "mat": "wood"},
|
|
{"size": Vector3(0.92, 0.08, 3.2), "at": Vector3(-9.9, 1.14, 5.6), "mat": "trim"},
|
|
{"size": Vector3(1.8, 1.10, 0.70), "at": Vector3(-9.6, 0.55, 4.45), "mat": "wood"},
|
|
# conference table + whiteboard
|
|
{"size": Vector3(3.9, 0.09, 1.35), "at": Vector3(-3.5, 0.74, -6.2), "mat": "wood"},
|
|
{"size": Vector3(0.16, 0.72, 0.90), "at": Vector3(-5.1, 0.36, -6.2), "mat": "trim"},
|
|
{"size": Vector3(0.16, 0.72, 0.90), "at": Vector3(-1.9, 0.36, -6.2), "mat": "trim"},
|
|
{"size": Vector3(2.5, 1.25, 0.03), "at": Vector3(-3.5, 1.6, -7.93), "mat": "trim"},
|
|
{"size": Vector3(2.4, 1.15, 0.05), "at": Vector3(-3.5, 1.6, -7.90), "mat": "ceiling"},
|
|
# break room kitchen + tables
|
|
{"size": Vector3(0.62, 0.88, 3.4), "at": Vector3(10.58, 0.44, 4.0), "mat": "wood"},
|
|
{"size": Vector3(0.70, 0.06, 3.5), "at": Vector3(10.58, 0.90, 4.0), "mat": "trim"},
|
|
{"size": Vector3(1.05, 0.07, 1.05), "at": Vector3(7.4, 0.73, 0.4), "mat": "ceiling"},
|
|
{"size": Vector3(0.12, 0.70, 0.12), "at": Vector3(7.4, 0.36, 0.4), "mat": "trim"},
|
|
{"size": Vector3(1.05, 0.07, 1.05), "at": Vector3(7.4, 0.73, 3.0), "mat": "ceiling"},
|
|
{"size": Vector3(0.12, 0.70, 0.12), "at": Vector3(7.4, 0.36, 3.0), "mat": "trim"},
|
|
# warehouse roller door
|
|
{"size": Vector3(2.6, 2.4, 0.12), "at": Vector3(7.8, 1.2, -7.94), "mat": "trim"},
|
|
],
|
|
"props": [
|
|
{"glb": "store-column-white", "at": Vector3(-2.2, 0.0, -3.4)},
|
|
{"glb": "store-column-white", "at": Vector3(2.2, 0.0, -3.4)},
|
|
{"glb": "store-aircon", "at": Vector3(2.6, 2.35, -7.9)},
|
|
{"glb": "office-plant", "at": Vector3(-6.4, 0.0, 6.6)},
|
|
{"glb": "office-plant", "at": Vector3(2.9, 0.0, 6.4)},
|
|
{"glb": "vending-machine", "at": Vector3(6.3, 0.0, 7.4), "yaw": PI},
|
|
{"glb": "vending-machine", "at": Vector3(7.3, 0.0, 7.4), "yaw": PI},
|
|
{"glb": "microwave", "at": Vector3(10.55, 0.93, 5.1), "yaw": -PI / 2},
|
|
],
|
|
"chairs": [
|
|
{"at": Vector3(-7.6, 0.0, 5.5), "yaw": -PI / 2},
|
|
{"at": Vector3(-7.6, 0.0, 6.35), "yaw": -PI / 2},
|
|
{"at": Vector3(-7.6, 0.0, 7.2), "yaw": -PI / 2},
|
|
{"at": Vector3(-4.85, 0.0, -7.35), "yaw": 0.0},
|
|
{"at": Vector3(-3.95, 0.0, -7.35), "yaw": 0.0},
|
|
{"at": Vector3(-3.05, 0.0, -7.35), "yaw": 0.0},
|
|
{"at": Vector3(-2.15, 0.0, -7.35), "yaw": 0.0},
|
|
{"at": Vector3(-4.85, 0.0, -5.05), "yaw": PI},
|
|
{"at": Vector3(-3.95, 0.0, -5.05), "yaw": PI},
|
|
{"at": Vector3(-3.05, 0.0, -5.05), "yaw": PI},
|
|
{"at": Vector3(-2.15, 0.0, -5.05), "yaw": PI},
|
|
{"at": Vector3(-8.8, 0.0, -7.1), "yaw": 0.0},
|
|
{"at": Vector3(-9.6, 0.0, -5.1), "yaw": PI},
|
|
{"at": Vector3(8.0, 0.0, 1.13), "yaw": 2.0},
|
|
{"at": Vector3(7.7, 0.0, -0.49), "yaw": 4.1},
|
|
{"at": Vector3(6.5, 0.0, 0.56), "yaw": 0.2},
|
|
{"at": Vector3(8.0, 0.0, 3.73), "yaw": 2.0},
|
|
{"at": Vector3(7.7, 0.0, 2.11), "yaw": 4.1},
|
|
{"at": Vector3(6.5, 0.0, 3.16), "yaw": 0.2},
|
|
],
|
|
"copier": {"at": Vector3(3.0, 0.0, -0.3), "yaw": -PI / 2},
|
|
"smashables": [
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(4.5, -1.6)},
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(4.5, -0.9)},
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(4.5, -0.2)},
|
|
{"glb": "water-cooler", "kind": "steel", "at": Vector2(-6.2, 3.4)},
|
|
{"glb": "water-cooler", "kind": "steel", "at": Vector2(5.9, -0.6)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(-2.3, 5.2)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(1.6, 5.4)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(2.1, 4.7)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(6.4, -3.3)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(7.3, -3.8)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(-9.7, 1.2)},
|
|
{"glb": "wastebin", "kind": "plastic", "at": Vector2(-6.0, -1.0)},
|
|
{"glb": "wastebin", "kind": "plastic", "at": Vector2(1.0, 1.0)},
|
|
{"glb": "desk-phone", "kind": "plastic", "at": Vector2(-9.8, 5.0), "sit_on": 1.18},
|
|
{"glb": "rack", "kind": "wood", "at": Vector2(9.4, -6.6), "frozen": true},
|
|
{"glb": "rack", "kind": "wood", "at": Vector2(9.4, -4.3), "frozen": true},
|
|
{"glb": "turntable", "kind": "wood", "at": Vector2(6.9, -5.9)},
|
|
{"glb": "guillotine", "kind": "steel", "at": Vector2(4.5, 1.2)},
|
|
{"glb": "stapler", "kind": "steel", "at": Vector2(-4.6, -2.9), "sit_on": 0.75},
|
|
],
|
|
"records": [Vector2(6.2, -6.6), Vector2(7.0, -6.9), Vector2(7.8, -6.6)],
|
|
"gauntlet": {"at": Vector3(0.0, 0.0, -3.9), "yaw": PI,
|
|
"stand": Vector3(0.0, 0.0, -1.7), "shredder": Vector3(2.7, 0.0, -2.4)},
|
|
"spawn": {"at": Vector3(-8.6, 0.0, 7.2), "yaw": deg_to_rad(196.0)},
|
|
}
|
|
|
|
# ================================================================ LEVEL 02
|
|
static func pawnee() -> Dictionary:
|
|
return {
|
|
"name": "PAWNEE CITY HALL",
|
|
"subtitle": "parks & recreation · 4th floor",
|
|
"bounds": {"x0": -10.0, "x1": 10.0, "z0": -7.0, "z1": 7.5, "h": 2.70},
|
|
"palette": {
|
|
"floor": Color(0.34, 0.36, 0.40), "wall": Color(0.84, 0.80, 0.68),
|
|
"ceiling": Color(0.90, 0.89, 0.85), "trim": Color(0.30, 0.22, 0.14),
|
|
"partition": Color(0.52, 0.50, 0.42), "wood": Color(0.50, 0.34, 0.19),
|
|
"accent": Color(0.16, 0.36, 0.28),
|
|
},
|
|
"floor_style": "carpet",
|
|
"ceiling": "tile",
|
|
"walls": [
|
|
# the department head's office, and the meeting room beside it
|
|
{"a": "x", "at": -3.4, "from": -10.0, "to": -5.6, "door": -7.0},
|
|
{"a": "z", "at": -5.6, "from": -7.0, "to": -3.4, "style": "glass_top"},
|
|
{"a": "x", "at": -3.4, "from": -5.6, "to": 0.4, "door": -1.6},
|
|
{"a": "z", "at": 0.4, "from": -7.0, "to": -3.4},
|
|
# records room, and the corridor wall that makes this place a warren
|
|
{"a": "z", "at": 4.6, "from": -7.0, "to": -2.0, "door": -4.4},
|
|
{"a": "x", "at": -2.0, "from": 4.6, "to": 10.0},
|
|
# the public counter divides the front third from everything else
|
|
{"a": "x", "at": 3.6, "from": -10.0, "to": 3.0, "door": -8.0, "style": "half"},
|
|
],
|
|
"windows": [{"a": "x", "at": 7.5, "from": -10.0, "to": 10.0,
|
|
"y0": 0.95, "y1": 2.30, "blinds": true}],
|
|
"lights": {"xs": [-7.5, -3.4, 0.7, 4.8, 8.4], "zs": [-5.2, -1.6, 2.0, 5.6],
|
|
"color": Color(1.0, 0.96, 0.86), "energy": 1.8, "style": "troffer",
|
|
"key_energy": 1.4},
|
|
"sun": {"color": Color(0.90, 0.88, 0.78), "energy": 0.55,
|
|
"rot": Vector3(-34, 20, 0)},
|
|
"env": {"bg": Color(0.62, 0.66, 0.62), "ambient": Color(0.50, 0.48, 0.44),
|
|
"ambient_energy": 0.52, "exposure": 1.02},
|
|
"clusters": [Vector2(-6.0, 0.4), Vector2(-1.4, 0.4), Vector2(2.6, 0.4)],
|
|
"cluster_gap": 0.78,
|
|
"slabs": [
|
|
# the public counter itself — the thing between you and the citizens
|
|
{"size": Vector3(6.6, 1.06, 0.66), "at": Vector3(-1.2, 0.53, 5.4), "mat": "wood"},
|
|
{"size": Vector3(6.9, 0.07, 0.86), "at": Vector3(-1.2, 1.10, 5.4), "mat": "trim"},
|
|
{"size": Vector3(0.66, 1.06, 2.2), "at": Vector3(2.1, 0.53, 6.4), "mat": "wood"},
|
|
# meeting room table
|
|
{"size": Vector3(2.9, 0.09, 1.25), "at": Vector3(-2.6, 0.74, -5.2), "mat": "wood"},
|
|
{"size": Vector3(0.14, 0.72, 0.84), "at": Vector3(-3.7, 0.36, -5.2), "mat": "trim"},
|
|
{"size": Vector3(0.14, 0.72, 0.84), "at": Vector3(-1.5, 0.36, -5.2), "mat": "trim"},
|
|
# pinboards — municipal offices are 40% pinboard by surface area
|
|
{"size": Vector3(2.2, 1.20, 0.05), "at": Vector3(5.0, 1.65, -6.93), "mat": "accent"},
|
|
{"size": Vector3(2.3, 1.30, 0.03), "at": Vector3(5.0, 1.65, -6.90), "mat": "trim"},
|
|
{"size": Vector3(0.05, 1.20, 2.6), "at": Vector3(-9.93, 1.62, 2.0), "mat": "accent"},
|
|
{"size": Vector3(0.03, 1.30, 2.7), "at": Vector3(-9.90, 1.62, 2.0), "mat": "trim"},
|
|
# department head's desk
|
|
{"size": Vector3(1.7, 0.08, 0.85), "at": Vector3(-7.4, 0.74, -5.4), "mat": "wood"},
|
|
{"size": Vector3(1.5, 0.66, 0.72), "at": Vector3(-7.4, 0.35, -5.4), "mat": "wood"},
|
|
],
|
|
"props": [
|
|
{"glb": "office-plant", "at": Vector3(-9.3, 0.0, 6.6)},
|
|
{"glb": "office-plant", "at": Vector3(3.2, 0.0, -2.6)},
|
|
{"glb": "office-plant", "at": Vector3(-9.3, 0.0, -1.0)},
|
|
{"glb": "sofa", "at": Vector3(-6.6, 0.0, 6.5), "yaw": PI},
|
|
{"glb": "vending-machine", "at": Vector3(9.2, 0.0, 6.6), "yaw": -PI / 2},
|
|
{"glb": "microwave", "at": Vector3(9.3, 0.90, 1.2), "yaw": -PI / 2},
|
|
{"glb": "store-aircon", "at": Vector3(-6.0, 2.30, -6.9)},
|
|
],
|
|
"chairs": [
|
|
{"at": Vector3(-7.4, 0.0, -4.2), "yaw": PI},
|
|
{"at": Vector3(-8.6, 0.0, -6.3), "yaw": 0.0},
|
|
{"at": Vector3(-3.5, 0.0, -6.3), "yaw": 0.0},
|
|
{"at": Vector3(-2.6, 0.0, -6.3), "yaw": 0.0},
|
|
{"at": Vector3(-1.7, 0.0, -6.3), "yaw": 0.0},
|
|
{"at": Vector3(-3.5, 0.0, -4.1), "yaw": PI},
|
|
{"at": Vector3(-2.6, 0.0, -4.1), "yaw": PI},
|
|
{"at": Vector3(-1.7, 0.0, -4.1), "yaw": PI},
|
|
{"at": Vector3(-4.0, 0.0, 6.4), "yaw": PI},
|
|
{"at": Vector3(0.4, 0.0, 6.5), "yaw": PI},
|
|
{"at": Vector3(1.2, 0.0, 6.5), "yaw": PI},
|
|
],
|
|
"copier": {"at": Vector3(6.4, 0.0, 2.4), "yaw": PI},
|
|
"smashables": [
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(5.4, -3.2)},
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(6.1, -3.2)},
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(6.8, -3.2)},
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(7.5, -3.2)},
|
|
{"glb": "water-cooler", "kind": "steel", "at": Vector2(3.9, 4.2)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(8.6, -5.4)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(9.2, -4.8)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(-4.8, 3.0)},
|
|
{"glb": "wastebin", "kind": "plastic", "at": Vector2(-8.8, -3.9)},
|
|
{"glb": "wastebin", "kind": "plastic", "at": Vector2(4.4, 0.9)},
|
|
{"glb": "guillotine", "kind": "steel", "at": Vector2(6.4, 3.6), "sit_on": 0.0},
|
|
{"glb": "desk-phone", "kind": "plastic", "at": Vector2(-7.4, -5.4), "sit_on": 0.78},
|
|
{"glb": "crt-monitor", "kind": "glass", "at": Vector2(-7.6, -5.2), "sit_on": 0.78},
|
|
],
|
|
"records": [],
|
|
"gauntlet": {"at": Vector3(7.2, 0.0, -5.8), "yaw": PI,
|
|
"stand": Vector3(7.2, 0.0, -3.9), "shredder": Vector3(5.2, 0.0, -6.2)},
|
|
"spawn": {"at": Vector3(-8.0, 0.0, 6.6), "yaw": deg_to_rad(178.0)},
|
|
}
|
|
|
|
# ================================================================ LEVEL 03
|
|
static func house() -> Dictionary:
|
|
return {
|
|
"name": "THE INCUBATOR",
|
|
"subtitle": "seed round · someone's house",
|
|
"bounds": {"x0": -10.0, "x1": 10.0, "z0": -8.0, "z1": 8.0, "h": 3.05},
|
|
"palette": {
|
|
"floor": Color(0.46, 0.33, 0.20), "wall": Color(0.92, 0.91, 0.88),
|
|
"ceiling": Color(0.95, 0.95, 0.94), "trim": Color(0.18, 0.17, 0.17),
|
|
"partition": Color(0.72, 0.72, 0.70), "wood": Color(0.40, 0.27, 0.16),
|
|
"accent": Color(0.22, 0.44, 0.62),
|
|
},
|
|
"floor_style": "timber",
|
|
"ceiling": "flat",
|
|
"walls": [
|
|
# only two real walls: a bedroom-turned-office and the bathroom nobody cleans
|
|
{"a": "z", "at": -4.6, "from": -8.0, "to": -2.4, "door": -4.0},
|
|
{"a": "x", "at": -2.4, "from": -10.0, "to": -4.6, "door": -7.4},
|
|
{"a": "z", "at": 4.0, "from": -8.0, "to": -5.2, "door": -6.6},
|
|
# the kitchen island's back wall
|
|
{"a": "x", "at": -1.0, "from": 4.0, "to": 10.0, "style": "half"},
|
|
],
|
|
"windows": [{"a": "x", "at": 8.0, "from": -10.0, "to": 10.0,
|
|
"y0": 0.35, "y1": 2.70, "blinds": false}],
|
|
"lights": {"xs": [-6.5, -1.5, 3.5, 7.5], "zs": [-5.0, 0.0, 5.0],
|
|
"color": Color(1.0, 0.90, 0.76), "energy": 2.4, "style": "pendant",
|
|
"key_energy": 1.7},
|
|
"sun": {"color": Color(1.0, 0.94, 0.80), "energy": 1.5,
|
|
"rot": Vector3(-46, -96, 0)},
|
|
"env": {"bg": Color(0.70, 0.80, 0.90), "ambient": Color(0.56, 0.55, 0.52),
|
|
"ambient_energy": 0.62, "exposure": 1.05},
|
|
# nobody has a desk; they work at the big table
|
|
"clusters": [Vector2(1.6, -1.4), Vector2(1.6, 2.6)],
|
|
"cluster_gap": 0.80,
|
|
"slabs": [
|
|
# kitchen island + counter
|
|
{"size": Vector3(2.6, 0.92, 1.05), "at": Vector3(4.2, 0.46, 5.6), "mat": "wood"},
|
|
{"size": Vector3(2.8, 0.08, 1.20), "at": Vector3(4.2, 0.95, 5.6), "mat": "ceiling"},
|
|
{"size": Vector3(6.0, 0.90, 0.65), "at": Vector3(5.0, 0.45, 7.5), "mat": "ceiling"},
|
|
{"size": Vector3(6.2, 0.06, 0.75), "at": Vector3(5.0, 0.92, 7.5), "mat": "trim"},
|
|
# the long table everyone actually works at
|
|
{"size": Vector3(1.5, 0.09, 4.6), "at": Vector3(-4.4, 0.75, 0.6), "mat": "wood"},
|
|
{"size": Vector3(0.12, 0.72, 0.12), "at": Vector3(-4.9, 0.36, -1.4), "mat": "trim"},
|
|
{"size": Vector3(0.12, 0.72, 0.12), "at": Vector3(-3.9, 0.36, 2.6), "mat": "trim"},
|
|
# whiteboard, obviously
|
|
{"size": Vector3(0.05, 1.40, 3.0), "at": Vector3(-9.93, 1.75, 1.0), "mat": "ceiling"},
|
|
{"size": Vector3(0.03, 1.50, 3.1), "at": Vector3(-9.90, 1.75, 1.0), "mat": "trim"},
|
|
# a low bookshelf run
|
|
{"size": Vector3(0.42, 0.90, 3.2), "at": Vector3(-9.7, 0.45, -5.0), "mat": "wood"},
|
|
# pool decking visible through the glass
|
|
{"size": Vector3(7.0, 0.10, 16.0), "at": Vector3(12.6, -0.05, 0.0),
|
|
"mat": "ceiling", "collide": false},
|
|
],
|
|
"props": [
|
|
{"glb": "sofa", "at": Vector3(-6.6, 0.0, 5.4), "yaw": -PI / 2},
|
|
{"glb": "sofa", "at": Vector3(-2.0, 0.0, 6.6), "yaw": PI},
|
|
{"glb": "office-plant", "at": Vector3(-0.6, 0.0, 3.2)},
|
|
{"glb": "office-plant", "at": Vector3(7.2, 0.0, -6.4)},
|
|
{"glb": "office-plant", "at": Vector3(-9.2, 0.0, 7.2)},
|
|
{"glb": "microwave", "at": Vector3(5.4, 0.95, 7.4), "yaw": PI},
|
|
{"glb": "server-rack", "at": Vector3(9.0, 0.0, -6.8), "yaw": -PI / 2},
|
|
],
|
|
"chairs": [
|
|
{"at": Vector3(-6.0, 0.0, -1.4), "yaw": -PI / 2},
|
|
{"at": Vector3(-6.0, 0.0, -0.2), "yaw": -PI / 2},
|
|
{"at": Vector3(-6.0, 0.0, 1.4), "yaw": -PI / 2},
|
|
{"at": Vector3(-6.0, 0.0, 2.6), "yaw": -PI / 2},
|
|
{"at": Vector3(-2.8, 0.0, -1.0), "yaw": PI / 2},
|
|
{"at": Vector3(-2.8, 0.0, 1.8), "yaw": PI / 2},
|
|
{"at": Vector3(4.2, 0.0, 4.2), "yaw": 0.0},
|
|
{"at": Vector3(5.2, 0.0, 4.2), "yaw": 0.0},
|
|
{"at": Vector3(-7.6, 0.0, -6.4), "yaw": 0.2},
|
|
],
|
|
"copier": {"at": Vector3(-8.6, 0.0, -3.4), "yaw": PI / 2},
|
|
"smashables": [
|
|
{"glb": "crt-monitor", "kind": "glass", "at": Vector2(-4.4, -2.2)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(8.4, 2.2)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(8.9, 1.5)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(-8.2, 6.4)},
|
|
{"glb": "wastebin", "kind": "plastic", "at": Vector2(-2.6, -3.2)},
|
|
{"glb": "wastebin", "kind": "plastic", "at": Vector2(6.2, 3.0)},
|
|
{"glb": "water-cooler", "kind": "steel", "at": Vector2(1.0, 6.8)},
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(-9.3, -1.6)},
|
|
{"glb": "turntable", "kind": "wood", "at": Vector2(-9.4, -6.6)},
|
|
{"glb": "desk-phone", "kind": "plastic", "at": Vector2(4.0, 5.6), "sit_on": 0.99},
|
|
{"glb": "guillotine", "kind": "steel", "at": Vector2(-9.4, -3.4)},
|
|
],
|
|
"records": [Vector2(-8.4, -7.0), Vector2(-7.6, -7.0)],
|
|
"gauntlet": {"at": Vector3(-7.2, 0.0, -7.2), "yaw": PI,
|
|
"stand": Vector3(-7.2, 0.0, -5.2), "shredder": Vector3(-5.0, 0.0, -6.8)},
|
|
"spawn": {"at": Vector3(-1.0, 0.0, 7.0), "yaw": deg_to_rad(186.0)},
|
|
}
|
|
|
|
# ================================================================ LEVEL 04
|
|
static func basement() -> Dictionary:
|
|
return {
|
|
"name": "SUB-LEVEL 4",
|
|
"subtitle": "i.t. department · no windows",
|
|
"bounds": {"x0": -12.0, "x1": 12.0, "z0": -6.0, "z1": 6.0, "h": 2.90},
|
|
"palette": {
|
|
"floor": Color(0.22, 0.22, 0.23), "wall": Color(0.50, 0.53, 0.46),
|
|
"ceiling": Color(0.20, 0.20, 0.21), "trim": Color(0.10, 0.10, 0.10),
|
|
"partition": Color(0.34, 0.36, 0.32), "wood": Color(0.30, 0.20, 0.12),
|
|
"accent": Color(0.52, 0.10, 0.09),
|
|
},
|
|
"floor_style": "concrete",
|
|
"ceiling": "flat",
|
|
"walls": [
|
|
# the boss's glass box, bolted into a room that never wanted one
|
|
{"a": "z", "at": 4.6, "from": -6.0, "to": 1.2, "door": -1.0,
|
|
"style": "glass_top"},
|
|
{"a": "x", "at": 1.2, "from": 4.6, "to": 12.0},
|
|
# server room behind a security door
|
|
{"a": "z", "at": -6.4, "from": -6.0, "to": 6.0, "door": 1.0},
|
|
# a stub wall someone put up and nobody took down
|
|
{"a": "x", "at": -1.4, "from": -4.0, "to": -1.6},
|
|
],
|
|
"windows": [], # it is a basement
|
|
"lights": {"xs": [-9.0, -4.5, 0.0, 4.5, 9.0], "zs": [-3.6, 0.4, 4.0],
|
|
"color": Color(0.86, 0.96, 0.84), "energy": 2.0, "style": "strip",
|
|
"key_energy": 1.1},
|
|
"env": {"bg": Color(0.06, 0.07, 0.06), "ambient": Color(0.32, 0.36, 0.32),
|
|
"ambient_energy": 0.40, "exposure": 1.08},
|
|
"clusters": [Vector2(3.6, 0.0)],
|
|
"cluster_gap": 0.82,
|
|
"slabs": [
|
|
# exposed services, because there's no ceiling to hide them
|
|
{"size": Vector3(24.0, 0.22, 0.22), "at": Vector3(0.0, 2.70, -3.0),
|
|
"mat": "trim", "collide": false},
|
|
{"size": Vector3(24.0, 0.16, 0.16), "at": Vector3(0.0, 2.62, 1.4),
|
|
"mat": "trim", "collide": false},
|
|
{"size": Vector3(24.0, 0.30, 0.10), "at": Vector3(0.0, 2.78, 4.2),
|
|
"mat": "trim", "collide": false},
|
|
# boss's desk in the glass box
|
|
{"size": Vector3(1.8, 0.08, 0.86), "at": Vector3(8.0, 0.74, 5.4), "mat": "wood"},
|
|
{"size": Vector3(1.6, 0.66, 0.74), "at": Vector3(8.0, 0.35, 5.4), "mat": "wood"},
|
|
# workbench along the back
|
|
{"size": Vector3(5.0, 0.08, 0.80), "at": Vector3(-6.0, 0.90, -5.5), "mat": "trim"},
|
|
{"size": Vector3(0.10, 0.88, 0.70), "at": Vector3(-8.4, 0.44, -5.5), "mat": "trim"},
|
|
{"size": Vector3(0.10, 0.88, 0.70), "at": Vector3(-3.6, 0.44, -5.5), "mat": "trim"},
|
|
# the famous red door
|
|
{"size": Vector3(1.10, 2.10, 0.10), "at": Vector3(1.0, 1.05, -6.35),
|
|
"mat": "accent"},
|
|
],
|
|
"props": [
|
|
{"glb": "server-rack", "at": Vector3(-10.6, 0.0, -4.4), "yaw": PI / 2},
|
|
{"glb": "server-rack", "at": Vector3(-10.6, 0.0, -2.4), "yaw": PI / 2},
|
|
{"glb": "server-rack", "at": Vector3(-10.6, 0.0, -0.4), "yaw": PI / 2},
|
|
{"glb": "server-rack", "at": Vector3(-10.6, 0.0, 1.6), "yaw": PI / 2},
|
|
{"glb": "sofa", "at": Vector3(-4.0, 0.0, 3.4), "yaw": 0.15},
|
|
{"glb": "office-plant", "at": Vector3(11.2, 0.0, 5.4)},
|
|
{"glb": "vending-machine", "at": Vector3(-0.4, 0.0, 5.4), "yaw": PI},
|
|
{"glb": "microwave", "at": Vector3(-5.0, 0.95, -5.5), "yaw": PI},
|
|
],
|
|
"chairs": [
|
|
{"at": Vector3(8.0, 0.0, 4.1), "yaw": PI},
|
|
{"at": Vector3(6.6, 0.0, 5.9), "yaw": 0.3},
|
|
{"at": Vector3(-6.6, 0.0, -4.2), "yaw": PI},
|
|
{"at": Vector3(-1.0, 0.0, 2.2), "yaw": 1.2},
|
|
],
|
|
"copier": {"at": Vector3(0.4, 0.0, -4.4), "yaw": 0.0},
|
|
"smashables": [
|
|
{"glb": "crt-monitor", "kind": "glass", "at": Vector2(-7.0, -5.5), "sit_on": 0.94},
|
|
{"glb": "crt-monitor", "kind": "glass", "at": Vector2(-5.0, -4.6)},
|
|
{"glb": "crt-monitor", "kind": "glass", "at": Vector2(-8.4, -3.2)},
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(10.8, 3.0)},
|
|
{"glb": "filing-cabinet", "kind": "steel", "at": Vector2(10.8, 2.2)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(-2.6, -4.8)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(-2.0, -5.3)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(-1.4, -4.6)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(5.6, -4.8)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(6.3, -5.2)},
|
|
{"glb": "cardboard-box", "kind": "cardboard", "at": Vector2(7.0, -4.6)},
|
|
{"glb": "wastebin", "kind": "plastic", "at": Vector2(2.0, 2.6)},
|
|
{"glb": "wastebin", "kind": "plastic", "at": Vector2(9.0, 4.4)},
|
|
{"glb": "water-cooler", "kind": "steel", "at": Vector2(0.6, 2.2)},
|
|
{"glb": "shredder", "kind": "plastic", "at": Vector2(-2.2, -2.0)},
|
|
{"glb": "desk-phone", "kind": "plastic", "at": Vector2(8.3, 5.4), "sit_on": 0.78},
|
|
{"glb": "turntable", "kind": "wood", "at": Vector2(-9.0, 4.4)},
|
|
{"glb": "guillotine", "kind": "steel", "at": Vector2(-6.0, -4.2)},
|
|
],
|
|
"records": [Vector2(-8.2, 5.0), Vector2(-7.5, 5.0)],
|
|
"gauntlet": {"at": Vector3(-3.4, 0.0, -3.4), "yaw": PI,
|
|
"stand": Vector3(-3.4, 0.0, -1.5), "shredder": Vector3(-2.2, 0.0, -2.0)},
|
|
"spawn": {"at": Vector3(1.0, 0.0, -5.2), "yaw": deg_to_rad(0.0)},
|
|
}
|
|
|
|
# ================================================================ LEVEL 00
|
|
## THE BACKROOMS. The only site whose walls are GENERATED rather than authored, which is
|
|
## both the honest test of the Floorplan spec and the right call for the fiction: this
|
|
## place is supposed to feel endless and samey, and a seeded RNG produces that better
|
|
## than a human placing slabs ever would.
|
|
##
|
|
## Layout follows the reference photographs rather than a maze algorithm — the Backrooms
|
|
## aren't corridors, they're big offset SLABS sitting in an open floor with gaps between
|
|
## them, so that's what this emits: partial wall runs along a coarse grid, plus pillars.
|
|
## A proper maze would be legible; this is deliberately not.
|
|
##
|
|
## Everything smashable here is INVISIBLE (see Dust.gd). You find it by walking into it.
|
|
const BR_SEED := 0xBACC
|
|
const BR_HALF := 19.0
|
|
const BR_H := 2.55 # low. lower than any real office.
|
|
|
|
static func backrooms() -> Dictionary:
|
|
var rng := RandomNumberGenerator.new()
|
|
rng.seed = BR_SEED
|
|
|
|
var walls: Array = []
|
|
# Wall runs on a 4.6 m lattice. Each line gets a few segments with gaps between, so
|
|
# you can always get through somewhere but never see far.
|
|
# Density matters more than it looks. The first pass put a run on every lattice line
|
|
# in both axes and the result had NO sightline longer than a few metres — which kills
|
|
# the entity outright, because a stalker you can never see can never be stared at. The
|
|
# reference photographs are mostly open floor with occasional slabs, so: skip roughly
|
|
# a third of the lines, and leave big gaps.
|
|
var lines := [-13.8, -9.2, -4.6, 0.0, 4.6, 9.2, 13.8]
|
|
for axis in ["x", "z"]:
|
|
for at in lines:
|
|
if rng.randf() < 0.34:
|
|
continue # this line is simply open floor
|
|
var cursor := -BR_HALF
|
|
while cursor < BR_HALF - 2.0:
|
|
var gap := rng.randf_range(4.5, 12.0)
|
|
cursor += gap
|
|
if cursor >= BR_HALF - 2.0:
|
|
break
|
|
var run := rng.randf_range(3.0, 7.5)
|
|
var end: float = minf(cursor + run, BR_HALF)
|
|
if end - cursor > 1.4:
|
|
walls.append({"a": axis, "at": at, "from": cursor, "to": end})
|
|
cursor = end
|
|
|
|
# freestanding pillars, because every Backrooms photo has one in the way
|
|
var slabs: Array = []
|
|
for i in 16:
|
|
var px := rng.randf_range(-BR_HALF + 2.0, BR_HALF - 2.0)
|
|
var pz := rng.randf_range(-BR_HALF + 2.0, BR_HALF - 2.0)
|
|
slabs.append({"size": Vector3(0.62, BR_H, 0.62),
|
|
"at": Vector3(px, BR_H * 0.5, pz), "mat": "wall"})
|
|
# skirting-height trim run around the outer wall, the one detail the photos all share
|
|
for s in [-1.0, 1.0]:
|
|
slabs.append({"size": Vector3(BR_HALF * 2.0, 0.12, 0.06),
|
|
"at": Vector3(0.0, 0.06, s * (BR_HALF - 0.03)), "mat": "trim",
|
|
"collide": false})
|
|
slabs.append({"size": Vector3(0.06, 0.12, BR_HALF * 2.0),
|
|
"at": Vector3(s * (BR_HALF - 0.03), 0.06, 0.0), "mat": "trim",
|
|
"collide": false})
|
|
|
|
# a dense grid of buzzing troffers — the light IS the horror
|
|
var lx: Array = []
|
|
var lz: Array = []
|
|
var v := -BR_HALF + 2.3
|
|
while v < BR_HALF:
|
|
lx.append(v)
|
|
lz.append(v)
|
|
v += 3.05
|
|
|
|
# sparse, wrong office objects. All invisible until you dust them.
|
|
var smash: Array = []
|
|
var kinds := [["office-chair", "plastic"], ["wastebin", "plastic"],
|
|
["cardboard-box", "cardboard"], ["filing-cabinet", "steel"],
|
|
["crt-monitor", "glass"], ["desk-phone", "plastic"],
|
|
["water-cooler", "steel"], ["office-plant", "wood"]]
|
|
# dense enough that a single cloud finds you two or three things — the level is
|
|
# a search, and a search with nothing in it is just a walk
|
|
for i in 78:
|
|
var k: Array = kinds[rng.randi() % kinds.size()]
|
|
smash.append({
|
|
"glb": String(k[0]), "kind": String(k[1]),
|
|
"at": Vector2(rng.randf_range(-BR_HALF + 2.5, BR_HALF - 2.5),
|
|
rng.randf_range(-BR_HALF + 2.5, BR_HALF - 2.5)),
|
|
"yaw": rng.randf_range(0.0, TAU),
|
|
})
|
|
|
|
return {
|
|
"name": "LEVEL 0",
|
|
"subtitle": "you noclipped out of reality",
|
|
"invisible": true, # Dust.gd hides every smashable here
|
|
"bounds": {"x0": -BR_HALF, "x1": BR_HALF, "z0": -BR_HALF, "z1": BR_HALF,
|
|
"h": BR_H},
|
|
"palette": {
|
|
# the whole point is that there is only one colour
|
|
"floor": Color(0.52, 0.47, 0.30), "wall": Color(0.76, 0.72, 0.42),
|
|
"ceiling": Color(0.80, 0.77, 0.55), "trim": Color(0.62, 0.58, 0.34),
|
|
"partition": Color(0.74, 0.70, 0.40), "wood": Color(0.62, 0.55, 0.32),
|
|
"accent": Color(0.70, 0.66, 0.38),
|
|
},
|
|
"floor_style": "carpet",
|
|
"ceiling": "tile",
|
|
"walls": walls,
|
|
"windows": [], # there is no outside
|
|
"slabs": slabs,
|
|
"lights": {"xs": lx, "zs": lz, "color": Color(1.0, 0.97, 0.80),
|
|
"energy": 1.15, "style": "troffer", "key_energy": 0.9},
|
|
"env": {"bg": Color(0.30, 0.28, 0.16), "ambient": Color(0.62, 0.58, 0.36),
|
|
"ambient_energy": 0.70, "exposure": 1.12},
|
|
"clusters": [],
|
|
"props": [],
|
|
"chairs": [],
|
|
"smashables": smash,
|
|
"records": [],
|
|
"gauntlet": {"at": Vector3(0.0, 0.0, -2.2), "yaw": PI,
|
|
"stand": Vector3(0.0, 0.0, 0.2), "shredder": Vector3(3.0, 0.0, -1.0)},
|
|
"spawn": {"at": Vector3(0.0, 0.0, 16.5), "yaw": PI},
|
|
}
|
|
|
|
# ================================================================ THE GROCER
|
|
## A greengrocer, and the only site whose contents are mostly SOFT.
|
|
##
|
|
## Everything else in the game shatters; here the stock bursts. That one material change
|
|
## rewrites the level: produce squashes instead of breaking, a pyramid crushes its own
|
|
## bottom layer as it collapses, and the floor fills with juice you then slip in. The
|
|
## glass bottles behind the juice bar are the exception, and the contrast is the point —
|
|
## one shelf in the room still rewards a proper swing.
|
|
##
|
|
## Bright, clean, warm track lighting on a pale floor, because the whole level is about
|
|
## making a mess and a mess needs somewhere clean to happen.
|
|
static func grocer() -> Dictionary:
|
|
var stacks: Array = []
|
|
# Angled island displays. `at` is the TOP surface a pyramid piles onto; Main builds
|
|
# the pyramid itself so the physics settles honestly rather than being placed.
|
|
var islands := [
|
|
[Vector3(-5.4, 0.95, -2.2), "apple", 5],
|
|
[Vector3(-5.4, 0.95, 1.4), "orange", 5],
|
|
[Vector3(-2.0, 0.95, -2.2), "tomato", 5],
|
|
[Vector3(-2.0, 0.95, 1.4), "apple", 4],
|
|
[Vector3(1.4, 0.95, -2.2), "cabbage", 3],
|
|
[Vector3(1.4, 0.95, 1.4), "orange", 4],
|
|
[Vector3(4.8, 0.80, -0.4), "melon", 3],
|
|
]
|
|
for i in islands:
|
|
stacks.append({"at": i[0], "item": String(i[1]), "rows": int(i[2])})
|
|
|
|
var slabs: Array = []
|
|
# the island tables themselves: a plinth, a timber top, and a raised back edge so a
|
|
# pyramid has something to fail against
|
|
for i in islands:
|
|
var p: Vector3 = i[0]
|
|
var big: bool = String(i[1]) == "melon"
|
|
var w := 2.4 if big else 1.5
|
|
var d := 1.9 if big else 1.5
|
|
var h: float = p.y
|
|
slabs.append({"size": Vector3(w, h - 0.10, d),
|
|
"at": Vector3(p.x, (h - 0.10) * 0.5, p.z), "mat": "trim"})
|
|
slabs.append({"size": Vector3(w + 0.14, 0.10, d + 0.14),
|
|
"at": Vector3(p.x, h - 0.05, p.z), "mat": "wood"})
|
|
for s in [-1.0, 1.0]:
|
|
slabs.append({"size": Vector3(w + 0.14, 0.10, 0.06),
|
|
"at": Vector3(p.x, h + 0.05, p.z + s * (d * 0.5 + 0.04)), "mat": "wood"})
|
|
slabs.append({"size": Vector3(0.06, 0.10, d + 0.14),
|
|
"at": Vector3(p.x + s * (w * 0.5 + 0.04), h + 0.05, p.z), "mat": "wood"})
|
|
|
|
# juice bar along the back, with shelving above it for the bottles
|
|
slabs.append({"size": Vector3(7.0, 1.05, 0.75), "at": Vector3(-3.0, 0.525, -7.4),
|
|
"mat": "trim"})
|
|
slabs.append({"size": Vector3(7.2, 0.09, 0.92), "at": Vector3(-3.0, 1.10, -7.4),
|
|
"mat": "wood"})
|
|
for k in range(3):
|
|
slabs.append({"size": Vector3(6.6, 0.06, 0.34),
|
|
"at": Vector3(-3.0, 1.62 + k * 0.46, -7.72), "mat": "wood"})
|
|
# chiller run down the right wall
|
|
slabs.append({"size": Vector3(0.80, 2.10, 8.0), "at": Vector3(10.4, 1.05, 1.0),
|
|
"mat": "trim"})
|
|
for k in range(4):
|
|
slabs.append({"size": Vector3(0.86, 0.05, 8.0),
|
|
"at": Vector3(10.3, 0.55 + k * 0.46, 1.0), "mat": "ceiling"})
|
|
|
|
var smash: Array = []
|
|
# bottles on the bar shelves — the one thing in here that still wants a proper swing
|
|
for k in range(3):
|
|
for b in range(11):
|
|
smash.append({"glb": "juice-bottle", "kind": "glass",
|
|
"at": Vector2(-6.0 + b * 0.60, -7.72), "sit_on": 1.65 + k * 0.46})
|
|
for b in range(9):
|
|
smash.append({"glb": "juice-bottle", "kind": "glass",
|
|
"at": Vector2(-5.6 + b * 0.62, -7.4), "sit_on": 1.15})
|
|
# loose crates of stock on the floor
|
|
for c in [Vector2(-8.6, 3.4), Vector2(-8.6, 4.4), Vector2(-8.0, 5.4),
|
|
Vector2(7.4, -4.6), Vector2(8.2, -4.0), Vector2(7.8, 5.2)]:
|
|
smash.append({"glb": "produce-crate", "kind": "wood", "at": c,
|
|
"yaw": randf_range(0.0, TAU)})
|
|
# a few bananas and cabbages just lying about
|
|
for b in [Vector2(-7.2, 0.4), Vector2(3.2, 4.2), Vector2(6.0, 2.0)]:
|
|
smash.append({"glb": "produce-banana", "kind": "produce", "at": b})
|
|
for c in [Vector2(-9.4, -2.0), Vector2(2.4, -5.6)]:
|
|
smash.append({"glb": "produce-cabbage", "kind": "produce", "at": c})
|
|
|
|
return {
|
|
"name": "THE GREENGROCER",
|
|
"subtitle": "everything here is soft except the bottles",
|
|
"bounds": {"x0": -11.0, "x1": 11.0, "z0": -8.0, "z1": 8.0, "h": 3.30},
|
|
"palette": {
|
|
"floor": Color(0.70, 0.68, 0.64), "wall": Color(0.90, 0.89, 0.85),
|
|
"ceiling": Color(0.20, 0.20, 0.21), "trim": Color(0.15, 0.15, 0.16),
|
|
"partition": Color(0.30, 0.44, 0.40), "wood": Color(0.52, 0.36, 0.20),
|
|
"accent": Color(0.20, 0.48, 0.42),
|
|
},
|
|
"floor_style": "lino",
|
|
"ceiling": "flat",
|
|
"walls": [],
|
|
"windows": [{"a": "z", "at": 8.0, "from": -11.0, "to": 11.0,
|
|
"y0": 0.35, "y1": 2.85, "blinds": false}],
|
|
"lights": {"xs": [-8.0, -4.0, 0.0, 4.0, 8.0], "zs": [-6.0, -2.0, 2.0, 6.0],
|
|
"color": Color(1.0, 0.94, 0.84), "energy": 2.4, "style": "strip",
|
|
"key_energy": 1.8},
|
|
"sun": {"color": Color(1.0, 0.96, 0.88), "energy": 1.1,
|
|
"rot": Vector3(-40, 8, 0)},
|
|
"env": {"bg": Color(0.76, 0.82, 0.88), "ambient": Color(0.60, 0.58, 0.55),
|
|
"ambient_energy": 0.66, "exposure": 1.04},
|
|
"clusters": [],
|
|
"chairs": [],
|
|
"props": [
|
|
{"glb": "office-plant", "at": Vector3(-10.2, 0.0, 7.0)},
|
|
{"glb": "office-plant", "at": Vector3(9.6, 0.0, 7.0)},
|
|
],
|
|
"slabs": slabs,
|
|
"smashables": smash,
|
|
"stacks": stacks,
|
|
"records": [],
|
|
"gauntlet": {"at": Vector3(-8.6, 0.0, -6.0), "yaw": PI,
|
|
"stand": Vector3(-8.6, 0.0, -4.0), "shredder": Vector3(-6.4, 0.0, -5.4)},
|
|
"spawn": {"at": Vector3(0.0, 0.0, 6.4), "yaw": PI},
|
|
}
|