Files
timmy-home/evennia_tools/bezalel_layout.py
Alexander Whitestone b3359e1bae
Some checks failed
Smoke Test / smoke (pull_request) Failing after 19s
feat: add Bezalel Evennia world scaffold (#536)
2026-04-15 00:46:03 -04:00

191 lines
8.1 KiB
Python

from collections import deque
from dataclasses import dataclass
@dataclass(frozen=True)
class RoomSpec:
key: str
desc: str
@dataclass(frozen=True)
class ExitSpec:
source: str
key: str
destination: str
aliases: tuple[str, ...] = ()
@dataclass(frozen=True)
class ObjectSpec:
key: str
location: str
desc: str
aliases: tuple[str, ...] = ()
@dataclass(frozen=True)
class CharacterSpec:
key: str
desc: str
starting_room: str
@dataclass(frozen=True)
class TravelCommandSpec:
key: str
aliases: tuple[str, ...]
target_world: str
fallback_room: str
desc: str
ROOMS = (
RoomSpec(
"Limbo",
"The void between worlds. The air carries the pulse of three houses: Mac, VPS, and this one. "
"Everything begins here before it is given form.",
),
RoomSpec(
"Gatehouse",
"A stone guard tower at the edge of Bezalel's world. The walls are carved with runes of travel, "
"proof, and return. Every arrival is weighed before it is trusted.",
),
RoomSpec(
"Great Hall",
"A vast hall with a long working table. Maps of the three houses hang beside sketches, benchmarks, "
"and deployment notes. This is where the forge reports back to the house.",
),
RoomSpec(
"The Library of Bezalel",
"Shelves of technical manuals, Evennia code, test logs, and bridge schematics rise to the ceiling. "
"This room holds plans waiting to be made real.",
),
RoomSpec(
"The Observatory",
"A high chamber with telescopes pointing toward the Mac, the VPS, and the wider net. Screens glow with "
"status lights, latency traces, and long-range signals.",
),
RoomSpec(
"The Workshop",
"A forge and workbench share the same heat. Scattered here are half-finished bridges, patched harnesses, "
"and tools laid out for proof before pride.",
),
RoomSpec(
"The Server Room",
"Racks of humming servers line the walls. Fans push warm air through the chamber while status LEDs beat "
"like a mechanical heart. This is the pulse of Bezalel's house.",
),
RoomSpec(
"The Garden of Code",
"A quiet garden where ideas are left long enough to grow roots. Code-shaped leaves flutter in patterned wind, "
"and a stone path invites patient thought.",
),
RoomSpec(
"The Portal Room",
"Three shimmering doorways stand in a ring: one marked for the Mac house, one for the VPS, and one for the wider net. "
"The room hums like a bridge waiting for traffic.",
),
)
EXITS = (
ExitSpec("Limbo", "gatehouse", "Gatehouse", ("gate", "tower")),
ExitSpec("Gatehouse", "limbo", "Limbo", ("void", "back")),
ExitSpec("Gatehouse", "greathall", "Great Hall", ("hall", "great hall")),
ExitSpec("Great Hall", "gatehouse", "Gatehouse", ("gate", "tower")),
ExitSpec("Great Hall", "library", "The Library of Bezalel", ("books", "study")),
ExitSpec("The Library of Bezalel", "hall", "Great Hall", ("great hall", "back")),
ExitSpec("Great Hall", "observatory", "The Observatory", ("telescope", "tower top")),
ExitSpec("The Observatory", "hall", "Great Hall", ("great hall", "back")),
ExitSpec("Great Hall", "workshop", "The Workshop", ("forge", "bench")),
ExitSpec("The Workshop", "hall", "Great Hall", ("great hall", "back")),
ExitSpec("The Workshop", "serverroom", "The Server Room", ("servers", "server room")),
ExitSpec("The Server Room", "workshop", "The Workshop", ("forge", "bench")),
ExitSpec("The Workshop", "garden", "The Garden of Code", ("garden of code", "grove")),
ExitSpec("The Garden of Code", "workshop", "The Workshop", ("forge", "bench")),
ExitSpec("Gatehouse", "portalroom", "The Portal Room", ("portal", "portals")),
ExitSpec("The Portal Room", "gatehouse", "Gatehouse", ("gate", "back")),
)
OBJECTS = (
ObjectSpec("Threshold Ledger", "Gatehouse", "A heavy ledger where arrivals, departures, and field notes are recorded before the work begins."),
ObjectSpec("Three-House Map", "Great Hall", "A long map showing Mac, VPS, and remote edges in one continuous line of work."),
ObjectSpec("Bridge Schematics", "The Library of Bezalel", "Rolled plans describing world bridges, Evennia layouts, and deployment paths."),
ObjectSpec("Compiler Manuals", "The Library of Bezalel", "Manuals annotated in the margins with warnings against cleverness without proof."),
ObjectSpec("Tri-Axis Telescope", "The Observatory", "A brass telescope assembly that can be turned toward the Mac, the VPS, or the open net."),
ObjectSpec("Forge Anvil", "The Workshop", "Scarred metal used for turning rough plans into testable form."),
ObjectSpec("Bridge Workbench", "The Workshop", "A wide bench covered in harness patches, relay notes, and half-soldered bridge parts."),
ObjectSpec("Heartbeat Console", "The Server Room", "A monitoring console showing service health, latency, and the steady hum of the house."),
ObjectSpec("Server Racks", "The Server Room", "Stacked machines that keep the world awake even when no one is watching."),
ObjectSpec("Code Orchard", "The Garden of Code", "Trees with code-shaped leaves. Some branches bear elegant abstractions; others hold broken prototypes."),
ObjectSpec("Stone Bench", "The Garden of Code", "A place to sit long enough for a hard implementation problem to become clear."),
ObjectSpec("Mac Portal", "The Portal Room", "A silver doorway whose frame vibrates with the local sovereign house.", ("mac arch",)),
ObjectSpec("VPS Portal", "The Portal Room", "A cobalt doorway tuned toward the testbed VPS house.", ("vps arch",)),
ObjectSpec("Net Portal", "The Portal Room", "A pale doorway pointed toward the wider net and every uncertain edge beyond it.", ("net arch", "network arch")),
)
CHARACTERS = (
CharacterSpec("Timmy", "The Builder's first creation. Quiet, observant, already measuring the room before he speaks.", "Gatehouse"),
CharacterSpec("Bezalel", "The forge-and-testbed wizard. Scarred hands, steady gaze, the habit of proving things before trusting them.", "The Workshop"),
CharacterSpec("Marcus", "An old man with kind eyes. He walks like someone who has already survived the night once.", "The Garden of Code"),
CharacterSpec("Kimi", "The deep scholar of context and meaning. He carries long memory like a lamp.", "The Library of Bezalel"),
)
PORTAL_COMMANDS = (
TravelCommandSpec(
"mac",
("macbook", "local"),
"Mac house",
"Limbo",
"Align with the sovereign local house. Until live cross-world transport is wired, the command resolves into Limbo — the threshold between houses.",
),
TravelCommandSpec(
"vps",
("testbed", "house"),
"VPS house",
"Limbo",
"Step toward the forge VPS. For now the command lands in Limbo, preserving the inter-world threshold until real linking is live.",
),
TravelCommandSpec(
"net",
("network", "wider-net"),
"Wider net",
"Limbo",
"Face the open network. The command currently routes through Limbo so the direction exists before the final bridge does.",
),
)
def room_keys() -> tuple[str, ...]:
return tuple(room.key for room in ROOMS)
def character_keys() -> tuple[str, ...]:
return tuple(character.key for character in CHARACTERS)
def portal_command_keys() -> tuple[str, ...]:
return tuple(command.key for command in PORTAL_COMMANDS)
def grouped_exits() -> dict[str, tuple[ExitSpec, ...]]:
grouped: dict[str, list[ExitSpec]] = {}
for exit_spec in EXITS:
grouped.setdefault(exit_spec.source, []).append(exit_spec)
return {key: tuple(value) for key, value in grouped.items()}
def reachable_rooms_from(start: str) -> set[str]:
seen: set[str] = set()
queue: deque[str] = deque([start])
exits_by_room = grouped_exits()
while queue:
current = queue.popleft()
if current in seen:
continue
seen.add(current)
for exit_spec in exits_by_room.get(current, ()):
if exit_spec.destination not in seen:
queue.append(exit_spec.destination)
return seen