- Seeded weather (clear/cloudy/rain/storm, snow and blizzards on cold days and above the snowline), lightning, synthesised rain/wind/thunder sound - Rain/snow particles stopped by roofs; wet ground, settled snow and wind via global shader uniforms - Snap-together wood floor, wall, door, roof and gable with structural support, collapse and X to dismantle - Shelter detection: dry under a roof, warmer and Rested inside with a fire; rain burns an uncovered campfire faster - Bed sets the spawn point and lets you sleep through the night - Trees, boulders and ground pickups regrow; timers saved - Grass cleared under floors; shorter HUD hint - New test_weather_building suite (62 checks) and tests/run_all.sh, which also fails on script errors
376 lines
15 KiB
GDScript
376 lines
15 KiB
GDScript
extends RefCounted
|
|
## Procedural meshes for items and placeable pieces, keyed by the "mesh" field
|
|
## in data/items.json. The same mesh is used for the inventory icon, the tool
|
|
## held in your hand and the object placed in the world.
|
|
##
|
|
## Convention: origin at the grip (tools) or at ground level, centred
|
|
## (placeables). Units are metres. Built from the low-poly helpers in
|
|
## proc_mesh.gd, so everything is flat-shaded with vertex colours.
|
|
|
|
const P = preload("res://scripts/world/proc_mesh.gd")
|
|
|
|
const HANDLE := Color(0.55, 0.40, 0.24)
|
|
const STONE := Color(0.55, 0.54, 0.52)
|
|
const FLINT := Color(0.22, 0.23, 0.27)
|
|
const PLANK := Color(0.62, 0.45, 0.27)
|
|
const PLANK_DARK := Color(0.42, 0.29, 0.17)
|
|
const IRON := Color(0.30, 0.30, 0.32)
|
|
const ASH := Color(0.18, 0.17, 0.16)
|
|
const BINDING := Color(0.75, 0.68, 0.48)
|
|
|
|
const FIBER := Color(0.45, 0.55, 0.22)
|
|
const BERRY := Color(0.62, 0.08, 0.16)
|
|
const MUSH_CAP := Color(0.72, 0.30, 0.18)
|
|
const MUSH_ROAST := Color(0.40, 0.24, 0.12)
|
|
const MUSH_STEM := Color(0.88, 0.84, 0.74)
|
|
const CLOTH := Color(0.60, 0.50, 0.32)
|
|
const SOIL := Color(0.30, 0.22, 0.15)
|
|
|
|
static var _cache := {}
|
|
|
|
static func build(key: String) -> ArrayMesh:
|
|
if _cache.has(key):
|
|
return _cache[key]
|
|
var m: ArrayMesh
|
|
match key:
|
|
"stick": m = _stick()
|
|
"stone": m = _pebble(11, STONE, Vector3(0.14, 0.10, 0.12))
|
|
"flint": m = _pebble(23, FLINT, Vector3(0.12, 0.07, 0.15), 0.5)
|
|
"wood": m = _wood()
|
|
"stone_axe": m = _axe()
|
|
"stone_pickaxe": m = _pickaxe()
|
|
"club": m = _club()
|
|
"campfire": m = _campfire()
|
|
"workbench": m = _workbench()
|
|
"chest": m = _chest()
|
|
"fiber": m = _fiber()
|
|
"berries": m = _berries()
|
|
"mushroom": m = _mushroom(MUSH_CAP)
|
|
"roasted_mushroom": m = _mushroom(MUSH_ROAST)
|
|
"torch": m = _torch()
|
|
"grave": m = _grave()
|
|
"wood_floor": m = _floor()
|
|
"wood_wall": m = _wall()
|
|
"wood_door": m = _door(true)
|
|
"wood_door_frame": m = _door(false)
|
|
"wood_door_panel": m = _door_panel()
|
|
"wood_roof": m = _roof()
|
|
"wood_gable": m = _gable()
|
|
"bed": m = _bed()
|
|
"berry_bush": m = _berry_bush(true)
|
|
"berry_bush_bare": m = _berry_bush(false)
|
|
_:
|
|
push_warning("item_meshes: no mesh for '%s', using a stone" % key)
|
|
m = _pebble(1, Color.MAGENTA, Vector3.ONE * 0.15)
|
|
_cache[key] = m
|
|
return m
|
|
|
|
static func _rng(seed: int) -> RandomNumberGenerator:
|
|
var r := RandomNumberGenerator.new()
|
|
r.seed = seed
|
|
return r
|
|
|
|
static func _box(st: SurfaceTool, center: Vector3, size: Vector3, col: Color, basis: Basis = Basis()) -> void:
|
|
var h := size * 0.5
|
|
var c := [
|
|
Vector3(-h.x, -h.y, -h.z), Vector3(h.x, -h.y, -h.z), Vector3(h.x, h.y, -h.z), Vector3(-h.x, h.y, -h.z),
|
|
Vector3(-h.x, -h.y, h.z), Vector3(h.x, -h.y, h.z), Vector3(h.x, h.y, h.z), Vector3(-h.x, h.y, h.z),
|
|
]
|
|
for i in range(8):
|
|
c[i] = center + basis * c[i]
|
|
var faces := [[0, 1, 2, 3], [5, 4, 7, 6], [4, 0, 3, 7], [1, 5, 6, 2], [3, 2, 6, 7], [4, 5, 1, 0]]
|
|
for f in faces:
|
|
var a: Vector3 = c[f[0]]
|
|
var b: Vector3 = c[f[1]]
|
|
var cc: Vector3 = c[f[2]]
|
|
var d: Vector3 = c[f[3]]
|
|
var out := (a + b + cc + d) * 0.25 - center
|
|
P._tri(st, a, b, cc, out, col)
|
|
P._tri(st, a, cc, d, out, col)
|
|
|
|
static func _pebble(seed: int, col: Color, radii: Vector3, sharp: float = 0.3) -> ArrayMesh:
|
|
var n := FastNoiseLite.new()
|
|
n.seed = seed
|
|
n.frequency = 1.4
|
|
var st := P._begin()
|
|
P._blob(st, Vector3(0, radii.y * 0.6, 0), radii, n, sharp, col, _rng(seed), 1)
|
|
return P._commit(st)
|
|
|
|
static func _stick() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(5)
|
|
P._cylinder(st, Vector3(-0.35, 0.03, 0), Vector3(0.35, 0.03, 0.02), 0.028, 0.02, 5, HANDLE, r, -1.0, PLANK)
|
|
P._cylinder(st, Vector3(0.05, 0.03, 0.0), Vector3(0.2, 0.05, 0.1), 0.012, 0.006, 4, HANDLE, r)
|
|
return P._commit(st)
|
|
|
|
static func _wood() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(9)
|
|
P._cylinder(st, Vector3(-0.3, 0.1, -0.06), Vector3(0.3, 0.1, -0.06), 0.1, 0.1, 6, P.BARK, r, -1.0, PLANK)
|
|
P._cylinder(st, Vector3(-0.28, 0.1, 0.13), Vector3(0.3, 0.1, 0.13), 0.09, 0.09, 6, P.BARK, r, -1.0, PLANK)
|
|
P._cylinder(st, Vector3(-0.29, 0.27, 0.04), Vector3(0.29, 0.27, 0.04), 0.09, 0.09, 6, P.BARK, r, -1.0, PLANK)
|
|
return P._commit(st)
|
|
|
|
## Handle along +Y from the grip at the origin.
|
|
static func _handle(st: SurfaceTool, length: float, r: RandomNumberGenerator) -> void:
|
|
P._cylinder(st, Vector3(0, -0.1, 0), Vector3(0, length, 0), 0.022, 0.02, 6, HANDLE, r, -1.0, HANDLE)
|
|
|
|
static func _axe() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(13)
|
|
_handle(st, 0.55, r)
|
|
_box(st, Vector3(0, 0.47, 0), Vector3(0.06, 0.07, 0.07), BINDING)
|
|
var n := FastNoiseLite.new()
|
|
n.seed = 3
|
|
n.frequency = 2.0
|
|
# Flint head: a flattened wedge pointing along +X.
|
|
P._blob(st, Vector3(0.075, 0.47, 0), Vector3(0.085, 0.055, 0.025), n, 0.2, FLINT, r, 1)
|
|
return P._commit(st)
|
|
|
|
static func _pickaxe() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(17)
|
|
_handle(st, 0.6, r)
|
|
_box(st, Vector3(0, 0.55, 0), Vector3(0.06, 0.07, 0.07), BINDING)
|
|
P._cylinder(st, Vector3(-0.02, 0.56, 0), Vector3(0.22, 0.5, 0), 0.04, 0.008, 5, STONE, r, -1.0, STONE)
|
|
P._cylinder(st, Vector3(0.02, 0.56, 0), Vector3(-0.2, 0.51, 0), 0.04, 0.008, 5, STONE, r, -1.0, STONE)
|
|
return P._commit(st)
|
|
|
|
static func _club() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(21)
|
|
P._cylinder(st, Vector3(0, -0.1, 0), Vector3(0, 0.62, 0), 0.025, 0.07, 7, PLANK_DARK, r, -1.0, PLANK)
|
|
return P._commit(st)
|
|
|
|
static func _campfire() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(31)
|
|
var n := FastNoiseLite.new()
|
|
n.seed = 31
|
|
n.frequency = 1.6
|
|
for i in range(9):
|
|
var a := TAU * i / 9.0
|
|
var c := Vector3(cos(a) * 0.55, 0.06, sin(a) * 0.55)
|
|
P._blob(st, c, Vector3(0.15, 0.11, 0.13) * r.randf_range(0.85, 1.15), n, 0.3, P._mul(STONE, r.randf_range(0.8, 1.05)), r, 1)
|
|
# Teepee of logs leaning into the middle.
|
|
for i in range(5):
|
|
var a := TAU * i / 5.0 + 0.3
|
|
var base := Vector3(cos(a) * 0.36, 0.0, sin(a) * 0.36)
|
|
P._cylinder(st, base, Vector3(0, 0.55, 0), 0.05, 0.035, 5, P.BARK, r, -1.0, PLANK)
|
|
P._blob(st, Vector3(0, 0.03, 0), Vector3(0.3, 0.04, 0.3), n, 0.2, ASH, r, 1)
|
|
return P._commit(st)
|
|
|
|
static func _workbench() -> ArrayMesh:
|
|
var st := P._begin()
|
|
_box(st, Vector3(0, 0.82, 0), Vector3(1.8, 0.1, 0.9), PLANK)
|
|
_box(st, Vector3(0, 0.79, 0.47), Vector3(1.82, 0.06, 0.04), PLANK_DARK)
|
|
for sx in [-0.8, 0.8]:
|
|
for sz in [-0.36, 0.36]:
|
|
_box(st, Vector3(sx, 0.38, sz), Vector3(0.1, 0.8, 0.1), PLANK_DARK)
|
|
_box(st, Vector3(0, 0.25, 0), Vector3(1.6, 0.06, 0.7), PLANK_DARK)
|
|
# A few tools lying on top.
|
|
_box(st, Vector3(0.45, 0.89, 0.1), Vector3(0.35, 0.03, 0.05), HANDLE, Basis(Vector3.UP, 0.4))
|
|
_box(st, Vector3(0.6, 0.9, 0.18), Vector3(0.09, 0.06, 0.09), FLINT)
|
|
_box(st, Vector3(-0.5, 0.92, -0.15), Vector3(0.4, 0.1, 0.22), P.BARK)
|
|
return P._commit(st)
|
|
|
|
static func _chest() -> ArrayMesh:
|
|
var st := P._begin()
|
|
_box(st, Vector3(0, 0.3, 0), Vector3(1.1, 0.6, 0.7), PLANK)
|
|
_box(st, Vector3(0, 0.66, 0), Vector3(1.14, 0.14, 0.74), PLANK_DARK)
|
|
for sx in [-0.4, 0.4]:
|
|
_box(st, Vector3(sx, 0.36, 0), Vector3(0.07, 0.74, 0.76), IRON)
|
|
_box(st, Vector3(0, 0.55, 0.37), Vector3(0.12, 0.14, 0.03), IRON)
|
|
return P._commit(st)
|
|
|
|
static func _fiber() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(41)
|
|
for i in range(7):
|
|
var a := r.randf_range(-0.25, 0.25)
|
|
var b := Vector3(r.randf_range(-0.03, 0.03), 0.02, r.randf_range(-0.03, 0.03))
|
|
P._cylinder(st, b + Vector3(-0.22, 0, 0), b + Vector3(0.22, 0.03 + a * 0.1, a), 0.008, 0.005, 3, P._mul(FIBER, r.randf_range(0.8, 1.15)), r)
|
|
_box(st, Vector3(0, 0.03, 0), Vector3(0.05, 0.05, 0.08), CLOTH)
|
|
return P._commit(st)
|
|
|
|
static func _berries() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(43)
|
|
var n := FastNoiseLite.new()
|
|
n.seed = 43
|
|
for i in range(9):
|
|
var c := Vector3(r.randf_range(-0.07, 0.07), 0.03 + r.randf_range(0.0, 0.05), r.randf_range(-0.07, 0.07))
|
|
P._blob(st, c, Vector3.ONE * r.randf_range(0.025, 0.035), n, 0.1, P._mul(BERRY, r.randf_range(0.8, 1.2)), r, 0)
|
|
P._blob(st, Vector3(0, 0.08, 0), Vector3(0.05, 0.012, 0.03), n, 0.2, P.BUSH, r, 0)
|
|
return P._commit(st)
|
|
|
|
static func _mushroom(cap: Color) -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(47)
|
|
var n := FastNoiseLite.new()
|
|
n.seed = 47
|
|
P._cylinder(st, Vector3(0, -0.02, 0), Vector3(0, 0.1, 0), 0.025, 0.02, 6, MUSH_STEM, r, -1.0, MUSH_STEM)
|
|
P._blob(st, Vector3(0, 0.11, 0), Vector3(0.075, 0.04, 0.075), n, 0.15, cap, r, 1)
|
|
return P._commit(st)
|
|
|
|
static func _torch() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(53)
|
|
_handle(st, 0.5, r)
|
|
P._cylinder(st, Vector3(0, 0.42, 0), Vector3(0, 0.58, 0), 0.045, 0.05, 6, CLOTH, r, -1.0, ASH)
|
|
return P._commit(st)
|
|
|
|
static func _grave() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(59)
|
|
var n := FastNoiseLite.new()
|
|
n.seed = 59
|
|
P._blob(st, Vector3(0, 0.0, 0), Vector3(0.5, 0.22, 0.8), n, 0.15, SOIL, r, 1)
|
|
_box(st, Vector3(0, 0.55, -0.62), Vector3(0.08, 1.0, 0.06), PLANK_DARK)
|
|
_box(st, Vector3(0, 0.8, -0.62), Vector3(0.5, 0.08, 0.06), PLANK_DARK)
|
|
for i in range(4):
|
|
var c := Vector3(r.randf_range(-0.35, 0.35), 0.15, r.randf_range(-0.6, 0.6))
|
|
P._blob(st, c, Vector3.ONE * r.randf_range(0.07, 0.12), n, 0.3, STONE, r, 0)
|
|
return P._commit(st)
|
|
|
|
## World berry bush (not an item). `ripe` adds the berries.
|
|
static func _berry_bush(ripe: bool) -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(61)
|
|
var n := FastNoiseLite.new()
|
|
n.seed = 61
|
|
n.frequency = 2.0
|
|
var leaf := P._mul(P.BUSH, 1.1)
|
|
var blobs: Array[Vector3] = []
|
|
for i in range(4):
|
|
var c := Vector3(r.randf_range(-0.4, 0.4), r.randf_range(0.3, 0.55), r.randf_range(-0.4, 0.4))
|
|
var rad := r.randf_range(0.35, 0.5)
|
|
P._blob(st, c, Vector3(rad, rad * 0.8, rad), n, 0.3, P._mul(leaf, r.randf_range(0.85, 1.1)), r, 1)
|
|
blobs.append(c + Vector3(0, rad * 0.4, 0))
|
|
if ripe:
|
|
for c in blobs:
|
|
for k in range(6):
|
|
var d := Vector3(r.randf_range(-1, 1), r.randf_range(0.2, 1), r.randf_range(-1, 1)).normalized() * 0.4
|
|
P._blob(st, c + d, Vector3.ONE * 0.045, n, 0.1, BERRY, r, 0)
|
|
return P._commit(st)
|
|
|
|
# --- building pieces ----------------------------------------------------------
|
|
# Dimensions must match the colliders in scripts/building/build_piece.gd.
|
|
|
|
const BEAM := Color(0.40, 0.27, 0.15)
|
|
const SHINGLE := Color(0.46, 0.33, 0.20)
|
|
const THATCH := Color(0.62, 0.52, 0.30)
|
|
const FUR := Color(0.45, 0.30, 0.20)
|
|
const LINEN := Color(0.80, 0.76, 0.64)
|
|
|
|
## Per-board tint so planks don't read as one flat sheet.
|
|
static func _board(r: RandomNumberGenerator, base: Color = PLANK) -> Color:
|
|
return P._mul(base, r.randf_range(0.82, 1.08))
|
|
|
|
## 2 x 2 m, top surface at y = 0, 0.2 m deep.
|
|
static func _floor() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(71)
|
|
for i in range(5):
|
|
_box(st, Vector3(-0.8 + 0.4 * i, -0.05, 0), Vector3(0.385, 0.1, 2.0), _board(r))
|
|
for z in [-0.85, 0.0, 0.85]:
|
|
_box(st, Vector3(0, -0.15, z), Vector3(2.0, 0.1, 0.22), BEAM)
|
|
return P._commit(st)
|
|
|
|
## Horizontal boards between two posts, 2 x 2 m, 0.2 m thick, bottom centre at origin.
|
|
static func _wall_body(st: SurfaceTool, r: RandomNumberGenerator, x0: float, x1: float, y0: float, y1: float) -> void:
|
|
var rows := maxi(roundi((y1 - y0) / 0.31), 1)
|
|
var h := (y1 - y0) / rows
|
|
for i in range(rows):
|
|
var y := y0 + h * (i + 0.5)
|
|
_box(st, Vector3((x0 + x1) * 0.5, y, 0), Vector3(x1 - x0, h - 0.015, 0.12), _board(r))
|
|
|
|
static func _wall() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(73)
|
|
_wall_body(st, r, -0.84, 0.84, 0.1, 1.9)
|
|
for x in [-0.92, 0.92]:
|
|
_box(st, Vector3(x, 1.0, 0), Vector3(0.16, 2.0, 0.2), BEAM)
|
|
for y in [0.06, 1.94]:
|
|
_box(st, Vector3(0, y, 0), Vector3(1.68, 0.12, 0.2), BEAM)
|
|
return P._commit(st)
|
|
|
|
## Door frame (1.1 x 1.9 m opening); `with_panel` adds the closed door, for the
|
|
## inventory icon and the placement ghost.
|
|
static func _door(with_panel: bool) -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(79)
|
|
for side in [-1.0, 1.0]:
|
|
_wall_body(st, r, side * 0.55 if side > 0 else -0.84, 0.84 if side > 0 else -0.55, 0.1, 1.9)
|
|
_box(st, Vector3(side * 0.92, 1.0, 0), Vector3(0.16, 2.0, 0.2), BEAM)
|
|
_box(st, Vector3(side * 0.6, 0.95, 0), Vector3(0.1, 1.9, 0.2), BEAM) # jamb
|
|
_box(st, Vector3(0, 1.95, 0), Vector3(1.68, 0.1, 0.2), BEAM)
|
|
_box(st, Vector3(-0.7, 0.06, 0), Vector3(0.28, 0.12, 0.2), BEAM)
|
|
_box(st, Vector3(0.7, 0.06, 0), Vector3(0.28, 0.12, 0.2), BEAM)
|
|
if with_panel:
|
|
_door_panel_into(st, Vector3(-0.54, 0, 0))
|
|
return P._commit(st)
|
|
|
|
## The door leaf, hinge at the origin, spanning +X.
|
|
static func _door_panel() -> ArrayMesh:
|
|
var st := P._begin()
|
|
_door_panel_into(st, Vector3.ZERO)
|
|
return P._commit(st)
|
|
|
|
static func _door_panel_into(st: SurfaceTool, o: Vector3) -> void:
|
|
var r := _rng(83)
|
|
for i in range(4):
|
|
_box(st, o + Vector3(0.135 + 0.27 * i, 0.95, 0), Vector3(0.26, 1.86, 0.07), _board(r))
|
|
for y in [0.35, 1.55]:
|
|
_box(st, o + Vector3(0.54, y, 0.05), Vector3(0.96, 0.12, 0.04), BEAM)
|
|
_box(st, o + Vector3(0.54, 0.95, 0.05), Vector3(0.1, 1.2, 0.04), BEAM, Basis(Vector3.BACK, 0.62))
|
|
_box(st, o + Vector3(0.95, 1.0, 0.07), Vector3(0.05, 0.14, 0.05), IRON)
|
|
_box(st, o + Vector3(0.95, 1.0, -0.07), Vector3(0.05, 0.14, 0.05), IRON)
|
|
|
|
## Sloped roof: low edge centre at the origin, rising 1 m over 2 m toward -Z,
|
|
## with a short eave hanging past the low edge.
|
|
static func _roof() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(89)
|
|
var a := 0.4636476
|
|
var b := Basis(Vector3.RIGHT, a)
|
|
var n := Vector3(0, cos(a), sin(a))
|
|
var along := Vector3(0, sin(a), -cos(a)) # up the slope
|
|
var length := sqrt(5.0)
|
|
# Boarded deck, then overlapping rows of shingles on top.
|
|
_box(st, along * (length * 0.5 - 0.15) + n * 0.03, Vector3(2.0, 0.06, length + 0.3), _board(r, BEAM), b)
|
|
var rows := 6
|
|
for i in range(rows):
|
|
var s := -0.3 + (length + 0.3) * (i + 0.5) / rows
|
|
var tilt := Basis(Vector3.RIGHT, a + 0.06)
|
|
_box(st, along * s + n * 0.085, Vector3(2.04, 0.05, (length + 0.3) / rows + 0.1), _board(r, SHINGLE), tilt)
|
|
return P._commit(st)
|
|
|
|
## Triangular gable end: 0 m tall at -X, 1 m tall at +X.
|
|
static func _gable() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(97)
|
|
for i in range(3):
|
|
var y0 := i / 3.0
|
|
var x0 := 2.0 * y0 - 1.0 + 0.1
|
|
_box(st, Vector3((x0 + 0.92) * 0.5, y0 + 1.0 / 6.0, 0), Vector3(0.92 - x0, 1.0 / 3.0 - 0.015, 0.12), _board(r))
|
|
_box(st, Vector3(0.92, 0.5, 0), Vector3(0.16, 1.0, 0.2), BEAM)
|
|
_box(st, Vector3(0, 0.06, 0), Vector3(2.0, 0.12, 0.2), BEAM)
|
|
return P._commit(st)
|
|
|
|
## Bed: 1 x 2.1 m frame with a straw mattress, pillow and fur blanket.
|
|
static func _bed() -> ArrayMesh:
|
|
var st := P._begin()
|
|
var r := _rng(101)
|
|
for sx in [-0.45, 0.45]:
|
|
for sz in [-0.98, 0.98]:
|
|
_box(st, Vector3(sx, 0.22, sz), Vector3(0.1, 0.44, 0.1), BEAM)
|
|
_box(st, Vector3(sx, 0.28, 0), Vector3(0.08, 0.14, 1.9), _board(r))
|
|
for sz in [-0.98, 0.98]:
|
|
_box(st, Vector3(0, 0.28, sz), Vector3(0.84, 0.14, 0.08), _board(r))
|
|
_box(st, Vector3(0, 0.62, -1.0), Vector3(0.96, 0.4, 0.08), _board(r)) # headboard
|
|
_box(st, Vector3(0, 0.38, 0), Vector3(0.86, 0.14, 1.9), THATCH)
|
|
_box(st, Vector3(0, 0.5, -0.72), Vector3(0.6, 0.1, 0.32), LINEN)
|
|
_box(st, Vector3(0, 0.47, 0.25), Vector3(0.9, 0.08, 1.3), FUR)
|
|
return P._commit(st)
|