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-10-10 14:30:29 +02:00
parent c245c7af87
commit a11cee2e0a
37 changed files with 2190 additions and 2414 deletions

View File

@@ -1,14 +1,16 @@
class_name Profile
extends RefCounted
## Spielstand: Münzen, Staub, Sammlung, Kampagne, Einstellungen.
## Jede Karte gehört jedem von Anfang an. Gesammelt wird die Seltenheitsstufe, und die
## ist reine Optik: sie ändert weder Werte noch Text einer Karte.
## Spielstand: Münzen, Staub, Sammlung, Stapel, Kampagne, Einstellungen.
## Man startet mit einem von vier Startdecks (je ein Element im Mittelpunkt); Booster und die
## Werkstatt bringen den Rest. Jede eigene Karte hat eine Seltenheitsstufe, die +1/+1 je Stufe
## gibt (Cards.Card.leveled); kommt eine seltenere Version, ersetzt sie die alte, die zu Staub wird.
const SAVE_VERSION := 6
const SAVE_VERSION := 7
const CRAFT_COST := 200 # Staub für eine neue Karte (Common)
const SAVE_PATH := "user://spielstand.json"
const BOOSTER_COST := 100
const BOOSTER_SIZE := 5
const RARITY_WEIGHTS := {"Common": 50.0, "Rare": 25.0, "Super Rare": 15.0, "Ultra Rare": 8.0, "Ultimate Rare": 2.0}
const RARITY_WEIGHTS := {"Common": 45.0, "Rare": 25.0, "Super Rare": 15.0, "Ultra Rare": 10.0, "Ultimate Rare": 5.0}
const START_COINS := 150
const REWARD_WIN := 100
const REWARD_LOSS := 50
@@ -24,19 +26,34 @@ const DUST_UPGRADE := {"Rare": 100, "Super Rare": 200, "Ultra Rare": 500, "Ultim
var coins := 0
var dust := 0
var collection := {} # id -> Seltenheitsstufe (Index in Cards.RARITIES), fehlend = Common
var collection := {} # eigene Karten: id -> Seltenheitsstufe (Index in Cards.RARITIES)
var deck: Array = [] # Karten-IDs des eigenen Stapels (Game.DECK_MIN bis DECK_MAX)
var campaign_stage := 0 # Anzahl abgeschlossener Kampagnenstufen
var settings := {"volume": 0.0, "music": 0.0, "ai_speed": 1.0, "animations": true, "language": "de", "difficulty": "normal", "big_font": false}
var notices: Array[String] = [] # Meldungen für die Oberfläche (Kampagnenfortschritt)
var perk := "" # gewähltes eigenes Merkmal (nach Kapitel 1)
## Neues Profil: noch ohne Karten, das Startdeck wählt der Spieler (choose_start).
static func starter() -> Profile:
var p := Profile.new()
p.coins = START_COINS
return p
## Hat der Spieler schon ein Startdeck gewählt?
func started() -> bool:
return not collection.is_empty()
## Das Startdeck eines Elements wird Sammlung und Stapel.
func choose_start(element: String) -> void:
collection = {}
deck = DeckGen.start_deck(element)
for id in deck:
collection[id] = 0
## Lädt den Spielstand; bei Schaden die Sicherung; sonst ein neues Profil.
static func load_or_new(path: String = SAVE_PATH) -> Profile:
for candidate in [path, path + ".bak"]:
@@ -52,7 +69,7 @@ static func load_or_new(path: String = SAVE_PATH) -> Profile:
## Liest jede Spielstand-Version; ältere Stände behalten Münzen, Staub, Kampagne und
## Einstellungen, die alte Sammlung (Anzahl je Karte) hat keine Entsprechung mehr.
## Einstellungen und bekommen die Startsammlung.
static func from_dict(d: Dictionary) -> Profile:
var p := Profile.new()
p.coins = int(d.get("coins", 0))
@@ -63,6 +80,11 @@ static func from_dict(d: Dictionary) -> Profile:
for cid in coll:
if Cards.has_id(cid):
p.collection[cid] = clampi(int(coll[cid]), 0, Cards.RARITIES.size() - 1)
var ids := []
for cid in d.get("deck", []):
if p.collection.has(cid) and not (cid in ids):
ids.append(cid)
p.deck = ids.slice(0, Game.DECK_MAX)
var se = d.get("settings", {})
p.settings = {"volume": float(se.get("volume", 0.0)), "music": float(se.get("music", 0.0)),
"ai_speed": float(se.get("ai_speed", 1.0)), "animations": bool(se.get("animations", true)),
@@ -77,7 +99,7 @@ static func from_dict(d: Dictionary) -> Profile:
func to_dict() -> Dictionary:
return {"version": SAVE_VERSION, "coins": coins, "dust": dust, "collection": collection,
return {"version": SAVE_VERSION, "coins": coins, "dust": dust, "collection": collection, "deck": deck,
"campaign_stage": campaign_stage, "settings": settings, "perk": perk}
@@ -97,7 +119,11 @@ func take_notices() -> Array[String]:
return out
# --- Sammlung: Seltenheit als Aussehen --------------------------------------------
# --- Sammlung und Stapel -----------------------------------------------------------
func owns(cid: String) -> bool:
return collection.has(cid)
func level(cid: String) -> int:
return int(collection.get(cid, 0))
@@ -116,17 +142,29 @@ func looks() -> Dictionary:
return out
## Anzahl Karten über Common.
func upgraded_count() -> int:
var n := 0
for cid in collection:
if int(collection[cid]) > 0:
n += 1
return n
## Der Stapel für den Kampf: der gewählte, mit weiteren eigenen Karten bis DECK_MIN aufgefüllt,
## falls er zu klein ist (Karten können durch Zerlegen wegfallen).
func deck_cards() -> Array:
return DeckGen.fill(deck.filter(func(id): return collection.has(id)), collection.keys(), Game.DECK_MIN)
## Karte in den Stapel oder heraus. Gibt "" zurück oder eine Fehlermeldung.
func toggle_deck(cid: String) -> String:
if cid in deck:
deck.erase(cid)
return ""
if not owns(cid):
return "Karte nicht in der Sammlung"
if deck.size() >= Game.DECK_MAX:
return "Der Stapel ist voll (%d Karten)" % Game.DECK_MAX
deck.append(cid)
return ""
## Wertet eine Karte um eine Stufe auf. Gibt "" zurück oder eine Fehlermeldung.
func upgrade(cid: String) -> String:
if not owns(cid):
return "Karte nicht in der Sammlung"
var lvl := level(cid)
if lvl >= Cards.RARITIES.size() - 1:
return "Schon auf der höchsten Stufe"
@@ -138,13 +176,29 @@ func upgrade(cid: String) -> String:
return ""
## Gibt eine Stufe ab und bekommt Staub dafür. Gibt "" zurück oder eine Fehlermeldung.
## Entzaubern: eine Stufe abgeben bringt Staub; eine Common-Karte verlässt die Sammlung.
## Gibt "" zurück oder eine Fehlermeldung.
func dismantle(cid: String) -> String:
if not owns(cid):
return "Karte nicht in der Sammlung"
var lvl := level(cid)
if lvl == 0:
return "Common-Karten lassen sich nicht zerlegen"
dust += DUST_DISMANTLE[Cards.RARITIES[lvl]]
collection[cid] = lvl - 1
if lvl == 0:
collection.erase(cid)
deck.erase(cid)
else:
collection[cid] = lvl - 1
return ""
## Herstellen: eine fehlende Karte für Staub als Common. Gibt "" zurück oder eine Fehlermeldung.
func craft(cid: String) -> String:
if owns(cid):
return "Karte schon in der Sammlung"
if dust < CRAFT_COST:
return "Nicht genug Staub (%d nötig)" % CRAFT_COST
dust -= CRAFT_COST
collection[cid] = 0
return ""
@@ -164,8 +218,9 @@ static func roll_booster(r: RandomNumberGenerator) -> Array:
return out
## Öffnet einen Booster. Höhere Stufen werten die Karte auf, alles andere wird zu Staub.
## Gibt die Ergebnisse zurück, leer wenn die Münzen nicht reichen.
## Öffnet einen Booster. Neue Karten kommen in Sammlung und Stapel (solange Platz ist). Von jeder
## Karte zählt die seltenste Version: eine höhere ersetzt die alte, die zu Staub wird; eine gleiche
## oder niedrigere wird selbst zu Staub. Gibt die Ergebnisse zurück, leer wenn die Münzen nicht reichen.
func open_booster(r: RandomNumberGenerator = null) -> Array:
if coins < BOOSTER_COST:
return []
@@ -175,14 +230,20 @@ func open_booster(r: RandomNumberGenerator = null) -> Array:
var out := roll_booster(r)
for res in out:
var lvl: int = Cards.RARITIES.find(res.rarity)
if lvl > level(res.card.id):
res["new"] = not owns(res.card.id)
res["upgraded"] = false
res["dust"] = 0
if res.new:
collection[res.card.id] = lvl
if deck.size() < Game.DECK_MAX:
deck.append(res.card.id)
elif lvl > level(res.card.id):
res["upgraded"] = true
res["dust"] = 0
res["dust"] = DUST_DISMANTLE[rarity(res.card.id)]
collection[res.card.id] = lvl
else:
res["upgraded"] = false
res["dust"] = DUST_DISMANTLE[res.rarity]
dust += res.dust
dust += res.dust
return out