update
This commit is contained in:
@@ -68,7 +68,6 @@ static func evaluate(g: Game, p: Game.Player) -> float:
|
||||
# --- Vorausschau ---------------------------------------------------------------
|
||||
|
||||
const MAX_TARGETS := 4 # je Angreifer nur die aussichtsreichsten Ziele prüfen
|
||||
static var allow_upgrade := true # zum Messen: Verbessern erwägen
|
||||
const DEEPEN := 8 # so viele beste Erstschritte bekommen Folgeschritte
|
||||
const FOLLOW_UPS := 10 # Folgeschritte je vertieftem Kandidat
|
||||
static var time_budget_ms := 150 # Zeitbudget je Entscheidung; danach der beste bisherige Zug
|
||||
@@ -99,18 +98,9 @@ static func candidate_actions(game: Game, p: Game.Player, prune: bool = false) -
|
||||
for card in p.hand:
|
||||
if game.can_play(p, card)[0]:
|
||||
out.append({"type": "play", "card": card, "face_down": false})
|
||||
var has_target := not game.enemies_of(p).is_empty()
|
||||
for cr in p.board:
|
||||
if cr.hidden:
|
||||
if game.can_reveal(p, cr)[0]:
|
||||
out.append({"type": "reveal", "creature": cr})
|
||||
elif allow_upgrade and has_target:
|
||||
# Nur Verbesserungen, die sich noch in diesem Zug auszahlen können: Doppelschlag für
|
||||
# ein Wesen, das gleich angreift; Flink für eines, das sonst erst nächsten Zug dürfte.
|
||||
if cr.can_attack() and game.can_upgrade(p, cr, "Doppelschlag")[0]:
|
||||
out.append({"type": "upgrade", "creature": cr, "keyword": "Doppelschlag"})
|
||||
if not cr.ready and not cr.has("Flink") and cr.power() > 0 and game.can_upgrade(p, cr, "Flink")[0]:
|
||||
out.append({"type": "upgrade", "creature": cr, "keyword": "Flink"})
|
||||
if cr.hidden and game.can_reveal(p, cr)[0]:
|
||||
out.append({"type": "reveal", "creature": cr})
|
||||
var pairs := []
|
||||
for i in p.board.size():
|
||||
for j in range(i + 1, p.board.size()):
|
||||
@@ -144,8 +134,6 @@ static func apply_on_clone(g2: Game, game: Game, action: Dictionary) -> void:
|
||||
g2.play_card(p2, action.card, bool(action.get("face_down", false)))
|
||||
"reveal":
|
||||
g2.reveal(p2, g2.find_creature(action.creature.uid))
|
||||
"upgrade":
|
||||
g2.upgrade(p2, g2.find_creature(action.creature.uid), action.keyword)
|
||||
"fuse":
|
||||
g2.fuse(p2, g2.find_creature(action.creature.uid), g2.find_creature(action.other.uid))
|
||||
_:
|
||||
@@ -269,10 +257,6 @@ static func choose_action_greedy(game: Game, p: Game.Player) -> Dictionary:
|
||||
var t = pick_attack_target(game, p, cr)
|
||||
if t != null:
|
||||
return {"type": "attack", "creature": cr, "target": t}
|
||||
if not game.enemies_of(p).is_empty():
|
||||
var strongest = _best(p.board.filter(func(c): return not c.hidden and game.can_upgrade(p, c, "Doppelschlag")[0]), func(c): return c.power())
|
||||
if strongest != null:
|
||||
return {"type": "upgrade", "creature": strongest, "keyword": "Doppelschlag"}
|
||||
if game.can_draw(p)[0]:
|
||||
return {"type": "draw"}
|
||||
return {"type": "end"}
|
||||
@@ -307,8 +291,6 @@ static func apply_action(game: Game, p: Game.Player, action: Dictionary) -> void
|
||||
game.draw(p)
|
||||
"reveal":
|
||||
game.reveal(p, action.creature)
|
||||
"upgrade":
|
||||
game.upgrade(p, action.creature, action.keyword)
|
||||
"attack":
|
||||
game.attack(action.creature, action.target)
|
||||
"fuse":
|
||||
|
||||
@@ -11,7 +11,7 @@ const STAGES := [
|
||||
{"name": "Nyx", "title": "Sturmruferin", "life": 26, "reward": 200, "perk": "extra_mana"},
|
||||
{"name": "Ignis", "title": "Inferno-Priester", "life": 26, "reward": 250, "perk": "element_doppelt"},
|
||||
{"name": "Thalassa", "title": "Tiefseekönigin", "life": 26, "reward": 250, "perk": "alle_flink"},
|
||||
{"name": "Zephyra", "title": "Blitzkaiserin", "life": 28, "reward": 300, "perk": "verbessern_billig"},
|
||||
{"name": "Zephyra", "title": "Blitzkaiserin", "life": 28, "reward": 300, "perk": "alle_flink"},
|
||||
{"name": "Archimagier", "title": "Meister der Elemente", "life": 28, "reward": 500, "perk": "start_energie"},
|
||||
]
|
||||
|
||||
@@ -21,12 +21,12 @@ const STAGES2 := [
|
||||
{"name": "Fenn", "title": "Flammenzähmer", "life": 22, "reward": 300, "perks": ["feuer_angriff", "start_energie"]},
|
||||
{"name": "Mara", "title": "Herrin der Gezeiten", "life": 22, "reward": 300, "perks": ["leben_35", "extra_mana"]},
|
||||
{"name": "Borin", "title": "Fels der Ewigkeit", "life": 24, "reward": 350, "perks": ["wesen_angriff", "alle_flink"]},
|
||||
{"name": "Liska", "title": "Sturmläuferin", "life": 24, "reward": 350, "perks": ["ziehen_gratis", "verbessern_billig"]},
|
||||
{"name": "Liska", "title": "Sturmläuferin", "life": 24, "reward": 350, "perks": ["ziehen_gratis", "wesen_angriff"]},
|
||||
{"name": "Vulkar", "title": "Aschekönig", "life": 24, "reward": 400, "perks": ["wesen_leben", "feuer_angriff"]},
|
||||
{"name": "Nyx", "title": "Gewitterruferin", "life": 26, "reward": 400, "perks": ["extra_mana", "ziehen_gratis"]},
|
||||
{"name": "Ignis", "title": "Inferno-Erzpriester", "life": 26, "reward": 450, "perks": ["element_doppelt", "wesen_leben"]},
|
||||
{"name": "Thalassa", "title": "Kaiserin der Tiefe", "life": 26, "reward": 450, "perks": ["alle_flink", "leben_35"]},
|
||||
{"name": "Zephyra", "title": "Blitzkaiserin", "life": 28, "reward": 500, "perks": ["verbessern_billig", "start_energie"]},
|
||||
{"name": "Zephyra", "title": "Blitzkaiserin", "life": 28, "reward": 500, "perks": ["alle_flink", "start_energie"]},
|
||||
{"name": "Archimagier", "title": "Herr aller Elemente", "life": 28, "reward": 800, "perks": ["start_energie", "element_doppelt"]},
|
||||
]
|
||||
|
||||
@@ -36,12 +36,12 @@ const STAGES3 := [
|
||||
{"name": "Fenn", "title": "Aschefürst", "life": 20, "reward": 600, "perks": ["feuer_angriff", "start_energie", "wesen_leben"]},
|
||||
{"name": "Mara", "title": "Sturmflut", "life": 20, "reward": 600, "perks": ["leben_35", "extra_mana", "alle_flink"]},
|
||||
{"name": "Borin", "title": "Berg selbst", "life": 22, "reward": 700, "perks": ["wesen_angriff", "alle_flink", "leben_35"]},
|
||||
{"name": "Liska", "title": "Windbraut", "life": 22, "reward": 700, "perks": ["ziehen_gratis", "verbessern_billig", "extra_mana"]},
|
||||
{"name": "Liska", "title": "Windbraut", "life": 22, "reward": 700, "perks": ["ziehen_gratis", "wesen_angriff", "extra_mana"]},
|
||||
{"name": "Vulkar", "title": "Magmakaiser", "life": 22, "reward": 800, "perks": ["wesen_leben", "feuer_angriff", "wesen_angriff"]},
|
||||
{"name": "Nyx", "title": "Orkanmutter", "life": 24, "reward": 800, "perks": ["extra_mana", "ziehen_gratis", "element_doppelt"]},
|
||||
{"name": "Ignis", "title": "Sonnenpriester", "life": 24, "reward": 900, "perks": ["element_doppelt", "wesen_leben", "start_energie"]},
|
||||
{"name": "Thalassa", "title": "Herz der Tiefe", "life": 24, "reward": 900, "perks": ["alle_flink", "leben_35", "element_doppelt"]},
|
||||
{"name": "Zephyra", "title": "Gewitterkaiserin", "life": 26, "reward": 1000, "perks": ["verbessern_billig", "start_energie", "wesen_leben"]},
|
||||
{"name": "Zephyra", "title": "Gewitterkaiserin", "life": 26, "reward": 1000, "perks": ["alle_flink", "start_energie", "wesen_leben"]},
|
||||
{"name": "Archimagier", "title": "Ewiger Meister", "life": 26, "reward": 1200, "perks": ["start_energie", "element_doppelt", "leben_35"]},
|
||||
]
|
||||
|
||||
|
||||
@@ -34,10 +34,9 @@ const RARITY_COLORS := {
|
||||
"Ultra Rare": Color("f0aa28"),
|
||||
"Ultimate Rare": Color("ff5a8c"),
|
||||
}
|
||||
# Eigenschaften haben Karten nicht von Haus aus; sie werden für Mana dazugekauft (Game.upgrade)
|
||||
# oder kommen vom Elementpaar der eigenen Seite (ELEMENT_KEYWORD, siehe Game.Creature.has).
|
||||
# Eigenschaften haben Karten nicht von Haus aus; sie kommen allein vom Elementpaar der eigenen
|
||||
# Seite (ELEMENT_KEYWORD, siehe Game.Creature.has).
|
||||
const KEYWORDS: Array[String] = ["Spott", "Flink", "Regeneration", "Doppelschlag"]
|
||||
const KEYWORD_COST := {"Spott": 2, "Flink": 2, "Regeneration": 3, "Doppelschlag": 4}
|
||||
const KEYWORD_TEXT := {
|
||||
"Spott": "Muss zuerst angegriffen werden",
|
||||
"Flink": "Greift sofort an",
|
||||
@@ -158,8 +157,8 @@ class Card extends RefCounted:
|
||||
var elements: Array
|
||||
var attack: int = 0
|
||||
var health: int = 0
|
||||
var cost: int = 0 # abgeleitet: (2 · Angriff + Leben) / 3, abgerundet, mindestens 1
|
||||
var keywords: Array = [] # dazugekauft, je Exemplar
|
||||
var cost: int = 0 # abgeleitet: (2 · Angriff + Leben) / 3, abgerundet
|
||||
var keywords: Array = [] # feste Eigenschaften der Karte (Elementpaare geben ihre zur Laufzeit)
|
||||
var fusions := 0 # wie oft verschmolzen (Verschmelzen kostet 1, 2, 4, 8 …)
|
||||
var look := -1 # Seltenheitsstufe verschmolzener Karten (die höhere der Eltern); -1: aus der Sammlung des Besitzers
|
||||
|
||||
@@ -211,7 +210,7 @@ class Card extends RefCounted:
|
||||
func fusion_cost() -> int:
|
||||
return 1 << fusions
|
||||
|
||||
## Kartentext: die gekauften Eigenschaften.
|
||||
## Kartentext: die festen Eigenschaften.
|
||||
func text() -> String:
|
||||
if keywords.is_empty():
|
||||
return ""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class_name Game
|
||||
extends RefCounted
|
||||
## Spielregeln: Duell, Mana je Zug, Ziehen aus dem gemeinsamen Stapel, verdeckte Wesen,
|
||||
## Elementboni, Verschmelzen und Verbessern.
|
||||
## Elementboni und Verschmelzen.
|
||||
|
||||
const MAX_BOARD := 5
|
||||
const MAX_HAND := 5
|
||||
@@ -21,7 +21,6 @@ const PERKS := {
|
||||
"extra_mana": "Bekommt jeden Zug 1 Mana mehr",
|
||||
"leben_35": "Beginnt mit 5 Leben mehr",
|
||||
"alle_flink": "Wesen greifen sofort an",
|
||||
"verbessern_billig": "Eigenschaften kosten 1 weniger",
|
||||
"start_energie": "Hat im ersten Zug 2 Mana mehr",
|
||||
"element_doppelt": "Elementbonus zählt doppelt",
|
||||
}
|
||||
@@ -65,8 +64,8 @@ class Creature extends RefCounted:
|
||||
func owner():
|
||||
return owner_ref.get_ref()
|
||||
|
||||
## Eigenschaft: gekauft, als Sondereffekt des Elementpaars der eigenen Seite oder als
|
||||
## Boss-Merkmal. Verdeckte Wesen haben keine.
|
||||
## Eigenschaft: als Sondereffekt des Elementpaars der eigenen Seite, aus der Karte
|
||||
## (verschmolzene erben) oder als Boss-Merkmal. Verdeckte Wesen haben keine.
|
||||
func has(kw: String) -> bool:
|
||||
if hidden:
|
||||
return false
|
||||
@@ -322,12 +321,6 @@ func draw_cost(p: Player) -> int:
|
||||
return 0 if "ziehen_gratis" in p.perks else DRAW_COST
|
||||
|
||||
|
||||
## Preis einer Eigenschaft für p.
|
||||
func upgrade_cost(p: Player, keyword: String) -> int:
|
||||
var c := int(Cards.KEYWORD_COST[keyword])
|
||||
return maxi(1, c - 1) if "verbessern_billig" in p.perks else c
|
||||
|
||||
|
||||
func draw(p: Player) -> String:
|
||||
var ok := can_draw(p)
|
||||
if not ok[0]:
|
||||
@@ -455,43 +448,6 @@ func _flip(cr: Creature) -> void:
|
||||
apply_auras()
|
||||
|
||||
|
||||
# --- Verbessern: Eigenschaften für Mana -------------------------------------
|
||||
|
||||
## target: eigenes Wesen auf dem Brett oder eigene Handkarte.
|
||||
func can_upgrade(p: Player, target, keyword: String) -> Array:
|
||||
if winner != "" or p != current():
|
||||
return [false, "Nicht dein Zug"]
|
||||
if not Cards.KEYWORD_COST.has(keyword):
|
||||
return [false, "Unbekannte Eigenschaft"]
|
||||
var card: Cards.Card = target.card if target is Creature else target
|
||||
if target is Creature:
|
||||
if not (target in p.board):
|
||||
return [false, "Nur eigene Wesen"]
|
||||
elif not (target in p.hand):
|
||||
return [false, "Nicht auf der Hand"]
|
||||
if keyword in card.keywords:
|
||||
return [false, "%s hat schon %s" % [card.name, keyword]]
|
||||
if p.energy < upgrade_cost(p, keyword):
|
||||
return [false, "Nicht genug Mana"]
|
||||
return [true, ""]
|
||||
|
||||
|
||||
func upgrade(p: Player, target, keyword: String) -> String:
|
||||
var ok := can_upgrade(p, target, keyword)
|
||||
if not ok[0]:
|
||||
return ok[1]
|
||||
p.energy -= upgrade_cost(p, keyword)
|
||||
var card: Cards.Card = (target.card if target is Creature else target).copy() # Kopien (KI) teilen sich Karten
|
||||
card.keywords.append(keyword)
|
||||
if target is Creature:
|
||||
target.card = card
|
||||
else:
|
||||
p.hand[p.hand.find(target)] = card
|
||||
say("%s bekommt %s." % [card.name, keyword])
|
||||
emit({"type": "upgrade", "player": players.find(p), "keyword": keyword, "uid": target.uid if target is Creature else -1})
|
||||
return ""
|
||||
|
||||
|
||||
# --- Verschmelzen ------------------------------------------------------------
|
||||
|
||||
static func card_of(x) -> Cards.Card:
|
||||
|
||||
@@ -398,12 +398,6 @@ func _apply(id: int, action: Dictionary) -> void:
|
||||
var cr := game.find_creature(int(action.get("uid", -1)))
|
||||
if cr != null:
|
||||
game.reveal(p, cr)
|
||||
"upgrade":
|
||||
var cr := game.find_creature(int(action.get("uid", -1)))
|
||||
var hi := int(action.get("hand", -1))
|
||||
var target = cr if cr != null else (p.hand[hi] if hi >= 0 and hi < p.hand.size() else null)
|
||||
if target != null:
|
||||
game.upgrade(p, target, str(action.get("keyword", "")))
|
||||
"attack":
|
||||
var cr := game.find_creature(int(action.get("uid", -1)))
|
||||
var t = resolve_ref(action.get("target"))
|
||||
|
||||
@@ -40,10 +40,6 @@ func play_events(evs: Array, centers: Dictionary) -> void:
|
||||
"reveal":
|
||||
sfx("combo")
|
||||
popup(tr("Aufgedeckt!"), Style.GOLD, screen.target_center({"kind": "creature", "uid": ev.uid}), 0.0)
|
||||
"upgrade":
|
||||
sfx("heal")
|
||||
if ev.uid >= 0:
|
||||
popup("+" + tr(ev.keyword), Style.GREEN, screen.target_center({"kind": "creature", "uid": ev.uid}), 0.0)
|
||||
"fuse":
|
||||
sfx("combo")
|
||||
popup("Verschmolzen!", Style.PURPLE, screen.target_center({"kind": "player", "index": ev.player}), 0.0)
|
||||
|
||||
@@ -661,21 +661,6 @@ func do_reveal(cr: Game.Creature) -> void:
|
||||
after_action()
|
||||
|
||||
|
||||
## Kauft eine Eigenschaft für eine Handkarte oder ein eigenes Wesen.
|
||||
func do_upgrade(target, keyword: String) -> void:
|
||||
clear_undo()
|
||||
if is_client():
|
||||
if target is Game.Creature:
|
||||
net.send_action({"type": "upgrade", "uid": target.uid, "keyword": keyword})
|
||||
else:
|
||||
net.send_action({"type": "upgrade", "hand": perspective.hand.find(target), "keyword": keyword})
|
||||
return
|
||||
var err := game.upgrade(perspective, target, keyword)
|
||||
if err != "":
|
||||
say(tr(err))
|
||||
after_action()
|
||||
|
||||
|
||||
## Kartenmenü neben einer Handkarte oder einem eigenen Wesen. full: auch verschmelzen anbieten
|
||||
## (Gamepad, das nicht ziehen kann).
|
||||
func open_menu(target, anchor: Rect2, full: bool = false) -> void:
|
||||
@@ -700,13 +685,9 @@ func open_menu(target, anchor: Rect2, full: bool = false) -> void:
|
||||
fuse_first = target
|
||||
say(tr("Ziel wählen"))
|
||||
refresh(), not partners.is_empty()])
|
||||
for kw in Cards.KEYWORDS:
|
||||
var k: String = kw
|
||||
var ok := game.can_upgrade(perspective, target, k)
|
||||
var text := "%s ◆ %d" % [tr(k), game.upgrade_cost(perspective, k)]
|
||||
if k in card.keywords:
|
||||
text = "%s ✓" % tr(k)
|
||||
entries.append([text, func(): do_upgrade(target, k), ok[0]])
|
||||
if entries.is_empty(): # offenes eigenes Wesen per Maus: nichts zu wählen
|
||||
close_menu()
|
||||
return
|
||||
var w := 230.0
|
||||
var h := 18.0 + entries.size() * 44 + 34
|
||||
var x := clampf(anchor.end.x + 8, 10, 1270 - w)
|
||||
|
||||
@@ -81,7 +81,7 @@ func _draw() -> void:
|
||||
var by := Style.fs(fs) + 13
|
||||
draw_rect(Rect2(size.x - bw - 4, by, bw, 16), Color(0.05, 0.05, 0.08, 0.75))
|
||||
Style.text(self, badge, 10, Style.GREEN if creature.aura > 0 else Style.RED, Vector2(size.x - 4 - bw / 2, by + 8), "center", true)
|
||||
# Eigenschaften als Symbole: gekaufte weiß, die vom Elementpaar in der Elementfarbe
|
||||
# Eigenschaften als Symbole in der Farbe des Elements, das sie gibt
|
||||
var icon := 7.0 if small else 9.0
|
||||
var kws := creature.keywords()
|
||||
var avail := size.x - (bw + 8 if badge != "" else 0.0)
|
||||
@@ -89,10 +89,9 @@ func _draw() -> void:
|
||||
var y := Style.fs(fs) + 14 + icon
|
||||
for k in kws:
|
||||
var col := Color("f2f2f6")
|
||||
if not (k in creature.card.keywords):
|
||||
for e in creature.card.elements:
|
||||
if Cards.ELEMENT_KEYWORD.get(e, "") == k:
|
||||
col = Style.lighter(Cards.ELEMENT_COLORS[e], 0.45)
|
||||
for e in creature.card.elements:
|
||||
if Cards.ELEMENT_KEYWORD.get(e, "") == k:
|
||||
col = Style.lighter(Cards.ELEMENT_COLORS[e], 0.45)
|
||||
Style.keyword_icon(self, k, Vector2(x + icon, y), icon, col)
|
||||
x += icon * 2 + 6
|
||||
_draw_stats(15 if small else 17, 12.0 if small else 14.0)
|
||||
|
||||
Reference in New Issue
Block a user