class_name FactionChoice extends HBoxContainer ## Selectable Bund cards with the OptionButton surface used by tools and tests. ## Index order follows DataCatalog.FACTIONS. Selected cards carry a text badge, ## a double frame and full-colour emblems; the others show a quiet "Wählen" hint. signal item_selected(index: int) # Play-style summaries are taken from DataCatalog ability texts; no invented mechanics. const PROFILES: Dictionary = { "glutpakt": {"emblem": "res://assets/ui/emblems/glutpakt.svg", "motto": "Schutz, Brand und Flächenschaden", "facts": ["Basaltschilde senken erlittenen Schaden, vor allem zu Kampfbeginn", "Glutklingen setzen bei jedem 3. Treffer Brand", "Aschenwerfer treffen mehrere Ziele, Herdhüter stärken Verbündete"]}, "wurzelbund": {"emblem": "res://assets/ui/emblems/wurzelbund.svg", "motto": "Heilung, Ranken und Keimbrand", "facts": ["Holzpanzer heilen sich, sobald sie verwundet sind", "Ranken verlangsamen Gegner", "Heiler versorgen Verbündete in 4 bis 4,5 m, Samenschützen setzen Keimbrand"]}, } var selected: int = -1 var cards: Array[Button] = [] var _badges: Array[Control] = [] var _hints: Array[Label] = [] var _emblems: Array[TextureRect] = [] var _group := ButtonGroup.new() func _ready() -> void: add_theme_constant_override("separation", 16) for id: String in DataCatalog.FACTIONS: _make_card(id) func _make_card(id: String) -> void: var profile: Dictionary = PROFILES[id] var card := Button.new() card.name = "Card_" + id card.theme_type_variation = "FactionCard" card.toggle_mode = true card.button_group = _group card.focus_mode = Control.FOCUS_ALL card.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND card.size_flags_horizontal = Control.SIZE_EXPAND_FILL card.custom_minimum_size = Vector2(220, 236) card.tooltip_text = "%s wählen · Startformation %d Gold" % [DataCatalog.FACTION_NAMES[id], starter_cost(id)] var content := VBoxContainer.new() content.mouse_filter = Control.MOUSE_FILTER_IGNORE content.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) content.offset_left = 16 content.offset_right = -16 content.offset_top = 18 content.offset_bottom = -14 content.add_theme_constant_override("separation", 6) card.add_child(content) var emblem := TextureRect.new() emblem.texture = load(profile.emblem) emblem.expand_mode = TextureRect.EXPAND_IGNORE_SIZE emblem.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED emblem.custom_minimum_size = Vector2(84, 84) emblem.mouse_filter = Control.MOUSE_FILTER_IGNORE content.add_child(emblem) var title := Label.new() title.text = DataCatalog.FACTION_NAMES[id] title.theme_type_variation = "CardTitleLabel" title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER title.mouse_filter = Control.MOUSE_FILTER_IGNORE content.add_child(title) var motto := Label.new() motto.text = profile.motto motto.theme_type_variation = "LoreLabel" motto.add_theme_font_size_override("font_size", 18) motto.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER motto.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART motto.mouse_filter = Control.MOUSE_FILTER_IGNORE content.add_child(motto) var spacer := Control.new() spacer.size_flags_vertical = Control.SIZE_EXPAND_FILL spacer.mouse_filter = Control.MOUSE_FILTER_IGNORE content.add_child(spacer) var foot := CenterContainer.new() foot.mouse_filter = Control.MOUSE_FILTER_IGNORE content.add_child(foot) var states := HBoxContainer.new() states.mouse_filter = Control.MOUSE_FILTER_IGNORE foot.add_child(states) var badge := PanelContainer.new() badge.theme_type_variation = "BadgePanel" badge.mouse_filter = Control.MOUSE_FILTER_IGNORE var badge_row := HBoxContainer.new() badge_row.mouse_filter = Control.MOUSE_FILTER_IGNORE badge_row.add_theme_constant_override("separation", 6) badge.add_child(badge_row) var mark := TextureRect.new() mark.texture = preload("res://assets/ui/controls/choice_on.svg") mark.expand_mode = TextureRect.EXPAND_IGNORE_SIZE mark.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED mark.custom_minimum_size = Vector2(12, 12) mark.modulate = Color("1a120a") mark.mouse_filter = Control.MOUSE_FILTER_IGNORE badge_row.add_child(mark) var badge_text := Label.new() badge_text.text = "DEIN BUND" badge_text.theme_type_variation = "BadgeLabel" badge_text.mouse_filter = Control.MOUSE_FILTER_IGNORE badge_row.add_child(badge_text) states.add_child(badge) var hint := Label.new() hint.text = "Wählen" hint.theme_type_variation = "MutedLabel" hint.add_theme_font_size_override("font_size", 14) hint.mouse_filter = Control.MOUSE_FILTER_IGNORE states.add_child(hint) content.minimum_size_changed.connect(func() -> void: card.custom_minimum_size.y = maxf(236.0, content.get_combined_minimum_size().y + 32.0)) var index: int = cards.size() card.pressed.connect(func() -> void: if selected != index: select(index) item_selected.emit(index)) add_child(card) cards.append(card) _badges.append(badge) _hints.append(hint) _emblems.append(emblem) static func starter_cost(id: String) -> int: var ids: Array[String] = DataCatalog.faction_ids(id) return int(DataCatalog.UNITS[ids[0]].cost + DataCatalog.UNITS[ids[1]].cost + DataCatalog.UNITS[ids[2]].cost) func select(index: int) -> void: if index < 0 or index >= cards.size(): return selected = index for i: int in range(cards.size()): var on: bool = i == index cards[i].set_pressed_no_signal(on) _badges[i].visible = on _hints[i].visible = not on _emblems[i].modulate = Color.WHITE if on else Color(.72, .70, .66) func focus_selected() -> void: if selected >= 0: cards[selected].grab_focus() func selected_id() -> String: return DataCatalog.FACTIONS[selected] if selected >= 0 else ""