229 lines
11 KiB
Markdown
229 lines
11 KiB
Markdown
# Einheiten: backend/tft/sim/player.py
|
|
stand: f41ac76b5789
|
|
|
|
## backend/tft/sim/player.py::InvalidAction
|
|
beschreibung: Markiert ungültige Spielaktionen als Ausnahme.
|
|
input: eine Fehlermeldung als Zeichenkette.
|
|
output: eine Exception, die von Aufrufern abgefangen wird.
|
|
entscheidungen:
|
|
- Wird als eigene Exception-Klasse statt generischer `Exception` definiert, damit Aufrufer gezielt reagieren können.
|
|
beleg: "class InvalidAction(Exception):"
|
|
- Enthält bewusst keine eigene Logik, sondern dient nur als Typ-Marker.
|
|
beleg: " pass"
|
|
kanten:
|
|
- wird-genutzt-von: backend/tft/sim/player.py::buy
|
|
- wird-genutzt-von: backend/tft/sim/player.py::sell
|
|
- wird-genutzt-von: backend/tft/sim/player.py::buy_xp
|
|
- wird-genutzt-von: backend/tft/sim/player.py::move
|
|
- wird-genutzt-von: backend/tft/sim/player.py::equip
|
|
- wird-genutzt-von: backend/tft/sim/player.py::pick_augment
|
|
|
|
## backend/tft/sim/player.py::PlayerState
|
|
beschreibung: Hält den kompletten Zustand eines Spielers über alle Runden hinweg.
|
|
input: Initialwerte für Name, Archetyp, HP, Gold und Level.
|
|
output: ein Datensatz-Objekt mit Board, Bench, Items, Augments und Shop.
|
|
entscheidungen:
|
|
- Verwendet `field(default_factory=list)` für mutable Defaults, um die geteilte-Liste-Falle zu vermeiden.
|
|
beleg: " board: list = field(default_factory=list)"
|
|
- `alive` ist als abgeleitete Property modelliert, damit Konsistenz mit `hp` garantiert ist.
|
|
beleg: " return self.hp > 0"
|
|
- Optionale Felder wie `placement` und `last_opponent` werden explizit typisiert, damit Phasen ohne Gegner sauber abgebildet werden.
|
|
beleg: " placement: int | None = None"
|
|
kanten:
|
|
- nutzt: backend/tft/sim/player.py::score
|
|
- wird-genutzt-von: backend/tft/sim/player.py::new_player
|
|
|
|
## backend/tft/sim/player.py::new_player
|
|
beschreibung: Erzeugt einen frischen `PlayerState` aus einer Konfiguration.
|
|
input: Name, Archetyp und ein Konfigurations-Dictionary.
|
|
output: ein neu initialisierter `PlayerState` mit Startwerten.
|
|
entscheidungen:
|
|
- Liest Startwerte aus `cfg`, um Regelvarianten ohne Code-Änderung zu erlauben.
|
|
beleg: " hp=cfg[\"damage\"][\"player_hp\"],"
|
|
- Fallback auf Level 1, falls `start_level` fehlt.
|
|
beleg: " level=cfg[\"xp\"].get(\"start_level\", 1),"
|
|
kanten:
|
|
- ruft-auf: backend/tft/sim/player.py::PlayerState
|
|
- nutzt: backend/tft/sim/player.py::PlayerState
|
|
|
|
## backend/tft/sim/player.py::score
|
|
beschreibung: Berechnet die Spielstärke eines Spielers für die Schaden-Berechnung.
|
|
input: ein Spielerzustand und ein Artifact-Dictionary.
|
|
output: ein Float-Score des aktuellen Boards inklusive Augments.
|
|
entscheidungen:
|
|
- Delegiert die eigentliche Berechnung an `score_board`, um die Bewertungslogik zentral zu halten.
|
|
beleg: " return score_board(p.board, p.augments, artifact)"
|
|
- Bezieht Augments in den Score ein, damit gewählte Bonüsse kampfrelevant zählen.
|
|
beleg: " return score_board(p.board, p.augments, artifact)"
|
|
kanten:
|
|
|
|
## backend/tft/sim/player.py::unit_worth
|
|
beschreibung: Liefert den ökonomischen Gegenwert einer Einheit für Aufstellungsentscheidungen.
|
|
input: Artifact-Dictionary und eine Einheit mit `api_name` und `stars`.
|
|
output: ein Float-Wert als Kombination aus Kosten und Sternen.
|
|
entscheidungen:
|
|
- Skaliert den Wert mit `3 ** (stars - 1)`, da Merge-Stufen das Vielfache an Einheiten ersetzen.
|
|
beleg: " return artifact[\"static\"][\"units\"][u[\"api_name\"]][\"cost\"] * 3 ** (u[\"stars\"] - 1)"
|
|
- Liest Einheitenkosten aus den statischen Artifact-Daten, damit Balance-Anpassungen ohne Code-Change greifen.
|
|
beleg: " return artifact[\"static\"][\"units\"][u[\"api_name\"]][\"cost\"] * 3 ** (u[\"stars\"] - 1)"
|
|
kanten:
|
|
- wird-genutzt-von: backend/tft/sim/player.py::fill_board
|
|
|
|
## backend/tft/sim/player.py::refresh_shop
|
|
beschreibung: Erneuert die Shop-Anzeige eines Spielers mit neuen Roll-Ergebnissen.
|
|
input: Spielerzustand, Pool, Konfiguration und RNG.
|
|
output: keine Rückgabe; der Shop des Spielers wird ersetzt.
|
|
entscheidungen:
|
|
- Überschreibt `p.shop` vollständig statt zu mischen, um das TFT-typische „neuer Roll" zu modellieren.
|
|
beleg: " p.shop = roll(pool, p.level, cfg, rng)"
|
|
kanten:
|
|
- wird-genutzt-von: backend/tft/sim/player.py::reroll
|
|
|
|
## backend/tft/sim/player.py::merge
|
|
beschreibung: Führt automatisch passende Einheiten gleicher Sternstufe zu höheren Sternen zusammen.
|
|
input: Spielerzustand, API-Name und aktuelle Sternstufe.
|
|
output: keine Rückgabe; Board und Bench werden konsolidiert.
|
|
entscheidungen:
|
|
- Iteriert mit `while True`, bis weniger als drei Kopien vorhanden sind.
|
|
beleg: " while True:"
|
|
- Übernimmt die Items der fusionierten Kopien auf die verbleibende Einheit.
|
|
beleg: " keep[\"items\"].extend(u[\"items\"])"
|
|
- Kürzt das Item-Inventar der behaltenen Einheit auf das maximale Limit.
|
|
beleg: " keep[\"items\"] = keep[\"items\"][:MAX_ITEMS_PER_UNIT]"
|
|
- Entfernt überschüssige Einheiten aus Board oder Bench je nach Herkunft.
|
|
beleg: " (p.board if u in p.board else p.bench).remove(u)"
|
|
kanten:
|
|
- wird-genutzt-von: backend/tft/sim/player.py::buy
|
|
- wird-genutzt-von: backend/tft/sim/player.py::grab_carousel_unit
|
|
|
|
## backend/tft/sim/player.py::buy
|
|
beschreibung: Kauft eine Einheit aus dem Shop und legt sie auf die Bank.
|
|
input: Spielerzustand, Shop-Slot, Pool und Artifact-Dictionary.
|
|
output: keine Rückgabe; Bench und Pool werden verändert.
|
|
entscheidungen:
|
|
- Prüft Shop-Slot, Gold, Bank-Kapazität und Pool-Verfügbarkeit in dieser Reihenfolge, um Mehrfach-Meldungen pro Aktion zu vermeiden.
|
|
beleg: " if not (0 <= slot < len(p.shop)) or p.shop[slot] is None:"
|
|
- Leert den Shop-Slot nach erfolgreichem Kauf explizit.
|
|
beleg: " p.shop[slot] = None"
|
|
- Startet sofort einen Merge-Versuch auf Sternstufe 1, damit Käufe direkt stapeln.
|
|
beleg: " merge(p, api, 1)"
|
|
kanten:
|
|
- ruft-auf: backend/tft/sim/player.py::merge
|
|
- nutzt: backend/tft/sim/player.py::InvalidAction
|
|
|
|
## backend/tft/sim/player.py::sell
|
|
beschreibung: Verkauft eine Einheit vom Board oder Bench und erstattet Gold und Items zurück.
|
|
input: Spielerzustand, Ort, Index, Pool und Artifact-Dictionary.
|
|
output: keine Rückgabe; Gold, Items und Pool werden aktualisiert.
|
|
entscheidungen:
|
|
- Berechnet die Anzahl der Pool-Copies exponentiell zur Sternstufe.
|
|
beleg: " copies = 3 ** (u[\"stars\"] - 1)"
|
|
- Zieht 1 Gold ab, sobald die Einheit nicht 1 kostet und mindestens 2 Sterne hat.
|
|
beleg: " if cost > 1 and u[\"stars\"] >= 2:"
|
|
- Gibt Items aus dem Inventar der Einheit in das Spieler-Inventar frei.
|
|
beleg: " p.items.extend(u[\"items\"])"
|
|
kanten:
|
|
- nutzt: backend/tft/sim/player.py::InvalidAction
|
|
|
|
## backend/tft/sim/player.py::reroll
|
|
beschreibung: Würfelt den Shop gegen Gold neu aus.
|
|
input: Spielerzustand, Pool, Konfiguration und RNG.
|
|
output: keine Rückgabe; der Shop wird aktualisiert.
|
|
entscheidungen:
|
|
- Prüft Gold erst nach dem Lesen der Kosten, damit einheitliche Fehlermeldungen entstehen.
|
|
beleg: " if p.gold < cost:"
|
|
- Delegiert das eigentliche Neu-Würfeln an `refresh_shop`, um Logik-Duplikation zu vermeiden.
|
|
beleg: " refresh_shop(p, pool, cfg, rng)"
|
|
kanten:
|
|
- ruft-auf: backend/tft/sim/player.py::refresh_shop
|
|
- nutzt: backend/tft/sim/player.py::InvalidAction
|
|
|
|
## backend/tft/sim/player.py::buy_xp
|
|
beschreibung: Kauft zusätzliche Erfahrungspunkte und aktualisiert das Level.
|
|
input: Spielerzustand und Konfiguration.
|
|
output: keine Rückgabe; Level und XP werden fortgeschrieben.
|
|
entscheidungen:
|
|
- Lehnt den Kauf ab, wenn das maximale Level bereits erreicht ist.
|
|
beleg: " if p.level >= xp[\"max_level\"]:"
|
|
- Übergibt die XP-Berechnung an `economy.apply_xp`, damit Level-Schwellen zentral gepflegt werden.
|
|
beleg: " p.level, p.xp = economy.apply_xp(p.level, p.xp, xp[\"buy_amount\"], cfg)"
|
|
kanten:
|
|
- nutzt: backend/tft/sim/player.py::InvalidAction
|
|
|
|
## backend/tft/sim/player.py::move
|
|
beschreibung: Verschiebt eine Einheit zwischen Bank und Kampf-Board.
|
|
input: Spielerzustand, Richtung und Index.
|
|
output: keine Rückgabe; Board oder Bench werden mutiert.
|
|
entscheidungen:
|
|
- Wählt Quell- und Ziel-Liste abhängig von der Richtung in einer Zeile.
|
|
beleg: " src, dst = (p.bench, p.board) if where == \"bench\" else (p.board, p.bench)"
|
|
- Prüft die Board-Kapazität gegen das aktuelle Level des Spielers, nicht gegen einen festen Maximalwert.
|
|
beleg: " if dst is p.board and len(p.board) >= p.level:"
|
|
kanten:
|
|
- nutzt: backend/tft/sim/player.py::InvalidAction
|
|
|
|
## backend/tft/sim/player.py::equip
|
|
beschreibung: Legt ein Item aus dem Inventar auf eine Board-Einheit und craftet bei passender Komponente.
|
|
input: Spielerzustand, Item-Index, Board-Index und optionales Artifact.
|
|
output: keine Rückgabe; Einheit und Inventar werden angepasst.
|
|
entscheidungen:
|
|
- Sortiert die beiden Komponenten vor dem Lookup, damit die Reihenfolge keine Rolle spielt.
|
|
beleg: " crafted = recipes.get(\"|\".join(sorted((held, new_item))))"
|
|
- Bricht die Funktion mit `return` ab, sobald ein Rezept erfolgreich gecraftet wurde.
|
|
beleg: " p.items.pop(item_idx)"
|
|
beleg: " return"
|
|
kanten:
|
|
- nutzt: backend/tft/sim/player.py::InvalidAction
|
|
|
|
## backend/tft/sim/player.py::pick_augment
|
|
beschreibung: Wählt einen Augment aus dem aktuellen Angebot des Spielers.
|
|
input: Spielerzustand und Wahl-Index.
|
|
output: keine Rückgabe; Augments-Liste wird erweitert und Angebot geleert.
|
|
entscheidungen:
|
|
- Lehnt die Aktion ab, wenn aktuell kein Angebot vorliegt.
|
|
beleg: " if not p.augment_offer:"
|
|
- Leert das Angebot nach der Auswahl, damit kein zweiter Pick möglich ist.
|
|
beleg: " p.augment_offer = []"
|
|
kanten:
|
|
- nutzt: backend/tft/sim/player.py::InvalidAction
|
|
|
|
## backend/tft/sim/player.py::grant_loot
|
|
beschreibung: Verteilt Loot-Belohnungen wie Komponenten und Gold an einen Spieler.
|
|
input: Spielerzustand, Anzahl Komponenten, Gold, Artifact und RNG.
|
|
output: keine Rückgabe; Inventar und Gold werden erhöht.
|
|
entscheidungen:
|
|
- Wählt die Item-Quelle in absteigender Priorität aus Komponenten- und Item-Pool.
|
|
beleg: " pool = (artifact.get(\"component_pool\") or artifact.get(\"item_pool\")"
|
|
- Erlaubt nur das Droppen von Komponenten, fertige Items entstehen ausschließlich durch Crafting.
|
|
beleg: " # Loot droppt Komponenten; fertige Items entstehen nur durch Craften."
|
|
kanten:
|
|
- nutzt: backend/tft/sim/player.py::InvalidAction
|
|
|
|
## backend/tft/sim/player.py::grab_carousel_unit
|
|
beschreibung: Greift eine zufällige Karussell-Einheit und legt sie auf die Bank.
|
|
input: Spielerzustand, Pool und RNG.
|
|
output: keine Rückgabe; Bench und Pool werden verändert.
|
|
entscheidungen:
|
|
- Sammelt Kandidaten aus den Kostenstufen 1 bis 3, da Karussell-Einheiten günstig sind.
|
|
beleg: " candidates = [a for c in (1, 2, 3) for a in pool.units_of_cost(c)]"
|
|
- Überspringt den Greif, wenn die Bank voll ist, ohne Fehler zu werfen.
|
|
beleg: " if candidates and len(p.bench) < BENCH_SIZE:"
|
|
- Startet sofort einen Merge-Versuch, damit Drops direkt stapeln.
|
|
beleg: " merge(p, api, 1)"
|
|
kanten:
|
|
- ruft-auf: backend/tft/sim/player.py::merge
|
|
|
|
## backend/tft/sim/player.py::fill_board
|
|
beschreibung: Füllt freie Board-Plätze und tauscht stärkere Bank-Einheiten ein.
|
|
input: Spielerzustand und Artifact-Dictionary.
|
|
output: keine Rückgabe; Board und Bench werden umsortiert.
|
|
entscheidungen:
|
|
- Sortiert die Bank absteigend nach `unit_worth`, damit starke Einheiten vorne stehen.
|
|
beleg: " p.bench.sort(key=lambda u: -unit_worth(artifact, u))"
|
|
- Tauscht Board-Einheiten nur aus, wenn der Bank-Kandidat strikt stärker ist.
|
|
beleg: " if unit_worth(artifact, best) > unit_worth(artifact, u):"
|
|
- Bricht die Swap-Schleife ab, sobald die Bank leer ist.
|
|
beleg: " if not p.bench:"
|
|
kanten:
|
|
- ruft-auf: backend/tft/sim/player.py::unit_worth
|