update
Some checks failed
Tests / headless (push) Has been cancelled
Tests / fenster-schnell (push) Has been cancelled
Tests / fenster-voll (push) Has been cancelled
Tests / balance (push) Has been cancelled

This commit is contained in:
Team3
2026-09-28 19:44:30 +02:00
parent dfcd3cb713
commit f0a8f18de8
37 changed files with 1588 additions and 880 deletions

View File

@@ -18,25 +18,23 @@ func C(id: String) -> Cards.Card:
return Cards.by_id(id)
func setup(human_hand: Array = [], opp_hand: Array = [], n_opp: int = 1) -> Array:
## Duell mit vollem Mana; der Gegner hat 15 Leben. Liefert [Spiel, Spieler, Gegner].
func setup(human_hand: Array = [], opp_hand: Array = []) -> Array:
var human := Game.Player.new("Spieler", true, 30)
var opps := []
for i in n_opp:
opps.append(Game.Player.new("Gegner %d" % (i + 1), false, 15))
var o := Game.Player.new("Gegner", false, 15)
var r := RandomNumberGenerator.new()
r.seed = 0
var g := Game.new(human, opps, r)
var g := Game.new(human, o, r)
g.turn = 1
human.max_energy = 10
human.energy = 10
for cid in human_hand:
human.hand.append(C(cid))
for o in opps:
o.max_energy = 10
o.energy = 10
for cid in opp_hand:
o.hand.append(C(cid))
return [g, human, opps]
o.max_energy = 10
o.energy = 10
for cid in opp_hand:
o.hand.append(C(cid))
return [g, human, o]
var next_uid := 9000
@@ -60,7 +58,6 @@ func _initialize() -> void:
test_wesen_spielen()
test_flink()
test_waechter()
test_waechter_nur_eigener_besitzer()
test_kampf_beidseitig()
test_schild()
test_doppelschlag()
@@ -76,15 +73,13 @@ func _initialize() -> void:
test_mana_effekt()
test_gleiche_regeln()
test_zugreihenfolge()
test_tote_gegner()
test_jeder_gegen_jeden()
test_gegnerzahl()
test_sieg_niederlage()
test_booster()
test_spielstand()
test_resonanz()
test_elementvorteil()
test_feld()
test_vorschau()
test_verschmelzen()
test_feldkombos()
test_schild_effekt_und_sonne()
@@ -141,7 +136,7 @@ func test_flink() -> void:
var s := setup(["l_falke"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
g.play_card(h, C("l_falke"))
check(g.attack(h.board[0], o) == "", "Flink greift sofort an")
check(o.life == 12, "Falke 3 Schaden")
@@ -151,7 +146,7 @@ func test_waechter() -> void:
var s := setup()
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var a := put(h, "f_wolf")
var w := put(o, "e_wall")
check(g.attack(a, o) != "", "Wächter blockt Angriff auf Held")
@@ -159,20 +154,11 @@ func test_waechter() -> void:
check(w.health == 1 and a.health == 2, "Schaden verrechnet")
func test_waechter_nur_eigener_besitzer() -> void:
var s := setup([], [], 2)
var g: Game = s[0]
var h: Game.Player = s[1]
var a := put(h, "f_wolf")
put(s[2][0], "e_wall")
check(g.attack(a, s[2][1]) == "" and s[2][1].life == 12, "Wächter schützt nur Besitzer")
func test_kampf_beidseitig() -> void:
var s := setup()
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var a := put(h, "f_asche")
var d := put(o, "w_reiter")
g.attack(a, d)
@@ -184,7 +170,7 @@ func test_schild() -> void:
var s := setup()
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var sh := put(o, "ee_bastion")
var a := put(h, "f_asche")
g.attack(a, sh)
@@ -198,7 +184,7 @@ func test_doppelschlag() -> void:
var s := setup()
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var a := put(h, "l_schlange")
g.attack(a, o)
g.attack(a, o)
@@ -210,7 +196,7 @@ func test_einfrieren() -> void:
var s := setup([], ["w_frost"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var a := put(h, "f_wolf")
g.end_turn()
check(g.play_card(o, C("w_frost"), a) == "", "Frostmagier spielen")
@@ -226,30 +212,29 @@ func test_effekt_ziel() -> void:
var s := setup(["w_frost", "f_ritter"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
check(g.play_card(h, C("w_frost")) == "" and h.board.size() == 1, "ohne Ziel kommt das Wesen trotzdem, der Effekt verpufft")
g.play_card(h, C("f_ritter"), o)
check(o.life == 14 and h.board.size() == 2, "Ritter macht 1 Schaden an den Helden")
func test_flaechenschaden() -> void:
var s := setup(["ff_phoenix"], [], 2)
var s := setup(["ff_phoenix"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o1: Game.Player = s[2][0]
var o2: Game.Player = s[2][1]
put(o1, "f_kobold")
put(o2, "e_golem")
var o: Game.Player = s[2]
put(o, "f_kobold")
put(o, "e_golem")
g.play_card(h, C("ff_phoenix"))
check(o1.life == 11 and o2.life == 11, "Helden 4 Schaden")
check(o1.board.is_empty() and o2.board[0].health == 1, "Wesen getroffen")
check(o.life == 11, "Held 4 Schaden")
check(o.board.size() == 1 and o.board[0].health == 1, "Wesen getroffen, Kobold tot")
func test_zurueck_auf_hand() -> void:
var s := setup(["wl_nebel"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var d := put(o, "e_troll")
g.play_card(h, C("wl_nebel"), d)
check(o.board.is_empty() and C("e_troll") in o.hand, "zurück auf Hand")
@@ -285,11 +270,10 @@ func test_limits() -> void:
## Grenzfälle, die schon einmal falsch waren.
func test_grenzfaelle() -> void:
var s := setup(["f_wolf"], [], 2)
var s := setup(["f_wolf"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o1: Game.Player = s[2][0]
var o2: Game.Player = s[2][1]
var o1: Game.Player = s[2]
# Nur Karten von der eigenen Hand
check(not g.can_play(h, C("e_troll"))[0] and g.play_card(h, C("e_troll")) == "Nicht auf der Hand", "fremde Karte lässt sich nicht spielen")
check(g.play_card(h, C("f_wolf")) == "" and h.board.size() == 1, "eigene Handkarte geht")
@@ -298,7 +282,7 @@ func test_grenzfaelle() -> void:
o1.life = 0
g.cleanup()
check(o1.board.is_empty() and not o1.alive() and g.log.any(func(l): return l.find("verschwindet mit") >= 0), "besiegter Spieler räumt sein Feld")
check(not (o1 in g.enemies_of(h)) and o2 in g.enemies_of(h), "Besiegte sind keine Ziele mehr")
check(g.enemies_of(h).is_empty(), "Besiegte sind keine Ziele mehr")
check(dead != null, "Wesen war vorher da")
# Verschmolzene Karte auf der Hand übersteht den Spielstand
var a := put(h, "f_kobold")
@@ -314,10 +298,10 @@ func test_grenzfaelle() -> void:
## Zweite Runde Grenzfälle: Konter ohne Angriff, Chimäre, Ereignisse mit verschmolzener Karte,
## ausgeschiedener Netzwerkspieler mitten im eigenen Zug.
func test_grenzfaelle_2() -> void:
var s := setup([], [], 2)
var s := setup()
var g: Game = s[0]
var h: Game.Player = s[1]
var o1: Game.Player = s[2][0]
var o1: Game.Player = s[2]
# Ein Wesen ohne Angriff schlägt nicht zurück, auch nicht mit Elementvorteil
var wall := put(o1, "e_wall") # Erde 0/4, Erde schlägt Wasser
var reiter := put(h, "w_reiter") # Wasser 3/3
@@ -347,10 +331,10 @@ func test_grenzfaelle_2() -> void:
net.game = g
net.rejoin_seconds = 0.0
net.waiting = {"Spieler": {"seat": g.players.find(h), "since": 0.0}}
o1.is_human = true # noch ein Mensch am Tisch, sonst wäre die Partie schlicht verloren
o1.is_human = true # ein Duell zweier Menschen
check(g.current() == h, "Spieler ist dran")
net.tick()
check(not h.alive() and h.board.is_empty() and g.current() != h, "Ausgeschiedener räumt das Feld und der Zug geht weiter")
check(not h.alive() and h.board.is_empty() and g.winner != "" and g.winner_player == o1, "Ausgeschiedener räumt das Feld, der andere gewinnt")
net.free()
@@ -421,7 +405,7 @@ func test_mana_effekt() -> void:
func test_gleiche_regeln() -> void:
var r := RandomNumberGenerator.new()
r.seed = 0
var g := Game.new_battle(3, r)
var g := Game.new_battle(r)
var first: Game.Player = g.players[0]
check(g.current() == first and first.max_energy == 1 and first.energy == 1, "Startspieler: 1 Mana, kein Bonus")
check(first.shop.size() == Game.SHOP_SIZE and first.hand.is_empty(), "jeder beginnt mit einem Laden und leerer Hand")
@@ -432,9 +416,9 @@ func test_gleiche_regeln() -> void:
g.end_turn()
var second: Game.Player = g.players[1]
check(g.current() == second and second.max_energy == 1 and second.energy == 2, "Nachzieher: 1 Mana plus Ausgleich")
for i in 4:
for i in 2:
g.end_turn()
check(g.current() == second and second.max_energy == 2, "Ausgleich nur einmal")
check(g.current() == second and second.max_energy == 2 and second.energy == 4, "Ausgleich nur einmal: 2 übrig plus 2 Einkommen")
func test_zugreihenfolge() -> void:
@@ -442,9 +426,9 @@ func test_zugreihenfolge() -> void:
for seed in 12:
var r := RandomNumberGenerator.new()
r.seed = seed
var g := Game.new_battle(2, r)
var g := Game.new_battle(r)
starters[g.players[0].name] = true
check(g.players.size() == 3 and g.human in g.players and g.opponents.size() == 2, "alle am Tisch")
check(g.players.size() == 2 and g.human in g.players and g.opponent in g.players, "beide am Tisch")
for i in g.players.size():
check(g.players[i].order == i, "Reihenfolge nummeriert")
check(g.log[0].begins_with("Zugreihenfolge:"), "Reihenfolge im Verlauf")
@@ -453,58 +437,15 @@ func test_zugreihenfolge() -> void:
check(starters.size() > 1, "Startspieler wechselt (%d verschiedene)" % starters.size())
func test_tote_gegner() -> void:
var s := setup([], [], 2)
var g: Game = s[0]
s[2][0].life = 0
g.end_turn()
check(g.current() == s[2][1], "toter Gegner übersprungen")
g.end_turn()
check(g.current() == s[1] and g.turn == 2, "zurück beim Spieler, Zug 2")
func test_jeder_gegen_jeden() -> void:
var s := setup([], [], 2)
var g: Game = s[0]
var h: Game.Player = s[1]
var o1: Game.Player = s[2][0]
var o2: Game.Player = s[2][1]
check(g.enemies_of(o1) == [h, o2], "Gegner bekämpft Spieler und anderen Gegner")
check(g.enemies_of(h) == [o1, o2], "Spieler bekämpft alle Gegner")
g.end_turn()
o1.hand = []
var a := put(o1, "f_wolf")
check(g.can_attack(a, o2)[0], "Gegner darf Gegner angreifen")
check(g.attack(a, o2) == "" and o2.life == 12, "Gegner trifft Gegner")
check(AI.choose_action(g, o1).type == "buy", "KI kauft aus ihrem Laden")
o1.shop = []
check(AI.choose_action(g, o1).type == "end", "ohne Angebot und ohne Angriff endet der Zug")
o2.life = 2
var b := put(o1, "f_kobold")
check(AI.choose_action(g, o1).target == o2, "KI nutzt Lethal gegen anderen Gegner")
func test_gegnerzahl() -> void:
var r := RandomNumberGenerator.new()
r.seed = 2
for n in range(1, Game.MAX_OPPONENTS + 1):
var g := Game.new_battle(n, r)
check(g.opponents.size() == n, "%d Gegner" % n)
check(g.players.all(func(o): return o.life == Game.START_LIFE), "gleiches Leben bei %d" % n)
check(g.players[0].max_energy == 1 and g.current() == g.players[0], "Startspieler bei %d" % n)
check(g.human.shop.size() == Game.SHOP_SIZE, "Laden bei %d" % n)
check(Profile.REWARD_WIN.has(n), "Belohnung bei %d" % n)
func test_sieg_niederlage() -> void:
var s := setup([], [], 2)
var s := setup()
var g: Game = s[0]
g.damage(s[2][0], 99)
g.damage(s[2], 14)
g.check_end()
check(g.winner == "", "noch offen")
g.damage(s[2][1], 99)
g.damage(s[2], 1)
g.check_end()
check(g.winner == "human", "Sieg")
check(g.winner == "human" and g.winner_player == s[1], "Sieg")
var s2 := setup()
var g2: Game = s2[0]
g2.damage(s2[1], 30)
@@ -562,7 +503,7 @@ func test_ki_lethal() -> void:
var s := setup()
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
o.life = 3
var a := put(h, "f_asche")
put(o, "w_reiter")
@@ -573,23 +514,20 @@ func test_ki_lethal() -> void:
func test_ki_spiele_enden() -> void:
var r := RandomNumberGenerator.new()
r.seed = 7
for n in [1, 3, 5]:
for i in 6:
var pool: Array = Cards.ELEMENTS.duplicate()
Game.shuffle(pool, r)
var g := Game.new_battle(n, r)
var guard := 0
while g.winner == "" and guard < 300:
AI.take_turn(g, g.current(), i % 2 == 0)
guard += 1
check(g.winner != "", "Spiel endet (%d Gegner)" % n)
for i in 12:
var g := Game.new_battle(r)
var guard := 0
while g.winner == "" and guard < 300:
AI.take_turn(g, g.current(), i % 2 == 0)
guard += 1
check(g.winner != "", "Spiel endet (Partie %d)" % i)
func test_resonanz() -> void:
var s := setup(["f_wolf", "f_kobold", "e_wall"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
g.play_card(h, C("f_wolf"))
check(h.board[0].power() == 3, "allein keine Resonanz")
g.play_card(h, C("f_kobold"))
@@ -621,7 +559,7 @@ func test_elementvorteil() -> void:
var s := setup(["f_ritter"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var mine := put(h, "w_reiter") # Wasser 3/3
var his := put(o, "f_wolf") # Feuer 3/2
g.attack(mine, his)
@@ -633,7 +571,7 @@ func test_elementvorteil() -> void:
s = setup(["f_ritter"])
g = s[0]
h = s[1]
o = s[2][0]
o = s[2]
var air := put(o, "l_laeufer") # Luft 3/4, Feuer schlägt Luft
g.play_card(h, C("f_ritter"), air)
check(air.health == 2, "Feuereffekt gegen Luft: 1 Schaden mehr")
@@ -644,7 +582,7 @@ func test_feld() -> void:
var s := setup(["f_ritter"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
check(g.field_element == "" and int(g.field_charge["Feuer"]) == 0, "das Feld beginnt neutral")
var wolf := put(h, "f_wolf")
for i in Cards.FIELD_CHARGE - 1:
@@ -669,11 +607,34 @@ func test_feld() -> void:
## Verschmelzen: zwei eigene Wesen werden eins, Werte Durchschnitt plus 1.
## Vorschau fürs Ausspielen: Resonanz, Feldbonus und Feldkombo mit Partner.
func test_vorschau() -> void:
var s := setup(["f_kobold", "e_wall"])
var g: Game = s[0]
var h: Game.Player = s[1]
var f := g.forecast(h, C("f_kobold"))
check(f.resonance == 0 and f.field == 0 and f.combo == "" and f.partner == null, "leeres Feld: keine Vorschau")
var wolf := put(h, "f_wolf")
put(h, "f_asche")
var reiter := put(h, "w_reiter")
f = g.forecast(h, C("f_kobold"))
check(f.resonance == 2 and f.combo == "Dampf" and f.partner == reiter, "zwei Feuerpartner geben +2, das Wasserwesen die Kombo Dampf")
f = g.forecast(h, C("e_wall"))
check(f.resonance == 0 and f.combo == "Lava" and f.partner == wolf, "Erde: kein Partner, Kombo Lava mit dem ersten Feuerwesen")
g.field_element = "Feuer"
check(g.forecast(h, C("f_kobold")).field == 1 and g.forecast(h, C("e_wall")).field == 0, "der Feldbonus zählt nur fürs eigene Element")
h.perks.append("resonanz_doppelt")
check(g.forecast(h, C("f_kobold")).resonance == 4, "doppelte Resonanz verdoppelt die Vorschau")
var real := g.play_card(h, C("f_kobold"))
var kobold: Game.Creature = h.board[-1]
check(real == "" and kobold.power() == 2 + 4 + 1, "das Ausspielen bringt genau den vorhergesagten Angriff")
func test_verschmelzen() -> void:
var s := setup()
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var a := put(h, "f_wolf") # Feuer 3/2, Kosten 2
var b := put(h, "w_reiter") # Wasser 3/3, Kosten 2
check(Cards.fusion_cost(a.card, b.card) == 2 and Cards.fusion_cost(C("f_kobold"), C("f_asche")) == 2, "Kosten: Durchschnitt, aufgerundet")
@@ -719,7 +680,7 @@ func test_feldkombos() -> void:
var s := setup(["w_reiter"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
put(h, "f_wolf")
var weak := put(o, "f_kobold")
var strong := put(o, "e_troll")
@@ -730,20 +691,19 @@ func test_feldkombos() -> void:
s = setup(["e_golem"])
g = s[0]
h = s[1]
o = s[2][0]
o = s[2]
put(h, "f_wolf")
var k := put(o, "f_kobold")
var big := put(o, "e_troll")
g.play_card(h, C("e_golem"))
check(k in o.board and big.health == 5, "Lava trifft nur das stärkste Wesen")
# Blitz: 2 Schaden an den schwächsten Gegner
s = setup(["l_wind"], [], 2)
# Blitz: 2 Schaden an den Gegner
s = setup(["l_wind"])
g = s[0]
h = s[1]
put(h, "f_wolf")
s[2][1].life = 5
g.play_card(h, C("l_wind"))
check(s[2][1].life == 3 and s[2][0].life == 15, "Blitz trifft den schwächsten Gegner")
check(s[2].life == 13, "Blitz trifft den Gegner")
# Schlamm heilt, Sturm gibt Mana, Sand gibt +1/+1
s = setup(["e_wall", "l_wind", "w_reiter"])
g = s[0]
@@ -773,7 +733,7 @@ func test_feldkombos() -> void:
s = setup(["fe_golem"])
g = s[0]
h = s[1]
o = s[2][0]
o = s[2]
put(h, "w_reiter")
var t := put(o, "e_troll")
g.play_card(h, C("fe_golem"))
@@ -784,7 +744,7 @@ func test_schild_effekt_und_sonne() -> void:
var s := setup(["el_duenen", "fff_sonne"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var a := put(h, "f_wolf")
g.play_card(h, C("el_duenen"), a)
check(a.shield, "Dünenläufer gibt Schild")
@@ -792,7 +752,7 @@ func test_schild_effekt_und_sonne() -> void:
s = setup(["fff_sonne"])
g = s[0]
h = s[1]
o = s[2][0]
o = s[2]
check(C("fff_sonne").elements == ["Feuer"] and C("fff_sonne").cost == 9, "Kern der Sonne ist ein teures Feuerwesen")
var troll := put(o, "e_troll")
g.play_card(h, C("fff_sonne"))
@@ -803,7 +763,7 @@ func test_kopie() -> void:
var s := setup(["f_wolf"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
var a := put(h, "f_asche")
var g2 := g.clone()
var a2 := g2.find_creature(a.uid)
@@ -823,7 +783,7 @@ func test_ki_besser_als_gierig() -> void:
for i in games:
var pool: Array = Cards.ELEMENTS.duplicate()
Game.shuffle(pool, r)
var g := Game.new_battle(1, r)
var g := Game.new_battle(r)
# abwechselnd beginnt die schlaue oder die gierige KI
var smart_is_human := i % 2 == 0
var guard := 0
@@ -855,22 +815,22 @@ func test_kampagne() -> void:
var r := RandomNumberGenerator.new()
r.seed = 4
check(Campaign.STAGES.size() == 10, "zehn Stufen")
var opps := Campaign.opponents(4)
check(opps.size() == 3 and opps[0].name == "Vulkar" and opps[0].title == "Herr der Lava", "Stufe 5: Vulkar mit 2 Begleitern")
check(opps[0].elements == ["Feuer", "Erde"] and opps[0].shop.all(func(c): return c.elements.all(func(e): return e in ["Feuer", "Erde"])), "Boss handelt nur mit seinen Elementen")
var g := Game.new_battle_with(opps, r)
check(g.opponents.size() == 3 and g.human.life == Game.START_LIFE, "Kampagnenkampf gestartet")
var boss := Campaign.opponent(4)
check(boss.name == "Vulkar" and boss.title == "Herr der Lava" and boss.life == 32, "Stufe 5: Vulkar mit 32 Leben")
check(boss.elements == ["Feuer", "Erde"] and boss.shop.all(func(c): return c.elements.all(func(e): return e in ["Feuer", "Erde"])), "Boss handelt nur mit seinen Elementen")
var g := Game.new_battle_with(boss, r)
check(g.opponent == boss and g.human.life == Game.START_LIFE, "Kampagnenkampf gestartet")
var p := Profile.starter()
var reward := p.record_battle(true, 1, 0)
var reward := p.record_battle(true, 0)
check(p.campaign_stage == 1 and reward == Campaign.STAGES[0].reward, "Stufe 1 abgeschlossen")
reward = p.record_battle(true, 1, 0)
check(p.campaign_stage == 1 and reward == Profile.REWARD_WIN[1], "Wiederholung gibt normale Belohnung")
reward = p.record_battle(false, 2, 1)
reward = p.record_battle(true, 0)
check(p.campaign_stage == 1 and reward == Profile.REWARD_WIN, "Wiederholung gibt normale Belohnung")
reward = p.record_battle(false, 1)
check(p.campaign_stage == 1 and reward == Profile.REWARD_LOSS, "Niederlage schaltet nichts frei")
p.campaign_stage = 9
p.record_battle(true, 5, 9)
p.record_battle(true, 9)
check(p.campaign_stage == 10, "Kampagne abgeschlossen")
var sim := Game.new_battle_with(Campaign.opponents(0), r)
var sim := Game.new_battle_with(Campaign.opponent(0), r)
var guard := 0
while sim.winner == "" and guard < 300:
AI.take_turn(sim, sim.current(), true)
@@ -916,7 +876,7 @@ func test_merkmale() -> void:
var s := setup(["f_wolf", "l_falke", "e_wall"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
h.perks = ["feuer_angriff", "flink_angriff", "waechter_leben", "schild_wesen", "alle_flink", "resonanz_doppelt"]
g.play_card(h, C("f_wolf"))
var wolf: Game.Creature = h.board[0]
@@ -932,15 +892,15 @@ func test_merkmale() -> void:
check(Campaign.STAGES.any(func(st): return st.perk == perk), "Merkmal vergeben: " + perk)
var r := RandomNumberGenerator.new()
r.seed = 2
var mara: Game.Player = Campaign.opponents(1)[0]
check(mara.life == 35 and mara.perks == ["leben_35"], "Mara hat 35 Leben")
var g3 := Game.new_battle_with(Campaign.opponents(9), r, true)
var archi: Game.Player = g3.opponents[0]
var mara: Game.Player = Game.new_battle_with(Campaign.opponent(1), r).opponent
check(mara.life == 35 and mara.max_life == 35 and mara.perks == ["leben_35"], "Mara hat mit ihrem Merkmal 35 Leben")
var g3 := Game.new_battle_with(Campaign.opponent(9), r, true)
var archi: Game.Player = g3.opponent
check(g3.players[0] == g3.human, "feste Reihenfolge: Mensch beginnt")
g3.end_turn()
check(g3.current() == archi and archi.energy == 3 + 1, "Archimagier beginnt mit 3 Mana (plus Ausgleich)")
var nyx: Game.Player = Campaign.opponents(5)[0]
var g4 := Game.new_battle_with([nyx], r, true)
var nyx: Game.Player = Campaign.opponent(5)
var g4 := Game.new_battle_with(nyx, r, true)
g4.end_turn()
# Einkommen 1, dazu 1 Mana für ihr Merkmal und 1 als Ausgleich für den späteren Start
check(nyx.max_energy == 1 and nyx.energy == 3, "Nyx bekommt 1 Mana mehr als ihr Einkommen")
@@ -952,7 +912,7 @@ func test_ki_zwei_schritte() -> void:
var s := setup(["el_koenig"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
h.turns = 2
o.life = 5
put(h, "f_wolf", false)
@@ -966,10 +926,10 @@ func test_ki_zwei_schritte() -> void:
func test_snapshot() -> void:
var s := setup(["f_wolf"], ["w_frost"], 2)
var s := setup(["f_wolf"], ["w_frost"])
var g: Game = s[0]
var h: Game.Player = s[1]
var o: Game.Player = s[2][0]
var o: Game.Player = s[2]
g.play_card(h, C("f_wolf"))
put(o, "e_troll")
var hi := g.players.find(h)
@@ -979,7 +939,7 @@ func test_snapshot() -> void:
var snap := g.snapshot(hi)
var json: Dictionary = JSON.parse_string(JSON.stringify(snap))
var g2 := Game.from_snapshot(json)
check(g2.players.size() == 3 and g2.turn == g.turn and g2.current_idx == g.current_idx, "Grunddaten")
check(g2.players.size() == 2 and g2.turn == g.turn and g2.current_idx == g.current_idx, "Grunddaten")
check(g2.players[hi].hand.is_empty(), "eigene Hand sichtbar")
check(g2.players[oi].hand.size() == 1 and g2.players[oi].hand[0] != C("w_frost"), "fremde Hand nur als Anzahl")
check(g2.players[oi].shop.is_empty() and g2.players[hi].shop.size() == Game.SHOP_SIZE, "eigener Laden sichtbar, fremder nicht")
@@ -1002,17 +962,17 @@ func test_kapitel_zwei_und_merkmalwahl() -> void:
check(st.has("perks") and st.perks.all(func(k): return Game.PERKS.has(k)), "Stufe %d hat gültige Merkmale" % (i + 1))
var r := RandomNumberGenerator.new()
r.seed = 8
var opps := Campaign.opponents(19)
check(opps.size() == 5 and opps[0].name == "Archimagier" and opps[0].perks.size() == 3, "letzte Stufe: Archimagier mit drei Merkmalen, voller Tisch")
var archi2 := Campaign.opponent(19)
check(archi2.name == "Archimagier" and archi2.perks.size() == 3 and archi2.life == 34, "letzte Stufe von Kapitel 2: Archimagier mit drei Merkmalen und 34 Leben")
var p := Profile.starter()
check(not p.perk_unlocked(), "Merkmalwahl erst nach Kapitel 1")
p.campaign_stage = 10
check(p.perk_unlocked(), "nach Kapitel 1 freigeschaltet")
p.perk = "feuer_angriff"
var g := Game.new_battle(1, r, {"human_perks": [p.perk]})
var g := Game.new_battle(r, {"human_perks": [p.perk]})
check(g.human.perks == ["feuer_angriff"] and g.log.any(func(l): return l.begins_with("Spieler: Feuerwesen")), "eigenes Merkmal wirkt und steht im Verlauf")
p.campaign_stage = 19
p.record_battle(true, 5, 19)
p.record_battle(true, 19)
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")
@@ -1021,7 +981,7 @@ func test_kapitel_zwei_und_merkmalwahl() -> void:
func test_ki_zeitbudget() -> void:
var r := RandomNumberGenerator.new()
r.seed = 12
var g := Game.new_battle(5, r)
var g := Game.new_battle(r)
var h: Game.Player = g.players[0]
h.energy = 10
h.max_energy = 10
@@ -1058,7 +1018,7 @@ func test_englische_karten() -> void:
func test_kampf_speichern() -> void:
var r := RandomNumberGenerator.new()
r.seed = 7
var g := Game.new_battle(2, r)
var g := Game.new_battle(r)
g.start()
AI.take_turn(g, g.current())
var d: Dictionary = JSON.parse_string(JSON.stringify(g.snapshot(-1)))
@@ -1075,7 +1035,7 @@ func test_kampf_speichern() -> void:
while g2.winner == "" and guard < 300:
AI.take_turn(g2, g2.current())
guard += 1
check(g2.winner != "", "fortgesetzte Partie ist bis zum Ende spielbar")
check(g2.winner != "", "der volle Spielstand ist bis zum Ende spielbar")
var s2: Dictionary = g.snapshot(-2)
check(s2.players.all(func(p): return not (p.hand is Array) and p.shop.is_empty()), "Zuschauer-Sicht ohne Hände und Läden")