Kampf fortsetzen, Gamepad im Deckbau, Deck-Codes, Kapitel 3, Elementbooster, englische Karten, Host-Wechsel und Zuschauer
- KI-Bewertung mit Bedrohung und Führenden-Bremse (62:38 gegen die alte im Duell, gleichauf zu viert) - Balance: Sand +1/+1 statt Schild, Erde+Luft und Erde geschwächt, Wasser angehoben, Messlauf mit N=200 möglich - Einzelspieler-Kämpfe werden laufend gespeichert (voller Spielstand, viewer -1) und im Menü fortgesetzt - Karten, Deckzeilen und Kartenrücken fokussierbar: Gamepad in Deckbau, Werkstatt und Booster - Kartennamen (name_en) und Kartentexte übersetzbar, Übersetzungstest deckt cards.gd mit ab - Deck-Code DINGER1:id*anzahl mit Zwischenablage; acht neue Karten; Kampagne Kapitel 3; Elementbooster 120 Münzen - Netzwerk: Nachfolge-Host mit vollem Spielstand, Neuverbindung der anderen, Zuschauer (Sicht -2); Bot kann hosten - Große Schrift: Kartennamen, Kartentext, Knopfleisten, Gegnervorschau, Dialogtext - Anleitung 1 garantiert ein 1-Energie-Wesen; Tests: DINGER_ONLY für einzelne Oberflächentests - Oberflächentest auch auf Xephyr mit llvmpipe (wie Xvfb in der CI) grün Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPgKvy5W9WRNFHjkm5QsHx
This commit is contained in:
@@ -6,6 +6,8 @@ const SAVE_VERSION := 5
|
||||
const PITY_BOOSTERS := 20 # danach ist eine mythische Karte garantiert
|
||||
const SAVE_PATH := "user://spielstand.json"
|
||||
const BOOSTER_COST := 100
|
||||
const ELEMENT_BOOSTER_COST := 120 # nur Karten eines Elements (auch seine Kombos)
|
||||
const CODE_PREFIX := "DINGER1:" # Deck-Code zum Teilen
|
||||
const BOOSTER_SIZE := 5
|
||||
const RARITY_WEIGHTS := {"gewöhnlich": 70.0, "selten": 20.0, "episch": 7.5, "legendär": 2.0, "mythisch": 0.5}
|
||||
const START_COINS := 150
|
||||
@@ -34,6 +36,7 @@ const ACHIEVEMENTS := [
|
||||
{"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},
|
||||
{"id": "wochenheld", "name": "Wochenheld", "text": "Bestehe eine wöchentliche Herausforderung.", "reward": 100},
|
||||
]
|
||||
@@ -336,7 +339,15 @@ func dismantle_extras() -> int:
|
||||
|
||||
# --- Booster ----------------------------------------------------------------------
|
||||
|
||||
static func roll_booster(r: RandomNumberGenerator) -> Array:
|
||||
## Kartenpool einer Seltenheit, bei Elementboostern nur Karten mit diesem Element.
|
||||
static func booster_pool(rarity: String, element: String) -> Array:
|
||||
var pool := Cards.of_rarity(rarity)
|
||||
if element != "":
|
||||
pool = pool.filter(func(c): return element in c.elements)
|
||||
return pool
|
||||
|
||||
|
||||
static func roll_booster(r: RandomNumberGenerator, element: String = "") -> Array:
|
||||
var rarities := RARITY_WEIGHTS.keys()
|
||||
var weights := PackedFloat32Array(RARITY_WEIGHTS.values())
|
||||
var cards := []
|
||||
@@ -345,23 +356,49 @@ static func roll_booster(r: RandomNumberGenerator) -> Array:
|
||||
if i == BOOSTER_SIZE - 1 and rarity == "gewöhnlich" \
|
||||
and cards.all(func(c): return c.rarity == "gewöhnlich"):
|
||||
rarity = "selten" # mindestens eine seltene Karte pro Booster
|
||||
var pool := Cards.of_rarity(rarity)
|
||||
var pool := booster_pool(rarity, element)
|
||||
cards.append(pool[r.randi_range(0, pool.size() - 1)])
|
||||
return cards
|
||||
|
||||
|
||||
## Öffnet einen Booster. Gibt die Karten zurück, leer wenn die Münzen nicht reichen.
|
||||
func open_booster(r: RandomNumberGenerator = null) -> Array:
|
||||
if coins < BOOSTER_COST:
|
||||
## Deck-Code zum Teilen: "DINGER1:id*anzahl,…" (sortiert, daher vergleichbar).
|
||||
static func deck_code(card_ids: Array) -> String:
|
||||
var counts := {}
|
||||
for cid in card_ids:
|
||||
counts[cid] = counts.get(cid, 0) + 1
|
||||
var keys := counts.keys()
|
||||
keys.sort()
|
||||
return CODE_PREFIX + ",".join(keys.map(func(k): return "%s*%d" % [k, counts[k]]))
|
||||
|
||||
|
||||
## Karten-IDs aus einem Deck-Code; leer bei ungültigem Code.
|
||||
static func parse_deck_code(code: String) -> Array:
|
||||
var s := code.strip_edges()
|
||||
if not s.begins_with(CODE_PREFIX):
|
||||
return []
|
||||
var out := []
|
||||
for part in s.substr(CODE_PREFIX.length()).split(",", false):
|
||||
var kv: PackedStringArray = part.strip_edges().split("*")
|
||||
if kv.size() != 2 or not Cards.has_id(kv[0]) or not kv[1].is_valid_int():
|
||||
return []
|
||||
for i in clampi(int(kv[1]), 0, Game.MAX_COPIES):
|
||||
out.append(kv[0])
|
||||
return out
|
||||
|
||||
|
||||
## Öffnet einen Booster (element: Elementbooster). Gibt die Karten zurück, leer wenn die Münzen nicht reichen.
|
||||
func open_booster(r: RandomNumberGenerator = null, element: String = "") -> Array:
|
||||
var cost := ELEMENT_BOOSTER_COST if element != "" else BOOSTER_COST
|
||||
if coins < cost:
|
||||
return []
|
||||
if r == null:
|
||||
r = Game.make_rng()
|
||||
coins -= BOOSTER_COST
|
||||
var cards := roll_booster(r)
|
||||
coins -= cost
|
||||
var cards := roll_booster(r, element)
|
||||
booster_since_mythic += 1
|
||||
var has_mythic: bool = cards.any(func(c): return c.rarity == "mythisch")
|
||||
if booster_since_mythic >= PITY_BOOSTERS and not has_mythic:
|
||||
var pool := Cards.of_rarity("mythisch")
|
||||
var pool := booster_pool("mythisch", element)
|
||||
cards[BOOSTER_SIZE - 1] = pool[r.randi_range(0, pool.size() - 1)]
|
||||
has_mythic = true
|
||||
if has_mythic:
|
||||
@@ -478,6 +515,8 @@ func _achieved(id: String, ctx: Dictionary) -> bool:
|
||||
"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
|
||||
|
||||
Reference in New Issue
Block a user