extends MainMenu ## The Phase 20A menu shell retitled for Champions of Luneraria. Match options here are ## the new mode's options (own Bund, lane, seed); they never touch the legacy GameState. signal host_requested(port: int, display_name: String) signal join_requested(address: String, port: int, display_name: String) var bund: String = "wurzelbund" var lane: String = "mid" var lane_choice: ChoiceGroup var _net_name: LineEdit var _net_address: LineEdit var _net_port: LineEdit func _ready() -> void: super._ready() title_label.text = "CHAMPIONS" subtitle_label.text = "OF LUNERARIA" subtitle_label.theme_type_variation = "TitleLabel" subtitle_label.add_theme_font_size_override("font_size", 54) title_label.add_theme_font_size_override("font_size", 64) var tagline := Label.new() tagline.text = "DREI LANES · 3 GEGEN 3 · AUTOBATTLER" tagline.theme_type_variation = "SubtitleLabel" brand_names.add_child(tagline) lore_label.text = "Führe deine Armee über drei Lanes. Die Partie endet erst, wenn ein Ancient fällt." emblem_rect.texture = load("res://assets/ui/emblems/luneraria.svg") version_label.text = "Prototyp %s · 1 Mensch + 5 Bots oder 6 über Direktverbindung" % str(ProjectSettings.get_setting("application/config/version", "")) _title_caption.text = "Glutpakt und Wurzelbund an den Ufern der Grünen Kluft" _retarget_setup() func _retarget_setup() -> void: # Replace the Saumwacht-only options (match length, rival, AI level, timed build). faction_choice.item_selected.disconnect(faction_choice.item_selected.get_connections()[0].callable) faction_choice.item_selected.connect(func(index: int) -> void: bund = DataCatalog.FACTIONS[index] sync()) var body: VBoxContainer = mode_choice.get_parent() var at: int = mode_choice.get_index() - 1 for node: Node in [mode_choice, length_summary, _advanced_button.get_parent(), _advanced]: node.visible = false body.get_child(at).visible = false var heading := Label.new() heading.text = "DEINE LANE" heading.theme_type_variation = "SectionLabel" body.add_child(heading) body.move_child(heading, at) lane_choice = ChoiceGroup.new(true) lane_choice.add_option("Top", "oberer Korridor") lane_choice.add_option("Mid", "direkter Weg") lane_choice.add_option("Bottom", "unterer Korridor") body.add_child(lane_choice) body.move_child(lane_choice, at + 1) lane_choice.item_selected.connect(func(index: int) -> void: lane = LuneMap.LANES[index] sync()) var rules := Label.new() rules.theme_type_variation = "MutedLabel" rules.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART rules.text = "Team Blau (Südwest) mit zwei Bot-Verbündeten gegen drei Bots in Team Rot. Kein Rundenlimit: Es gewinnt, wer den gegnerische Ancient zerstört. Für sechs Menschen hosten oder beitreten; freie Plätze bleiben Bots. Der Host ist autoritativ." body.add_child(rules) body.move_child(rules, at + 2) var net_heading := Label.new() net_heading.text = "NETZWERK · DIREKTVERBINDUNG" net_heading.theme_type_variation = "SectionLabel" body.add_child(net_heading) _net_name = LineEdit.new() _net_name.placeholder_text = "Anzeigename" _net_name.text = "Spieler" body.add_child(_net_name) var net_row := HBoxContainer.new() _net_address = LineEdit.new() _net_address.placeholder_text = "Host-Adresse" _net_address.text = "127.0.0.1" _net_address.size_flags_horizontal = Control.SIZE_EXPAND_FILL _net_port = LineEdit.new() _net_port.placeholder_text = "Port" _net_port.text = "24571" _net_port.custom_minimum_size.x = 90 net_row.add_child(_net_address) net_row.add_child(_net_port) body.add_child(net_row) var buttons := HBoxContainer.new() var host_btn := Button.new() host_btn.text = "Hosten" host_btn.tooltip_text = "Partie eröffnen. Freie Plätze sind Bots." host_btn.pressed.connect(func() -> void: host_requested.emit(int(_net_port.text), _net_name.text)) var join_btn := Button.new() join_btn.text = "Beitreten" join_btn.tooltip_text = "Mit Host und Port verbinden." join_btn.pressed.connect(func() -> void: join_requested.emit(_net_address.text.strip_edges(), int(_net_port.text), _net_name.text)) buttons.add_child(host_btn) buttons.add_child(join_btn) body.add_child(buttons) func sync() -> void: super.sync() if lane_choice == null: return faction_choice.select(DataCatalog.FACTIONS.find(bund)) lane_choice.select(LuneMap.LANES.find(lane)) _style_heading.text = "SPIELWEISE · " + DataCatalog.FACTION_NAMES[bund].to_upper() var lines: PackedStringArray = [] for fact: String in FactionChoice.PROFILES[bund].facts: lines.append("• " + fact) _style_facts.text = "\n".join(lines) _timed_hint.text = "Planung wartet auf dich · Leertaste startet den Kampf" var names: PackedStringArray = [] for entry: Array in Stage.SETUPS[bund].figures: names.append(str(DataCatalog.get_unit(entry[0]).display_name)) _setup_caption.text = "IM BILD " + " · ".join(names) if screen == Screen.SETUP and _active and stage.current_shot() != bund: stage.set_shot_named(bund, reduced_motion) func _setup_shot() -> String: return bund func _on_title_primary() -> void: show_screen(Screen.SETUP)