extends Node3D ## Wurzelknoten: hält Spieler und Oberfläche, wechselt zwischen den Welten ## und wickelt Interaktionen ab. const REICHWEITE_OBJEKT := 4.2 const REICHWEITE_MENSCH := 3.6 var player: Player var ui: UI var welt: Node3D var auf_erde := false var _fokus: Node3D = null var _fokus_mensch: Node3D = null func _ready() -> void: ui = UI.new() add_child(ui) ui.panel_opened.connect(func() -> void: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE player.look_enabled = false) ui.panel_closed.connect(func() -> void: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED player.look_enabled = true) player = Player.new() add_child(player) Game.mission_done.connect(func(_id: String) -> void: Game.notified.emit("Kehre zur Traumwelt zurück — die Säule im Park bringt dich hin.", Color(0.8, 0.95, 1))) _traumwelt() ui.intro_panel(func() -> void: pass) func _traumwelt() -> void: auf_erde = false _setze_welt(DreamWorld.new()) player.set_mode(Player.Mode.TRAUM) player.global_position = (welt as DreamWorld).spawn player.yaw = 0.0 player.pitch = -0.18 func _erde() -> void: auf_erde = true _setze_welt(EarthWorld.new()) player.set_mode(Player.Mode.GEIST) player.global_position = (welt as EarthWorld).spawn player.yaw = 0.0 player.pitch = -0.42 func _setze_welt(neu: Node3D) -> void: if welt != null: remove_child(welt) welt.queue_free() welt = neu add_child(welt) move_child(welt, 0) Game.teleport_lock = 1.0 _fokus = null _fokus_mensch = null func _process(delta: float) -> void: Game.advance_time(delta) Game.teleport_lock = maxf(0.0, Game.teleport_lock - delta) if ui.offen: ui.setze_hinweis("") return _fokus_suchen() _hinweis_setzen() func _fokus_suchen() -> void: _fokus = null _fokus_mensch = null var p := player.global_position var best := REICHWEITE_OBJEKT for n in get_tree().get_nodes_in_group("interactable"): var d: float = p.distance_to((n as Node3D).global_position) if d < best: best = d _fokus = n if auf_erde: var bestm := REICHWEITE_MENSCH for m in (welt as EarthWorld).humans: var d: float = p.distance_to((m as Node3D).global_position + Vector3(0, 1.0, 0)) if d < bestm: bestm = d _fokus_mensch = m if _fokus_mensch != null and (_fokus == null or bestm < best): _fokus = null elif _fokus != null: _fokus_mensch = null func _hinweis_setzen() -> void: if _fokus_mensch != null: ui.setze_hinweis("[E] %s ansprechen — %s" % [_fokus_mensch.data["name"], HumanDB.activity_text(_fokus_mensch.activity)]) elif _fokus != null: var kind: String = _fokus.get_meta("kind") var titel: String = _fokus.get_meta("titel") match kind: "technik": ui.setze_hinweis("[E] %s%s" % [titel, "" if not Game.knows(_fokus.get_meta("arg")) else " (gelernt)"]) "mission": ui.setze_hinweis("[E] %s — Mission ansehen" % titel) "vertiefen": ui.setze_hinweis("[E] Meditieren") "erde": ui.setze_hinweis("[E] Zur Erde reisen") "traum": ui.setze_hinweis("[E] Zurück in die Traumwelt") _: ui.setze_hinweis("[E] %s" % titel) else: ui.setze_hinweis("") func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("ui_cancel") and not ui.offen: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE if \ Input.mouse_mode == Input.MOUSE_MODE_CAPTURED else Input.MOUSE_MODE_CAPTURED player.look_enabled = Input.mouse_mode == Input.MOUSE_MODE_CAPTURED get_viewport().set_input_as_handled() return if ui.offen: return if event is InputEventMouseButton and event.pressed and Input.mouse_mode == Input.MOUSE_MODE_VISIBLE: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED player.look_enabled = true return if event.is_action_pressed("kodex"): ui.kodex_panel() get_viewport().set_input_as_handled() return if event.is_action_pressed("interagieren"): _interagieren() get_viewport().set_input_as_handled() func _interagieren() -> void: if _fokus_mensch != null: ui.anwenden_panel(_fokus_mensch) return if _fokus == null: return var kind: String = _fokus.get_meta("kind") var arg: String = _fokus.get_meta("arg") match kind: "technik": ui.technik_panel(arg) "mission": ui.mission_panel(arg) "vertiefen": ui.vertiefen_panel() "erde": if Game.active_mission == "" and Game.completed.size() < HumanDB.LIST.size(): Game.notified.emit( "Das Tor öffnet sich nur mit einer angenommenen Mission.", Color(1, 0.8, 0.5)) else: _erde() "traum": _traumwelt()