class_name NetState ## Serialisierter Spielzustand für das Netzwerk (ausgelagert aus den Spielregeln). ## Serialisierter Zustand aus Sicht eines Spielers: fremde Hände, Decks und Fallen nur als Anzahl. ## viewer -1: alles sichtbar (Spielstand, Host-Wechsel); -2: nichts Verborgenes (Zuschauer). static func snapshot(g: Game, viewer: int) -> Dictionary: var ps := [] for i in g.players.size(): var p: Game.Player = g.players[i] var mine := i == viewer or viewer == -1 var board := [] for c in p.board: board.append({"uid": c.uid, "card": c.card.id, "attack": c.attack, "resonance": c.resonance, "health": c.health, "max_health": c.max_health, "shield": c.shield, "frozen": c.frozen, "ready": c.ready, "attacks_left": c.attacks_left}) ps.append({"name": p.name, "title": p.title, "is_human": p.is_human, "life": p.life, "max_life": p.max_life, "energy": p.energy, "max_energy": p.max_energy, "fatigue": p.fatigue, "start_bonus": p.start_bonus, "order": p.order, "perks": p.perks, "turns": p.turns, "mulligan_done": p.mulligan_done, "hand": p.hand.map(func(c): return c.id) if mine else p.hand.size(), "deck": p.deck.map(func(c): return c.id) if viewer == -1 else p.deck.size(), "traps": p.traps.map(func(c): return c.id) if mine else p.traps.size(), "board": board}) var evs := [] for ev in g.events: var e: Dictionary = ev.duplicate() if e.has("card"): e["card"] = e.card.id evs.append(e) return {"players": ps, "human": g.players.find(g.human), "turn": g.turn, "current_idx": g.current_idx, "winner": g.winner, "winner_player": g.players.find(g.winner_player) if g.winner_player != null else -1, "next_uid": g.next_uid, "log": g.log.slice(maxi(0, g.log.size() - 80)), "events": evs} ## Baut einen Spielzustand aus einem Snapshot; verborgene Karten werden durch Platzhalter ersetzt. static func from_snapshot(d: Dictionary) -> Game: var placeholder: Cards.Card = Cards.all()[0] var list := [] for pd in d.players: var p := Game.Player.new(pd.name, [], pd.is_human, int(pd.life), pd.title) p.max_life = int(pd.max_life) p.energy = int(pd.energy) p.max_energy = int(pd.max_energy) p.fatigue = int(pd.fatigue) p.start_bonus = int(pd.start_bonus) p.order = int(pd.order) p.perks = Array(pd.perks) p.turns = int(pd.turns) p.mulligan_done = bool(pd.mulligan_done) if pd.hand is Array: for cid in pd.hand: p.hand.append(Cards.by_id(cid)) else: for i in int(pd.hand): p.hand.append(placeholder) if pd.deck is Array: for cid in pd.deck: p.deck.append(Cards.by_id(cid)) else: for i in int(pd.deck): p.deck.append(placeholder) if pd.traps is Array: for cid in pd.traps: p.traps.append(Cards.by_id(cid)) else: for i in int(pd.traps): p.traps.append(placeholder) for cd in pd.board: var c := Game.Creature.new(Cards.by_id(cd.card), p, int(cd.uid)) c.attack = int(cd.attack) c.resonance = int(cd.resonance) c.health = int(cd.health) c.max_health = int(cd.max_health) c.shield = bool(cd.shield) c.frozen = bool(cd.frozen) c.ready = bool(cd.ready) c.attacks_left = int(cd.attacks_left) p.board.append(c) list.append(p) var hi := int(d.human) var g := Game.new(list[hi], list.slice(0, hi) + list.slice(hi + 1), RandomNumberGenerator.new()) g.players = list g.turn = int(d.turn) g.current_idx = int(d.current_idx) g.winner = d.winner g.winner_player = list[int(d.winner_player)] if int(d.winner_player) >= 0 else null g.next_uid = int(d.next_uid) for line in d.log: g.log.append(str(line)) for ev in d.events: var e: Dictionary = ev.duplicate() if e.has("card"): e["card"] = Cards.by_id(e.card) for key in ["player", "uid", "count", "amount"]: if e.has(key): e[key] = int(e[key]) for key in ["target", "attacker", "source"]: if e.has(key): var r: Dictionary = e[key] if r.has("uid"): r["uid"] = int(r.uid) if r.has("index"): r["index"] = int(r.index) g.events.append(e) return g