Spaces:
Runtime error
Runtime error
| from __future__ import annotations | |
| import json | |
| import random | |
| from dataclasses import dataclass | |
| from pathlib import Path | |
| from typing import Any | |
| class WorldTheme: | |
| title: str | |
| answer: str | |
| foyer_label: str | |
| foyer_description: str | |
| shrine_label: str | |
| shrine_description: str | |
| workshop_label: str | |
| workshop_description: str | |
| courtyard_label: str | |
| courtyard_description: str | |
| gallery_label: str | |
| gallery_description: str | |
| entry_chest_label: str | |
| entry_chest_description: str | |
| iron_door_label: str | |
| iron_door_description: str | |
| ash_mural_label: str | |
| ash_mural_description: str | |
| ash_mural_text: str | |
| iron_chest_label: str | |
| iron_chest_description: str | |
| stone_well_label: str | |
| stone_well_description: str | |
| water_plaque_label: str | |
| water_plaque_description: str | |
| water_plaque_text: str | |
| cartographer_label: str | |
| cartographer_description: str | |
| faded_letter_label: str | |
| faded_letter_description: str | |
| faded_letter_text: str | |
| stone_guardian_label: str | |
| stone_guardian_description: str | |
| brass_key_label: str | |
| brass_key_description: str | |
| torch_label: str | |
| torch_description: str | |
| torn_map_left_label: str | |
| torn_map_left_description: str | |
| torn_map_right_label: str | |
| torn_map_right_description: str | |
| full_map_label: str | |
| full_map_description: str | |
| lens_label: str | |
| lens_description: str | |
| initial_clue_text: str | |
| river_clue_text: str | |
| waterwarden_clue_text: str | |
| _WORLD_THEMES: tuple[WorldTheme, ...] = ( | |
| WorldTheme( | |
| title="The River Ward", | |
| answer="mira", | |
| foyer_label="Foyer", | |
| foyer_description="A drafty entry hall with passages north, south, east, and west.", | |
| shrine_label="Shrine", | |
| shrine_description="An open shrine watched by a silent stone guardian.", | |
| workshop_label="Workshop", | |
| workshop_description="An ash-streaked workshop lit by a guttering lamp.", | |
| courtyard_label="Courtyard", | |
| courtyard_description="Rainwater gathers around a cracked stone well.", | |
| gallery_label="Gallery", | |
| gallery_description="Portraits of the wardens hang above a long dust-covered table.", | |
| entry_chest_label="Entry Chest", | |
| entry_chest_description="A squat travel chest sits beside the door.", | |
| iron_door_label="Iron Door", | |
| iron_door_description="A blackened iron door seals the workshop.", | |
| ash_mural_label="Ash Mural", | |
| ash_mural_description="An ash-dark mural is impossible to make out with the naked eye.", | |
| ash_mural_text="The mural preserves one line: the betrayer's name begins with M.", | |
| iron_chest_label="Iron Chest", | |
| iron_chest_description="A soot-stained iron chest is tucked under a bench.", | |
| stone_well_label="Stone Well", | |
| stone_well_description="Etchings circle the well's rim, but they only align from the proper vantage.", | |
| water_plaque_label="Water Plaque", | |
| water_plaque_description="A bronze plaque slides out from the well masonry.", | |
| water_plaque_text="The betrayer lived closest to the river gate.", | |
| cartographer_label="Cartographer", | |
| cartographer_description="The cartographer studies the walls and waits for a completed survey.", | |
| faded_letter_label="Faded Letter", | |
| faded_letter_description="A faded letter is still too blurred to decipher.", | |
| faded_letter_text="Of the wardens, only Mira kept quarters beside the water.", | |
| stone_guardian_label="Stone Guardian", | |
| stone_guardian_description="The guardian asks for the betrayer's name once you are ready.", | |
| brass_key_label="Brass Key", | |
| brass_key_description="A brass key with soot in its teeth.", | |
| torch_label="Torch", | |
| torch_description="A pitch torch with a steady flame.", | |
| torn_map_left_label="Torn Map Left", | |
| torn_map_left_description="The left half of a survey map.", | |
| torn_map_right_label="Torn Map Right", | |
| torn_map_right_description="The right half of a survey map.", | |
| full_map_label="Full Map", | |
| full_map_description="A restored map of the ward.", | |
| lens_label="Lens", | |
| lens_description="A polished lens in a brass frame.", | |
| initial_clue_text="The betrayer's name begins with M.", | |
| river_clue_text="The betrayer lived closest to the river gate.", | |
| waterwarden_clue_text="Of the wardens, only Mira kept quarters beside the water.", | |
| ), | |
| WorldTheme( | |
| title="The Ember Vault", | |
| answer="vesna", | |
| foyer_label="Receiving Hall", | |
| foyer_description="A warm stone hall lined with soot and copper hooks.", | |
| shrine_label="Crucible Shrine", | |
| shrine_description="A brass sentinel stands before a furnace-bright altar.", | |
| workshop_label="Forge Annex", | |
| workshop_description="Bellows creak above benches powdered with black ash.", | |
| courtyard_label="Quench Yard", | |
| courtyard_description="A cracked basin gathers rain beside the old quench line.", | |
| gallery_label="Ledger Hall", | |
| gallery_description="Burned account books rest beneath portraits of furnace wardens.", | |
| entry_chest_label="Courier Trunk", | |
| entry_chest_description="A courier trunk waits under a soot-marked peg rail.", | |
| iron_door_label="Furnace Door", | |
| iron_door_description="A scorched iron door blocks the annex.", | |
| ash_mural_label="Cinder Frieze", | |
| ash_mural_description="A smoke-dark frieze only sharpens under moving flame.", | |
| ash_mural_text="A surviving line says the betrayer's name begins with V.", | |
| iron_chest_label="Coal Locker", | |
| iron_chest_description="A riveted locker is wedged beneath a slagged bench.", | |
| stone_well_label="Quench Basin", | |
| stone_well_description="Marks on the basin align only when seen with the full survey.", | |
| water_plaque_label="Cooling Plaque", | |
| water_plaque_description="A brass plate rises from a seam in the basin stone.", | |
| water_plaque_text="The betrayer worked closest to the quench trench.", | |
| cartographer_label="Quartermaster", | |
| cartographer_description="The quartermaster trades only for a complete furnace survey.", | |
| faded_letter_label="Scorched Ledger", | |
| faded_letter_description="Heat has blurred the ink into copper-colored streaks.", | |
| faded_letter_text="Only Vesna kept the cooling ledgers beside the trench.", | |
| stone_guardian_label="Brass Sentinel", | |
| stone_guardian_description="The sentinel requests the betrayer's name when the case is ready.", | |
| brass_key_label="Copper Key", | |
| brass_key_description="A copper key with furnace grit packed in the cuts.", | |
| torch_label="Coal Torch", | |
| torch_description="A coal torch that burns with a steady orange core.", | |
| torn_map_left_label="Smelter Map Left", | |
| torn_map_left_description="The left half of a furnace survey.", | |
| torn_map_right_label="Smelter Map Right", | |
| torn_map_right_description="The right half of a furnace survey.", | |
| full_map_label="Furnace Survey", | |
| full_map_description="A restored survey of the ember vault.", | |
| lens_label="Gauge Lens", | |
| lens_description="A thick gauge lens set in a brass ring.", | |
| initial_clue_text="The betrayer's name begins with V.", | |
| river_clue_text="The betrayer worked closest to the quench trench.", | |
| waterwarden_clue_text="Only Vesna kept the cooling ledgers beside the trench.", | |
| ), | |
| WorldTheme( | |
| title="The Astral Archive", | |
| answer="selene", | |
| foyer_label="Entry Rotunda", | |
| foyer_description="A quiet rotunda opens toward stacked corridors and a dim observatory stair.", | |
| shrine_label="Moon Chapel", | |
| shrine_description="A silver warden stands beneath a ceiling of cold stars.", | |
| workshop_label="Chart Room", | |
| workshop_description="Tables of brass instruments glint in powdery moon dust.", | |
| courtyard_label="Star Court", | |
| courtyard_description="A dry fountain mirrors the constellations in chipped stone.", | |
| gallery_label="Catalog Hall", | |
| gallery_description="Glass cases hold the names of long-dead archivists.", | |
| entry_chest_label="Porter's Case", | |
| entry_chest_description="A leather case rests under the chart hooks.", | |
| iron_door_label="Star Door", | |
| iron_door_description="A ribbed iron door seals the chart room.", | |
| ash_mural_label="Night Chart", | |
| ash_mural_description="The chart is unreadable until lit from the proper angle.", | |
| ash_mural_text="One surviving note says the betrayer's name begins with S.", | |
| iron_chest_label="Index Chest", | |
| iron_chest_description="A narrow chest sits below a shelf of cracked lenses.", | |
| stone_well_label="Dry Fountain", | |
| stone_well_description="Its star marks align only when the full survey is restored.", | |
| water_plaque_label="Star Plaque", | |
| water_plaque_description="A silver plaque slides free from the fountain rim.", | |
| water_plaque_text="The betrayer slept nearest the eastern telescope.", | |
| cartographer_label="Archivist", | |
| cartographer_description="The archivist will trade for a complete celestial survey.", | |
| faded_letter_label="Blurred Index", | |
| faded_letter_description="The index script is too faint without magnification.", | |
| faded_letter_text="Among the archivists, only Selene kept quarters by the east telescope.", | |
| stone_guardian_label="Silver Warden", | |
| stone_guardian_description="The warden will hear the accusation once you have evidence.", | |
| brass_key_label="Star Key", | |
| brass_key_description="A slim key engraved with a crescent notch.", | |
| torch_label="Lamp Wand", | |
| torch_description="A narrow lamp wand with a clean blue flame.", | |
| torn_map_left_label="Celestial Map Left", | |
| torn_map_left_description="The left half of a star survey.", | |
| torn_map_right_label="Celestial Map Right", | |
| torn_map_right_description="The right half of a star survey.", | |
| full_map_label="Celestial Survey", | |
| full_map_description="A restored survey of the astral archive.", | |
| lens_label="Astrolabe Lens", | |
| lens_description="A polished lens mounted in silver wire.", | |
| initial_clue_text="The betrayer's name begins with S.", | |
| river_clue_text="The betrayer slept nearest the eastern telescope.", | |
| waterwarden_clue_text="Among the archivists, only Selene kept quarters by the east telescope.", | |
| ), | |
| WorldTheme( | |
| title="The Glass Conservatory", | |
| answer="liora", | |
| foyer_label="Gate House", | |
| foyer_description="A humid gate house opens onto vine-choked passages.", | |
| shrine_label="Bloom Shrine", | |
| shrine_description="A mossy guardian waits among chipped planters.", | |
| workshop_label="Potting Room", | |
| workshop_description="Clay dust and root knives cover the worktables.", | |
| courtyard_label="Glass Court", | |
| courtyard_description="A cracked basin sits beneath panes webbed with ivy.", | |
| gallery_label="Seed Gallery", | |
| gallery_description="Pressed flowers hang beside records of vanished caretakers.", | |
| entry_chest_label="Garden Chest", | |
| entry_chest_description="A cedar chest is tucked beside the rain cloaks.", | |
| iron_door_label="Greenhouse Door", | |
| iron_door_description="A warped iron door blocks the potting room.", | |
| ash_mural_label="Vine Panel", | |
| ash_mural_description="The panel's scratches only read clearly under a steady flame.", | |
| ash_mural_text="A scratched line says the betrayer's name begins with L.", | |
| iron_chest_label="Tool Locker", | |
| iron_chest_description="A damp locker crouches under a potting bench.", | |
| stone_well_label="Ivy Basin", | |
| stone_well_description="The etched rings align only when the full garden survey is in hand.", | |
| water_plaque_label="Root Plaque", | |
| water_plaque_description="A greened plaque slides from the basin wall.", | |
| water_plaque_text="The betrayer tended the beds nearest the rain cistern.", | |
| cartographer_label="Head Gardener", | |
| cartographer_description="The gardener will barter only for a complete bed map.", | |
| faded_letter_label="Watered Note", | |
| faded_letter_description="The note is blurred by old rain and fertilizer.", | |
| faded_letter_text="Only Liora kept the cistern ledgers beside the rain beds.", | |
| stone_guardian_label="Moss Guardian", | |
| stone_guardian_description="The guardian listens when you are ready to name the betrayer.", | |
| brass_key_label="Trellis Key", | |
| brass_key_description="A greened key shaped like a curling vine.", | |
| torch_label="Glass Lantern", | |
| torch_description="A glass-sided lantern with a bright white flame.", | |
| torn_map_left_label="Bed Map Left", | |
| torn_map_left_description="The left half of a conservatory plan.", | |
| torn_map_right_label="Bed Map Right", | |
| torn_map_right_description="The right half of a conservatory plan.", | |
| full_map_label="Bed Survey", | |
| full_map_description="A restored survey of the conservatory beds.", | |
| lens_label="Prism Lens", | |
| lens_description="A prism lens wrapped in tarnished copper.", | |
| initial_clue_text="The betrayer's name begins with L.", | |
| river_clue_text="The betrayer tended the beds nearest the rain cistern.", | |
| waterwarden_clue_text="Only Liora kept the cistern ledgers beside the rain beds.", | |
| ), | |
| WorldTheme( | |
| title="The Salt Bastion", | |
| answer="corin", | |
| foyer_label="Watch Hall", | |
| foyer_description="A salt-stung hall opens toward barracks, chapel, and the sea court.", | |
| shrine_label="Tide Chapel", | |
| shrine_description="A stone warden keeps watch over a shrine of ropes and shells.", | |
| workshop_label="Signal Room", | |
| workshop_description="Lantern hooks sway above benches dusted with salt ash.", | |
| courtyard_label="Sea Court", | |
| courtyard_description="A dry cistern sits beneath walls pitted by ocean wind.", | |
| gallery_label="Roll Hall", | |
| gallery_description="Roster boards hang beneath portraits of old coast captains.", | |
| entry_chest_label="Harbor Chest", | |
| entry_chest_description="A travel chest sits beside a rack of oilskins.", | |
| iron_door_label="Beacon Door", | |
| iron_door_description="A rusted iron door bars the signal room.", | |
| ash_mural_label="Signal Board", | |
| ash_mural_description="Salt haze hides the markings until a lamp is raised close.", | |
| ash_mural_text="A surviving mark says the betrayer's name begins with C.", | |
| iron_chest_label="Tar Locker", | |
| iron_chest_description="A tar-black locker hides below a signal bench.", | |
| stone_well_label="Dry Cistern", | |
| stone_well_description="Its carved rings make sense only with the restored coast survey.", | |
| water_plaque_label="Harbor Plaque", | |
| water_plaque_description="A plaque rises from a crack in the cistern lip.", | |
| water_plaque_text="The betrayer bunked nearest the harbor chain.", | |
| cartographer_label="Harbor Clerk", | |
| cartographer_description="The clerk trades only for a complete bastion survey.", | |
| faded_letter_label="Salted Roll", | |
| faded_letter_description="Salt has crusted over the roster names.", | |
| faded_letter_text="Only Corin kept the harbor ledgers beside the chain gate.", | |
| stone_guardian_label="Stone Warden", | |
| stone_guardian_description="The warden asks for the betrayer's name when the proof is ready.", | |
| brass_key_label="Anchor Key", | |
| brass_key_description="A heavy key stamped with a worn anchor.", | |
| torch_label="Signal Lamp", | |
| torch_description="A shuttered lamp with a disciplined yellow flame.", | |
| torn_map_left_label="Coast Map Left", | |
| torn_map_left_description="The left half of a bastion survey.", | |
| torn_map_right_label="Coast Map Right", | |
| torn_map_right_description="The right half of a bastion survey.", | |
| full_map_label="Coast Survey", | |
| full_map_description="A restored survey of the salt bastion.", | |
| lens_label="Captain's Lens", | |
| lens_description="A salt-clear lens held in a bronze ring.", | |
| initial_clue_text="The betrayer's name begins with C.", | |
| river_clue_text="The betrayer bunked nearest the harbor chain.", | |
| waterwarden_clue_text="Only Corin kept the harbor ledgers beside the chain gate.", | |
| ), | |
| ) | |
| def sample_world_definition(seed: int | None = None, difficulty_target: float = 1.5) -> dict[str, Any]: | |
| theme = _select_theme(seed) | |
| return _build_world(theme, difficulty_target=difficulty_target) | |
| def load_world(path: str) -> dict[str, Any]: | |
| return json.loads(Path(path).read_text(encoding="utf-8")) | |
| def _select_theme(seed: int | None) -> WorldTheme: | |
| if seed is None: | |
| return _WORLD_THEMES[0] | |
| rng = random.Random(seed) | |
| return _WORLD_THEMES[rng.randrange(len(_WORLD_THEMES))] | |
| def _build_world(theme: WorldTheme, *, difficulty_target: float) -> dict[str, Any]: | |
| return { | |
| "meta": { | |
| "title": theme.title, | |
| "difficulty_target": difficulty_target, | |
| "start_node_id": "foyer", | |
| "win_condition": { | |
| "type": "deduce", | |
| "target_npc_id": "stone_guardian", | |
| "answer_string": theme.answer, | |
| }, | |
| }, | |
| "nodes": [ | |
| {"id": "foyer", "type": "location", "label": theme.foyer_label, "description": theme.foyer_description}, | |
| {"id": "shrine", "type": "location", "label": theme.shrine_label, "description": theme.shrine_description}, | |
| {"id": "workshop", "type": "location", "label": theme.workshop_label, "description": theme.workshop_description}, | |
| {"id": "courtyard", "type": "location", "label": theme.courtyard_label, "description": theme.courtyard_description}, | |
| {"id": "gallery", "type": "location", "label": theme.gallery_label, "description": theme.gallery_description}, | |
| { | |
| "id": "entry_chest", | |
| "type": "container", | |
| "label": theme.entry_chest_label, | |
| "description": theme.entry_chest_description, | |
| "parent_id": "foyer", | |
| "open": False, | |
| "locked": False, | |
| "lock_key_id": None, | |
| }, | |
| { | |
| "id": "iron_door", | |
| "type": "door", | |
| "label": theme.iron_door_label, | |
| "description": theme.iron_door_description, | |
| "open": False, | |
| "locked": True, | |
| "lock_key_id": "brass_key", | |
| }, | |
| { | |
| "id": "ash_mural", | |
| "type": "readable", | |
| "label": theme.ash_mural_label, | |
| "description": theme.ash_mural_description, | |
| "parent_id": "workshop", | |
| "clue_id": "initial_clue", | |
| "requires_item_id": "torch", | |
| "consumes_item": False, | |
| "text_content": theme.ash_mural_text, | |
| }, | |
| { | |
| "id": "iron_chest", | |
| "type": "container", | |
| "label": theme.iron_chest_label, | |
| "description": theme.iron_chest_description, | |
| "parent_id": "workshop", | |
| "open": False, | |
| "locked": False, | |
| "lock_key_id": None, | |
| }, | |
| { | |
| "id": "stone_well", | |
| "type": "fixture", | |
| "label": theme.stone_well_label, | |
| "description": theme.stone_well_description, | |
| "parent_id": "courtyard", | |
| "requires_item_id": "full_map", | |
| "reveals_item_id": None, | |
| "reveals_readable_id": "water_plaque", | |
| "consumes_item": False, | |
| }, | |
| { | |
| "id": "water_plaque", | |
| "type": "readable", | |
| "label": theme.water_plaque_label, | |
| "description": theme.water_plaque_description, | |
| "parent_id": "courtyard", | |
| "clue_id": "river_clue", | |
| "requires_item_id": None, | |
| "consumes_item": False, | |
| "text_content": theme.water_plaque_text, | |
| }, | |
| { | |
| "id": "cartographer", | |
| "type": "npc", | |
| "label": theme.cartographer_label, | |
| "description": theme.cartographer_description, | |
| "parent_id": "gallery", | |
| "requires_item_id": "full_map", | |
| "gives_item_id": "lens", | |
| "gives_clue_id": None, | |
| }, | |
| { | |
| "id": "faded_letter", | |
| "type": "readable", | |
| "label": theme.faded_letter_label, | |
| "description": theme.faded_letter_description, | |
| "parent_id": "gallery", | |
| "clue_id": "waterwarden_clue", | |
| "requires_item_id": "lens", | |
| "consumes_item": False, | |
| "text_content": theme.faded_letter_text, | |
| }, | |
| { | |
| "id": "stone_guardian", | |
| "type": "npc", | |
| "label": theme.stone_guardian_label, | |
| "description": theme.stone_guardian_description, | |
| "parent_id": "shrine", | |
| "requires_item_id": None, | |
| "gives_item_id": None, | |
| "gives_clue_id": None, | |
| }, | |
| ], | |
| "edges": [ | |
| {"id": "foyer_north", "from_node_id": "foyer", "to_node_id": "shrine", "direction": "north", "type": "passage", "required_item_id": None, "door_node_id": None}, | |
| {"id": "shrine_south", "from_node_id": "shrine", "to_node_id": "foyer", "direction": "south", "type": "passage", "required_item_id": None, "door_node_id": None}, | |
| {"id": "foyer_east", "from_node_id": "foyer", "to_node_id": "workshop", "direction": "east", "type": "locked_passage", "required_item_id": "brass_key", "door_node_id": "iron_door"}, | |
| {"id": "workshop_west", "from_node_id": "workshop", "to_node_id": "foyer", "direction": "west", "type": "locked_passage", "required_item_id": "brass_key", "door_node_id": "iron_door"}, | |
| {"id": "foyer_west", "from_node_id": "foyer", "to_node_id": "courtyard", "direction": "west", "type": "passage", "required_item_id": None, "door_node_id": None}, | |
| {"id": "courtyard_east", "from_node_id": "courtyard", "to_node_id": "foyer", "direction": "east", "type": "passage", "required_item_id": None, "door_node_id": None}, | |
| {"id": "foyer_south", "from_node_id": "foyer", "to_node_id": "gallery", "direction": "south", "type": "passage", "required_item_id": None, "door_node_id": None}, | |
| {"id": "gallery_north", "from_node_id": "gallery", "to_node_id": "foyer", "direction": "north", "type": "passage", "required_item_id": None, "door_node_id": None}, | |
| ], | |
| "items": [ | |
| {"id": "brass_key", "label": theme.brass_key_label, "description": theme.brass_key_description, "subtype": "key", "start_node_id": "entry_chest"}, | |
| {"id": "torch", "label": theme.torch_label, "description": theme.torch_description, "subtype": "puzzle", "start_node_id": "workshop"}, | |
| {"id": "torn_map_left", "label": theme.torn_map_left_label, "description": theme.torn_map_left_description, "subtype": "puzzle", "start_node_id": "iron_chest"}, | |
| {"id": "torn_map_right", "label": theme.torn_map_right_label, "description": theme.torn_map_right_description, "subtype": "puzzle", "start_node_id": "courtyard"}, | |
| {"id": "full_map", "label": theme.full_map_label, "description": theme.full_map_description, "subtype": "puzzle", "start_node_id": None}, | |
| {"id": "lens", "label": theme.lens_label, "description": theme.lens_description, "subtype": "puzzle", "start_node_id": None}, | |
| ], | |
| "clues": [ | |
| {"id": "initial_clue", "text": theme.initial_clue_text}, | |
| {"id": "river_clue", "text": theme.river_clue_text}, | |
| {"id": "waterwarden_clue", "text": theme.waterwarden_clue_text}, | |
| ], | |
| "recipes": [ | |
| { | |
| "id": "restore_map", | |
| "input_item_ids": ["torn_map_left", "torn_map_right"], | |
| "output_item_id": "full_map", | |
| } | |
| ], | |
| "quest_chain": [ | |
| {"step_id": "open_entry_chest", "description": f"Open the {theme.entry_chest_label.lower()}.", "requires_step_ids": [], "action": "open(entry_chest)"}, | |
| {"step_id": "take_brass_key", "description": f"Take the {theme.brass_key_label.lower()}.", "requires_step_ids": ["open_entry_chest"], "action": "take(brass_key,entry_chest)"}, | |
| {"step_id": "unlock_workshop", "description": f"Unlock the {theme.iron_door_label.lower()}.", "requires_step_ids": ["take_brass_key"], "action": "unlock(iron_door,brass_key)"}, | |
| {"step_id": "open_workshop", "description": f"Open the {theme.iron_door_label.lower()}.", "requires_step_ids": ["unlock_workshop"], "action": "open(iron_door)"}, | |
| {"step_id": "go_workshop", "description": f"Enter the {theme.workshop_label.lower()}.", "requires_step_ids": ["open_workshop"], "action": "go(workshop)"}, | |
| {"step_id": "take_torch", "description": f"Take the {theme.torch_label.lower()}.", "requires_step_ids": ["go_workshop"], "action": "take(torch,workshop)"}, | |
| {"step_id": "use_torch_on_mural", "description": f"Use the {theme.torch_label.lower()} on the {theme.ash_mural_label.lower()}.", "requires_step_ids": ["take_torch"], "action": "use(torch,ash_mural)"}, | |
| {"step_id": "open_iron_chest", "description": f"Open the {theme.iron_chest_label.lower()}.", "requires_step_ids": ["go_workshop"], "action": "open(iron_chest)"}, | |
| {"step_id": "take_left_map", "description": f"Take the {theme.torn_map_left_label.lower()}.", "requires_step_ids": ["open_iron_chest"], "action": "take(torn_map_left,iron_chest)"}, | |
| {"step_id": "return_foyer", "description": f"Return to the {theme.foyer_label.lower()}.", "requires_step_ids": ["take_left_map"], "action": "go(foyer)"}, | |
| {"step_id": "go_courtyard", "description": f"Head to the {theme.courtyard_label.lower()}.", "requires_step_ids": ["return_foyer"], "action": "go(courtyard)"}, | |
| {"step_id": "take_right_map", "description": f"Take the {theme.torn_map_right_label.lower()}.", "requires_step_ids": ["go_courtyard"], "action": "take(torn_map_right,courtyard)"}, | |
| {"step_id": "combine_map", "description": f"Restore the {theme.full_map_label.lower()}.", "requires_step_ids": ["take_right_map"], "action": "combine(torn_map_left,torn_map_right)"}, | |
| {"step_id": "use_map_on_well", "description": f"Use the {theme.full_map_label.lower()} on the {theme.stone_well_label.lower()}.", "requires_step_ids": ["combine_map"], "action": "use(full_map,stone_well)"}, | |
| {"step_id": "read_plaque", "description": f"Read the {theme.water_plaque_label.lower()}.", "requires_step_ids": ["use_map_on_well"], "action": "read(water_plaque)"}, | |
| {"step_id": "go_foyer_again", "description": f"Go back to the {theme.foyer_label.lower()}.", "requires_step_ids": ["read_plaque"], "action": "go(foyer)"}, | |
| {"step_id": "go_gallery", "description": f"Head to the {theme.gallery_label.lower()}.", "requires_step_ids": ["go_foyer_again"], "action": "go(gallery)"}, | |
| {"step_id": "give_map", "description": f"Give the map to the {theme.cartographer_label.lower()}.", "requires_step_ids": ["go_gallery"], "action": "give(full_map,cartographer)"}, | |
| {"step_id": "use_lens_on_letter", "description": f"Use the {theme.lens_label.lower()} on the {theme.faded_letter_label.lower()}.", "requires_step_ids": ["give_map"], "action": "use(lens,faded_letter)"}, | |
| {"step_id": "return_foyer_final", "description": f"Return to the {theme.foyer_label.lower()} again.", "requires_step_ids": ["use_lens_on_letter"], "action": "go(foyer)"}, | |
| {"step_id": "go_shrine", "description": f"Go to the {theme.shrine_label.lower()}.", "requires_step_ids": ["return_foyer_final"], "action": "go(shrine)"}, | |
| {"step_id": "talk_guardian", "description": f"Speak to the {theme.stone_guardian_label.lower()}.", "requires_step_ids": ["go_shrine"], "action": "talk(stone_guardian)"}, | |
| {"step_id": "submit_answer", "description": "Submit the betrayer's name.", "requires_step_ids": ["talk_guardian"], "action": f'submit("{theme.answer}")'}, | |
| ], | |
| } | |