saumwacht-godot/scripts/ui/components/faction_choice.gd
Martin Stickelbroeck c2b447610c Baseline: Saumwacht 0.15.0 (Phase 20A) vor dem Umbau zu Champions of Luneraria
Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern
unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore
unversioniert; letztere sind unter ../backups gesichert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:00:36 +02:00

143 lines
5.6 KiB
GDScript

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 ""