extends CanvasLayer ## Startmenü: Einzelspieler, Mehrspieler (Host/Client mit Lobby), Beenden. const BOT_NAMES_MAX := 7 var screens: Dictionary = {} # Einzelspieler var solo_bots: SpinBox # Mehrspieler var name_edit: LineEdit var ip_edit: LineEdit var multi_bots: SpinBox var lobby_list: Label var status: Label var host_btn: Button var join_btn: Button var start_btn: Button var leave_btn: Button func _ready() -> void: var root := Control.new() root.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) add_child(root) var bg := ColorRect.new() bg.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) bg.color = Color(0.05, 0.06, 0.09) root.add_child(bg) screens["main"] = _screen(root, _build_main()) screens["single"] = _screen(root, _build_single()) screens["multi"] = _screen(root, _build_multi()) Net.lobby_changed.connect(_refresh) Net.connection_failed.connect(_on_failed) Net.server_closed.connect(_on_closed) _show("main") # ------------------------------------------------------------ Aufbau func _screen(root: Control, content: Control) -> CenterContainer: var cc := CenterContainer.new() cc.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) cc.add_child(content) root.add_child(cc) return cc func _show(which: String) -> void: for key: String in screens: screens[key].visible = key == which if which == "multi": _refresh() func _box(width: int) -> VBoxContainer: var v := VBoxContainer.new() v.custom_minimum_size = Vector2(width, 0) v.add_theme_constant_override("separation", 10) return v func _text(t: String, size: int, col := Color.WHITE) -> Label: var l := Label.new() l.text = t l.add_theme_font_size_override("font_size", size) l.add_theme_color_override("font_color", col) l.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER return l func _row(caption: String, ctrl: Control) -> HBoxContainer: var h := HBoxContainer.new() var l := Label.new() l.text = caption l.custom_minimum_size = Vector2(150, 0) h.add_child(l) ctrl.size_flags_horizontal = Control.SIZE_EXPAND_FILL h.add_child(ctrl) return h func _button(text: String, parent: Control, action: Callable) -> Button: var b := Button.new() b.text = text b.custom_minimum_size = Vector2(0, 42) b.size_flags_horizontal = Control.SIZE_EXPAND_FILL b.pressed.connect(action) parent.add_child(b) return b func _title(box: VBoxContainer) -> void: box.add_child(_text("LIAR'S DICE 3D", 40)) box.add_child(_text("Würfeln - Bluffen - Boostern", 16, Color(0.6, 0.63, 0.7))) box.add_child(HSeparator.new()) func _build_main() -> Control: var box := _box(360) _title(box) _button("Einzelspieler", box, _show.bind("single")) _button("Mehrspieler", box, _show.bind("multi")) _button("Beenden", box, func() -> void: get_tree().quit()) return box func _build_single() -> Control: var box := _box(400) _title(box) box.add_child(_text("Einzelspieler", 22, Color(1.0, 0.82, 0.32))) solo_bots = SpinBox.new() solo_bots.min_value = 1 solo_bots.max_value = BOT_NAMES_MAX solo_bots.value = 3 box.add_child(_row("Bots", solo_bots)) box.add_child(_text("Ohne Netzwerk - du spielst allein gegen die Bots.", 13, Color(0.55, 0.58, 0.65))) box.add_child(HSeparator.new()) var row := HBoxContainer.new() row.add_theme_constant_override("separation", 8) box.add_child(row) _button("Starten", row, _on_solo_start) _button("Zurück", row, _show.bind("main")) return box func _build_multi() -> Control: var box := _box(440) _title(box) box.add_child(_text("Mehrspieler", 22, Color(1.0, 0.82, 0.32))) name_edit = LineEdit.new() name_edit.text = "Spieler" name_edit.placeholder_text = "Dein Name" box.add_child(_row("Name", name_edit)) ip_edit = LineEdit.new() ip_edit.text = "127.0.0.1" box.add_child(_row("Server-IP", ip_edit)) multi_bots = SpinBox.new() multi_bots.min_value = 0 multi_bots.max_value = BOT_NAMES_MAX multi_bots.value = 1 box.add_child(_row("Bots (nur Host)", multi_bots)) var brow := HBoxContainer.new() brow.add_theme_constant_override("separation", 8) box.add_child(brow) host_btn = _button("Spiel hosten", brow, _on_host) join_btn = _button("Beitreten", brow, _on_join) box.add_child(HSeparator.new()) box.add_child(_text("Lobby", 18, Color(1.0, 0.82, 0.32))) lobby_list = _text("-", 15, Color(0.85, 0.87, 0.92)) box.add_child(lobby_list) var arow := HBoxContainer.new() arow.add_theme_constant_override("separation", 8) box.add_child(arow) start_btn = _button("Spiel starten", arow, _on_start) leave_btn = _button("Trennen", arow, _on_leave) _button("Zurück", box, _on_back) status = _text("", 14, Color(0.95, 0.55, 0.5)) box.add_child(status) return box # ------------------------------------------------------------ Aktionen func _on_solo_start() -> void: Net.start_singleplayer("Spieler", int(solo_bots.value)) func _on_host() -> void: status.text = "" if Net.host_game(name_edit.text.strip_edges()): status.text = "Server läuft auf Port %d. Warte auf Mitspieler." % Net.PORT func _on_join() -> void: status.text = "Verbinde..." Net.join_game(ip_edit.text.strip_edges(), name_edit.text.strip_edges()) func _on_leave() -> void: Net.leave() status.text = "" func _on_back() -> void: if Net.is_online(): Net.leave() status.text = "" _show("main") func _on_start() -> void: var humans: int = Net.lobby.size() var ai: int = mini(int(multi_bots.value), Net.MAX_HUMANS - humans) if humans + ai < 2: status.text = "Mindestens 2 Spieler nötig (Mitspieler oder Bots)." return Net.start_game(ai) func _on_failed(msg: String) -> void: status.text = msg _refresh() func _on_closed() -> void: status.text = "Server hat die Verbindung beendet." _refresh() func _refresh() -> void: if status == null: return var connected := Net.is_online() host_btn.disabled = connected join_btn.disabled = connected leave_btn.disabled = not connected start_btn.disabled = not (connected and Net.is_host) multi_bots.editable = not connected or Net.is_host if Net.lobby.is_empty(): lobby_list.text = "- nicht verbunden -" else: var names: Array = [] for id: int in Net.lobby: names.append("%s%s" % [Net.lobby[id], " (Host)" if id == 1 else ""]) lobby_list.text = "\n".join(names)