From 89db101137825398e52c4c9d717d7d0b1236597a Mon Sep 17 00:00:00 2001 From: Team3 Date: Thu, 17 Sep 2026 21:37:58 +0200 Subject: [PATCH] Erfolge entfernt, der Bildschirm zeigt nur noch Statistik MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Die dreizehn Erfolge samt Belohnungen, Meldungen und Spielstandfeld sind weg - Der bisherige Erfolgs-Bildschirm heißt Statistik und zeigt Kämpfe, Tagesaufgabe, Bestenliste, beste Karten und den CSV-Export Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01QPgKvy5W9WRNFHjkm5QsHx --- README.md | 8 +- anforderungen.md | 2 +- scripts/profile.gd | 77 +----------------- scripts/ui/achievements_screen.gd.uid | 1 - scripts/ui/menu_screen.gd | 2 +- ...achievements_screen.gd => stats_screen.gd} | 18 +--- scripts/ui/stats_screen.gd.uid | 1 + tests/test_runner.gd | 21 ++--- tests/ui_test.gd | 17 ++-- translations/ui.csv | 2 +- translations/ui.en.translation | Bin 10076 -> 10076 bytes 11 files changed, 29 insertions(+), 120 deletions(-) delete mode 100644 scripts/ui/achievements_screen.gd.uid rename scripts/ui/{achievements_screen.gd => stats_screen.gd} (67%) create mode 100644 scripts/ui/stats_screen.gd.uid diff --git a/README.md b/README.md index 4ed6c97..e8850b0 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Der Spielstand liegt unter `user://spielstand.json` - 100 Karten in `data/karten.json`: 4 Elemente, 10 Zweier-Kombos (auch gleiche Elemente), 4 mythische Dreifach-Kombos, 4 Fallen - Resonanz: gleiche Elemente auf dem Feld verstärken sich. Feldkombos: verschiedene Elemente lösen beim Ausspielen Effekte aus - Fallen liegen verdeckt und lösen im gegnerischen Zug aus (die KI kennt fremde Fallen nicht) -- Jeder gegen jeden mit ausgeloster Zugreihenfolge, 1 bis 5 KI-Gegner (KI mit Vorausschau), Kampagne mit 10 Magiern, Erfolge, Tagesaufgabe +- Jeder gegen jeden mit ausgeloster Zugreihenfolge, 1 bis 5 KI-Gegner (KI mit Vorausschau), Kampagne mit 10 Magiern je Kapitel, Tagesaufgabe - Booster, fünf Deck-Slots, Werkstatt (Zerlegen und Herstellen aus Staub), Einstellungen (Ton, KI-Tempo, Animationen) - Spielstand versioniert mit Sicherungskopie (`spielstand.json.bak`) - Anleitung (geführte erste Partie), Mulligan im ersten Zug, Tastatur (Leertaste, 1 bis 9, Esc, Enter) @@ -66,7 +66,7 @@ Der Spielstand liegt unter `user://spielstand.json` `tests/run_headless.sh` führt Import, statische Prüfung (`tests/lint.gd`) und Headless-Prüfungen aus. `.github/workflows/tests.yml`: Headless und schneller Fenster-Test bei jedem Push, voller Fenster-Test und Archetypen-Messung nachts um 3 Uhr oder von Hand (Xvfb, lokal nicht geprüft). `DINGER_FAST=1` lässt den Fenster-Test ohne die langen Kämpfe laufen (etwa ein Drittel der Zeit). -Statistiken aus Spieltests lassen sich unter Erfolge als CSV exportieren. +Statistiken aus Spieltests lassen sich unter Statistik als CSV exportieren. ``` godot --headless --path . --import # einmalig nach dem Klonen: Ressourcen importieren (macht start.sh auch) @@ -98,9 +98,9 @@ godot --headless --path . --export-release Windows build/dinger-windows.exe - `scripts/deckgen.gd` – Deckstärke, Gegnerdecks entlang der Energiekurve, Archetypen - `scripts/netstate.gd` – Zustandsbilder fürs Netzwerk - `scripts/ai.gd` – KI mit Vorausschau (plus gierige Vergleichs-KI) -- `scripts/profile.gd` – Spielstand (versioniert), Booster, Erfolge, Tagesaufgabe, Einstellungen +- `scripts/profile.gd` – Spielstand (versioniert), Booster, Tagesaufgabe, Einstellungen - `scripts/campaign.gd` – Kampagnenstufen -- `scripts/ui/` – Oberfläche: Menü, Gegnerauswahl, Kampagne, Lobby, Booster, Deckbau, Werkstatt, Kampf (Bildschirm, Layout, Effekte, Anleitung, Mulligan, Gamepad), Erfolge, Einstellungen, Regeln, Ton +- `scripts/ui/` – Oberfläche: Menü, Gegnerauswahl, Kampagne, Lobby, Booster, Deckbau, Werkstatt, Kampf (Bildschirm, Layout, Effekte, Anleitung, Mulligan, Gamepad), Statistik, Einstellungen, Regeln, Ton - `scenes/main.tscn` – Startszene - `scripts/net.gd` – Netzwerkspiel (ENet) mit Wiederverbinden - `translations/ui.csv` – englische Oberflächentexte diff --git a/anforderungen.md b/anforderungen.md index 76cb55e..bcc9986 100644 --- a/anforderungen.md +++ b/anforderungen.md @@ -5,7 +5,7 @@ - PC-Spiel - Jeder gegen jeden: Spieler und 1 bis 5 KI-Gegner (oder Spieler), alle mit gleichen Regeln - Einzelspieler-Knopf führt zur Auswahl der Gegnerzahl -- Kampagne gegen benannte Magier, Erfolge und Tagesaufgaben als Fortschritt +- Kampagne gegen benannte Magier und Tagesaufgaben als Fortschritt - Im lokalen Netz zu mehreren spielbar, auch als Zuschauer - Ein unterbrochener Kampf lässt sich später fortsetzen - Geführte erste Partie als Einstieg diff --git a/scripts/profile.gd b/scripts/profile.gd index 78dae17..f38b6ef 100644 --- a/scripts/profile.gd +++ b/scripts/profile.gd @@ -1,6 +1,6 @@ class_name Profile extends RefCounted -## Spielstand: Sammlung, Münzen, Decks, Staub, Booster, Statistik, Erfolge, Tagesaufgabe, Einstellungen. +## Spielstand: Sammlung, Münzen, Decks, Staub, Booster, Statistik, Tagesaufgabe, Einstellungen. const SAVE_VERSION := 5 const PITY_BOOSTERS := 20 # danach ist eine mythische Karte garantiert @@ -24,22 +24,6 @@ const DIFFICULTIES := { const DUST_DISMANTLE := {"gewöhnlich": 5, "selten": 20, "episch": 100, "legendär": 400, "mythisch": 1600} const DUST_CRAFT := {"gewöhnlich": 40, "selten": 100, "episch": 400, "legendär": 1600, "mythisch": 3200} -const ACHIEVEMENTS := [ - {"id": "erster_sieg", "name": "Erster Sieg", "text": "Gewinne einen Kampf.", "reward": 50}, - {"id": "duellant", "name": "Duellant", "text": "Gewinne ein Duell.", "reward": 50}, - {"id": "tischherr", "name": "Herr des Tisches", "text": "Gewinne gegen 3 oder mehr Gegner.", "reward": 100}, - {"id": "chaosmeister", "name": "Chaosmeister", "text": "Gewinne gegen 5 Gegner.", "reward": 200}, - {"id": "sammler", "name": "Sammler", "text": "Besitze 50 verschiedene Karten.", "reward": 100}, - {"id": "vollstaendig", "name": "Vollständig", "text": "Besitze jede Karte.", "reward": 500}, - {"id": "boosterfreund", "name": "Boosterfreund", "text": "Öffne 10 Booster.", "reward": 100}, - {"id": "elementarist", "name": "Elementarist", "text": "Gewinne mit einem Deck aus nur einem Element.", "reward": 100}, - {"id": "kombokoenig", "name": "Kombokönig", "text": "Gewinne mit mindestens 6 Kombokarten im Deck.", "reward": 100}, - {"id": "kampagnenheld", "name": "Kampagnenheld", "text": "Schließe Kapitel 1 der Kampagne ab.", "reward": 300}, - {"id": "elementmeister", "name": "Meister der Elemente", "text": "Schließe Kapitel 2 der Kampagne ab.", "reward": 500}, - {"id": "archimagier", "name": "Archimagier", "text": "Schließe Kapitel 3 der Kampagne ab.", "reward": 800}, - {"id": "serie", "name": "Siegesserie", "text": "Gewinne fünf Kämpfe in Folge.", "reward": 150}, -] - const DAILY_TASKS := [ {"id": "sieg", "kind": "win", "text": "Gewinne einen Kampf", "goal": 1, "reward": 80}, {"id": "kaempfe", "kind": "game", "text": "Bestreite zwei Kämpfe", "goal": 2, "reward": 60}, @@ -63,11 +47,10 @@ var collection := {} # id -> Anzahl var decks: Array = [] # DECK_SLOTS Einträge {"name": String, "cards": Array von ids} var active_deck := 0 var stats := {"games": 0, "wins": 0, "boosters": 0, "wins_by_opp": {}} -var achievements: Array = [] var campaign_stage := 0 # Anzahl abgeschlossener Kampagnenstufen var daily := {"date": "", "task": "", "progress": 0, "done": false} var settings := {"volume": 0.8, "music": 0.5, "ai_speed": 1.0, "animations": true, "language": "de", "difficulty": "normal", "big_font": false} -var notices: Array[String] = [] # Meldungen für die Oberfläche (Erfolge, Tagesaufgabe) +var notices: Array[String] = [] # Meldungen für die Oberfläche (Tagesaufgabe, Fortschritt) var card_stats := {} # id -> {"played", "games", "wins"} var booster_since_mythic := 0 var tutorial_done := false @@ -151,8 +134,6 @@ static func from_dict(d: Dictionary) -> Profile: p.stats.boosters = int(st.get("boosters", 0)) for k in st.get("wins_by_opp", {}): p.stats.wins_by_opp[str(k)] = int(st.wins_by_opp[k]) - for a in d.get("achievements", []): - p.achievements.append(str(a)) p.campaign_stage = int(d.get("campaign_stage", 0)) var dl = d.get("daily", {}) p.daily = {"date": str(dl.get("date", "")), "task": str(dl.get("task", "")), @@ -186,7 +167,7 @@ static func from_dict(d: Dictionary) -> Profile: func to_dict() -> Dictionary: return {"version": SAVE_VERSION, "coins": coins, "dust": dust, "collection": collection, "decks": decks, "active_deck": active_deck, - "stats": stats, "achievements": achievements, "campaign_stage": campaign_stage, + "stats": stats, "campaign_stage": campaign_stage, "daily": daily, "settings": settings, "card_stats": card_stats, "booster_since_mythic": booster_since_mythic, "tutorial_done": tutorial_done, "perk": perk, "records": records, "tutorial2_done": tutorial2_done} @@ -320,7 +301,6 @@ func craft(cid: String) -> String: dust -= cost collection[cid] = collection.get(cid, 0) + 1 daily_event("craft") - check_achievements() return "" @@ -404,11 +384,10 @@ func open_booster(r: RandomNumberGenerator = null, element: String = "") -> Arra collection[c.id] = collection.get(c.id, 0) + 1 stats.boosters += 1 daily_event("booster") - check_achievements() return cards -# --- Kampfergebnis, Erfolge, Tagesaufgabe ------------------------------------------- +# --- Kampfergebnis, Tagesaufgabe ------------------------------------------- ## Verbucht ein Kampfergebnis und gibt die Münzbelohnung zurück. ## stage >= 0: Kampagnenstufe; ein erster Sieg schaltet die nächste Stufe frei. @@ -459,7 +438,6 @@ func record_battle(won: bool, n_opp: int, deck_used: Array, stage: int = -1, pla daily_event("win_vs3") for e in Game.deck_elements(deck_used): daily_event("win_element:" + e) - check_achievements({"won": won, "n_opp": n_opp, "deck": deck_used}) return reward @@ -469,53 +447,6 @@ func _stat(cid: String) -> Dictionary: return card_stats[cid] -func check_achievements(ctx: Dictionary = {}) -> Array: - var unlocked := [] - for a in ACHIEVEMENTS: - if a.id in achievements: - continue - if _achieved(a.id, ctx): - achievements.append(a.id) - coins += a.reward - unlocked.append(a) - notices.append("Erfolg: %s (+%d Münzen)" % [a.name, a.reward]) - return unlocked - - -func _achieved(id: String, ctx: Dictionary) -> bool: - var won: bool = ctx.get("won", false) - var n: int = ctx.get("n_opp", 0) - var deck_used: Array = ctx.get("deck", []) - match id: - "erster_sieg": - return stats.wins >= 1 - "duellant": - return won and n == 1 - "tischherr": - return won and n >= 3 - "chaosmeister": - return won and n == 5 - "sammler": - return distinct_owned() >= 50 - "vollstaendig": - return distinct_owned() >= Cards.all().size() - "boosterfreund": - return stats.boosters >= 10 - "elementarist": - return won and Game.deck_elements(deck_used).size() == 1 - "kombokoenig": - return won and deck_used.filter(func(c): return c.is_combo()).size() >= 6 - "kampagnenheld": - return campaign_stage >= Campaign.STAGES.size() - "elementmeister": - return campaign_stage >= 2 * Campaign.STAGES.size() - "archimagier": - return campaign_stage >= Campaign.total() - "serie": - return records.best_streak >= 5 - return false - - func difficulty() -> Dictionary: return DIFFICULTIES.get(settings.get("difficulty", "normal"), DIFFICULTIES.normal) diff --git a/scripts/ui/achievements_screen.gd.uid b/scripts/ui/achievements_screen.gd.uid deleted file mode 100644 index a1cfb54..0000000 --- a/scripts/ui/achievements_screen.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cw4rtcukefdl8 diff --git a/scripts/ui/menu_screen.gd b/scripts/ui/menu_screen.gd index 886a7ae..53825ee 100644 --- a/scripts/ui/menu_screen.gd +++ b/scripts/ui/menu_screen.gd @@ -46,7 +46,7 @@ func _ready() -> void: Style.cbutton(grid, "Booster öffnen", sz, func(): app.show_screen(BoosterScreen.new())) Style.cbutton(grid, "Deck bauen", sz, func(): app.show_screen(DeckScreen.new())) Style.cbutton(grid, "Werkstatt", sz, func(): app.show_screen(WorkshopScreen.new())) - Style.cbutton(grid, "Erfolge", sz, func(): app.show_screen(AchievementsScreen.new())) + Style.cbutton(grid, "Statistik", sz, func(): app.show_screen(StatsScreen.new())) Style.cbutton(grid, "Regeln", sz, func(): app.show_screen(RulesScreen.new())) Style.cbutton(grid, "Einstellungen", sz, func(): app.show_screen(SettingsScreen.new())) Style.cbutton(grid, "Beenden", sz, func(): get_tree().quit()) diff --git a/scripts/ui/achievements_screen.gd b/scripts/ui/stats_screen.gd similarity index 67% rename from scripts/ui/achievements_screen.gd rename to scripts/ui/stats_screen.gd index 2ca1f1d..05dc013 100644 --- a/scripts/ui/achievements_screen.gd +++ b/scripts/ui/stats_screen.gd @@ -1,5 +1,6 @@ -class_name AchievementsScreen +class_name StatsScreen extends Control +## Statistik: Kämpfe, Tagesaufgabe, Bestenliste, beste Karten und CSV-Export. var app var export_label: Label @@ -8,7 +9,7 @@ var export_label: Label func _ready() -> void: var p: Profile = app.profile var col := Style.column(self, 900, 12, 4) - Style.clabel(col, "Erfolge", 32, Style.GOLD, "center", true) + Style.clabel(col, "Statistik", 32, Style.GOLD, "center", true) var st: Dictionary = p.stats Style.clabel(col, "Kämpfe %d · Siege %d · Booster %d · Kampagne %d/%d" % [ st.games, st.wins, st.boosters, p.campaign_stage, Campaign.total()], 16, Style.MUTED) @@ -19,17 +20,6 @@ func _ready() -> void: Style.clabel(col, "Serie: %d (beste %d) · Schnellster Sieg: %s" % [p.records.streak, p.records.best_streak, ("%d Züge" % p.records.fastest_win) if p.records.fastest_win > 0 else "–"], 15, Style.MUTED) Style.spacer(col, 4) - for a in Profile.ACHIEVEMENTS: - var done: bool = a.id in p.achievements - var panel := PanelContainer.new() - panel.add_theme_stylebox_override("panel", Style.box(Style.PANEL if done else Style.darker(Style.PANEL, 0.8), 6)) - col.add_child(panel) - var r := Style.row(panel, 12) - r.custom_minimum_size = Vector2(0, 36) - Style.clabel(r, "✓" if done else "·", 22, Style.GREEN if done else Style.MUTED, "center", true, 40) - Style.clabel(r, a.name, 18, Style.TEXT if done else Style.MUTED, "left", true, 250) - Style.clabel(r, a.text, 15, Style.MUTED, "left", false, 380) - Style.clabel(r, "+%d" % a.reward, 16, Style.GOLD, "right", true, 90) var top := p.top_cards(5) if not top.is_empty(): Style.spacer(col, 4) @@ -52,5 +42,5 @@ func export_stats() -> void: func _input(event: InputEvent) -> void: - if event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE: + if event.is_action_pressed("ui_cancel"): app.show_screen(MenuScreen.new()) diff --git a/scripts/ui/stats_screen.gd.uid b/scripts/ui/stats_screen.gd.uid new file mode 100644 index 0000000..4704774 --- /dev/null +++ b/scripts/ui/stats_screen.gd.uid @@ -0,0 +1 @@ +uid://t0h7fpmpeuq4 diff --git a/tests/test_runner.gd b/tests/test_runner.gd index fea35f1..0d51eae 100644 --- a/tests/test_runner.gd +++ b/tests/test_runner.gd @@ -93,7 +93,7 @@ func _initialize() -> void: test_ki_besser_als_gierig() test_ki_spiele_enden() test_spielstand_migration() - test_erfolge_und_tagesaufgabe() + test_tagesaufgabe() test_kampagne() test_fallen() test_ki_sieht_fallen_nicht() @@ -648,29 +648,25 @@ func test_spielstand_migration() -> void: var alt := {"coins": 300, "collection": {"f_kobold": 2, "unbekannt": 1}, "deck": ["f_kobold", "f_kobold"]} var p := Profile.from_dict(alt) check(p.coins == 300 and p.collection == {"f_kobold": 2} and p.deck.size() == 2, "Version 1 gelesen") - check(p.stats.games == 0 and p.achievements.is_empty() and p.campaign_stage == 0, "Standardwerte ergänzt") + check(p.stats.games == 0 and p.campaign_stage == 0, "Standardwerte ergänzt") check(p.settings.volume == 0.8 and p.settings.animations, "Einstellungen Standard") p.stats.wins = 3 - p.achievements.append("erster_sieg") p.campaign_stage = 2 p.settings.volume = 0.3 var d := p.to_dict() check(d.version == Profile.SAVE_VERSION, "Version gespeichert") var p2 := Profile.from_dict(JSON.parse_string(JSON.stringify(d))) - check(p2.stats.wins == 3 and p2.achievements == ["erster_sieg"] and p2.campaign_stage == 2, "Version 2 gelesen") + check(p2.stats.wins == 3 and p2.campaign_stage == 2, "Version 2 gelesen") check(is_equal_approx(p2.settings.volume, 0.3), "Einstellungen gelesen") -func test_erfolge_und_tagesaufgabe() -> void: +func test_tagesaufgabe() -> void: Profile.today_override = "2026-09-16" var p := Profile.starter() var coins := p.coins var reward := p.record_battle(true, 1, p.deck_cards()) check(reward == Profile.REWARD_WIN[1], "Duell-Belohnung") - check("erster_sieg" in p.achievements and "duellant" in p.achievements, "Erfolge Erster Sieg und Duellant") - check(not ("tischherr" in p.achievements), "Herr des Tisches noch offen") - check(p.coins == coins + reward + 100 + (p.daily_task().reward if p.daily.done else 0), "Münzen inklusive Erfolge") - check(p.notices.size() >= 2, "Meldungen vorhanden") + check(p.coins == coins + reward + (p.daily_task().reward if p.daily.done else 0), "Münzen verbucht") p.take_notices() check(p.notices.is_empty(), "Meldungen abgeholt") check(p.daily.date == "2026-09-16" and p.daily.task != "", "Tagesaufgabe gesetzt") @@ -690,14 +686,12 @@ func test_erfolge_und_tagesaufgabe() -> void: p.refresh_daily() check(p.daily.date == "2026-09-17" and not p.daily.done and p.daily.progress == 0, "neuer Tag, neue Aufgabe") Profile.today_override = "" - # Mono-Deck-Erfolg var mono := [] for cid in ["f_funke", "f_kobold", "f_wolf", "f_feuerball", "f_asche", "f_glutpfeil", "f_elementar"]: for i in 3: mono.append(Cards.by_id(cid)) mono = mono.slice(0, 20) p.record_battle(true, 3, mono) - check("elementarist" in p.achievements and "tischherr" in p.achievements, "Elementarist und Herr des Tisches") check(p.stats.wins == 3 and p.stats.wins_by_opp["1"] == 2, "Statistik") @@ -719,7 +713,7 @@ func test_kampagne() -> void: check(p.campaign_stage == 1 and reward == Profile.REWARD_LOSS, "Niederlage schaltet nichts frei") p.campaign_stage = 9 p.record_battle(true, 5, p.deck_cards(), 9) - check(p.campaign_stage == 10 and "kampagnenheld" in p.achievements, "Kampagne abgeschlossen") + check(p.campaign_stage == 10, "Kampagne abgeschlossen") var sim := Game.new_battle_with(Profile.starter().deck_cards(), Campaign.opponents(0, r), r) var guard := 0 while sim.winner == "" and guard < 300: @@ -1140,7 +1134,7 @@ func test_kapitel_zwei_und_merkmalwahl() -> void: check(g.human.perks == ["feuer_angriff"] and g.log.any(func(l): return l.begins_with("Du: Feuerwesen")), "eigenes Merkmal wirkt und steht im Verlauf") p.campaign_stage = 19 p.record_battle(true, 5, p.deck_cards(), 19) - check(p.campaign_stage == 20 and "elementmeister" in p.achievements, "Kapitel 2 abgeschlossen") + check(p.campaign_stage == 20, "Kapitel 2 abgeschlossen") var v := Profile.from_dict(JSON.parse_string(JSON.stringify(p.to_dict()))) check(v.perk == "feuer_angriff" and v.campaign_stage == 20, "Version 5 gelesen") @@ -1163,7 +1157,6 @@ func test_bestenliste() -> void: check(p.records.streak == 0 and p.records.best_streak == 2, "Niederlage bricht die Serie") for i in 5: p.record_battle(true, 1, mono, -1, [], 10) - check("serie" in p.achievements, "Siegesserie-Erfolg") var path := "user://test_statistik.csv" check(p.export_stats(path) == "", "Statistik exportiert") var text := FileAccess.get_file_as_string(path) diff --git a/tests/ui_test.gd b/tests/ui_test.gd index 3575e98..2a7fe0e 100644 --- a/tests/ui_test.gd +++ b/tests/ui_test.gd @@ -165,7 +165,7 @@ func _ready() -> void: await frames(3) var fast := OS.get_environment("DINGER_FAST") != "" var suite := [test_menu_und_regeln, test_gamepad_menue, test_booster, test_deckbau, test_gegnerauswahl, test_einstellungen, - test_erfolge, test_kampagne, test_werkstatt, test_sprache, test_anleitung, test_anleitung2, + test_statistik, test_kampagne, test_werkstatt, test_sprache, test_anleitung, test_anleitung2, test_kampf_fortsetzen, test_gamepad_deckbau, test_deckcode, test_elementbooster] if not fast: suite += [test_kampf.bind(2, 3), test_kampf_abbrechen] @@ -202,13 +202,8 @@ func test_booster() -> void: var scr = screen() check(scr is BoosterScreen, "Boosterbildschirm") var coins: int = main.profile.coins - var ach_before: int = main.profile.achievements.size() await click(scr.b_buy) - var bonus := 0 - for a in Profile.ACHIEVEMENTS: - if a.id in main.profile.achievements.slice(ach_before): - bonus += a.reward - check(main.profile.coins == coins - Profile.BOOSTER_COST + bonus, "Booster bezahlt (plus Erfolgsmünzen %d)" % bonus) + check(main.profile.coins == coins - Profile.BOOSTER_COST, "Booster bezahlt") check(scr.cards.size() == 5 and scr.revealed.is_empty(), "5 verdeckte Karten") await shot("03_booster_zu") var backs: Array = scr.slots.get_children().filter(func(c): return c is BoosterScreen.CardBack) @@ -573,15 +568,15 @@ func test_einstellungen() -> void: check(screen() is MenuScreen, "zurück im Menü") -func test_erfolge() -> void: - await click(find_button("Erfolge")) - check(screen() is AchievementsScreen, "Erfolge geöffnet") +func test_statistik() -> void: + await click(find_button("Statistik")) + check(screen() is StatsScreen, "Statistik geöffnet") var csv := "user://statistik.csv" if FileAccess.file_exists(csv): DirAccess.remove_absolute(ProjectSettings.globalize_path(csv)) await click(find_button("Statistik exportieren")) check(FileAccess.file_exists(csv) and "Gespeichert" in screen().export_label.text, "Statistik exportiert") - await shot("14_erfolge") + await shot("14_statistik") await click(find_button("Zurück")) check(screen() is MenuScreen, "zurück im Menü") diff --git a/translations/ui.csv b/translations/ui.csv index 831ef1b..bcdf836 100644 --- a/translations/ui.csv +++ b/translations/ui.csv @@ -7,7 +7,6 @@ Netzwerkspiel,Network game Booster öffnen,Open boosters Deck bauen,Build deck Werkstatt,Workshop -Erfolge,Achievements Regeln,Rules Einstellungen,Settings Anleitung,Tutorial @@ -209,3 +208,4 @@ Starten,Start %d Gegner,%d opponents Übernehmen,Apply KI-Gegner,AI opponents +Statistik,Statistics diff --git a/translations/ui.en.translation b/translations/ui.en.translation index dfd34b49a35ad7e595df8b8b0260b508d1ed2357..fe8cbf12c8344004c86517186ff36cec328b6237 100644 GIT binary patch delta 3266 zcmZu!3s96*6yD!hl*b~=0(XCrWPQ<^u~DPARw5z;YUC`Gx#fgdrj`;^P#THkP#U1& zLD6hdNK>o{i72dST$@QkYM`VCK2m2aL(CQ}p#u8OvUld69hv#qd+#~tJI{L;PCsz^ zfy3qzMFl#Yt`Hc)&nx&W^R9W%KihovJF&0vIXj5`2f#w&CCB zu>W=VEMuq#i{9bQP#-=Ay=y;Z*eDR6;oh~DWDL$?fXTpAjeL5;?<4B`>?{rdRWMK; zUC>+~sMAfv`d(nB(vYMhW}< z;0lN2R^S$|#z1Sp*3bNPy4lz-1}^m#%_x8#`}f448+%(1IYtS!8SeBrWk}B#ubdtK zJQa@;)}$bv4m2L*_$?Vf4#vLPm9g$kW#oePDY)k-EWk@edu;|koh}mVNr2>D`po%g zK}vv7hR79ax?{(uLEYuBWc_k-gqielvkry7LfHYr zItj`wXGpt054s#p@XNJg6yE))pOdNsglf}h%V?ggaJ4z916*fD>2yZuM*(%~-q|w* z(h#f}Qv3IW-p8`Y7%0?o6k!1*FKeU+yZf(&QBt5-wGI9!Lvn{kns@w-X*WOwH=cMU z=h^D`WxFsMp*W8KWC!2ubvN?Rp#h%!YhR4J^ey%iu%8ChBws$fo?M7!5Z2K+(R!N_ zI5?C^Zb(L^*2@+~G=y@)=f>QcUL-&muas&xyBSgM6xP5D%;a@b% z1dFj6tBv0^y+45Dn2Bdq_G572r3MGQaNdm5%YWIENv?-U(IdocP zCK>H(?{u!GVuP?2KqRB6+IiI#h9tN)Jm*sTu(9p76XXI{7EXPmQ&XSK+f8n8#lcq2 zg3R>$jCB1J9LgJcw*AY;LMT2&*c(7EPxobBsHz3AtfI8u*3iFm7W8EO8lQKh#85G; zXCf>1#gOy(%-H(NbD=FG+|~c9-vsCh=INlJ$n zS$a~)HCkBhNP7$sXI>A{y|Epn70dD+$Am7!14Jf|3$H8<9sC` zeO#mb#nVw1euKwp&J8a-Jnd!54i)Mlq=Zs=Ag!Dm9&eAq4G`)E*s74)G`1Hl$z9v= zJ__{<#5oZXhP0j99b1t??oeUBhEsmE*ze}TucGWIfEDW`0EQlmHG8fu?MFTwA7@`< zvnF4lB%@I0BPic`{@qftFM{$Qoq-0jjrNusuKVr%lByxCx=Bt!1L?;WQHN1j4UqD^ z;AxR@R2G%?)nU(b!C2T{=zNuoVZwUeJKNlOseM=e;e<9E@Y}`JS-s}BIf;1xg<5)( zsITi=KXXzsxYCg+zgb)r$<;aYm@NvSa7X!V$ud7u8$~W~?L;7aBN?)~2NoR7tR*+3 z3z34nMN%48w>)<~SxiFhMI65K)?$9U*hvnPP1#Jv(3t|StizBD9VK-Gk5au!SfBL9 z%HLC0X5?M(L^S*zFkYiwP?|dC7`aViUJtlflV8Tch!0EBH5~wvhkwhG_S}nDa|KxU zsj&T2p3Kl9B?lgN7HE5 zQ_$u$^Ga>kU!T_x!WaL&QLZ`f>5lr)50zYivsIe&!pr|8P9P;hsEZIt0wl{d(%!@$ zrtPM9NUPCC`9?`!k+Wk`%P1Stqp*>aCZ!)oZwW7^iU?tyh{DU@V z>YQy<9cgp)fq?In_M1Lq+*>DBYO;v&FY><|_2&NZ>vX(ODPIOw-z?u-=4|XFixBpF zXvto_pO%&~5@E^LNJgC2Ht)baxa^70%>v@qUR#kvd9dz7f#fTYyV{-m0etZ-Vc*g^ z+i=R=g*`-`Ta7S-M;y0g{wIH6eFr&IoALt{t3nCqzeDvqa{9{mP`xT5 rmV%gHofv@Y!f$I1ol%!G%pDVK5QCX5^V2s5@;?R~1+!*kW+eX)S#xm| delta 3266 zcmZuz3s6+o8QzO5frXXF0%xy6bxA~5Q`WV^=sK;4D@9@xvk)7wRNWL~e4wleCRQr$ zw9H@;6Y>+$GzmV)18WA5kkM2-E@q-pl7T8_RAMw8Q-V^1k|K^kzkl5`b7v>aeBN{Z z$M?U^Icv{TJx?{8L&`Vlbh=l7G5l@Aw=%HiJ^$?r+Sg+LPLQkt`$Ir8@NqzQ9N%`J z6Sx?VJ!Bjk>%sophqBzUUM&6_Fc`%5eqgOr9wrrrZ%kk<3HX}`SrU)}Ow;IRwSFJc z6zZ4)Q3R->fc?pvPaHSsbdO>EOJJ^YG^-to=~!n1F!f_zRNW;(U5^MgCPb$*LK>&h zR#!Df#*z{)9M6I)9-5y4;{p~VXCq$yEKH}Hk9|JSd#`+s7j_)qpMx%G+7P+Ig?a|z z^pG-S?oT57_JDlAX}zA?&v@w?C>YKai)T#dEldcMZjQAF3l)f=wU#ln6f(DcWH z^#*idJk|_p{r&7a%h!^{Ak;l*$YN;zq|tuRH+(mlTn4e`ZNyK7=I0u%=k#moA; z{P{}GtNZQGHQ<=UK%M}|X})=9pe-6kNW))!<11;sm#}{n`*h%d^Jeo7>Ow9NC_fnz zZM5lz(Xr*EL<;pq`0zZ;fQ)&i)0MG{?9d(tJ)cqTpwu30?Hl@#+>xT-BvipYnDOd8 zV;Bym2_8uruRs6m=;3hKGZUX%IgimLy{(0a!gVuxR((^yoVp@~l1Vi&CjD!psoV2N ziLxnM$sQ#fr(nd~JcqWONp;O2lqXnn4jq5y_XW_)-caVgnXTlB64nPOLY^;a{qD*y zy1UWVN8rK8KeT%1UTTRFY6W&&JwsOC)IIq5Ho6{Vi){&LILd;{9S;_g#VC~5$!jp_ z8=IUL3dv;@>P^gA)+RX|TV@vQAg@tay->-xb$f36l2HnGM|;kjV>_l@Bpm$c;%YH9K$A43LE1T@lcEDFgmfG8Am)ZYKZfNUaFZ(IAO^$^X{Zs?( zETqac@?DbJvEN#5Jx#u7VO@x(O@M|`vFWSiBiM89+MAKR`$FR|DKR3a0bD#KE!W8D zCoY5`{Cvn?0A!52RGOcOw(yHQNh3GD{A_w9xnqRdhLX@KKcrW|_CIvaz#R~36?|1_ zZ5rPj7U$)C8Mj_>Qi{tJn`)uMuG{A~=CICmjM{)h_ zm7xgF`Em6JY*uGKWyT71DWt*u{NI_1hRNiC)`vMkr!O~m>j=a+!e{yJ-6MKid1-_{JN|#FKbLCAGi)85x$WO z+1>XSpUnG+2B2Mr667tC+PJ1wB}>U-66y%@2tIFT%tq@Ehb_01ajqHs{T2i!E4Bde+5!B)|;!cCwxHzCXq7)F1F;iaWvsbMZRVNAoBC? zD(o!z0c-96+pdj!xAHFX6nt7$Q@5kdU5uoJ%eN=1YxB4a?iAEF<#p+QS&5eAQ*F#QBr6>&Ol5IrzwvCbb_Y?~30^H3`CML*r%b>xvh& z4PhV5l_CCCiBp>(ln?RJn)HI+sQ3#hi8kdWvL_1bUPO>S@*)BZ%8YaBYqw@CZzo;&HSb1!Q0o*Y&lHV<|@F@BFumnqf7=x}gd ze}Ar^?HXBxaBPQ_oZjI@i?ZU7hW^q>aAuc}PHDvNl&~qqWHF1_5!lF{ zT}o>|k&E9{lm3MhU;oukZZqC$^p4+FzS(kW?wwsr-lQ6{P!{;-aHi^wb@k*k3(I*} zaYUZvqrY0}*oYH76>B~-MYUP8yJ^@wRY@g_D%AYIR5)+Re7|<MxNZn{u7Js!%53 zWi{z{Z@5=|h+0&Uunxrh&P)clFZ`O8(AR3AVKj4Zc*w>F;|!y%b0!##QJe*{=H}%( F{|_eJY>NN@