extends Node3D class_name DreamWorld ## Die Traumwelt: Insel mit drei betretbaren Gebäuden und dem Tor zur Erde. const INNEN_Y := -300.0 var spawn := Vector3(0, 2.0, 14.0) var _deko: Array = [] var _regale: Dictionary = {} # tech_id -> MeshInstance3D var _stelen: Dictionary = {} # human_id -> Dictionary func _ready() -> void: _environment() _insel() _gebaeude_bibliothek() _gebaeude_missionshalle() _gebaeude_meditation() _tor_zur_erde() Game.state_changed.connect(_refresh) _refresh() func _environment() -> void: var we := WorldEnvironment.new() var env := Environment.new() env.background_mode = Environment.BG_SKY var sky := Sky.new() var mat := ProceduralSkyMaterial.new() mat.sky_top_color = Color(0.10, 0.05, 0.24) mat.sky_horizon_color = Color(0.42, 0.24, 0.55) mat.ground_bottom_color = Color(0.06, 0.03, 0.14) mat.ground_horizon_color = Color(0.32, 0.18, 0.45) mat.sun_angle_max = 40.0 sky.sky_material = mat env.sky = sky env.ambient_light_source = Environment.AMBIENT_SOURCE_SKY env.ambient_light_energy = 1.8 env.glow_enabled = true env.glow_intensity = 0.5 env.glow_bloom = 0.15 env.fog_enabled = true env.fog_light_color = Color(0.30, 0.18, 0.45) env.fog_density = 0.006 we.environment = env add_child(we) var sun := DirectionalLight3D.new() sun.rotation_degrees = Vector3(-46, 25, 0) sun.light_energy = 1.15 sun.light_color = Color(0.85, 0.80, 1.0) sun.shadow_enabled = true sun.shadow_blur = 2.0 add_child(sun) func _insel() -> void: Prims.cyl(self, Vector3(0, -1.0, 0), 50.0, 2.0, Color(0.28, 0.20, 0.42)) Prims.cyl(self, Vector3(0, -4.0, 0), 38.0, 4.0, Color(0.20, 0.14, 0.32), false) Prims.cyl(self, Vector3(0, -9.0, 0), 20.0, 6.0, Color(0.15, 0.10, 0.26), false) # Wege var wege: Array[Vector3] = [Vector3(-22, 0, -6), Vector3(0, 0, -12), Vector3(22, 0, -6), Vector3(0, 0, 8)] for w in wege: var d: Vector3 = w.normalized() * (w.length() * 0.5) var b := Prims.box(self, Vector3(d.x, 0.02, d.z), Vector3(3.0, 0.08, w.length()), Color(0.45, 0.35, 0.62), false) b.rotation.y = atan2(w.x, w.z) # schwebende Deko var rng := RandomNumberGenerator.new() rng.seed = 7 for i in range(34): var a := rng.randf() * TAU var r := rng.randf_range(16.0, 46.0) var p := Vector3(cos(a) * r, rng.randf_range(4.0, 22.0), sin(a) * r) var s := rng.randf_range(0.6, 2.0) var c := Color(0.6 + rng.randf() * 0.3, 0.5 + rng.randf() * 0.4, 1.0) var wuerfel := Prims.box(self, p, Vector3(s, s, s), c, false, 1.1) wuerfel.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF _deko.append(wuerfel) func _process(delta: float) -> void: for i in range(_deko.size()): var n: Node3D = _deko[i] n.rotation.y += delta * (0.2 + 0.05 * (i % 5)) n.rotation.x += delta * 0.13 n.position.y += sin(Time.get_ticks_msec() * 0.0007 + i) * delta * 0.6 # ---------------------------------------------------------------- Bausteine ## Erzeugt Außenbau + Innenraum und verbindet beide mit Tür-Zonen. func _gebaeude(titel: String, a_center: Vector3, a_size: Vector3, i_center: Vector3, i_size: Vector3, farbe: Color) -> Node3D: Prims.room(self, a_center, a_size, farbe, farbe.darkened(0.3), Vector3.BACK, 3.6, false) Prims.box(self, a_center + Vector3(0, a_size.y + 0.25, 0), Vector3(a_size.x + 1.0, 0.5, a_size.z + 1.0), farbe.lightened(0.15)) Prims.box(self, a_center + Vector3(0, a_size.y + 1.1, 0), Vector3(a_size.x * 0.5, 1.2, a_size.z * 0.5), farbe.lightened(0.3)) Prims.label(self, a_center + Vector3(0, a_size.y + 3.0, 0), titel, 1.4, Color(1, 0.95, 0.8)) var aussen_tuer := a_center + Vector3(0, 0, a_size.z * 0.5) var draussen := a_center + Vector3(0, 0.2, a_size.z * 0.5 + 3.2) var innen := Node3D.new() innen.name = titel.replace(" ", "_") add_child(innen) Prims.room(innen, i_center, i_size, farbe.lightened(0.12), farbe.darkened(0.25), Vector3.BACK, 3.6, true) Prims.box(innen, i_center + Vector3(0, i_size.y + 0.2, 0), Vector3(i_size.x, 0.4, i_size.z), farbe.darkened(0.4)) for sx: float in [-1.0, 1.0]: for sz: float in [-1.0, 1.0]: var l := OmniLight3D.new() l.position = i_center + Vector3(sx * i_size.x * 0.28, i_size.y - 0.8, sz * i_size.z * 0.28) l.omni_range = 34.0 l.light_energy = 4.5 l.light_color = Color(0.90, 0.90, 1.0) innen.add_child(l) var innen_spawn := i_center + Vector3(0, 0.3, i_size.z * 0.5 - 3.0) _tuer(self, aussen_tuer + Vector3(0, 1.2, 0), innen_spawn) _tuer(innen, i_center + Vector3(0, 1.2, i_size.z * 0.5), draussen) Prims.label(innen, i_center + Vector3(0, i_size.y - 0.9, i_size.z * 0.5 - 0.35), "Ausgang", 0.45, Color(1, 0.85, 0.6)) return innen func _tuer(parent: Node, pos: Vector3, ziel: Vector3) -> void: var a := Area3D.new() a.position = pos var cs := CollisionShape3D.new() var sh := BoxShape3D.new() sh.size = Vector3(3.4, 2.4, 1.6) cs.shape = sh a.add_child(cs) parent.add_child(a) a.body_entered.connect(func(body: Node3D) -> void: if body is Player and Game.teleport_lock <= 0.0: Game.teleport_lock = 0.9 body.global_position = ziel body.velocity = Vector3.ZERO) func _interaktion(parent: Node, pos: Vector3, kind: String, arg: String, titel: String) -> Node3D: var n := Node3D.new() n.position = pos parent.add_child(n) n.add_to_group("interactable") n.set_meta("kind", kind) n.set_meta("arg", arg) n.set_meta("titel", titel) return n # ---------------------------------------------------------------- Gebäude func _gebaeude_bibliothek() -> void: var innen := _gebaeude("Bibliothek der Techniken", Vector3(-24, 0, -16), Vector3(16, 5, 14), Vector3(0, INNEN_Y, 0), Vector3(34, 6, 24), Color(0.58, 0.50, 0.80)) Prims.label(innen, Vector3(0, INNEN_Y + 5.0, -10.5), "Berühre eine Technik, um ihre Hinweise zu lesen.", 0.4, Color(0.9, 0.9, 1)) var ids := TechDB.ids() for i in range(ids.size()): var reihe := i / 6 var spalte := i % 6 var p := Vector3(-12.5 + spalte * 5.0, INNEN_Y, -6.5 + reihe * 7.0) var t := TechDB.by_id(ids[i]) Prims.cyl(innen, p + Vector3(0, 0.5, 0), 0.8, 1.0, Color(0.30, 0.26, 0.45)) var kristall := Prims.box(innen, p + Vector3(0, 1.8, 0), Vector3(0.9, 0.9, 0.9), t["farbe"], false, 1.4) kristall.rotation = Vector3(0.6, 0.8, 0.0) _regale[ids[i]] = kristall Prims.label(innen, p + Vector3(0, 3.2 + float(reihe) * 0.6, 0), t["name"], 0.36, Color(1, 1, 1)) _interaktion(innen, p + Vector3(0, 1.2, 0), "technik", ids[i], t["name"]) func _gebaeude_missionshalle() -> void: var innen := _gebaeude("Missionshalle", Vector3(0, 0, -28), Vector3(18, 5, 14), Vector3(90, INNEN_Y, 0), Vector3(26, 6, 20), Color(0.74, 0.55, 0.48)) Prims.label(innen, Vector3(90, INNEN_Y + 5.0, -8.5), "Menschen, deren Traum feststeckt.", 0.42, Color(1, 0.92, 0.8)) for i in range(HumanDB.LIST.size()): var h: Dictionary = HumanDB.LIST[i] var p := Vector3(90.0 + (float(i) - 1.5) * 7.0, INNEN_Y, -3.0) Prims.cyl(innen, p + Vector3(0, 0.4, 0), 1.2, 0.8, Color(0.35, 0.28, 0.26)) var saeule := Prims.box(innen, p + Vector3(0, 2.0, 0), Vector3(1.4, 3.2, 1.4), h["farbe"], false, 0.8) var sphere := Prims.sphere(innen, p + Vector3(0, 4.1, 0), 0.55, (h["farbe"] as Color).lightened(0.4), 1.6) var lab := Prims.label(innen, p + Vector3(0, 5.2, 0), h["name"], 0.32, Color(1, 1, 1)) _stelen[h["id"]] = {"saeule": saeule, "kugel": sphere, "label": lab} _interaktion(innen, p + Vector3(0, 1.5, 0), "mission", h["id"], h["name"]) func _gebaeude_meditation() -> void: var innen := _gebaeude("Meditationskammer", Vector3(24, 0, -16), Vector3(14, 5, 14), Vector3(-90, INNEN_Y, 0), Vector3(20, 6, 18), Color(0.46, 0.66, 0.74)) Prims.label(innen, Vector3(-90, INNEN_Y + 5.0, -7.5), "Übung vertieft, was du schon kannst.", 0.42, Color(0.85, 1, 1)) Prims.cyl(innen, Vector3(-90, INNEN_Y + 0.5, -1.0), 3.0, 1.0, Color(0.24, 0.34, 0.40)) var kugel := Prims.sphere(innen, Vector3(-90, INNEN_Y + 2.6, -1.0), 1.2, Color(0.55, 0.95, 1.0), 1.8) kugel.name = "Meditationskugel" _interaktion(innen, Vector3(-90, INNEN_Y + 1.5, -1.0), "vertiefen", "", "Meditationskugel") func _tor_zur_erde() -> void: var pos := Vector3(0, 0, 18) Prims.cyl(self, pos + Vector3(0, 0.3, 0), 5.0, 0.6, Color(0.35, 0.30, 0.50)) for i in range(10): var a := PI * float(i) / 9.0 Prims.box(self, pos + Vector3(cos(a) * 4.2, sin(a) * 4.2 + 0.6, 0), Vector3(0.7, 0.7, 0.7), Color(0.5, 0.85, 1.0), false, 1.8) var scheibe := Prims.cyl(self, pos + Vector3(0, 2.6, 0), 3.0, 0.2, Color(0.45, 0.75, 1.0, 0.28), false, 1.0) scheibe.rotation.x = PI * 0.5 Prims.label(self, pos + Vector3(0, 6.4, 0), "Tor zur Erde", 0.7, Color(0.7, 0.95, 1)) _interaktion(self, pos + Vector3(0, 1.6, 0), "erde", "", "Tor zur Erde") # ---------------------------------------------------------------- Aktualisieren func _refresh() -> void: for id in _regale: var m: MeshInstance3D = _regale[id] var t := TechDB.by_id(id) if Game.knows(id): m.material_override = Prims.mat(t["farbe"], 2.2) m.scale = Vector3.ONE * (1.0 + 0.12 * Game.skill_of(id)) else: m.material_override = Prims.mat((t["farbe"] as Color).darkened(0.35), 0.5) m.scale = Vector3.ONE * 0.75 for id in _stelen: var s: Dictionary = _stelen[id] var h := HumanDB.by_id(id) var lab: Label3D = s["label"] if Game.completed.has(id): s["kugel"].material_override = Prims.mat(Color(0.5, 1.0, 0.6), 2.4) lab.text = h["name"] + "\n★ erfüllt" elif Game.active_mission == id: s["kugel"].material_override = Prims.mat(Color(1, 0.85, 0.35), 2.4) lab.text = h["name"] + "\naktive Mission · %d %%" % int(Game.mission_progress(id)) else: s["kugel"].material_override = Prims.mat((h["farbe"] as Color).lightened(0.4), 1.2) lab.text = h["name"] + "\nwartet"