Files
cards/scripts/ui/campaign_screen.gd
Team3 4c6bf96eeb Kampf fortsetzen, Gamepad im Deckbau, Deck-Codes, Kapitel 3, Elementbooster, englische Karten, Host-Wechsel und Zuschauer
- KI-Bewertung mit Bedrohung und Führenden-Bremse (62:38 gegen die alte im Duell, gleichauf zu viert)
- Balance: Sand +1/+1 statt Schild, Erde+Luft und Erde geschwächt, Wasser angehoben, Messlauf mit N=200 möglich
- Einzelspieler-Kämpfe werden laufend gespeichert (voller Spielstand, viewer -1) und im Menü fortgesetzt
- Karten, Deckzeilen und Kartenrücken fokussierbar: Gamepad in Deckbau, Werkstatt und Booster
- Kartennamen (name_en) und Kartentexte übersetzbar, Übersetzungstest deckt cards.gd mit ab
- Deck-Code DINGER1:id*anzahl mit Zwischenablage; acht neue Karten; Kampagne Kapitel 3; Elementbooster 120 Münzen
- Netzwerk: Nachfolge-Host mit vollem Spielstand, Neuverbindung der anderen, Zuschauer (Sicht -2); Bot kann hosten
- Große Schrift: Kartennamen, Kartentext, Knopfleisten, Gegnervorschau, Dialogtext
- Anleitung 1 garantiert ein 1-Energie-Wesen; Tests: DINGER_ONLY für einzelne Oberflächentests
- Oberflächentest auch auf Xephyr mit llvmpipe (wie Xvfb in der CI) grün

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPgKvy5W9WRNFHjkm5QsHx
2026-09-16 18:50:09 +02:00

99 lines
4.5 KiB
GDScript

class_name CampaignScreen
extends Control
var app
var chapter := 1
var perk_box: OptionButton
func _ready() -> void:
var p: Profile = app.profile
chapter = mini(Campaign.chapter(p.campaign_stage), Campaign.CHAPTERS.size())
build()
func build() -> void:
Style.clear(self)
var p: Profile = app.profile
var col := Style.column(self, 1000, 16, 5)
Style.clabel(col, "Kampagne", 34, Style.GOLD, "center", true)
var tabs := Style.row(col, 10)
tabs.alignment = BoxContainer.ALIGNMENT_CENTER
for c in Campaign.CHAPTERS.size():
var b := Style.cbutton(tabs, "Kapitel %d" % (c + 1), Vector2(140, 36), set_chapter.bind(c + 1), Color("285a3c") if chapter == c + 1 else null)
b.disabled = p.campaign_stage < c * Campaign.STAGES.size()
if p.perk_unlocked():
var pr := Style.row(tabs, 8)
Style.clabel(pr, "Dein Merkmal:", 15, Style.MUTED, "right", false, 110)
perk_box = OptionButton.new()
perk_box.custom_minimum_size = Vector2(300, 36)
perk_box.add_item("keins")
var keys: Array = Game.PERKS.keys()
for k in keys:
perk_box.add_item(Game.PERKS[k])
perk_box.select(keys.find(p.perk) + 1 if p.perk != "" else 0)
perk_box.item_selected.connect(func(i: int):
p.perk = "" if i == 0 else keys[i - 1]
app.save())
pr.add_child(perk_box)
var intro := ["Zehn Magier je Kapitel. Jede Stufe bringt mehr Gegner an den Tisch. Bosse haben Merkmale (★).",
"Die Magier kehren mit zwei Merkmalen und größerem Gefolge zurück.",
"Kapitel 3: drei Merkmale, volle Tische und die stärksten Decks."]
Style.clabel(col, intro[chapter - 1], 14, Style.MUTED)
var offset := (chapter - 1) * Campaign.STAGES.size()
for k in Campaign.STAGES.size():
var i := offset + k
var st := Campaign.stage(i)
var done := i < p.campaign_stage
var next := i == p.campaign_stage
var panel := PanelContainer.new()
panel.add_theme_stylebox_override("panel", Style.box(Style.PANEL if not done else Style.darker(Style.PANEL, 0.8), 6,
Style.GOLD if next else null, 2 if next else 0))
col.add_child(panel)
var r := Style.row(panel, 10)
r.custom_minimum_size = Vector2(0, 50)
Style.clabel(r, str(i + 1), 18, Style.GOLD if next else Style.MUTED, "center", true, 36)
Style.clabel(r, "%s · %s" % [st.name, st.title], 16, Style.TEXT if not done else Style.MUTED, "left", true, 290)
var dots := Control.new()
dots.custom_minimum_size = Vector2(50, 0)
dots.mouse_filter = Control.MOUSE_FILTER_IGNORE
var elems: Array = st.elements
dots.draw.connect(func():
for m in elems.size():
dots.draw_circle(Vector2(10 + m * 18, dots.size.y / 2), 7, Cards.ELEMENT_COLORS[elems[m]]))
r.add_child(dots)
var extra: int = mini(st.extra, Game.MAX_OPPONENTS - 1)
var table: String = "Duell" if extra == 0 else "%d am Tisch" % (extra + 2)
var perks_text: String = ", ".join(st.perks.map(func(pk): return Game.PERKS[pk]))
var target := Campaign.target_rating(i, p.target_rating())
Style.clabel(r, "%s · Stärke %.1f · %d Münzen\n★ %s" % [table, target, st.reward, perks_text], 12, Style.MUTED, "left", false, 360)
if done:
Style.clabel(r, "abgeschlossen", 13, Style.GREEN, "right", false, 100)
Style.cbutton(r, "Wiederholen", Vector2(130, 36), _start.bind(i))
elif next:
Style.clabel(r, "", 13, Style.GREEN, "right", false, 100)
Style.cbutton(r, "Kämpfen", Vector2(130, 36), _start.bind(i), Color("285a3c"))
else:
Style.clabel(r, "", 13, Style.GREEN, "right", false, 100)
var b := Style.cbutton(r, "Gesperrt", Vector2(130, 36), func(): pass)
b.disabled = true
if p.campaign_stage >= Campaign.total():
Style.clabel(col, "Alle drei Kapitel abgeschlossen. Der Archimagier ist endgültig besiegt!", 16, Style.GREEN, "center", true)
var br := Style.row(col)
br.alignment = BoxContainer.ALIGNMENT_CENTER
Style.cbutton(br, "Zurück", Vector2(160, 40), func(): app.show_screen(MenuScreen.new()))
func set_chapter(c: int) -> void:
chapter = c
build()
func _start(stage: int) -> void:
app.show_screen(BattleScreen.new(0, stage))
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE:
app.show_screen(MenuScreen.new())