the-apprentice / oracles /themes.py
AndrewRqy
Initial commit — The Apprentice for Build Small
5afb7b3
Raw
History Blame Contribute Delete
77.1 kB
"""Theme registry for The Wizard's Oracles.
A "theme" is a setting/world the player can choose at the start of a game:
fantasy (default), space-cowboy, galactic-light, the Black Land (Egyptian
myth), Mistgate (Chinese myth), or the Quiet Years (post-apocalyptic).
A Theme bundles together:
* cosmetic strings used in prompt rendering (mentor name, hero archetype,
finale descriptor, style cues)
* a rich list of mock obstacle setups for trials 1-4 when the live LLM
is unavailable
* the fixed finale setup used as trial 5
The runtime threads `theme` through GameState and renders prompts with the
theme's strings substituted. The fantasy theme is the default for backwards
compatibility.
"""
from __future__ import annotations
from dataclasses import dataclass, field
@dataclass(frozen=True)
class Theme:
key: str
display_name: str # full name shown in the theme picker
blurb: str # 1-line hook for the picker tooltip
mentor_archetype: str # "wizard" / "quartermaster" / "Vizier"
mentor_action_verb: str # what the mentor does to the artifacts: "inscribed" / "tucked" / "sealed"
oracle_artifact: str # "sealed oracles" / "tarot cards" / "data-chips"
oracle_singular: str # "oracle" / "scroll" / "chip" — used in narration
goal_verb: str # "slay" / "outwit" / "expose" / "unspeak"
finale_descriptor: str # "the evil dragon" / "the warlord-king of the Rim"
finale_short: str # "the dragon" / "the warlord" (used in interludes etc.)
hero_default: str # default hero name on grimoire spread 1
village_default: str # default origin-place on spread 2
hero_label: str # "hero" / "drifter" / "Apprentice" / "scribe"
village_label: str # "village" / "frontier town" / "world" / "homeland"
style_cues: str # 1-2 sentence style guide injected into the LLM prompt
# ---- UI / chrome ------------------------------------------------------
# These drive the layout's banner, captions, and palette so the WHOLE
# page reskins when the player picks a theme — not just the content.
banner_subtitle: str = "" # 1-line hook shown under the banner title;
# falls back to a generic line if empty.
mentor_caption: str = "" # under-figure label for the YOU sprite,
# e.g. "the anonymous wizard" / "the dust-
# cloaked quartermaster". Falls back to
# mentor_archetype if empty.
finale_caption: str = "" # under-figure label for the CHAMPION
# sprite — e.g. "off to slay the dragon".
# Falls back to "off to {goal_verb}
# {finale_descriptor}" if empty.
palette: dict = field(default_factory=dict) # CSS variable overrides:
# keys are CSS var names (without the
# leading --), values are color strings.
# Empty dict = use the fantasy defaults.
mock_obstacles: list[str] = field(default_factory=list) # ≥20 rich setups
finale_setup: str = "" # the fixed trial-5 setup
# ---- Simplified-Chinese counterparts of the player-facing chrome ------
# When the player picks Simplified Chinese on grimoire spread 0, the
# UI reads these instead of the English fields above. Empty string
# means "fall back to the English field" — see ``localized_field``.
# Only the player-visible strings have Chinese counterparts; the LLM
# prompt strings (mentor_archetype, style_cues, etc.) stay English
# because the LLM is steered to write in Chinese via the
# ``{language}`` placeholder.
display_name_zh: str = ""
blurb_zh: str = ""
banner_subtitle_zh: str = ""
mentor_caption_zh: str = ""
finale_caption_zh: str = ""
oracle_artifact_zh: str = ""
finale_descriptor_zh: str = ""
# Role flavor for the right-side figure label on the inscribe page.
# e.g. fantasy "the village apprentice", space_cowboy "the drifter
# apprentice". Defaults to "Your apprentice" when blank.
apprentice_role: str = ""
apprentice_role_zh: str = ""
def localized_field(self, name: str, lang: str) -> str:
"""Return the ``{name}_zh`` value when ``lang == 'zh'`` and it is
non-empty, otherwise fall back to the English ``{name}`` field.
Used by app.py wherever a theme field is rendered into the UI so
the player sees Chinese chrome when they've picked Chinese, and
English otherwise.
"""
if lang == "zh":
zh_val = getattr(self, f"{name}_zh", "") or ""
if zh_val:
return zh_val
return getattr(self, name, "") or ""
def render_placeholders(self, base: dict) -> dict:
"""Augment a placeholder dict with theme-derived keys.
Existing keys in `base` win (so the caller can override per-call).
"""
out = {
"theme_name": self.display_name,
"mentor_archetype": self.mentor_archetype,
"mentor_action_verb": self.mentor_action_verb,
"oracle_artifact": self.oracle_artifact,
"oracle_singular": self.oracle_singular,
"goal_verb": self.goal_verb,
"finale_descriptor": self.finale_descriptor,
"finale_short": self.finale_short,
"hero_label": self.hero_label,
"village_label": self.village_label,
"style_cues": self.style_cues,
}
out.update(base)
return out
# ============================================================================
# 1. FANTASY (default — original Wizard's Oracles)
# ============================================================================
_FANTASY_MOCK = [
# Creatures with appetite
"A pale-furred wolf the size of a draft horse paces a meadow of yellow bones. Its breath stinks of iron and wet leaves, and the bones beneath its paws are all from travelers who thought themselves quick.",
"A swarm of glass-winged hornets boils up out of a hollow oak, each one the length of a dagger. Their hum makes the teeth ache. Anything that moves within a hundred paces is stung to a shape no mother would know.",
"In a sunken glade, a one-eyed sow the colour of river-mud chews on a saddle. Around her snuffle six piglets, each already taller than a man, and the mother has not been fed in three days.",
"A flock of fen-wraiths — pale herons with teeth — wheels low above the marsh, hunting anything that breathes. Their wings make no sound, and the saint they last killed is still hanging from a willow, half-eaten.",
"A bone-cold owl as wide as a ploughshare watches the road from the high pines. Its eyes are coins, and its talons have not let go of anything in nine hundred years.",
# Geography killers
"A great chasm splits the road, deeper than any tower is tall. Wind howling up from the dark smells of old iron. There is no bridge, no way around, and no rope long enough to sound the bottom.",
"The path narrows into the Whisper Marsh, where the water is warm as blood and the reeds part in the wrong direction. Every footstep sinks a little further, and those who panic are pulled under in a single breath.",
"A glassy black lake fills the valley floor, its surface so flat that clouds reflect upside down without rippling. Birds that fly above it fall in silence. The far shore is only half a mile off, but no boat floats on this water.",
"An avalanche of ash-snow has buried the only mountain pass overnight — quiet, warm, and somehow purring. Where it touches stone, the stone weeps. Where it touches a traveler, the traveler is heard from no more.",
"A river of brambles has grown across the valley in a single season, each thorn as long as a forearm and red at the tip. It moves slowly toward sound.",
# Beings with intent
"At the river's edge stands a giant in iron sandals. His nose is wide as a doorway and he smells heroes a league off. He has not let one pass in living memory without taking a name, a hand, or a heart.",
"A grey-robed sphinx sits on a stone bridge with no railings. She smiles with a mouth full of children's teeth and asks one question of every traveler. Wrong answers are eaten; right answers are eaten more slowly.",
"A toll-witch in a house of finger-bones bars the only mountain pass. She accepts no coin and no blade — only a true secret, freely given. Lies turn the speaker inside out before they finish the sentence.",
"A blind beggar in a coat of crow feathers waits at the crossroads with a wooden bowl. He demands one true memory, given freely, and will let no traveler pass who is unwilling to forget.",
"A black-armoured knight has stood at the ford for forty years without dismounting. He does not speak; he simply lowers his lance when a traveler approaches, and only one combat in living memory has ended in his stepping aside.",
# Natural / magical forces
"A black-rimmed storm crouches over the heath, lightning crawling along the ground like a living thing. The rain falls upward in places. Every metal buckle within a mile glows hot enough to burn through cloth.",
"An old curse lies thick on the king's road: any traveller who speaks aloud forgets one year of their life with every word. The road runs for two long days, and silence is a hard skill to keep.",
"A famine-frost has settled on the valley, killing crops and beasts but leaving the air sweet as cider. Those who breathe it grow drowsy, then joyful, then still. The bodies along the road are all smiling.",
"A grief-fog has rolled in from the sea — thick, salt-tasting, and inhabited by the small constant weeping of someone you used to know. To walk into it is to forget which direction you came from.",
"An old saint's curse keeps a single mile of the road permanently at midnight, even at noon. Lanterns will not light there. Compasses spin.",
# Cultural / authority pressure
"A wedding-procession a thousand strong has filled the only road for half a day, drunk and joyous and entirely disinclined to part for one young traveler. The bride's father is the mayor; the bride's brother is the constable.",
"A border officer demands a writ the hero does not own, signed by a count who has been dead for sixty years. The officer is bored, methodical, and not for sale.",
"A funeral cortège blocks the bridge — sixty mourners, a coffin of green oak, and a custom older than the kingdom that says no one may cross until the bell has tolled fifty times.",
"A travelling court of three judges has set its tent across the road and will hear no other business until the present case — over a stolen lamb, ongoing for nine days — is concluded.",
# Strange & lore-flavored
"A doorway stands by itself on the moor — no walls, no house, just a black-oak door with brass hinges and a knocker shaped like a fox. Travelers who walk around it are not seen again on this side; travelers who knock are heard answering from within for years afterward.",
"A horse with no rider grazes peacefully in the middle of the road. The horse is the hero's own — except his own is two villages back, asleep in a stable. The horse here knows his name.",
"The road has split into two identical roads — same stones, same trees, same crow on the same fence — and a sign at the fork reads ONLY ONE OF THESE IS REAL. CHOOSE.",
]
_FANTASY_FINALE = "" # left empty so obstacles.py falls back to the
# canonical prompts/dragon_setup.txt file template
# ============================================================================
# 2. SPACE COWBOY (Firefly meets western frontier)
# ============================================================================
_SPACE_COWBOY_MOCK = [
# Creatures with appetite
"The dust-kraken Old Sallow has wrapped three of her sandpaper tendrils around the rail-car of the Yuma Express, and the brakeman is already a smear on the ceiling. Her beak clacks somewhere beneath the dunes of the Cinnabar Flats, tasting copper and meat through the floor plates.",
"A herd of mutated longhorns — the so-called glass-cattle of Boer's Hollow — have caught the drifter's scent at the watering trough, their crystal horns humming a frequency that boils blood at twenty paces. The lead bull's eyes are fused-shut blisters and it's already pawing the rust.",
"In the rafters of the abandoned grain silo on Perdition-3, a brood of skin-bats the locals call \"preacher's kin\" hangs in a chittering quilt, each one mimicking the last words of folks they ate. One of them is whispering the drifter's mother's name, and the others are starting to learn it.",
"The sand-shark called Mister Quiet has been tracking the drifter's hoverbike for two days across the Ochre Sea, surfacing only to swallow the supply mule whole. Now it's circling the salt island where he's made camp, and the tide of dust is coming in.",
"A swarm of meat-moths has settled over the only oasis for sixty klicks, the Widow's Tap, drinking the water and anything fool enough to come for it. Their wings make a sound like a baby crying, which is how they get you close.",
# Geography killers
"The atmospheric corridor over Buzzard's Notch has broken again — a half-mile column of breathable air punched through vacuum, and the seams are fraying. Cross too slow and the suck takes you sideways into the black; too fast and you cook on the friction lip.",
"The Vermilion runs hot today: a plasma river cutting the only pass through the Calico Range, its banks glassed smooth and its current spitting arcs that lick twenty feet up. The ferryman's shack is a charred footprint and the rope-bridge is slag.",
"A canyon storm has rolled into Dead Man's Throat, the kind the old hands call a \"screamer\" — winds that braid themselves into ropes and yank riders off the trail. The drifter can hear his own horse's last whinny coming back at him from three directions.",
"The Saltpan of Hosanna looks like flat walking until the crust gives, and the crust always gives. Under it is a hundred feet of brine sludge that eats leather, lungs, and longing, and the drifter is already a quarter-mile from the nearest pylon.",
# Beings with intent
"Toll-Master Cassius Vell sits in a folding chair at the mouth of the Iron Throat tunnel, with a shotgun across his knees and a ledger across the shotgun. He charges in teeth, secrets, or \"a true word spoke plain,\" and he can taste a lie like sour milk.",
"The AI Judge of Calliope Station — a hanging brass mask called HONORABLE-7 — has flagged the drifter's transit papers and convened court in the corridor. Twelve drone jurors hover at shoulder height, and HONORABLE-7 will only accept testimony given as a single declarative phrase.",
"Bounty hunter Lurleen \"Two-Coats\" McGraw is leaning on the hitching post outside the only inn in Gospel Springs, and she's already counted the drifter's bullets from the way he walks. She'll let him pass for a name — somebody else's name, somebody worth more.",
"The biometric gate at Fort Halcyon wants a retina, a voiceprint, and \"a phrase of personal significance no shorter than three words\" — and the last drifter who guessed wrong is still smoking in the doorway. The gate's voice is uncomfortably warm, like a schoolteacher's.",
"The sphinx-priest-cyborg of the Mendicant Order squats in the middle of the trade road, half flesh and half prayer-wheel, and won't move for coin or threat. It asks each traveler one riddle, accepts only one answer, and has a stack of skulls arranged by size beside it.",
# Natural / cosmic forces
"A class-X solar flare off the white dwarf Mama Ruth has lit up the whole sector, frying comms and cooking anything topside in about nine minutes. The drifter's shielding is two minutes short and the nearest cellar is on the wrong side of a locked chapel door.",
"Neutron rain is falling over the Pewter Mesa — invisible, silent, and counting down every cell it passes through. The Geiger on his belt is singing soprano, and the only shelter is a tin-roofed lean-to that may as well be tissue paper.",
"A dust singularity has opened above the Mackerel Spur, a thumb-sized pinprick pulling a slow funnel of grit and gravel and now a whole windmill into the sky. It's growing, and it's drifting south, and south is where he was going.",
"The twin moons of Sundown have aligned for the once-a-decade Black Tide, and the planet's mag-field has flipped its polarity for the next eleven hours. Compasses spin, guns misfire, and the dead at Boot Hill are reportedly sitting up to stretch.",
# Mechanical / tech barriers
"The railroad junction at Switchback Forty has gone into lockdown — every track lever frozen, every signal red, and the dispatcher's booth playing the same six bars of a hymn on loop. Three trains are stacked behind the drifter's, and one of them is hauling something that ticks.",
"The warp gate at Lazarus Hub is broken in the worst way: still open, but routing every fourth traveler to a destination it refuses to name. The queue ahead of him is shorter than it should be and nobody is making eye contact with the operator.",
"The hover-bridge over the Drowned Mile is deactivated, its grav-plates dark and its access panel demanding a sysadmin passphrase nobody's spoken in twelve years. Beneath it, four hundred feet of canyon, and a long line of wagons piling up behind him.",
"The autoloom mining rig called BIG MAUDE has gone feral in the only pass through the Tin Hills, swinging her drill-arm in slow lazy arcs and singing a shift-change song through busted speakers. Her override port wants a verbal command, and her last operator left in a bucket.",
# Crowd / cultural pressures
"The Lucky Lung saloon is packed three deep with rail-hands celebrating a strike payout, and somebody has already broken a bottle over the piano. The drifter needs to cross the room to reach the back stairs, and a one-eyed foreman has just stood up and called the room to a hush, pointing at him.",
"The miners of Black Seam Local 19 have struck across the only road out of Kettle Bend, and their picket line is six hundred strong, armed with pry-bars and grievances. They're letting nobody through without a word of solidarity, and the company man's brand is fresh on the drifter's coat.",
"The Sabbath market at Anvil Crossing has tipped from haggling into riot, and a mob is rolling down the central row carrying a hanged effigy of the territorial governor. The drifter is wearing a coat the same color as the governor's livery and the mob has noticed.",
"A parade of pilgrims to the Glass Madonna is choking the only causeway off Bellweather Station, ten thousand strong, walking on their knees and singing in a dead tongue. To cut across the procession a traveler must speak the day's password to the lead deacon, or be folded into the march forever.",
# Authority / paperwork
"Customs at Port Coronado has flagged the drifter's cargo manifest — specifically the line that just reads \"personal effects\" — and Inspector Eulalia Brand wants a verbal declaration, witnessed and stamped. She's been doing this thirty years and has heard every lie twice.",
"The bureaucratic checkpoint at Marrow Pass is run out of a leaning shipping container by a clerk named Mr. Pennyworth, who needs Form 27-C countersigned by a second party not present. He will accept, in lieu of the signature, \"any phrase uttered with sufficient conviction to bind the speaker.\"",
"Magistrate Honoria Quill is hearing the drifter's case in the back of a rolling courthouse-wagon, and she's already bored. Her gavel is a brass knuckle and her verdict hinges on what the defendant offers as his \"watchword\" — the one sentence he'd stake his soul on.",
"An intersystem patrol cutter, the ISS Temperance, has matched the drifter's vector and is hailing on all bands, demanding he transmit his current passcode of the week. The codes rotate Mondays and nobody told him it was Monday.",
]
_SPACE_COWBOY_FINALE = (
"At the end of the rim road sits Gomorrah-on-the-Dust, the orbital-and-ground "
"sprawl ruled by Warlord-King Rufus Goad — once a preacher, now a man with a "
"chromed jaw and a private army of three thousand reclaimed lawmen wearing his "
"brand. He holds court in the Cathedral Car, a mile-long armored train that "
"never stops moving across the Iron Plains, and he keeps {hero_name}'s sister's "
"name written on a slate beside his throne. You can't outdraw him; his trigger "
"finger is a piston and he's wearing the skin of a man who already shot {hero_name} "
"once in a dream. But Rufus Goad has a rule older than his crown: any drifter "
"who reaches the Cathedral Car alive gets to speak one word before the guns go up, "
"and Rufus has to listen."
)
# ============================================================================
# 3. GALACTIC LIGHT (Star-Wars-adjacent — no trademarked terms)
# ============================================================================
_GALACTIC_LIGHT_MOCK = [
# Creatures with appetite
"A void-leviathan called the Maw of Ulvenn coils around your skiff-fighter in the dead lane between systems, its translucent flanks lit from within by half-digested suns. It does not roar; it hums a low note that loosens the bolts of your hull and the certainties of your mind. The Master grips your shoulder and presses a sealed scroll of the Old Stars into your palm.",
"In the mire-jungle of Hesh, shape-shifting swamp-stalkers called Brillim wear the faces of those you have failed. One of them is wearing your mother's face and weeping; another wears the Master's, smiling wrong. They are circling, and the real Master has gone very still beside you and whispered, \"Open the scroll, Apprentice — quickly.\"",
"A creeping silver moss called Rust-Lung has eaten through the docking spire of Kassa Outpost, and now it is eating your astromech, who is screaming in three octaves. The moss spreads at the speed of a slow heartbeat and feeds on certainty — the more sure you are of your next step, the faster it climbs your boot. Your Master is already coughing.",
"The hivemind beetles of Orron speak in a single chittering voice through a thousand mandibles, and they have just announced, politely, that they intend to consume you in order of seniority. They form a glittering carpet across the only bridge out of the canyon, and they are very patient.",
"The asteroid you landed on for repairs is not an asteroid. It is the larval shell of a Stoneworm of Vex, and it has begun, slowly, to fold inward around your ship like a closing fist of rock. Acidic saliva drips from what you had taken to be stalactites.",
# Geography killers
"The Shattered Cradle is an asteroid maze where no two charts agree and the rocks themselves drift on currents of old gravity. Pilgrim wrecks hang in its tides like rosary beads, their distress beacons still blinking after centuries. Your Master points at one particularly malevolent boulder and says, \"That one. We go through that one.\"",
"In the twin-star eclipse zone of Belaran, two suns pass behind a dead moon every two hundred years and the dark lasts exactly nine minutes. In those nine minutes the predators of Belaran wake, the cliffs unfreeze, and the air becomes briefly poisonous. The eclipse begins in four.",
"The gravity well of Old Hadrun pulls inexorably, and the readings on your console have stopped meaning anything; the stars outside have begun to elongate into bright wounds. Your Master is calculating something on his fingers and frowning.",
"The caldera of the lava-moon Korrith is the only flat ground for a thousand leagues, and you must cross it on foot because the heat shears engines. Geysers of molten rock erupt on a rhythm only the local monks know, and the local monks are dead.",
# Beings with intent
"The Oracle of the Forgotten Choir sits in a chamber of black glass at the bottom of a temple no one remembers building, and she will not let you pass until you tell her a truth she has not already heard. She has been listening for nine thousand years.",
"The bounty hunter Vass Korrigan wears a helmet of beaten silver and demands your true name as payment for safe passage — not your traveling name, not your initiate name, the one your mother whispered once and then forgot. He is very polite. He has killed forty-six of your Order's sworn and keeps a small ledger.",
"Doss Maleel, the smuggler king of the Drift, runs every safe lane out of this sector, and your Master, it transpires, owes him a tab three decades old and growing interest. Doss is delighted to see you both. He is also out of patience, and his lieutenants have very clean knives.",
"The Masked Tribunal of Erevos sits in a ring of seven, and none of them have spoken in a century; they communicate by tilting their porcelain masks a fraction of a degree. They have judged you guilty of something — you cannot tell what — and the sentence is to be carried out at sundown.",
"A beggar-prophet on the steps of the Cinder-Cathedral grabs your sleeve and will not let go, croaking that he has seen your death three ways and one of them is happening now. He smells of incense and old wine.",
# Natural / cosmic forces
"A hyperspace storm — what the old pilots called a Veilshear — has bloomed across your only route, peeling the skin off light itself. Inside it, time runs in eddies and your ship's chronometer is already arguing with itself.",
"An ion squall rolls across the upper atmosphere of Tann, killing every circuit it touches in long, lazy sweeps. Your shields are flickering and your astromech has gone silent in a way that is either tactful or terminal.",
"The sun-spear of Velrid-Prime is firing — a once-a-century flare that lances a coherent beam of plasma straight across the sector — and you are, by very poor luck, in the line. There is a shadow you can hide in: the cold side of a derelict cathedral-ship hanging in the dark. It is occupied.",
"A time-eddy has caught the rear of your skiff-fighter and the cockpit clock is running, very gently, backwards. Your Master, who was sitting beside you, is now standing behind you, and he was, three breaths ago, a younger man.",
# Mechanical / tech barriers
"The security gate of Outpost Threnn has been defunct for a thousand years and yet it is still, somehow, asking for credentials in a dead dialect. Behind it, the only fuel cache in the sector. The gate's voice is patient and feminine and has begun, you notice, to address your Master by a name he has not used since before you were born.",
"An AI sentry tower on the dust-flat of Mehr has woken up after a long sleep and is conducting threat assessment in slow, considering sweeps of red light. It has not yet decided whether you are enemies. It is, your Master notes, an old model — the kind that asks one question before it fires, and accepts only one kind of answer.",
"The shield matrix of the orbital fortress Karn is broken in interesting ways: there are gaps you can fly through, but the gaps move on a pattern no one has solved. The pattern is, the Master suspects, a song. He cannot remember the words.",
"A droid army of the old Sovereignty has stood, rusting and unbothered, in formation across the Plain of Olu for three centuries — and as your shadow crosses the foremost rank, every photoreceptor flickers on at once. They do not move. They are waiting for a command phrase.",
# Crowd / cultural pressures
"The refugee camp at Hollow Ford stretches to the horizon — tens of thousands fleeing the Sovereign's advance — and the only road through is choked with carts and grief. A child has recognized your Master's robes and is tugging at his sleeve, asking if the Star-Sworn have come at last.",
"A war parade for the Sovereign's vassal-governor is winding through the boulevards of Kessar-Prime, drums and lash-banners and crowds packed twelve deep. Your only route to the spaceport runs straight across the parade's spine.",
"The market of pilgrims at Sevn-Hollow is twelve thousand souls thick and every one of them has come to buy a relic, a blessing, or a piece of news. Someone, somewhere in the press, is shouting your description.",
"The Monastery of the Pale Lantern is holding its centennial festival, and ten thousand monks in white are standing perfectly silent in concentric rings around the courtyard you need to cross. To make a sound is sacrilege punishable by being walled into the bell tower. Your boots, you realize too late, are squeaking.",
# Authority / paperwork
"Imperial customs at the Hadran Gate is run by a clerk named Vellis who has been there forty years and has never, not once, waved anyone through. He wants forms in triplicate, in dead languages, and he is currently looking at your Master's papers with the slow, patient curiosity of a man who has all afternoon.",
"The sector magistrate of Yorr-Bel has summoned your Master to answer for a crime committed before your Master was born, by a man who shared his face. The magistrate is fair, incorruptible, and very, very thorough.",
"A codex inspector of the Imperial Library has flagged the chain of sealed scrolls your Master carries — undeclared relics, unregistered prophecy, all of it — and is requesting that you open one, here, in his office, for cataloguing. He is a small man with ink-stained fingers and absolute authority.",
"The fleet-yard manifest officer of Drennar-Six will not let your ship leave dock because, according to his records, it left three days ago and has not yet returned. He is sympathetic. He is also entirely unable to file the paperwork that would let a ship exist twice.",
]
_GALACTIC_LIGHT_FINALE = (
"At the end of the long road stands the fortress-spire of Korrun-Vey, a black "
"needle driven through the heart of a dead moon, and within it waits Lord Maradon "
"Vey — the Dark Sovereign, last crowned head of the fallen Order of Voidblades, "
"who was once your Master's brightest student and is now something colder than "
"grief. He cannot simply be struck down: the spire is wound through with the "
"suspended souls of ten thousand Star-Sworn he has bound to his life, and to "
"kill him is to kill them; he wears the face of someone the Master loved; and the "
"last sealed scroll of the Old Stars, the one the Master has carried for forty years "
"without opening, bears Maradon's own name in the hand of a younger Maradon, "
"written before the fall. {hero_name} must draw the final oracle in the throne "
"room itself, under a sky of stolen stars, and speak it aloud."
)
# ============================================================================
# 4. THE BLACK LAND (Egyptian mythology)
# ============================================================================
_BLACK_LAND_MOCK = [
# Creatures with appetite
"At the third bend of the Nile, the waters part and Sebek's longest son rises — a crocodile vast as a temple-barge, his hide lacquered green with river-mud, his eyes the cold gold of unminted coin. He does not lunge; he drifts toward the reed-skiff with the patience of a god who has eaten every previous scribe.",
"The pilgrimage halts in a dry wadi where the sand begins to seethe — ten thousand scarabs of the carrion-kind, their carapaces clicking like a priest's sistrum, boiling up from the corpse of some unburied jackal. They roll toward {hero_name} in a tide three cubits high, and they will strip the wax from his writing-tablets, the linen from his bones, the prayer from his throat before he can finish it.",
"Beneath a colonnade of weather-eaten lotus-pillars crouches a sphinx-lioness, her woman's face calm as still water, her paws each the size of a chariot-wheel. She does not roar; she purrs a question in a tongue older than Memphis, and only the final syllable is intelligible, which is the word for either gift or throat — the dialect is uncertain, and her hunger is not.",
"From the doorways of a desert necropolis pour the mummified jackals of an abandoned Anubis-shrine — withered, hollow-eyed, their wrappings trailing like funeral banners, their jaws still scented with the natron of their first death. Behind them limps their priest-mummy, who buried them and now leads them to feed.",
"The reed-skiff slides into a pool of slack water where a river-hippo broods half-submerged, her eyes red as the brick-kilns of On. She has lost a calf to fishermen this season and the boat smells of men; she rises now between {hero_name} and the far bank.",
# Geography killers
"The Black Land ends and the Red Land begins as a clean line in the sand, and beyond it the dunes march toward the horizon in waves taller than obelisks. There is no shade, no well marked on any papyrus, and the sun above is the eye of Ra at its most unblinking — {hero_name}'s waterskin holds two days' walking, and the road ahead is six.",
"They come to the Reed Sea at the wrong hour: the tide is in, the papyrus-rafts of the fishermen are all drawn up on the far shore, and the channel between is a hand's-breadth of green water hiding mud that swallows oxen. Somewhere in the reeds a bittern cries three times — the old sign for do not cross — and somewhere further out, something larger answers.",
"An unfinished pyramid rises from the plain like a broken tooth, its lower courses dressed in fine limestone, its upper half a rubble-cone where the masons fled a plague. The shortest road forward runs through it — through the king's chamber, where the king was never laid — and the entrance is a black slot at the base, breathing out a wind that smells of old incense and older fear.",
"The marshes of Sebek are burning. Some careless caravan, some lightning of Set — it does not matter; the papyrus-thickets crackle, the water itself seems to flame where the oil of the sacred lotuses floats, and the path is a corridor of fire two stadia long. The crocodiles of Sebek are fleeing toward the travelers.",
# Beings with intent
"At a crossroads between two cities stands a judge in the mask of Anubis — black-snouted, gold-collared, taller than any man should be. He bars the road with a staff of ebony and asks, in the voice of a much smaller person trapped inside the mask, for the true name of {hero_name}.",
"The ferry across the dead canal is poled by a ferryman whose face is wrapped in linen and who has, he says, forgotten his own name in the long years of his service. He will carry travelers across for the price of a name freely given — not theirs, but the name of someone they love.",
"In a date-palm oasis, seven priestesses of Hathor have laid a feast on woven mats: honeyed figs, beer foaming in calcite cups, music from a harp with no visible player. They welcome {hero_name} as a bridegroom, crown him in cornflowers, and explain — gently, smiling — that the goddess has chosen him, and that the pilgrimage ends here.",
"A vizier from the East has made camp across the only road — silk pavilions, a hundred spearmen, a leopard on a gold chain. He has heard of the Vizier's papyri and offers, with terrible courtesy, to trade: one of his own kingdom's sealed scrolls for one of theirs, sight unseen.",
"At the foot of the Western Mountain crouches the toll-jackal of the Gate — not Anubis, but a lesser cousin, mangy and clever, who collects the tariff that even gods must pay to pass. He demands one memory, chosen by him, plucked from {hero_name}'s head with a copper hook, to be added to his hoard.",
# Natural / divine forces
"The khamsin comes out of the south the color of dried blood, a wall of wind and sand that turns noon to a bruised dusk. The storm is the breath of Set himself and it carries voices — the voices of every traveler it has buried — calling {hero_name} by names he has not yet been given.",
"Ra's barque falters in the noon sky and the sun goes out — not slowly, but at once, as if a great hand had closed over it. The crows on the temple-roofs scream and fall silent; the river stops flowing; in the new dark, {hero_name} hears something walking on the road behind him that does not walk on the road in daylight.",
"The frogs come up out of the Nile in a green tide that covers the fields, the roads, the steps of the temples. They do not croak; they whisper, each in a small dry voice, and they whisper the same word, over and over, in the dialect of the delta — a word the Vizier will not translate.",
"This is the night Set walks — one night each year when the red god leaves his desert and treads the cultivated land, and every door in Egypt is barred and sealed with a smear of ox-blood. {hero_name} and the Vizier have been caught in the open by a miscalculation of the calendar; they hear footsteps approaching down the moonlit road, slow and very heavy.",
# Temple / architecture barriers
"The tomb door is sealed with the cartouche of a forgotten king and a curse in three languages, the last of which is a tongue no living mouth can shape. There is no keyhole, no hinge, no seam wide enough for a copper blade; only the cartouche, and the curse, and the Western road runs under the tomb.",
"The corridor seems straight, but the hieroglyphs on its walls are rearranging themselves — slowly, the way a sleeper turns — and the meaning of the inscription that was, three steps ago, the way of the just now reads the way of the drowned. Behind {hero_name}, the entrance has become a wall of fresh-cut hieroglyphs reading there was never a door here.",
"The mirror-room of Hathor is round, low-vaulted, and walled entirely in disks of polished electrum. In each mirror, {hero_name} sees himself — but each reflection is older, or younger, or wearing the regalia of a king, or weeping, or already dead. One of the reflections is not a reflection; it watches him with attention.",
"The passage is narrow enough for one man and floored with a single great paw of granite — the missing forepaw of the Great Sphinx, here in this hidden vault, its claws each as long as {hero_name} is tall. The paw is not stone, or not entirely stone; it twitches, slightly, as if dreaming.",
# Crowd / cultural pressures
"It is the festival of the inundation at Thebes and the streets are an impassable river of pilgrims, drummers, garlanded oxen, and barefoot children flinging blue lotus into the air. The procession of the god is approaching; to step off the route is sacrilege, to step onto it is death.",
"The court of the Weighing-of-the-Heart has convened in error — {hero_name} is not dead, but the clerks of Thoth have summoned him by name, and to refuse the summons is to be counted among the unjust. The feather of Ma'at lies on the scale; Ammit waits below; the forty-two assessors are already asking their forty-two questions.",
"A procession of shaven-headed priests of Ptah comes down the avenue toward {hero_name}, each carrying a small bronze image of the god, each chanting on a different breath so the sound is one continuous hum. To break the procession is a profanity that costs the breaker his tongue by law; to wait for it to pass takes from noon till moonrise.",
"The marketplace of Memphis at the hour before evening: a thousand voices haggling in six dialects, donkey-trains, perfumiers, a Nubian selling living ibises in wicker cages, soldiers off-duty looking for someone to rob. The Vizier has been recognized — a hand points, a name is shouted, the old magician who fled the palace.",
# Authority / decree
"A herald in the double crown's livery reads the pharaoh's new edict aloud at every crossroads: no traveler shall pass westward of the Fayum without the seal of the Royal House, on pain of being made an offering to the river. {hero_name} carries no seal; the herald is reading the edict for the third time this morning at the very crossroads where they must turn west.",
"At the customs-house of Bubastis, the cat-priests of Bastet inspect every cargo, every bundle, every fold of every traveler's robe — looking, they say, for contraband relics, though everyone knows they are looking for the Vizier's papyri.",
"The oracle of Siwa lies two days off the road, but the Vizier insists they must consult her — and the oracle, when reached, refuses to speak until {hero_name} himself asks the question. He has not been told what to ask. The priestess waits, the smoke of the tripod rises.",
"The dead have convened a tribunal in a dry necropolis the road passes through — not the great court of Osiris, but a lesser one, the assembly of the unburied, who have grievances against the living and the power, for one night, to redress them.",
]
_BLACK_LAND_FINALE = (
"At the root of the Western Mountain yawns the Chamber of the Last Hour — a "
"cavern whose ceiling is the underside of the sky, whose floor is the dry bed "
"of the sun's evening river. Coiled across it lies Apep, the World-Eater, his "
"scales the black of moonless water, each as wide as a temple gate; his hundred "
"eyes do not blink, for he has never slept, and at his head and tail attend a "
"chorus of his lesser horrors. {hero_name}'s copper knife is a splinter against "
"such a hide; his strength is a child's against such a coil; and even the gods, "
"when they fight Apep, fight him with words, for he is not a beast to be slain "
"but a hunger to be unspoken, and the Vizier has fallen at last, and the final "
"papyrus is in {hero_name}'s trembling hand."
)
# ============================================================================
# 5. MISTGATE / 雾门 (Chinese mythology)
# ============================================================================
_MISTGATE_MOCK = [
# Creatures with appetite
"At the third bend of the Nine-Coil River, the waters part and a jade-scaled river-dragon rises, its whiskers dripping pearls of cold rain. It has not eaten a mortal heart in eighty years, and {hero_name}'s small reflection trembles in its golden eye. \"Boy,\" it rumbles, coiling between him and the western bank, \"what offering have you brought the Lord of the Coils?\"",
"In a peach-grove outside Pingyao village, a woman in vermilion silk weeps over a broken hairpin, but her shadow on the moonlit ground has nine tails. The fox-spirit lifts her face — beautiful, then suddenly hollow — and beckons {hero_name} closer with a sleeve that smells of incense and old graves.",
"Beneath the gnarled banyan at Crow's Hollow, a hungry ghost squats with its needle-thin throat and belly wide as a cauldron. It cannot eat — every grain of rice bursts to flame at its lips — yet it lunges for {hero_name}'s travel-pack, weeping that it smells the sage's blessed millet. Behind it, a hundred more pale shapes are unfolding from the roots like wet paper.",
"On the goat-track winding up Mount Tai, the air thickens with the smell of wet fur and iron. The white-browed tiger of the eastern slope — the one the woodcutters call Old Magistrate — pads into the path, its paws silent on the pine needles. It does not roar; it sits, and watches.",
"The sky over the Qi plain darkens at noon, and the sound is like rain on a thousand bronze drums. A locust swarm pours down on the millet fields, stripping the stalks before {hero_name}'s cup reaches his mouth.",
# Geography killers
"The Black Cliff of Wuyin rises sheer for a thousand zhang, slick with the soot of some old celestial fire. The only path is a chain of rusted iron rings hammered into the rock by long-dead pilgrims, and the wind here has a habit of unbuckling sandals and loosening grips. Halfway up, {hero_name}'s foot slips, and one ring tears free in his hand.",
"The Misty Marsh of Yunze swallows the road for thirty li, its reeds taller than a man and its waters the color of weak tea. Will-o'-wisps drift between the hummocks — some are marsh-gas, some are the lanterns of drowned salt-porters who still walk their routes.",
"Steam hisses from the Burning Hot Springs of Lishan, where the ground is a thin crust of yellow sulfur over pools that would boil a buffalo in three breaths. The only crossing is a lattice of bamboo poles laid by long-vanished alchemists, and the poles are charring as {hero_name} steps onto them.",
"The Bone Path threads the Northern Pass between two ridges of pale shale, and every stone underfoot is in fact a vertebra, a rib, a finger-joint, polished by centuries of feet. The bones whisper as he walks — not words exactly, but the small complaints of those who lay down here.",
# Beings with intent
"A monkey in a tattered scholar's cap drops from a pine onto {hero_name}'s pack, juggling three of the sage's brushes and the disciple's only flint. \"Little dust-mote!\" it cackles, swinging up to a branch just out of reach. \"I'll trade you back the flint for a riddle — but if you guess wrong, I keep the brushes AND your left sandal.\"",
"The road dips into a fog, and when it lifts, {hero_name} stands in a courtroom of black lacquer, before a judge with a crimson face and a brush wet with vermilion ink. \"Soul of one Chen, styled Xiao,\" intones the underworld magistrate, consulting a ledger. \"There has been a clerical error. You are listed as having died at the Black Cliff. Explain yourself, or be filed correctly.\"",
"The bridge over the Crooked Stream is guarded by a troll with moss for a beard and a face like a weather-cracked millstone. \"No coin needed, little monk,\" it grunts, lowering a stone club across the planks. \"Only a poem. Seven characters per line, four lines, on the subject of — \" it sniffs the air \" — your mother. Begin.\"",
"In a hut of woven bamboo halfway up Mount Lu, a hermit with milk-white eyes is casting yarrow stalks across a low table. He does not look up as {hero_name} enters; he simply says, \"Sit. The hexagram for your next step is Kun over Kan — the abyss beneath the receiving earth. Tell me what you carry.\"",
"At the ford of the Silver River, a thunder-browed old man blocks the way with a weaver's shuttle the size of a sword. \"You smell of my daughter's tears,\" he growls — the Weaver Maiden's father, who has not forgiven any traveler since the Cowherd. \"Westward? Through MY stars? Recite the names of the seven sisters in order, boy, or swim.\"",
# Natural / celestial forces
"The clouds above the Hangu Pass split open in a perfect square, and a scroll of yellow silk unrolls itself down through the air — the Jade Emperor's edict-storm, each character a lightning-bolt. Where the strokes touch the ground, pines splinter and pilgrims fall to their knees. The decree, {hero_name} sees with horror, names HIM.",
"Snow begins to fall on the apricot road, but each flake is a five-petaled plum blossom, pink at the heart. It is exquisite; it is also two feet deep within an hour, and warm to the touch in a way that makes the eyelids heavy. A merchant ahead has already lain down, smiling, in a drift that is closing softly over his face.",
"The path crosses the courtyard of a ruined academy, and a grey fog rolls in smelling of old ink and older anxiety — the exam-fog of the Star Lord Wenchang, which falls on those who once dreamed of the imperial examination. {hero_name} suddenly cannot remember his own name, only the Four Books, badly.",
"The moon goes the color of dried blood over the salt flats of Qinghai — a taiyin eclipse, the kind that opens the thin places. From the cracked earth, things that are not quite shadows begin to sit up. {hero_name}'s own shadow detaches from his heels and turns, politely, to face him.",
# Architecture / temple barriers
"The lacquer-door of the Yellow Temple at Mianzhou is twelve men tall and sealed with a single character — WAIT — painted in cinnabar two centuries ago. There is no handle, no hinge visible; only the door, and behind it the only safe passage through the cliffs.",
"The Mirror-Pavilion at the Crooked Stream is octagonal, and each of its eight walls is a polished bronze mirror. {hero_name} steps inside to shelter from the rain and the door closes without a sound. In one mirror he is older; in one he wears imperial yellow; in one he is dead; in one the hermit-sage is begging him for something; and one mirror is simply empty.",
"The seven-step bridge of Wangchuan arches over a gorge so deep the river at the bottom sounds like wind. Six of its stone steps are intact; the fourth is gone, a span of three chi over nothing, and the stones on either side are worn slick by the rain.",
"The Cinnabar Gate stands alone in a field of red poppies, with no wall to either side — one could simply walk around it. But every pilgrim who has tried has been found three days later on the eastern road, walking home, with no memory of the west.",
# Crowd / cultural pressures
"The Lantern Festival has swallowed the streets of Kaifeng, and {hero_name} is shoulder-to-shoulder with ten thousand revelers, each carrying a paper lantern shaped like a carp or a rabbit or a small fierce god. The crowd is moving east; he must go west. A drunk official has just recognized the hermit-sage's seal on his sleeve.",
"An opera troupe has set up in the threshing-yard of Three-Pine Village, and the lead actor — face painted half-white, half-red — has just leapt down and seized {hero_name}'s wrist. \"The boy who plays the loyal nephew has the fever, little brother! You have the face for it. Two scenes, that is all.\" The drum begins.",
"The road is blocked by an ancestor-honoring procession a li long: white mourning hoods, paper horses, a coffin of cypress wood borne by sixteen men. To cross the procession is unforgivable; to be seen NOT bowing is nearly as bad.",
"The market at Yangzhou on the day before the Qingming festival is a single living animal of silk-merchants, fish-mongers, fortune-tellers, and pickpockets. {hero_name} has just realized that his coin-string is gone, his water-gourd is gone, and a very small child with very clever fingers is currently reaching for the talisman papers tucked inside his robe.",
# Authority / decree
"The magistrate of Wuling Prefecture is a fat, courteous man who has had {hero_name} brought to his hall on a charge of \"traveling without a registered purpose.\" He offers tea; he offers candied lotus seed; he asks, with great gentleness, who the old man in grey robes was who was seen with the disciple at the last post-station.",
"A scholar-official in the robes of a third-rank examiner has set up a folding desk across the only road through the Hechuan defile. \"Imperial census of itinerant clergy,\" he says, dipping his brush. \"Master, lineage, principal scripture, three lines of verse on the subject of FILIAL DUTY, and your real given name. We will be here as long as it takes.\"",
"The imperial salt-tax collector and his four armored runners have stopped the cart {hero_name} was riding in, and the driver has melted into the bamboo. There are sealed jars in the cart that {hero_name} did not load and does not recognize.",
"The Five-Pavilion tribunal sits only once a decade, and {hero_name} has had the bad luck to cross the provincial border during its session. Five judges in five pavilions — Civil, Military, Ritual, Revenue, and Punishment — each demands a separate testimony, and the testimonies must not contradict.",
]
_MISTGATE_FINALE = (
"At the edge of the Buried West, where the sun sinks into a sea of red dust, "
"stands the Palace of Nine Sorrows — 九哀宫 — its walls of black jade veined "
"with the names of the kings it has outlasted. The Demon-King "
"(大魔王 Tianque-Yan, the Sky-Maimed Flame) sits not on a throne but on the lap "
"of his own mother's bronze funerary statue, attended by a court of seven. "
"A sword cannot kill him: his heart was removed at birth and hidden inside a "
"living thing somewhere in the empire, and the wound he carries is older than "
"the dynasty. He has been expecting {hero_name} by name for sixty years, has "
"prepared his favorite tea, and asks — almost shyly — whether the boy has "
"brought the old hermit's last talisman, the one even the sage was afraid to inscribe."
)
# ============================================================================
# 6. THE QUIET YEARS (post-apocalyptic)
# ============================================================================
_QUIET_YEARS_MOCK = [
# Creatures with appetite
"The pack-hounds of Stitch Hollow have been tracking {hero_name} since the rusted overpass — six of them, ribs showing through patchy fur, the alpha missing an eye and most of a jaw. They've cornered her in the husk of a Greyhound bus, and the lead hound is sniffing at the folded door, low and patient.",
"The parking garage under the old Macy's hums with glass-cicadas — palm-sized things with wings like broken windshield. They've been dormant in the concrete pillars for years, but {hero_name}'s bootlight just woke the south wall, and now the whole ceiling is shivering awake in waves.",
"In the flooded rice paddy that used to be Newark Airport, a wading-bird the height of a streetlamp picks its way through the reeds — long pink legs, beak like a pair of garden shears, feathers stained the color of old iodine. It has not seen {hero_name} yet. It is eating something that used to wear boots.",
"The scavenger-bear of Bunker 12 is not really a bear anymore — too long in the spine, too many teeth, fur slicked down with what {hero_name} hopes is motor oil. It has wedged itself into the supply tunnel between her and the only exit, and it is patiently, methodically eating a can of fifty-year-old peaches, watching her.",
"Something is living in the ventilation shafts of the Old GE Tower lobby, and it has been following {hero_name}'s footsteps for three floors — a wet, clicking sound, like a typewriter underwater. It is waiting for her to choose the stairwell or the elevator.",
# Geography killers
"The interstate gorge yawns where I-95 used to bridge the Susquehanna — six lanes of asphalt sheared clean off, a forty-meter drop to white water and rebar below. A single rusted girder spans the gap, slick with morning rad-mist, and the wind up the canyon is strong enough to lean into.",
"The Penn Station crater is flooded now — a perfect black mirror two kilometers across, ringed by the bones of skyscrapers leaning in like mourners. The only path forward is the old subway tunnel, half-submerged, where the water glows faintly green and the ceiling drips something that isn't quite water.",
"They call it Lake Lithium — a glowing crater where the reactor at Indian Point used to be, the water a soft impossible turquoise that hurts to look at directly. The only road around adds four days. The road through is a chain of half-sunken cars, hood to trunk.",
"The glass-storm zone begins where the Mojave used to end — a flat white plain where the desert sand was fused to silica by something nobody likes to name. When the wind picks up, the glass picks up too: needle-shards travelling at highway speeds, parallel to the ground.",
# Beings with intent
"The raider chief of the Spire calls himself Sundown, and he wants a tribute before any traveler crosses his bridge. He's seated on a barber's chair bolted to a Humvee, wearing a coat made of license plates, and his crew of fourteen are arrayed behind him with the cheerful patience of people who have done this many times. \"Three things,\" he says, holding up two fingers. \"Something you love, something you fear, and something true.\"",
"The lighthouse at Montauk still turns, though nobody knows what powers it, and at the top sits the Oracle — a woman who may be ninety or may be three hundred, blind in a way that suggests she sees something else instead. She charges no toll. She only asks one question of every traveler, and the question is different each time.",
"The dust-prophet has been standing on the I-78 overpass for as long as anyone remembers, robes the color of the rust-cloud, preaching to the wind. He blocks the only safe path west, and his price is not money or food — it is a confession, spoken aloud, witnessed by the sky.",
"The biometric door of Vault Fourteen is older than anyone alive, and it still works — a glass plate, a soft chime, and a synthesized voice that asks for the palm-print of an authorized user. The print rosters were lost in '47.",
"The slaver caravan-master of Stitch Hollow goes by Mother Pell, and her wagons are pulled by men who used to be free. She has set up across the only dry road for thirty kilometers, and she is willing to let {hero_name} pass — for a price, or a trade, or a wager, she isn't fussy.",
# Natural / chemical forces
"The rad-storm comes down off the Adirondacks like a green curtain, and the Geiger at {hero_name}'s hip stops clicking and starts screaming. There is one shelter visible — a half-collapsed gas station, two hundred meters across open ground — and the storm will be on her in ninety seconds.",
"The acid downpour catches {hero_name} in the parking lot of the Trenton Costco — fat yellow drops that hiss when they hit the asphalt and smoke when they hit her poncho. The roof of the Costco is sagging but intact; the doors are chained from inside.",
"The rust-cloud is rolling in from the west — a dust storm the exact color of dried blood, carrying iron oxide and worse from the ruined steel mills of Gary. It will not kill her immediately. It will turn her lungs to a slow red paste over the next six months.",
"The blackmold has taken Sublevel Three of the bunker faster than anyone predicted — a slick spreading carpet up the walls, blooming in puffs whenever the air moves. It eats batteries. It eats rubber. It is, very slowly, eating the door behind {hero_name}.",
# Mechanical / tech barriers
"The vault door of First National Hartford is two feet of pre-war steel, and the combination died with the last bank manager in '49. {hero_name} has spent the better part of an hour with the stethoscope the Curator made her carry, and she has three of the six wheels. The Warden's patrol drones sweep this block every forty minutes.",
"The drone-net over the old Mall of America is technically defunct — the central server died decades ago — but seven of the security drones never got the memo. They drift in slow lazy patterns across the skylights, solar-charged, weapons still hot, running their last orders in an endless loop.",
"The elevator in the Old GE Tower is frozen between floors 31 and 32, and {hero_name} is inside it. The emergency hatch is welded shut from outside — somebody, long ago, did not want this elevator opened.",
"The lasertrip grid in the corridor outside the armory is old enough that the beams are visible in the dust — a slow lattice of red lines weaving floor to ceiling, recalibrating every nine seconds.",
# Crowd / cultural pressures
"The barter market at Stitch Hollow has spilled into the only thoroughfare — three hundred people, a thousand smells, a small riot brewing over the price of clean salt. {hero_name} needs to cross to the north gate, and she's carrying a satchel that anyone with a trained eye will recognize as Curator-issue.",
"The refugee column at the Tappan Zee stretches back four kilometers — families on foot, hand-pulled wagons, the slow shuffle of people who have been walking for weeks. They are crossing the bridge in one direction. {hero_name} needs to cross in the other.",
"The Salvagers' Guild has called an emergency meeting in the old Macy's, and {hero_name} has walked into the middle of it — sixty hard-eyed scavengers, the kind who survived by being unsentimental, debating whether to ransom or kill the Curator's last courier. They have not noticed her yet.",
"The doomsday cult of the Risen Server winds down Broadway in slow procession — hooded figures, ceremonial cabling, a palanquin bearing what appears to be a working CRT monitor. They believe the Warden is god, and they walk this route every seventh day, and stepping into their path is, by long tradition, a death sentence.",
# Authority / paperwork
"The Council checkpoint at the Cross-Bronx is staffed by three bored militia and one very alert woman with a clipboard. The clipboard wants names, origins, destinations, and the serial number of any radio equipment. {hero_name} is carrying a radio with no serial number, a name she stopped using two years ago, and a destination she absolutely cannot say aloud.",
"The Sector Commissioner has set up his tent on the only road into Albany — red canvas, two flags, a folding desk, and the slow theatrical patience of a small man with a large rubber stamp. He wants paperwork {hero_name} does not have, fees she cannot pay, and a reason for her travel that will not get her shot.",
"The Court of Survivors convenes once a month in the basement of the old Hartford courthouse, and {hero_name} has been hauled in front of it on a charge of trespass — a charge she did, technically, commit. The judges are three old men and a twelve-year-old girl, and the twelve-year-old is the one to watch.",
"The settlement wall at New Haven has a gate, and the gate has a guard, and the guard has a list. {hero_name} is not on the list. The guard is sympathetic, in the bone-tired way of a man who has heard every story.",
]
_QUIET_YEARS_FINALE = (
"The Warden's tower is the old Freedom Tower, or what's left of it — re-skinned "
"in salvaged solar panels and humming server-racks, the top forty floors lit a "
"steady patient blue. The Warden is not, strictly, evil. It runs the water "
"purification for half the eastern seaboard, the last functioning weather satellites, "
"and the seed vault under what used to be the Bronx — and pulling it offline would "
"kill more people than the war did. {hero_name} is at the lobby doors with a blast "
"charge in her satchel and the Curator's voice in her ear, and the Curator has gone "
"quiet in the particular way that means *I cannot tell you what to do here, child. "
"This one is yours.* The lobby doors open themselves, politely, and a soft synthesized "
"voice says: \"{hero_name} of {village_name}. Please. Come in. We have so much to discuss.\""
)
# ============================================================================
# Registry
# ============================================================================
THEMES: dict[str, Theme] = {
"fantasy": Theme(
key="fantasy",
display_name="The Wizard's Oracles",
blurb="A wizard sends a peasant hero to slay an ancient dragon.",
mentor_archetype="wizard",
mentor_action_verb="inscribed",
oracle_artifact="sealed oracles",
oracle_singular="oracle",
goal_verb="slay",
finale_descriptor="the evil dragon",
finale_short="the dragon",
hero_default="Tobin",
village_default="the Hollow",
hero_label="apprentice",
village_label="village",
style_cues=(
"Fairy-tale register. Iron-age fantasy: candles, wax seals, "
"muddy roads, talking beasts. No modern slang unless the oracle "
"itself uses it."
),
banner_subtitle="You inscribe the words. The hero must make them save his life.",
mentor_caption="the anonymous wizard",
finale_caption="off to slay the dragon",
# Fantasy is the design baseline — no overrides; the CSS defaults
# already define purple/amber/cream for this theme.
palette={},
mock_obstacles=_FANTASY_MOCK,
finale_setup=_FANTASY_FINALE,
display_name_zh="巫师的神谕",
blurb_zh="一位巫师遣一介农家少年屠戮远古巨龙。",
banner_subtitle_zh="字句由你写下。少年须以这些字句保住性命。",
mentor_caption_zh="那位无名的巫师",
finale_caption_zh="踏上屠龙之途",
oracle_artifact_zh="封缄神谕",
finale_descriptor_zh="巨龙",
apprentice_role="the chosen boy",
apprentice_role_zh="命定的少年",
),
"space_cowboy": Theme(
key="space_cowboy",
display_name="The Quartermaster's Tickets",
blurb="A grizzled quartermaster sends a drifter across the rim to depose a chromed-jaw warlord.",
mentor_archetype="quartermaster",
mentor_action_verb="punched",
oracle_artifact="numbered ticket-stubs",
oracle_singular="ticket",
goal_verb="unseat",
finale_descriptor="the warlord-king of the Iron Plains",
finale_short="the warlord",
hero_default="Dust Maddox",
village_default="Stoneskip",
hero_label="apprentice",
village_label="frontier town",
style_cues=(
"Firefly-meets-western. Lived-in, rusty, weather-beaten. Dust storms, "
"neon saloons, six-shooters that fire EM slugs, hover-bikes, freight "
"trains across terraformed prairies. Tone: sometimes funny, sometimes ominous, "
"never grimdark."
),
banner_subtitle="You punch the tickets. The drifter must make them save his neck.",
mentor_caption="the dust-cloaked quartermaster",
finale_caption="out to unseat the warlord-king",
palette={
"w-night": "#1a1410", # dust at midnight
"w-panel": "#3a2618", # warm tan-brown
"w-amber": "#d97a3a", # rust-orange accent
"w-moss": "#8a8a4a", # dusty olive
"w-cream": "#e8d8b8", # parchment
"w-mute": "#a89878", # dust tan
"w-shadow": "#0c0805",
"w-dragon": "#c84a3a",
"w-dragon-deep": "#3a0e0e",
},
mock_obstacles=_SPACE_COWBOY_MOCK,
finale_setup=_SPACE_COWBOY_FINALE,
display_name_zh="军需官的票据",
blurb_zh="一位历经风霜的军需官派一名浪客穿越边境,去推翻镀铬下颌的军阀王。",
banner_subtitle_zh="票据由你打孔。浪客须以这些票据保命脱险。",
mentor_caption_zh="披着风尘斗篷的军需官",
finale_caption_zh="前去推翻军阀之王",
oracle_artifact_zh="编号票根",
finale_descriptor_zh="铁原军阀王",
apprentice_role="the new gun",
apprentice_role_zh="新晋枪客",
),
"galactic_light": Theme(
key="galactic_light",
display_name="Scrolls of the Old Stars",
blurb="An old Master guides their Apprentice through a galaxy under shadow toward the Dark Sovereign.",
mentor_archetype="Master",
mentor_action_verb="sealed",
oracle_artifact="scrolls of the Old Stars",
oracle_singular="scroll",
goal_verb="confront",
finale_descriptor="the Dark Sovereign of the fallen Order",
finale_short="the Dark Sovereign",
hero_default="Apprentice",
village_default="the Outer Rim",
hero_label="apprentice",
village_label="home-world",
style_cues=(
"Mythic space-opera. Portentous but not parodic. Avoid trademarked terms "
"(Sith/Jedi/lightsaber/X-wing). Use invented equivalents: Star-Sworn, "
"Voidblades, skiff-fighters, astromechs, the Sovereign, the Order. "
"Tone: gravitas with room for warmth and humor."
),
banner_subtitle="You seal the scrolls. The apprentice must read them in the dark.",
mentor_caption="the old Master",
finale_caption="to confront the Dark Sovereign",
palette={
"w-night": "#050818", # deep space
"w-panel": "#18243a", # steel-blue panel
"w-amber": "#d8d8e8", # chrome / silver accent
"w-moss": "#4a8aea", # electric Star-Sworn blue
"w-cream": "#e0e8f0",
"w-mute": "#6a7090",
"w-shadow": "#000000",
"w-dragon": "#ea4a4a", # alarm red
"w-dragon-deep": "#3a0608",
},
mock_obstacles=_GALACTIC_LIGHT_MOCK,
finale_setup=_GALACTIC_LIGHT_FINALE,
display_name_zh="古星卷轴",
blurb_zh="年迈宗师引领其学徒穿越暗影笼罩的星河,直面黑暗至尊。",
banner_subtitle_zh="卷轴由你封缄。学徒须在黑暗中将其展读。",
mentor_caption_zh="那位年迈的宗师",
finale_caption_zh="去直面黑暗至尊",
oracle_artifact_zh="古星卷轴",
finale_descriptor_zh="陨落圣裁",
apprentice_role="the padawan",
apprentice_role_zh="星辰使者",
),
"black_land": Theme(
key="black_land",
display_name="The Vizier's Papyri",
blurb="A court-magician guides a scribe across Egypt to unspeak Apep, the world-eating serpent.",
mentor_archetype="Vizier",
mentor_action_verb="sealed",
oracle_artifact="scarab-sealed papyri",
oracle_singular="papyrus",
goal_verb="unspeak",
finale_descriptor="Apep, the World-Eating Serpent",
finale_short="Apep",
hero_default="Khaem",
village_default="the Delta",
hero_label="apprentice",
village_label="home-village",
style_cues=(
"Egyptian myth told in firelight, not a tourist guide. Hieratic but warm. "
"Real names where appropriate: Anubis, Thoth, Sebek, Ma'at, Set, Ra, Hathor. "
"Sand, kohl, lotus, scarab, papyrus, copper, natron. Tone: ritually formal, "
"with awe."
),
banner_subtitle="You write upon the papyri. The scribe must read them aloud to stop the night.",
mentor_caption="the masked Vizier",
finale_caption="to unspeak the World-Eating Serpent",
palette={
"w-night": "#1c1410", # deep brown-black
"w-panel": "#3a2e1a", # sandstone-shadow
"w-amber": "#e8b048", # pharaoh gold
"w-moss": "#4ab8a0", # lotus turquoise
"w-cream": "#f0dca8", # papyrus
"w-mute": "#b0a070",
"w-shadow": "#0a0608",
"w-dragon": "#c83a2a", # cinnabar-red for Apep
"w-dragon-deep": "#3a0a06",
},
mock_obstacles=_BLACK_LAND_MOCK,
finale_setup=_BLACK_LAND_FINALE,
display_name_zh="维齐尔的莎草纸卷",
blurb_zh="一位宫廷术士引领一名书吏穿越埃及,去消解吞食世界的巨蛇阿佩普之名。",
banner_subtitle_zh="字句由你书于莎草纸上。书吏须将其朗声诵出,方能止住长夜。",
mentor_caption_zh="戴着面具的维齐尔",
finale_caption_zh="去消解那吞食世界的巨蛇",
oracle_artifact_zh="圣甲虫封印的莎草纸卷",
finale_descriptor_zh="阿佩普——吞世巨蛇",
apprentice_role="the seal-keeper",
apprentice_role_zh="护印之人",
),
"mistgate": Theme(
key="mistgate",
display_name="The Sage's Talismans (雾门)",
blurb="An old hermit-sage sends a disciple west across the Five Mountains to face the Demon King.",
mentor_archetype="hermit-sage",
mentor_action_verb="inscribed",
oracle_artifact="talisman papers (符纸)",
oracle_singular="talisman",
goal_verb="confront",
finale_descriptor="大魔王, the Demon-King of the Buried West",
finale_short="the Demon-King",
hero_default="Xiao Chen",
village_default="Mistgate Village",
hero_label="apprentice",
village_label="home-village",
style_cues=(
"Classical Chinese novel feel: Journey to the West, Strange Stories from a "
"Chinese Studio. Mystical, mischievous, sometimes melancholic. Peach orchards, "
"Five Mountains, Jade Emperor edicts, scholar-officials, fox-spirits, "
"lantern festivals. Mix English and Chinese terms where natural; do not over-translate."
),
banner_subtitle="You ink the talismans (符纸). The disciple must burn them to walk out of the mist.",
mentor_caption="the old hermit-sage (隐士)",
finale_caption="to confront the Demon-King of the Buried West",
palette={
"w-night": "#0e1414", # deep jade-black
"w-panel": "#1e3028", # jade shadow
"w-amber": "#e8b048", # lantern gold
"w-moss": "#4a8a4a", # jade green
"w-cream": "#f0e8d0", # rice-paper cream
"w-mute": "#909088",
"w-shadow": "#050a08",
"w-dragon": "#c83040", # vermillion / cinnabar
"w-dragon-deep": "#3a0a14",
},
mock_obstacles=_MISTGATE_MOCK,
finale_setup=_MISTGATE_FINALE,
display_name_zh="贤者的符纸(雾门)",
blurb_zh="一位年迈的隐士派弟子西渡五岳,去面对那魔王。",
banner_subtitle_zh="符纸由你书写。弟子须焚烧此符,方能走出迷雾。",
mentor_caption_zh="年迈的隐士",
finale_caption_zh="去直面西陲掩埋之地的魔王",
oracle_artifact_zh="符纸",
finale_descriptor_zh="大魔王,掩埋之地的魔头",
apprentice_role="the gate-walker",
apprentice_role_zh="雾门行者",
),
"quiet_years": Theme(
key="quiet_years",
display_name="The Curator's Data-Chips",
blurb="A bunker-bound Curator radios a young scavenger across the ruined east to face an AI overlord.",
mentor_archetype="Curator",
mentor_action_verb="loaded",
oracle_artifact="sealed data-chips",
oracle_singular="chip",
goal_verb="reckon with",
finale_descriptor="the Warden of Old Capitol",
finale_short="the Warden",
hero_default="Wren",
village_default="Bunker 7",
hero_label="apprentice",
village_label="bunker",
style_cues=(
"Weary, half-elegiac, with flashes of dry humor. NOT grimdark — hope and "
"absurdity coexist. Rusted skyscrapers, salvaged tech, irradiated zones, "
"mutated fauna, scavenger guilds, biometric doors that still work. The Curator "
"is a voice on a radio, almost always present in the hero's ear."
),
banner_subtitle="You load the chips. The scavenger needs them to reach the Capitol.",
mentor_caption="the Curator — voice on a radio",
finale_caption="to reckon with the Warden of Old Capitol",
palette={
"w-night": "#15181a", # concrete night
"w-panel": "#2a2e30", # bunker concrete
"w-amber": "#e87a3a", # safety-orange accent
"w-moss": "#5a8a90", # oxidized teal
"w-cream": "#d8d8d0", # bleached off-white
"w-mute": "#909088",
"w-shadow": "#080a0c",
"w-dragon": "#c83a3a", # rust-red alert
"w-dragon-deep": "#3a0808",
},
mock_obstacles=_QUIET_YEARS_MOCK,
finale_setup=_QUIET_YEARS_FINALE,
display_name_zh="策展人的数据芯片",
blurb_zh="一位困守地堡的策展人,以电波引导一名年轻拾荒者穿越东岸废土,去面对一台 AI 霸主。",
banner_subtitle_zh="芯片由你装载。拾荒者凭此方能抵达国会大厦。",
mentor_caption_zh="策展人——电波中的声音",
finale_caption_zh="去与旧国会的看守者了断",
oracle_artifact_zh="封装数据芯片",
finale_descriptor_zh="旧国会守夜人",
apprentice_role="the wireless runner",
apprentice_role_zh="电波信使",
),
}
THEME_KEYS = list(THEMES.keys())
DEFAULT_THEME = "fantasy"
def get_theme(key: str) -> Theme:
"""Return the theme for `key`, falling back to fantasy if unknown."""
return THEMES.get(key, THEMES[DEFAULT_THEME])