class_name ShellState extends RefCounted ## The HUD state the Main Window shell owns (§2: state). Seed values mirror mock ## 2a; later systems (combat vitals, inventory consumables) become the writers. ## No Luck/LCK value lives here — it is never surfaced (§7). var vitals: Dictionary = {"hp": 0, "hp_max": 0, "mp": 0, "mp_max": 0, "purse_copper": 0} var turn_order: Array[TurnEntry] = [] var consumables: Array = [] var round_label: String = "" var location_label: String = "" var dock_open: bool = true func toggle_dock() -> bool: dock_open = not dock_open return dock_open static func seed() -> ShellState: var s := ShellState.new() s.vitals = {"hp": 42, "hp_max": 60, "mp": 18, "mp_max": 30, "purse_copper": 347} s.turn_order = [ TurnEntry.new("EL", 17, &"you", true, false), TurnEntry.new("DW", 12, &"ally"), TurnEntry.new("HU", 9, &"ally"), TurnEntry.new("GK", 0, &"enemy", false, true), ] var labels := ["Salve", "Draught", "Bomb", "Antidote", "Ration", "Torch", "", ""] s.consumables = [] for i in range(labels.size()): s.consumables.append({"hotkey": i + 1, "label": labels[i]}) s.round_label = "ROUND 4" s.location_label = "THE LOWER WARD" s.dock_open = true return s static func for_character(state: GameState, log: CanonLog) -> ShellState: ## The real HUD state for a constructed character. Vitals + location come from ## the character (§2 — code owns them); turn_order/consumables/round_label are ## still seed() placeholders because combat (M5) and inventory (M7) own those. var s := ShellState.seed() # start from the placeholders, then overwrite what is real s.vitals = { "hp": state.sheet.hp, "hp_max": state.sheet.max_hp(), "mp": state.sheet.mp, "mp_max": state.sheet.max_mp(), "purse_copper": state.purse_copper, } s.location_label = log.location.name return s