"""Run state: the journey between combats. Phase 0 keeps this minimal — a linear node sequence and the player's persistent resources. The branching map graph, challenges, and items arrive in later phases. """ from __future__ import annotations from dataclasses import dataclass, field from enum import Enum from .cards import Card class NodeKind(Enum): BATTLE = "battle" SHELL = "shell" # sandbox exploration between fights ALTAR = "altar" # the Warden's command-for-power deal CARD_CHOICE = "card_choice" FORK = "fork" # the path splits; payload is a fork id @dataclass(frozen=True) class Node: kind: NodeKind payload: str = "" # encounter id for battles @dataclass class RunState: deck: list[Card] nodes: list[Node] position: int = 0 cycles: int = 0 ttys: int = 2 # losses remaining before the run ends over: bool = False victorious: bool = False @property def current(self) -> Node | None: return self.nodes[self.position] if self.position < len(self.nodes) else None def advance(self) -> None: self.position += 1 if self.current is None: self.over = True self.victorious = True def lose_tty(self) -> None: self.ttys -= 1 if self.ttys <= 0: self.over = True self.victorious = False def resolve_fork(self, encounter_id: str) -> None: """The player chose a door: the FORK node becomes that battle.""" node = self.current if node is None or node.kind is not NodeKind.FORK: raise ValueError("not standing at a fork") self.nodes[self.position] = Node(NodeKind.BATTLE, encounter_id) def new_run( starter_deck: list[Card], encounter_ids: list[str], fork_ids: frozenset[str] = frozenset(), ) -> RunState: """battle → shell → altar → draft → battle → … → final battle. Ids in fork_ids become FORK nodes: the battle is chosen at the door. """ nodes: list[Node] = [] for i, enc in enumerate(encounter_ids): kind = NodeKind.FORK if enc in fork_ids else NodeKind.BATTLE nodes.append(Node(kind, enc)) if i < len(encounter_ids) - 1: nodes.append(Node(NodeKind.SHELL)) nodes.append(Node(NodeKind.ALTAR)) nodes.append(Node(NodeKind.CARD_CHOICE)) return RunState(deck=list(starter_deck), nodes=nodes)