Anleitung 2, Gamepad, große Schrift, Profil-Reset, Würfel-Limit, Tipp nach Spielverlauf, KI-Zeitbudget, Deck-Warnung, Gischtläufer, Kampfbildschirm aufgeteilt
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPgKvy5W9WRNFHjkm5QsHx
This commit is contained in:
@@ -110,12 +110,13 @@ func _initialize() -> void:
|
||||
test_starter_gegen_passende_gegner()
|
||||
test_kurve_statistik_vorschlag_verbesserung()
|
||||
test_wasser_antworten()
|
||||
test_ki_zeitbudget()
|
||||
print("%d Prüfungen bestanden, %d fehlgeschlagen" % [passed, failed])
|
||||
quit(1 if failed > 0 else 0)
|
||||
|
||||
|
||||
func test_kartenpool() -> void:
|
||||
check(Cards.all().size() == 109, "109 Karten")
|
||||
check(Cards.all().size() == 110, "110 Karten")
|
||||
for key in Cards.COMBOS:
|
||||
var found: bool = Cards.all().any(func(c): return c.is_combo() and Cards.combo_key(c.elements) == key)
|
||||
check(found, "Kombo vorhanden: " + key)
|
||||
@@ -1282,8 +1283,18 @@ func test_kurve_statistik_vorschlag_verbesserung() -> void:
|
||||
var mono := starter
|
||||
check(p.suggest_difficulty() == "", "kein Vorschlag am Anfang")
|
||||
for i in 3:
|
||||
p.record_battle(true, 1, mono)
|
||||
check(p.suggest_difficulty() == "schwer" and p.notices.any(func(n): return n.begins_with("Tipp: 3 Siege")), "drei Siege: Schwer vorschlagen")
|
||||
p.record_battle(true, 1, mono, -1, [], 6, {}, 1.0, 4)
|
||||
check(p.suggest_difficulty() == "", "drei knappe Siege: noch kein Vorschlag")
|
||||
p.records.streak = 0
|
||||
p.records.margins = []
|
||||
for i in 3:
|
||||
p.record_battle(true, 1, mono, -1, [], 6, {}, 1.0, 20)
|
||||
check(p.suggest_difficulty() == "schwer" and p.notices.any(func(n): return n.begins_with("Tipp: 3 Siege")), "drei deutliche Siege: Schwer vorschlagen")
|
||||
p.records.streak = 0
|
||||
p.records.margins = []
|
||||
for i in 5:
|
||||
p.record_battle(true, 1, mono, -1, [], 6, {}, 1.0, 2)
|
||||
check(p.suggest_difficulty() == "schwer" and p.records.margins.size() == 5, "fünf Siege egal wie knapp")
|
||||
p.settings.difficulty = "schwer"
|
||||
p.take_notices()
|
||||
for i in 3:
|
||||
@@ -1319,3 +1330,27 @@ func test_wasser_antworten() -> void:
|
||||
g.play_card(h, C("w_strudel"), t)
|
||||
check(o.board.is_empty() and C("e_troll") in o.hand and h.hand.size() == hand, "Strudel: zurück auf die Hand, eine Karte gezogen")
|
||||
check(C("w_ebbe").rarity == "gewöhnlich" and Profile.starter().collection.has("w_ebbe"), "Ebbe in der Startsammlung")
|
||||
|
||||
|
||||
func test_ki_zeitbudget() -> void:
|
||||
var r := RandomNumberGenerator.new()
|
||||
r.seed = 12
|
||||
var g := Game.new_battle(Profile.starter().deck_cards(), 5, r)
|
||||
var h: Game.Player = g.players[0]
|
||||
h.mulligan_done = true
|
||||
h.energy = 10
|
||||
h.max_energy = 10
|
||||
for i in 8:
|
||||
h.hand.append(Cards.by_id("f_funke"))
|
||||
for p in g.players:
|
||||
for i in 3:
|
||||
put(p, "e_troll")
|
||||
AI.time_budget_ms = 1
|
||||
var t0 := Time.get_ticks_msec()
|
||||
var act := AI.choose_action(g, h)
|
||||
var ms := Time.get_ticks_msec() - t0
|
||||
AI.time_budget_ms = 150
|
||||
check(act.type in ["play", "attack", "end"] and ms < 80, "Zeitbudget greift (%d ms)" % ms)
|
||||
check(Cards.by_id("wl_gischt").keywords == ["Flink"] and Cards.by_id("wl_gischt").combo() == "Sturm", "Gischtläufer für Sturm")
|
||||
var v := Profile.from_dict(JSON.parse_string(JSON.stringify(Profile.starter().to_dict())))
|
||||
check(v.settings.has("big_font") and not v.tutorial2_done and v.records.margins is Array, "Version 5 mit neuen Feldern")
|
||||
|
||||
@@ -74,6 +74,14 @@ func key(code: int) -> void:
|
||||
await frames(2)
|
||||
|
||||
|
||||
func pad(button: int) -> void:
|
||||
var ev := InputEventJoypadButton.new()
|
||||
ev.button_index = button
|
||||
ev.pressed = true
|
||||
get_viewport().push_input(ev)
|
||||
await frames(2)
|
||||
|
||||
|
||||
## Mulligan-Maske wegklicken (Hand behalten), falls sie offen ist.
|
||||
func clear_mulligan(scr) -> void:
|
||||
if scr.mulligan_box.visible:
|
||||
@@ -155,9 +163,10 @@ func _ready() -> void:
|
||||
await frames(3)
|
||||
var fast := OS.get_environment("DINGER_FAST") != ""
|
||||
var suite := [test_menu_und_regeln, test_booster, test_deckbau, test_gegnerauswahl, test_einstellungen,
|
||||
test_erfolge, test_kampagne, test_werkstatt, test_sprache, test_anleitung, test_herausforderung]
|
||||
test_erfolge, test_kampagne, test_werkstatt, test_sprache, test_anleitung, test_anleitung2, test_herausforderung]
|
||||
if not fast:
|
||||
suite += [test_hotseat, test_netzwerk, test_kampf.bind(2, 3), test_kampf_abbrechen]
|
||||
suite.append(test_profil_zuruecksetzen)
|
||||
for t in suite:
|
||||
await ensure_menu()
|
||||
await t.call()
|
||||
@@ -290,7 +299,14 @@ func test_deckbau() -> void:
|
||||
await click(find_button("Auto-Ausfüllen"))
|
||||
check(scr.deck.size() == 20 and main.profile.deck_valid(2)[0], "Slot 3 automatisch gefüllt und spielbar")
|
||||
await shot("25_deck_slots")
|
||||
await click(scr.deck_list.get_children()[0]) # ungespeicherte Änderung: eine Karte entfernt
|
||||
check(scr.dirty(), "Deck geändert")
|
||||
await click(find_button("Zurück"))
|
||||
check(scr.confirm.visible and screen() == scr, "Warnung bei ungespeicherten Änderungen")
|
||||
await click(find_button("Weiter bearbeiten"))
|
||||
check(not scr.confirm.visible, "weiter bearbeiten")
|
||||
await click(find_button("Zurück"))
|
||||
await click(find_button("Verwerfen"))
|
||||
check(screen() is MenuScreen and main.profile.deck.size() == 20, "Änderungen verworfen")
|
||||
|
||||
|
||||
@@ -360,6 +376,9 @@ func test_gegnerauswahl() -> void:
|
||||
check(sel is OpponentSelectScreen, "Gegnerauswahl geöffnet")
|
||||
check("Deckstärke" in sel.rating_label.text, "Deckstärke angezeigt")
|
||||
check(sel.preview_labels[3].text.count("(") == 3 and sel.previews[3].size() == 3, "Vorschau zeigt drei Gegner mit Stärke")
|
||||
for i in 3:
|
||||
await click(sel.b_reroll)
|
||||
check(sel.rerolls_left == 0 and sel.b_reroll.disabled, "höchstens dreimal neu würfeln")
|
||||
await click(find_button("Schwer"))
|
||||
check(main.profile.settings.difficulty == "schwer" and Profile.load_or_new(SAVE).settings.difficulty == "schwer", "Schwer gewählt und gespeichert")
|
||||
var previewed: Array = sel.previews[1].map(func(o): return o.title)
|
||||
@@ -382,11 +401,13 @@ func test_gegnerauswahl() -> void:
|
||||
await click(find_button("Einzelspieler"))
|
||||
await click(find_button("Normal"))
|
||||
main.profile.records.streak = 3
|
||||
main.profile.records.margins = [20, 22, 18]
|
||||
screen().refresh()
|
||||
check(screen().b_tip.visible and "Schwer" in screen().tip_label.text, "Vorschlag nach drei Siegen")
|
||||
check(screen().b_tip.visible and "Schwer" in screen().tip_label.text, "Vorschlag nach drei deutlichen Siegen")
|
||||
await click(find_button("Übernehmen"))
|
||||
check(main.profile.settings.difficulty == "schwer", "Vorschlag übernommen")
|
||||
main.profile.records.streak = 0
|
||||
main.profile.records.margins = []
|
||||
await click(find_button("Normal"))
|
||||
await click(find_button("Zurück"))
|
||||
check(screen() is MenuScreen, "zurück im Menü")
|
||||
@@ -434,7 +455,15 @@ func test_einstellungen() -> void:
|
||||
check(main.profile.settings.animations == false, "Animationen abschaltbar")
|
||||
check(is_equal_approx(Profile.load_or_new(SAVE).settings.volume, 0.3), "Einstellungen auf Platte")
|
||||
scr.anim.button_pressed = true
|
||||
scr.big_font.button_pressed = true
|
||||
await frames(2)
|
||||
check(main.profile.settings.big_font and Style.font_scale > 1.0 and screen() is SettingsScreen, "große Schrift aktiv")
|
||||
screen().big_font.button_pressed = false
|
||||
await frames(2)
|
||||
check(is_equal_approx(Style.font_scale, 1.0), "normale Schrift")
|
||||
var scr_b = screen()
|
||||
await shot("13_einstellungen")
|
||||
scr = scr_b
|
||||
await click(find_button("Zurück"))
|
||||
check(screen() is MenuScreen, "zurück im Menü")
|
||||
|
||||
@@ -484,6 +513,45 @@ func test_werkstatt() -> void:
|
||||
check(screen() is MenuScreen, "zurück im Menü")
|
||||
|
||||
|
||||
func test_anleitung2() -> void:
|
||||
check(main.profile.tutorial_done and not main.profile.tutorial2_done, "Teil 1 erledigt, Teil 2 offen")
|
||||
check(find_button("Anleitung 2: Fallen") != null, "Menü bietet Teil 2 an")
|
||||
await click(find_button("Anleitung 2: Fallen"))
|
||||
var scr = screen()
|
||||
check(scr is BattleScreen and scr.tutorial and scr.tutorial_part == 2, "Anleitung 2 gestartet")
|
||||
scr.ai_delay = 0.0
|
||||
var g: Game = scr.game
|
||||
check(g.opponents[0].name == "Mara" and g.human.hand.any(func(c): return c.id == "w_falle") and g.human.hand.any(func(c): return c.id == "w_reiter"), "Mara, Frostfalle und Wellenreiter auf der Hand")
|
||||
await frames(2)
|
||||
check(scr.mulligan_box.visible and scr.tutorial_step == 0, "Schritt 1: Mulligan-Maske")
|
||||
await click(scr.b_keep)
|
||||
check(scr.tutorial_step == 1 and "Frostfalle" in scr.tutorial_text.text, "Schritt 2: Falle legen")
|
||||
await shot("29_anleitung2")
|
||||
# Zug 1 hat nur 1 Energie: Zug beenden, dann Falle legen
|
||||
await key(KEY_SPACE)
|
||||
await wait_for_human(scr)
|
||||
check(scr.highlight_layer.get_child_count() >= 1, "Falle hervorgehoben")
|
||||
var idx: int = g.human.hand.map(func(c): return c.id).find("w_falle")
|
||||
check(idx >= 0 and idx < 9, "Falle auf der Hand")
|
||||
await key(KEY_1 + idx)
|
||||
check(g.human.traps.size() == 1 and scr.tutorial_step == 2, "Falle gelegt, Schritt 3")
|
||||
await give_up()
|
||||
check(main.profile.tutorial2_done and find_button("Anleitung") != null, "Teil 2 erledigt")
|
||||
|
||||
|
||||
func test_profil_zuruecksetzen() -> void:
|
||||
await click(find_button("Einstellungen"))
|
||||
await click(find_button("Profil zurücksetzen"))
|
||||
var scr = screen()
|
||||
check(scr.confirm.visible, "Rückfrage")
|
||||
await click(find_button("Abbrechen"))
|
||||
check(not scr.confirm.visible, "abgebrochen")
|
||||
await click(find_button("Profil zurücksetzen"))
|
||||
await click(find_button("Ja, zurücksetzen"))
|
||||
check(screen() is MenuScreen and main.profile.coins == Profile.START_COINS and not main.profile.tutorial_done, "Profil zurückgesetzt")
|
||||
check(Profile.load_or_new(SAVE).coins == Profile.START_COINS, "zurückgesetzt gespeichert")
|
||||
|
||||
|
||||
func test_herausforderung() -> void:
|
||||
await click(find_button("Herausforderung"))
|
||||
var scr = screen()
|
||||
@@ -602,6 +670,20 @@ func test_anleitung() -> void:
|
||||
await key(KEY_1 + idx)
|
||||
check(g.human.board.size() == 1, "erneut gespielt")
|
||||
await shot("22_anleitung")
|
||||
# Gamepad: Zeiger bewegen, Karte spielen
|
||||
await pad(JOY_BUTTON_DPAD_RIGHT)
|
||||
check(scr.gp_zone == "hand" and scr.gp_index == 1 and scr.cursor_layer.get_child_count() == 1, "Gamepad-Zeiger auf zweiter Handkarte")
|
||||
var pad_idx := -1
|
||||
for i in g.human.hand.size():
|
||||
if g.human.hand[i].is_creature() and g.can_play(g.human, g.human.hand[i])[0]:
|
||||
pad_idx = i
|
||||
break
|
||||
if pad_idx >= 0:
|
||||
while scr.gp_index != pad_idx:
|
||||
await pad(JOY_BUTTON_DPAD_RIGHT)
|
||||
var board_before: int = g.human.board.size()
|
||||
await pad(JOY_BUTTON_A)
|
||||
check(g.human.board.size() == board_before + 1, "Gamepad A spielt das Wesen")
|
||||
scr.ai_delay = 0.75
|
||||
await key(KEY_SPACE)
|
||||
check(g.current() != g.human or g.turn >= 2, "Zug per Leertaste beendet")
|
||||
@@ -639,9 +721,16 @@ func test_netzwerk() -> void:
|
||||
var pid := OS.create_process(OS.get_executable_path(), args)
|
||||
check(pid > 0, "Bot-Prozess gestartet")
|
||||
var wait := 0
|
||||
while main.net.names.size() < 2 and wait < 900:
|
||||
while main.net.names.size() < 2 and wait < 600:
|
||||
await frames(1)
|
||||
wait += 1
|
||||
if main.net.names.size() < 2:
|
||||
print("HINWEIS: Bot kam nicht, zweiter Versuch")
|
||||
OS.kill(pid)
|
||||
pid = OS.create_process(OS.get_executable_path(), args)
|
||||
while main.net.names.size() < 2 and wait < 1500:
|
||||
await frames(1)
|
||||
wait += 1
|
||||
check(main.net.names.size() == 2, "Bot ist beigetreten (Pfad %s)" % main.net.get_path())
|
||||
await shot("23_lobby")
|
||||
await click(find_button("Start"))
|
||||
|
||||
Reference in New Issue
Block a user