extends Node3D ## Sparse office props and bounded fire animation; Web/Compatibility safe. const FIRE_MIN := 1.9 const FIRE_MAX := 2.8 var fire_light: OmniLight3D var _time := 0.0 func _ready() -> void: name = "OfficeAtmosphere" _desk(Vector3(-5, 0, -4)) _desk(Vector3(5, 0, 4)) _chair(Vector3(-5, 0, -2.6), 0) _chair(Vector3(5, 0, 5.4), PI) _chair(Vector3(6.8, 0, -4), -0.35) _barrel(Vector3(-4, 0, 4)) func _material(color: Color, metallic: float = 0.0) -> StandardMaterial3D: var mat := StandardMaterial3D.new() mat.albedo_color = color mat.roughness = 0.85 mat.metallic = metallic return mat func _box(parent: Node3D, pos: Vector3, size: Vector3, mat: Material) -> MeshInstance3D: var mesh := BoxMesh.new() mesh.size = size mesh.material = mat var node := MeshInstance3D.new() node.mesh = mesh node.position = pos parent.add_child(node) return node func _body(pos: Vector3, label: String) -> StaticBody3D: var body := StaticBody3D.new() body.name = label body.position = pos body.collision_layer = 1 body.collision_mask = 0 body.add_to_group("office_props") add_child(body, true) return body func _collision(body: StaticBody3D, center: Vector3, size: Vector3) -> void: var shape := BoxShape3D.new() shape.size = size var collider := CollisionShape3D.new() collider.shape = shape collider.position = center body.add_child(collider) func _desk(pos: Vector3) -> void: var desk := _body(pos, "OfficeDesk") var wood := _material(Color(0.19, 0.12, 0.07)) var metal := _material(Color(0.12, 0.15, 0.14), 0.5) _box(desk, Vector3(0, 0.84, 0), Vector3(2.5, 0.12, 1.15), wood) for x in [-1.05, 1.05]: for z in [-0.43, 0.43]: _box(desk, Vector3(x, 0.4, z), Vector3(0.08, 0.8, 0.08), metal) _box(desk, Vector3(-0.82, 0.53, 0), Vector3(0.48, 0.5, 0.94), metal) for y in [0.4, 0.62]: _box(desk, Vector3(-0.82, y, 0.49), Vector3(0.23, 0.025, 0.035), wood) _box(desk, Vector3(0.3, 0.91, 0.05), Vector3(0.48, 0.015, 0.35), _material(Color(0.45, 0.43, 0.32))) _collision(desk, Vector3(0, 0.45, 0), Vector3(2.5, 0.9, 1.15)) _lamp(desk, Vector3(0.84, 0.91, -0.23)) func _chair(pos: Vector3, yaw: float) -> void: var chair := _body(pos, "OfficeChair") chair.rotation.y = yaw var metal := _material(Color(0.12, 0.12, 0.13), 0.6) var fabric := _material(Color(0.1, 0.14, 0.12)) _box(chair, Vector3(0, 0.48, 0), Vector3(0.58, 0.12, 0.56), fabric) _box(chair, Vector3(0, 0.84, 0.25), Vector3(0.58, 0.64, 0.09), fabric) for x in [-0.23, 0.23]: for z in [-0.22, 0.22]: _box(chair, Vector3(x, 0.21, z), Vector3(0.045, 0.42, 0.045), metal) _collision(chair, Vector3(0, 0.53, 0), Vector3(0.6, 1.06, 0.6)) func _cylinder(parent: Node3D, pos: Vector3, radius: float, height: float, mat: Material) -> void: var mesh := CylinderMesh.new() mesh.top_radius = radius mesh.bottom_radius = radius mesh.height = height mesh.radial_segments = 24 mesh.material = mat var node := MeshInstance3D.new() node.mesh = mesh node.position = pos parent.add_child(node) func _lamp(parent: Node3D, pos: Vector3) -> void: var lamp := Node3D.new() lamp.name = "DeskLamp" lamp.position = pos parent.add_child(lamp) var metal := _material(Color(0.13, 0.19, 0.15), 0.5) _cylinder(lamp, Vector3(0, 0.035, 0), 0.16, 0.07, metal) _box(lamp, Vector3(0, 0.24, 0), Vector3(0.04, 0.4, 0.04), metal) _box(lamp, Vector3(0, 0.44, 0), Vector3(0.4, 0.12, 0.24), metal) var bulb := _material(Color(0.8, 0.63, 0.3)) bulb.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED _box(lamp, Vector3(0, 0.375, 0), Vector3(0.32, 0.012, 0.18), bulb) var light := OmniLight3D.new() light.name = "DeskLampLight" light.position = Vector3(0, 0.31, 0) light.light_color = Color(1.0, 0.7, 0.35) light.light_energy = 1.2 light.omni_range = 5.5 light.shadow_enabled = false lamp.add_child(light) func _barrel(pos: Vector3) -> void: var barrel := _body(pos, "FireBarrel") var metal := _material(Color(0.15, 0.1, 0.075), 0.65) _cylinder(barrel, Vector3(0, 0.5, 0), 0.43, 1.0, metal) for y in [0.12, 0.78, 1.01]: _cylinder(barrel, Vector3(0, y, 0), 0.46, 0.055, metal) _cylinder(barrel, Vector3(0, 1.045, 0), 0.39, 0.015, _material(Color(0.025, 0.012, 0.005))) _collision(barrel, Vector3(0, 0.52, 0), Vector3(0.92, 1.04, 0.92)) var fire := CPUParticles3D.new() fire.name = "BarrelFlames" fire.position = Vector3(0, 1.08, 0) fire.amount = 28 fire.lifetime = 0.85 fire.preprocess = 1.0 fire.emission_shape = CPUParticles3D.EMISSION_SHAPE_SPHERE fire.emission_sphere_radius = 0.23 fire.direction = Vector3.UP fire.spread = 12 fire.gravity = Vector3(0, 0.6, 0) fire.initial_velocity_min = 0.5 fire.initial_velocity_max = 1.15 fire.scale_amount_min = 0.5 fire.scale_amount_max = 1.0 var gradient := Gradient.new() gradient.set_color(0, Color(1, 0.65, 0.12, 0.8)) gradient.set_color(1, Color(0.6, 0.04, 0.005, 0)) fire.color_ramp = gradient var quad := QuadMesh.new() quad.size = Vector2(0.48, 0.8) var flame := StandardMaterial3D.new() flame.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED flame.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA flame.blend_mode = BaseMaterial3D.BLEND_MODE_ADD flame.billboard_mode = BaseMaterial3D.BILLBOARD_PARTICLES flame.albedo_texture = load("res://assets/effects/flame.png") flame.vertex_color_use_as_albedo = true flame.cull_mode = BaseMaterial3D.CULL_DISABLED quad.material = flame fire.mesh = quad fire.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF barrel.add_child(fire) fire_light = OmniLight3D.new() fire_light.name = "BarrelFireLight" fire_light.position = Vector3(0, 1.5, 0) fire_light.light_color = Color(1, 0.36, 0.07) fire_light.light_energy = (FIRE_MIN + FIRE_MAX) * 0.5 fire_light.omni_range = 10 fire_light.shadow_enabled = true barrel.add_child(fire_light) func _process(dt: float) -> void: _time += dt # Smooth, deterministic, bounded flicker: no per-frame random flashes. var wave := 0.5 + 0.3 * sin(_time * 7.1) + 0.2 * sin(_time * 11.7 + 1.2) fire_light.light_energy = lerpf(FIRE_MIN, FIRE_MAX, wave)