update
This commit is contained in:
166
tests/ui_test.gd
166
tests/ui_test.gd
@@ -3,6 +3,7 @@ extends Node
|
||||
## DINGER_SHOTS=/pfad/zum/ordner godot --path . tests/ui_test.tscn
|
||||
|
||||
const SAVE := "user://test_ui_spielstand.json"
|
||||
const DEVICE := 7 # Gerätenummer der Testereignisse; alles andere fängt der InputFilter ab
|
||||
|
||||
var main: Control
|
||||
var shots := ""
|
||||
@@ -20,6 +21,21 @@ func check(cond: bool, msg: String) -> void:
|
||||
get_tree().quit(1)
|
||||
|
||||
|
||||
## Lässt nur Ereignisse des Tests durch; echte Maus und Tastatur des Nutzers werden abgefangen,
|
||||
## bevor Knöpfe oder Bildschirme sie sehen. Sitzt als letzter Knoten im Baum und bekommt _input
|
||||
## darum als Erster.
|
||||
class InputFilter extends Node:
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event.device != DEVICE:
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
## Testereignis an das Fenster, mit der eigenen Gerätenummer.
|
||||
func push(ev: InputEvent) -> void:
|
||||
ev.device = DEVICE
|
||||
get_viewport().push_input(ev)
|
||||
|
||||
|
||||
func frames(n: int = 2) -> void:
|
||||
for i in n:
|
||||
await get_tree().process_frame
|
||||
@@ -39,10 +55,10 @@ func click_at(pos: Vector2) -> void:
|
||||
down.global_position = pos
|
||||
down.button_index = MOUSE_BUTTON_LEFT
|
||||
down.pressed = true
|
||||
get_viewport().push_input(down)
|
||||
push(down)
|
||||
var up: InputEventMouseButton = down.duplicate()
|
||||
up.pressed = false
|
||||
get_viewport().push_input(up)
|
||||
push(up)
|
||||
await frames(2)
|
||||
|
||||
|
||||
@@ -63,11 +79,11 @@ func double_click_at(pos: Vector2) -> void:
|
||||
down.button_index = MOUSE_BUTTON_LEFT
|
||||
down.pressed = true
|
||||
down.double_click = true
|
||||
get_viewport().push_input(down)
|
||||
push(down)
|
||||
var up: InputEventMouseButton = down.duplicate()
|
||||
up.pressed = false
|
||||
up.double_click = false
|
||||
get_viewport().push_input(up)
|
||||
push(up)
|
||||
await frames(2)
|
||||
|
||||
|
||||
@@ -77,10 +93,10 @@ func right_click_at(pos: Vector2, button: int = MOUSE_BUTTON_RIGHT) -> void:
|
||||
down.global_position = pos
|
||||
down.button_index = button
|
||||
down.pressed = true
|
||||
get_viewport().push_input(down)
|
||||
push(down)
|
||||
var up: InputEventMouseButton = down.duplicate()
|
||||
up.pressed = false
|
||||
get_viewport().push_input(up)
|
||||
push(up)
|
||||
await frames(2)
|
||||
|
||||
|
||||
@@ -88,11 +104,11 @@ func key(code: int) -> void:
|
||||
var down := InputEventKey.new()
|
||||
down.keycode = code
|
||||
down.pressed = true
|
||||
get_viewport().push_input(down)
|
||||
push(down)
|
||||
var up := InputEventKey.new()
|
||||
up.keycode = code
|
||||
up.pressed = false
|
||||
get_viewport().push_input(up)
|
||||
push(up)
|
||||
await frames(2)
|
||||
|
||||
|
||||
@@ -100,7 +116,7 @@ func pad(button: int) -> void:
|
||||
var ev := InputEventJoypadButton.new()
|
||||
ev.button_index = button
|
||||
ev.pressed = true
|
||||
get_viewport().push_input(ev)
|
||||
push(ev)
|
||||
await frames(2)
|
||||
|
||||
|
||||
@@ -109,7 +125,7 @@ func hover(node: Control) -> void:
|
||||
var ev := InputEventMouseMotion.new()
|
||||
ev.position = node.get_global_rect().get_center()
|
||||
ev.global_position = ev.position
|
||||
get_viewport().push_input(ev)
|
||||
push(ev)
|
||||
await frames(2)
|
||||
|
||||
|
||||
@@ -168,6 +184,7 @@ func _ready() -> void:
|
||||
main = load("res://scenes/main.tscn").instantiate()
|
||||
main.save_path = SAVE
|
||||
add_child(main)
|
||||
add_child(InputFilter.new()) # nach main, damit er im Baum zuletzt steht
|
||||
main.sfx.muted = true # Tests bleiben still
|
||||
await frames(3)
|
||||
var suite := [test_start, test_menu, test_gamepad_menue, test_booster, test_gegnerauswahl, test_einstellungen,
|
||||
@@ -244,46 +261,65 @@ func target_view(scr, valid: Array) -> Control:
|
||||
return null
|
||||
|
||||
|
||||
## Zieht eine Karte oder Kachel auf eine andere und hält sie dort, bis die beiden verschmelzen.
|
||||
## Zieht eine Karte oder Kachel auf eine andere und lässt sie dort los; danach wartet das Ergebnis
|
||||
## über dem Ziel auf accept_fuse oder „Abbrechen“.
|
||||
func drag_fuse(scr, from: Control, to: Control) -> void:
|
||||
await frames(20) # Kacheln sind noch unterwegs (Einfliegen, Nachrücken)
|
||||
await settle(scr)
|
||||
var a := from.get_global_rect().get_center()
|
||||
var b := to.get_global_rect().get_center()
|
||||
var fo = from.card if from is CardView else from.creature
|
||||
var to_o = to.card if to is CardView else to.creature
|
||||
var down := InputEventMouseButton.new()
|
||||
down.position = a
|
||||
down.global_position = a
|
||||
down.button_index = MOUSE_BUTTON_LEFT
|
||||
down.pressed = true
|
||||
get_viewport().push_input(down)
|
||||
push(down)
|
||||
await frames(1)
|
||||
for i in range(1, 6):
|
||||
var m := InputEventMouseMotion.new()
|
||||
m.position = a.lerp(b, i / 5.0)
|
||||
m.global_position = m.position
|
||||
m.button_mask = MOUSE_BUTTON_MASK_LEFT
|
||||
get_viewport().push_input(m)
|
||||
push(m)
|
||||
await frames(1)
|
||||
if scr.drag_ghost == null or scr.drag_target == null:
|
||||
var fo = from.card if from is CardView else from.creature
|
||||
var to_o = to.card if to is CardView else to.creature
|
||||
print("DEBUG drag: ghost=", scr.drag_ghost, " target=", scr.drag_target, " press=", scr.press_target, " dran=", scr.my_turn(),
|
||||
" overlay=", scr.any_overlay(), " mana=", scr.game.human.energy, " kann=", scr.game.can_fuse(scr.game.human, fo, to_o), " from=", from.get_global_rect(), " to=", to.get_global_rect())
|
||||
check(scr.drag_ghost != null and scr.drag_target != null, "Karte schwebt über einem Verschmelzungsziel")
|
||||
var waited := 0
|
||||
while scr.drag_ghost != null and waited < 240:
|
||||
var still := InputEventMouseMotion.new() # die Maus bleibt auf dem Ziel, auch wenn die echte zuckt
|
||||
still.position = b
|
||||
still.global_position = b
|
||||
still.button_mask = MOUSE_BUTTON_MASK_LEFT
|
||||
get_viewport().push_input(still)
|
||||
await frames(1)
|
||||
waited += 1
|
||||
check(scr.drag_ghost != null and scr.drag_target == to_o and to.drop, "Karte schwebt über einem Verschmelzungsziel, das golden gerahmt ist")
|
||||
var up: InputEventMouseButton = down.duplicate()
|
||||
up.pressed = false
|
||||
up.position = b
|
||||
up.global_position = b
|
||||
get_viewport().push_input(up)
|
||||
push(up)
|
||||
await frames(2)
|
||||
var want: Cards.Card = Game.fusion_result(scr.game.human, fo, to_o)
|
||||
var shown: Array = scr.menu_layer.get_children().filter(func(c): return c is CardView)
|
||||
check(scr.fuse_pending == [fo, to_o] and scr.menu_layer.visible and shown.size() == 1 and shown[0].card.name == want.name and shown[0].card.attack == want.attack and shown[0].card.health == want.health, "nach dem Loslassen schwebt %s (%d/%d) über dem Ziel und wartet auf Bestätigung" % [want.name, want.attack, want.health])
|
||||
check(shown[0].position.y + shown[0].size.y < to.get_global_rect().position.y and not to.drop, "das Ergebnis steht über dem Ziel, der goldene Rahmen ist weg")
|
||||
|
||||
|
||||
## Bestätigt die offene Verschmelzungsfrage; die neue Karte gleitet von oben in die Hand.
|
||||
func accept_fuse(scr) -> void:
|
||||
var pair: Array = scr.fuse_pending
|
||||
check(pair != null, "eine Verschmelzung wartet")
|
||||
var before: Array = scr.game.human.hand.duplicate()
|
||||
var btn := find_button("Verschmelzen", scr.menu_layer)
|
||||
check(btn != null, "Knopf Verschmelzen")
|
||||
var at := btn.get_global_rect().get_center()
|
||||
var down := InputEventMouseButton.new()
|
||||
down.position = at
|
||||
down.global_position = at
|
||||
down.button_index = MOUSE_BUTTON_LEFT
|
||||
down.pressed = true
|
||||
push(down)
|
||||
var up: InputEventMouseButton = down.duplicate()
|
||||
up.pressed = false
|
||||
push(up)
|
||||
await frames(1)
|
||||
var fresh: Array = scr.hand_views.filter(func(v): return not (v.card in before))
|
||||
check(fresh.size() == 1 and (fresh[0].position.y < BattleLayout.HAND_Y - 40 or not scr.fx.enabled), "die neue Karte gleitet von oben in die Hand")
|
||||
await frames(2)
|
||||
|
||||
|
||||
@@ -367,7 +403,8 @@ func test_gegnerauswahl() -> void:
|
||||
var opp: Game.Player = hard.game.opponent
|
||||
check(opp.max_life == Profile.DIFFICULTIES.schwer.life and hard.smart_ai, "Schwer: Gegner mit %d Leben, Vorausschau-KI" % Profile.DIFFICULTIES.schwer.life)
|
||||
check(hard.game.human.hand.size() == Game.START_HAND and hard.hand_views.size() == Game.START_HAND, "Start: fünf Karten auf der Hand")
|
||||
check(hard.game.human.hand.all(func(c): return c.cost <= Game.START_MANA), "alle fünf sind im ersten Zug spielbar")
|
||||
var mine: Array = main.profile.deck_cards()
|
||||
check(hard.game.human.hand.all(func(c): return c.id in mine), "die Starthand kommt ungefiltert vom eigenen Stapel")
|
||||
await shot("05_starthand")
|
||||
check(hard.hero_panels[opp].position == BattleLayout.OPP_BOX.position, "der Gegner steht links oben")
|
||||
await shot("11_kampf")
|
||||
@@ -445,6 +482,14 @@ func test_deck() -> void:
|
||||
check(scr is DeckScreen, "Deck geöffnet")
|
||||
var p: Profile = main.profile
|
||||
check(scr.grid.views().size() == p.collection.size() and scr.count_label.text == "Stapel: %d Karten (%d bis %d)" % [p.deck.size(), Game.DECK_MIN, Game.DECK_MAX], "alle eigenen Karten, Zähler stimmt")
|
||||
check(scr.strength_label.text == "Stärke 100", "Startdeck aus Grundkarten: Stärke 100")
|
||||
p.collection[p.deck[0]] = 4
|
||||
scr.refresh()
|
||||
await frames(2)
|
||||
check(scr.strength_label.text == "Stärke %d" % roundi((39 * 100 + 500) / 40.0), "eine Ultimate Rare hebt die Stärke: " + scr.strength_label.text)
|
||||
p.collection[p.deck[0]] = 0
|
||||
scr.refresh()
|
||||
await frames(2)
|
||||
var views: Array = scr.grid.views()
|
||||
check(views.all(func(v): return not v.dim) and p.deck.size() == Game.DECK_MIN, "nach dem Start sind alle eigenen Karten im Stapel")
|
||||
var first_id: String = views[0].card.id
|
||||
@@ -518,6 +563,7 @@ func test_gamepad_menue() -> void:
|
||||
var down := InputEventJoypadButton.new()
|
||||
down.button_index = JOY_BUTTON_DPAD_DOWN
|
||||
down.pressed = true
|
||||
down.device = DEVICE
|
||||
Input.parse_input_event(down)
|
||||
await frames(2)
|
||||
var f2 := get_viewport().gui_get_focus_owner()
|
||||
@@ -527,12 +573,12 @@ func test_gamepad_menue() -> void:
|
||||
var accept := InputEventJoypadButton.new()
|
||||
accept.button_index = JOY_BUTTON_A
|
||||
accept.pressed = true
|
||||
get_viewport().push_input(accept)
|
||||
push(accept)
|
||||
await frames(1)
|
||||
var release := InputEventJoypadButton.new()
|
||||
release.button_index = JOY_BUTTON_A
|
||||
release.pressed = false
|
||||
get_viewport().push_input(release)
|
||||
push(release)
|
||||
await frames(3)
|
||||
check(not (screen() is MenuScreen) or target_text == "Beenden", "A öffnet den fokussierten Bildschirm (%s)" % target_text)
|
||||
await hover(main)
|
||||
@@ -657,17 +703,13 @@ func test_kampf_grenzen() -> void:
|
||||
g.human.energy = 100
|
||||
scr.refresh()
|
||||
await frames(1)
|
||||
# Hand voll ziehen
|
||||
var guard := 0
|
||||
while g.human.hand.size() < Game.MAX_HAND and guard < 30:
|
||||
guard += 1
|
||||
# Keine Grenze für Handkarten: acht weitere ziehen
|
||||
var hand_before: int = g.human.hand.size()
|
||||
for i in 8:
|
||||
await click(scr.deck)
|
||||
check(g.human.hand.size() == Game.MAX_HAND, "Hand auf %d gefüllt" % Game.MAX_HAND)
|
||||
check(not scr.deck.enabled, "bei voller Hand lässt sich nichts ziehen")
|
||||
await click(scr.deck)
|
||||
check(scr.msg_label.text == tr("Deine Hand ist voll"), "Meldung bei voller Hand: " + scr.msg_label.text)
|
||||
check(g.human.hand.size() == hand_before + 8 and scr.deck.enabled and scr.hand_views.size() == hand_before + 8, "acht Karten nachgezogen, Ziehen bleibt möglich")
|
||||
# Feld voll spielen
|
||||
guard = 0
|
||||
var guard := 0
|
||||
while g.human.board.size() < Game.MAX_BOARD and guard < 30:
|
||||
guard += 1
|
||||
if g.human.hand.is_empty():
|
||||
@@ -681,9 +723,10 @@ func test_kampf_grenzen() -> void:
|
||||
await shot("25_kampf_voll")
|
||||
# Verschmelzen per Ziehen macht wieder Platz
|
||||
var before: int = g.human.board.size()
|
||||
scr.hold_time = 0.3
|
||||
var hand_n: int = g.human.hand.size()
|
||||
await drag_fuse(scr, scr.own_views[0], scr.own_views[1])
|
||||
check(g.human.board.size() == before - 1, "Verschmelzen macht einen Platz frei")
|
||||
await accept_fuse(scr)
|
||||
check(g.human.board.size() == before - 2 and g.human.hand.size() == hand_n + 1, "Verschmelzen macht zwei Plätze frei, das Ergebnis liegt auf der Hand")
|
||||
# Ohne Mana kein Ziehen
|
||||
g.human.energy = 0
|
||||
g.human.draws = 1
|
||||
@@ -699,12 +742,11 @@ func test_kampf_elemente_und_verschmelzen() -> void:
|
||||
var scr = screen()
|
||||
check(scr is BattleScreen, "Kampf gestartet")
|
||||
scr.ai_delay = 0.0
|
||||
scr.hold_time = 0.3
|
||||
await wait_for_human(scr)
|
||||
var g: Game = scr.game
|
||||
g.human.board.clear()
|
||||
scr.opponent().board.clear() # was die KI im ersten Zug gelegt hat, stört die Zähler
|
||||
for e in Cards.ELEMENTS:
|
||||
for e in Cards.ELEMENTS + [Cards.NEUTRAL]:
|
||||
scr.opponent().played[e] = 0
|
||||
var put := func(p: Game.Player, id: String, hidden: bool = false) -> Game.Creature:
|
||||
var cr := Game.Creature.new(Cards.by_id(id).copy(), p, g.next_uid)
|
||||
@@ -756,18 +798,23 @@ func test_kampf_elemente_und_verschmelzen() -> void:
|
||||
mine_hidden.ready = true
|
||||
await click(scr.own_views[3])
|
||||
check(not mine_hidden.hidden and scr.element_view.text().begins_with("Feuer 3/1 (Doppelschlag)"), "aufgedeckt: drei offene Feuer, eine ausgespielt: " + scr.element_view.text())
|
||||
check(wolf.power() == 3 and falke.power() == 3 and mine_hidden.can_attack(), "unter fünf Karten kein Bonus, aufgedeckt greift sofort an")
|
||||
g.human.played["Feuer"] = 5
|
||||
check(wolf.power() == 3 and falke.power() == 3 and mine_hidden.can_attack(), "unter drei Karten kein Bonus, aufgedeckt greift sofort an")
|
||||
g.human.played["Feuer"] = 3
|
||||
g.apply_auras()
|
||||
scr.refresh()
|
||||
await frames(1)
|
||||
check(scr.element_view.text().begins_with("Feuer 3/5 (Doppelschlag) (+1/+1)") and wolf.power() == 4 and falke.power() == 3, "fünf Feuerkarten: +1/+1 für die eigenen Feuerwesen: " + scr.element_view.text())
|
||||
check(scr.element_view.text().begins_with("Feuer 3/3 (Doppelschlag) (+1/+1)") and wolf.power() == 4 and falke.power() == 3, "drei Feuerkarten: +1/+1 für die eigenen Feuerwesen: " + scr.element_view.text())
|
||||
check(scr.hand_views[0].bonus == 0, "die Luftkarte auf der Hand zeigt keinen Bonus")
|
||||
await shot("23b_vier_feuer")
|
||||
# Angriffsziel: Elementvorteil, verdeckte ohne Anzeige, Held gesperrt
|
||||
# Angriffsziel: Elementvorteil schlägt durch den Stapelbonus des Ziels, verdeckte ohne Anzeige, Held gesperrt
|
||||
scr.opponent().played["Luft"] = 3
|
||||
g.apply_auras()
|
||||
scr.refresh()
|
||||
await frames(1)
|
||||
check(falke.aura == 1 and falke.power() == 4 and scr.opp_element_view.text() == "Luft 1/3 (+1/+1)", "der Gegner hat drei Luftkarten gespielt, der Falke trägt +1/+1: " + scr.opp_element_view.text())
|
||||
await click(scr.own_views[0])
|
||||
check(scr.selected == wolf and scr.tiles[falke.uid].matchup == 1 and scr.tiles[secret.uid].matchup == 0, "Angreifer gewählt: +1 gegen Luft, nichts gegen Verdeckte")
|
||||
check(scr.tiles[falke.uid].shown_stats() == [falke.power() - 1, falke.health], "der Falke zeigt seinen Konter gegen den Wolf (1 weniger) und sein echtes Leben")
|
||||
check(scr.selected == wolf and scr.tiles[falke.uid].matchup == 1 and scr.tiles[secret.uid].matchup == 0, "Angreifer gewählt: +1 gegen den Falken (sein Bonus zählt nicht), nichts gegen Verdeckte")
|
||||
check(scr.tiles[falke.uid].shown_stats() == [falke.power() - 1, falke.health], "der Falke zeigt seinen Konter gegen den Wolf (ohne seinen Bonus) und sein echtes Leben")
|
||||
await hover(scr.tiles[falke.uid])
|
||||
check(scr.tiles[falke.uid].doomed and not scr.own_views[0].doomed and scr.own_views[0].shown_stats()[0] == wolf.power() + 1, "über dem Falken: er stirbt, der Wolf nicht, der Wolf schlägt mit +1 zu")
|
||||
await shot("23c_angreifer_gewaehlt")
|
||||
@@ -777,19 +824,27 @@ func test_kampf_elemente_und_verschmelzen() -> void:
|
||||
check(wolf.attacks_left() == 1, "Doppelschlag: ein Angriff bleibt")
|
||||
await double_click_at(scr.own_views[0].get_global_rect().get_center())
|
||||
check(scr.msg_label.text == "Erst die Wesen" and scr.opponent().life == 30, "Doppelklick zielt auf das Leben, hier stehen noch Wesen: " + scr.msg_label.text)
|
||||
# Verschmelzen per Ziehen: den Aschekrieger auf den Wellenreiter ziehen und kurz halten
|
||||
# Verschmelzen per Ziehen: den Aschekrieger auf den Wellenreiter ziehen, erst abbrechen, dann bestätigen
|
||||
mana = g.human.energy
|
||||
var before: int = g.human.board.size()
|
||||
await drag_fuse(scr, scr.own_views[1], scr.own_views[2])
|
||||
check(g.human.board.size() == before - 1 and g.human.board.any(func(c): return c.name == "Dampf") and g.human.energy == mana - 3, "zu Dampf verschmolzen, 3 Mana bezahlt (halbe Manasumme)")
|
||||
var dampf: Game.Creature = g.human.board.filter(func(c): return c.name == "Dampf")[0]
|
||||
check(scr.tiles[dampf.uid].rarity() == "Ultra Rare" and dampf.card.look == 3, "die Fusion trägt die höhere Stufe (der Reiter war Ultra Rare)")
|
||||
await shot("24a_verschmelzen_frage")
|
||||
await click(find_button("Abbrechen", scr.menu_layer))
|
||||
check(scr.fuse_pending == null and not scr.menu_layer.visible and g.human.board.size() == before and g.human.energy == mana, "Abbrechen lässt beide Wesen und das Mana, wie sie waren")
|
||||
await drag_fuse(scr, scr.own_views[1], scr.own_views[2])
|
||||
await accept_fuse(scr)
|
||||
var dampf_cards: Array = g.human.hand.filter(func(c): return c.name == "Dampf")
|
||||
check(g.human.board.size() == before - 2 and dampf_cards.size() == 1 and g.human.energy == mana, "beide Wesen verlassen das Brett, Dampf liegt auf der Hand, kostenlos")
|
||||
var dampf: Cards.Card = dampf_cards[0]
|
||||
var dampf_views: Array = scr.hand_views.filter(func(v): return v.card == dampf)
|
||||
check(dampf.look == 3 and dampf.attack == 8 and dampf.health == 7 and dampf.cost == 4 and dampf_views.size() == 1 and dampf_views[0].rarity == "Ultra Rare", "Dampf 5/4 für 4 Mana aus den Grundwerten, Stufe 3 des Reiters macht 8/7")
|
||||
await shot("24_verschmelzen")
|
||||
# Verschmelzen auf der Hand per Ziehen
|
||||
g.human.hand = [Cards.by_id("f_2_1").copy(), Cards.by_id("f_2_1").copy(), Cards.by_id("l_1_1").copy()]
|
||||
scr.refresh()
|
||||
await frames(1)
|
||||
await drag_fuse(scr, scr.hand_views[0], scr.hand_views[1])
|
||||
await accept_fuse(scr)
|
||||
check(g.human.hand.size() == 2 and g.human.hand[0].name == "Inferno" and g.human.hand[0].attack == 3 and g.human.hand[0].health == 2, "zwei Funken auf der Hand zu Inferno 3/2")
|
||||
# Gamepad-Menü (Y) bietet Verdeckt legen und Verschmelzen mit …
|
||||
scr.open_menu(g.human.hand[0], Rect2(scr.hand_views[0].position, scr.hand_views[0].size), true)
|
||||
@@ -797,7 +852,12 @@ func test_kampf_elemente_und_verschmelzen() -> void:
|
||||
await click(find_button("Verschmelzen mit …", scr.menu_layer))
|
||||
check(scr.fuse_first == g.human.hand[0], "Partner wählen")
|
||||
await click(scr.hand_views[1])
|
||||
check(g.human.hand.size() == 1 and g.human.hand[0].name == "Blitz", "Inferno und Windgeist zu Blitz")
|
||||
check(g.human.hand.size() == 1 and g.human.hand[0].name == "Blitz", "Inferno und Hauch zu Blitz")
|
||||
# Handkarte mit Wesen: Blitz auf den Kobold ziehen
|
||||
var board_n: int = g.human.board.size()
|
||||
await drag_fuse(scr, scr.hand_views[0], scr.own_views[0])
|
||||
await accept_fuse(scr)
|
||||
check(g.human.board.size() == board_n - 1 and g.human.hand.size() == 1 and g.human.hand[0].name == "Blitz" and g.human.hand[0].base_attack() == 4, "Handkarte und Wesen verschmelzen: der Kobold verlässt das Brett, Blitz 4/4 bleibt auf der Hand")
|
||||
await give_up()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user