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>
143 lines
5.6 KiB
GDScript
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 ""
|