From da809bea3124b343c9dc313cb3bc62d771ded238 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Tue, 10 Feb 2026 22:48:40 -0500 Subject: [PATCH] Add zones and building doc --- docs/how/zones-and-building.rst | 596 ++++++++++++++++++++++++++++++++ 1 file changed, 596 insertions(+) create mode 100644 docs/how/zones-and-building.rst diff --git a/docs/how/zones-and-building.rst b/docs/how/zones-and-building.rst new file mode 100644 index 0000000..25eb465 --- /dev/null +++ b/docs/how/zones-and-building.rst @@ -0,0 +1,596 @@ +zones and building — from grids to worlds +========================================= + +a design doc. captures the vision for how players and builders create, +connect, and inhabit spaces in the MUD. born from a riffing session, fed +by research into how other engines handle this. living document — update +as decisions get made and things get built. + +see also: ``things-and-building.rst`` (item/verb system), +``architecture-plan.txt`` (engine/content boundary), +``prompt-system.txt`` (modal prompts). + + +the core idea — everything is a zone +-------------------------------------- + +a zone is a rectangular grid of tiles. it has dimensions, a palette, and +tile data. that's it. everything is a zone. + +- the procedural overworld? a zone with a generator (perlin noise) +- a hand-built treehouse? a zone with tile data from a file +- a single room (office, closet)? a small zone +- a dungeon? a zone with procedural guts +- the flower you spawn in? a tiny zone + +the differences between zones are properties, not types: + +**wrapping** + does the zone loop? options: toroidal (wraps both axes, like a sphere + — walk far enough and you're back), cylindrical (wraps one axis), + bounded (hard edges, you hit a wall or void). + +**generator** + how tiles get filled. ``none`` means blank canvas (you paint it). + ``perlin`` means procedural terrain from a seed. ``file`` means tile + data loaded from a TOML. generators and hand-placed tiles can coexist + — generate a base, then paint over specific areas. + +**dimensions** + 5x5, 100x50, 1000x1000. whatever the space needs. + +**palette** + what each symbol means. char + name + color + properties (passable, + movement cost, opacity, etc). every zone has a palette. zones can + share palettes or define their own. + + +zone data format +----------------- + +the web editor already saves something close to this. extend it with +zone metadata and portal definitions. + +:: + + [zone] + name = "treehouse" + description = "a treehouse nestled in the canopy of an ancient oak" + wrapping = "bounded" + spawn = [10, 7] + + [map] + width = 20 + height = 15 + data = """ + ..oooo..TTT......... + ..o..o..TTT......... + ..o..o..TTT......... + ..oooo....T......... + ..........T......... + ........+.T......... + ..........T......... + ..........TTTTT..... + ................~~~~ + ................~~~~ + .................... + .................... + .................... + .................... + .................... + """ + + [palette] + entries = """ + o|wall|#8b4513|solid + .|floor|#d2b48c|passable + T|leaves|#0a5f0a|passable + ~|water|#2244aa|solid + +|door|#c8a456|passable + """ + + [[portals]] + x = 10 + y = 14 + target = "zone:forest_path:20,5" + label = "a rope bridge stretches into the canopy" + + [[portals]] + x = 10 + y = 0 + target = "overworld:450,300" + label = "a ladder descends to the ground far below" + +zones live in ``content/zones/``. loaded at startup like mobs and +commands. hot-reloadable via ``reload``. + + +player location model +---------------------- + +today a player is ``(x, y)`` on the overworld. with zones, a player is +either on the overworld OR in a zone. + +conceptually: ``(zone_name, x, y)`` where ``zone_name`` is ``None`` for +the overworld. the viewport, movement, look — all the same mechanics, +just reading from a different grid. + +portals are tiles with a target. step on one, you transition. your +location changes from ``(treehouse, 10, 14)`` to +``(forest_path, 20, 5)``. the viewport redraws with the new zone's +tiles and palette. + +open question: do portals auto-trigger (step on tile = transition) or +require explicit action (``enter``, ``use door``)? could depend on the +portal — a path auto-triggers, a locked door requires a key and +``open door`` + ``enter``. the portal definition could specify this:: + + [[portals]] + x = 5 + y = 3 + target = "zone:basement:5,0" + trigger = "auto" # step on it and you go + label = "stairs descend into darkness" + + [[portals]] + x = 12 + y = 7 + target = "zone:vault:0,0" + trigger = "manual" # requires 'enter' command + label = "a heavy iron door" + requires = "iron_key" # item check (future) + + +the flower spawn +----------------- + +new player experience. you wake up inside a sealed flower. + +the flower is a tiny zone, maybe 7x7. petals surround you. the +description mentions perfume, texture on your hands, dim light filtering +through. you can look around but every direction is sealed — petal walls. + +any force command (push, kick, punch, pull) opens the flower. the petal +tiles change (solid → passable, or the zone swaps entirely), you "fall" +— a text transition, maybe a brief animation of symbols scrolling — and +land in the treehouse zone. + +the treehouse is the real starting area. hand-built, 20x15 or whatever +feels right. has a few things to interact with, maybe a note or a simple +puzzle. eventually you find the way down (a portal) and land on the +overworld. infinite procedural landscape in every direction. + +tutorial funnel: tiny space → medium space → infinite space. + +:: + + flower (7x7, sealed) + ↓ player breaks out + treehouse (20x15, hand-built) + ↓ portal (ladder, rope, etc) + overworld (1000x1000, procedural) + ↓ portals to other zones + dungeons, houses, other players' creations... + + +creating zones — three workflows +---------------------------------- + +all three produce the same format. interchangeable. + +workflow A: web editor +~~~~~~~~~~~~~~~~~~~~~~~ + +open the map editor in a browser. paint tiles, define palette, set +dimensions. save as TOML. drop the file in ``content/zones/``. reload +in the MUD (or restart). the zone exists. + +the web editor is not special — it's just faster for large-scale work. +photoshop vs MS paint. good for: laying out a big area, precise pixel +work, working offline, iterating visually. + +workflow B: in-game commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + @new-zone jareds-house 100 50 + +creates a blank bounded zone. you're placed in the center. the viewport +shows void/empty tiles. now you build. + +:: + + @new-zone the-wilds 500 500 --wrap + +creates a toroidal zone. walk far enough and you loop. + +:: + + @new-zone dungeon-3 40 40 --gen perlin + +creates a zone with procedural terrain. paint over specific parts. + +workflow C: paint mode +~~~~~~~~~~~~~~~~~~~~~~~ + +this is the one that buzzes. push into paint mode like editor mode or IF +mode. your ``@`` becomes a cursor. movement works freely — no passability +checks, you float over everything. + +two states within paint mode: + +**survey** (default) + move around, look at things, nothing changes. scouting. + +**painting** + every tile you leave behind gets stamped with your brush. walk east + 5 tiles, leave 5 walls behind you. + +toggle with ``p``. status line shows state:: + + [paint: . floor] survey + [paint: o wall] PAINTING + +change brush: type the symbol character. type ``o`` and your brush is +now wall. type ``.`` for floor. type ``~`` for water. single-char input +sets the brush — no ambiguity because you're in a special mode where +normal commands don't apply. + +or explicit: ``b o`` for brush=wall. both work. + +you could even render as the brush symbol instead of ``@`` when painting. +you see an ``o`` moving around leaving ``o``'s behind it. + +entering and exiting:: + + @paint enter paint mode (survey by default) + p toggle painting on/off + o set brush to 'o' (wall) + n/s/e/w/ne/etc move (and paint if painting) + @paint exit paint mode (or :q, or @done) + +workflow D: @dig (expanding the canvas) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +not room-linking like traditional MUDs. you're extending the zone's tile +grid itself. + +:: + + @dig 5 e zone grows 5 tiles east (new tiles are void) + @dig 10 s zone grows 10 tiles south + @dig n grow 1 tile north (default) + +new space is void/empty. paint it into existence. + +this means zones aren't fixed-size — they grow as you build. start with +a 1x1 zone and @dig your way to a mansion. + + +materials and palettes +----------------------- + +every symbol needs at minimum: char, name, color. that's the palette. + +:: + + [palette] + entries = """ + .|floor|#d2b48c|passable + o|wall|#8b4513|solid + ~|water|#2244aa|solid + +|door|#c8a456|passable + #|window|#87ceeb|solid + ^|mountain|#666666|solid + T|tree|#0a5f0a|passable + :|gravel|#9a9996|passable + =|brick|#a51d2d|solid + """ + +each zone has a palette. could be inline or reference a shared one:: + + [zone] + palette = "default" # use content/palettes/default.toml + +a shared palette means consistent symbols across zones. a custom palette +means a zone can redefine what ``~`` looks like (lava instead of water). + +future properties per material: movement cost (forest is slower), opacity +(walls block line of sight), damage (lava hurts), wetness (water makes +you wet). for now, just passable/solid is enough. + + +portals connect zones +---------------------- + +a portal is a tile with a target. defined in the zone TOML or placed +in-game. + +in-game portal creation:: + + @portal here → jareds-house:5,3 + +"this tile, right where I'm standing, is a portal to jareds-house at +coordinates 5,3." + +portals are bidirectional by default? or one-way? probably one-way by +default (you set up both ends), with a convenience flag for +bidirectional:: + + @portal here ↔ jareds-house:5,3 # creates both sides + +what stepping on a portal looks like: the viewport dissolves (or snaps) +to the new zone. you get a brief transition message. your prompt updates +if the zone has different ambient info. + + +connecting to the overworld +---------------------------- + +the overworld is just another zone — the big one. portals from the +overworld into smaller zones work the same way. a tile at (450, 300) on +the overworld has a portal to ``treehouse:10,0``. the treehouse has a +portal back to ``overworld:450,300``. + +buildings, dungeons, caves, interiors — all zones with portals from +the overworld. the overworld tile might show a special symbol (a door +icon, a cave mouth) to hint that something's there. + + +procedural as a tool, not the default +--------------------------------------- + +the procedural perlin world is useful but it's a tool. good for: + +- wilderness areas (forests, plains, mountains) +- dungeon generation (random layouts with a seed) +- filler terrain between hand-built areas +- prototyping (generate a base, paint over it) + +the main game world should be hand-built. the starting experience, key +locations, cities, landmarks — all authored by humans. procedural fills +in the gaps, provides variety, makes the world feel larger than what was +hand-crafted. + +a zone can mix both: generate perlin terrain, then overlay hand-placed +features (roads, buildings, rivers) on top. the generator runs first, +then the overlay applies. + + +layers (future) +---------------- + +jared mentioned up/down and layers. a zone could have a z-axis — floor 1 +is the ground, floor 2 is the second story, floor -1 is the basement. +same x,y grid, different z level. portals (stairs, ladders, holes) +connect layers vertically. + +not needed for v1 but the data model should not prevent it. a zone's +tile data could eventually be:: + + [map] + width = 20 + height = 15 + layers = 3 + data.0 = """...""" # ground floor + data.1 = """...""" # second floor + data.-1 = """...""" # basement + +or layers could just be separate zones with portals. simpler, same +result. decide later. + + +what we learned from other engines +----------------------------------- + +research into how DikuMUD, LPC, MOO, Evennia, and others handle +building. key takeaways and things to avoid. + +what works +~~~~~~~~~~~ + +**MOO's immediacy.** in LambdaMOO, @dig creates a room and you're done. +no save step, no compilation, no restart. changes are instant. builders +stay in flow. we want this — @new-zone, @paint, and your changes are +live. + +**evennia's XYZGrid.** optional coordinate system drawn as ASCII maps in +python files. rooms at grid intersections, links along paths. transition +nodes connect separate maps. proves grid-based worlds work in a +room-based engine. their wilderness contrib is smart: players get their +own room instance at a coordinate, share when co-located. + +**diku OLC menus.** redit/oedit/medit push you into an edit mode with +numbered options. simple, discoverable, no memorization. the nested +mode pattern (game → editor → description editor) maps well to our mode +stack. + +**LPC file-based content.** builders write .c files, ``update`` compiles +them live. version controllable, diffable, shareable. our TOML approach +has the same benefits without requiring a programming language. + +**ranvier's hybrid coordinates.** optional (x,y,z) per room, local to +each area. explicit exits override inferred ones. areas can mix +coordinate and non-coordinate rooms. flexible and clean. + +**dead souls QCS.** wizard-driven creation (``addnpc``, ``addroom``) +generates LPC files via interactive prompts. lowers the barrier — +builders answer questions instead of writing code. + +what people hate +~~~~~~~~~~~~~~~~~ + +**menu-driven OLC is clunky.** everyone acknowledges OLC is better than +manual file editing, but it's still tedious. numbered menus, nested +sub-menus, explicit save commands. modern builders expect something +faster. our paint mode is a direct response to this. + +**descriptions nobody reads.** "most players don't read the descriptions +after seeing them the first time, and probably only skim them the first +time anyway." high effort, low return. our tile-based visual approach +sidesteps this — you SEE the room, you don't read a paragraph about it. +descriptions can supplement the visual, not replace it. + +**too much coding required.** evennia requires python for anything beyond +basic building. MUSHcode has a brutal learning curve. MOO programming is +its own language. builders want to create content, not learn to program. +our approach: TOML data files for definitions, paint mode for visuals, +minimal programming needed for basic building. + +**collaborative building is an afterthought.** evennia's default setup +doesn't support collaborative building well. MOO's permission system +creates unexpected barriers. we should design for collaboration from the +start — multiple builders in a zone, clear ownership, easy sharing. + +**framework lock-in.** evennia's ObjectDB forces assumptions that don't +fit all games. our zone model is simple data (TOML files, tile grids) — +no complex object hierarchy to fight against. + +**no good copy-paste or templating.** every room built from scratch. +repetitive work. our web editor handles this naturally (select, copy, +paste). in-game: could support @copy-region or stamp/template tools. + +**saving and losing work.** diku OLC requires explicit saves; crash +before saving = lost work. MOO's auto-persistence is better. our zones +should auto-save on edit (or at least on leaving paint mode). + +**recruiting builders is hard.** the harder the tools, the fewer +builders you get. "building can be an enjoyable activity, but it's got +its downsides. which probably explains why MUD creators have a difficult +time recruiting dedicated builders." paint mode should make building +feel like play, not work. + +patterns from zone connectivity +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**evennia XYZGrid transition nodes.** metadata-only nodes that hold +target coordinates on another map. never spawn as rooms. clean +abstraction for zone-to-zone links. similar to our portal concept. + +**diku inter-zone exits.** reference format: ``room_name@zone_name``. +globally unique vnums (virtual numbers). our equivalent: +``zone_name:x,y``. + +**evennia wilderness fixed locations.** certain wilderness coordinates +are "fixed rooms" — reach those coords, transition into a real room. +this is how building entrances work in their wilderness system. maps +directly to our portal-on-overworld-tile concept. + +**alex kallend's wilderness (1999).** generate descriptions +deterministically from coordinates. same coords always produce same +room. memory-efficient. this is basically what our perlin generator +does. + +**ranvier cross-area linking.** reference format: ``areaname:roomid``. +works between coordinate and non-coordinate rooms. our format: +``zone:name:x,y`` or ``overworld:x,y``. + +.. note:: + + open research: dig deeper into other MUD codebases for building + patterns. specifically: + + - evennia's prototype/spawn system for templating objects across zones + - how discworld (LPC) handles its massive hand-built world + - AresMUSH's web-based building tools (they moved building to the browser) + - graphicMUD's tile-based building (closest to our model — they use + sixel graphics on a tile grid) + - how any engine handles "undo" for building mistakes + - permission models that actually work for collaborative building + without being bureaucratic + + +build order +------------ + +rough priority. each step is usable on its own. + +1. **zone data model + registry.** load TOML zone files from + ``content/zones/``. zone has dimensions, tile grid, palette, portals, + metadata. registry maps zone names to loaded zones. + +2. **player-in-zone tracking.** extend player location from ``(x, y)`` + to ``(zone, x, y)``. zone=None means overworld. persist to sqlite. + +3. **viewport reads from zone.** ``look`` checks which zone the player + is in and reads tiles from that zone's grid instead of the overworld. + movement checks that zone's passability rules. same rendering + pipeline, different data source. + +4. **@new-zone + @goto.** create blank zones from in-game. ``@goto + treehouse`` teleports you into a zone. ``@goto overworld`` returns + you. builder/admin commands. + +5. **paint mode.** push onto mode stack. cursor movement without + passability. brush selection. paint toggle. status line integration. + +6. **file import/export.** load zone from TOML file (web editor output). + save zone state back to TOML. the web editor and in-game building + produce the same files. + +7. **portals.** portal definitions in zone TOML. portal tiles trigger + zone transitions. ``@portal`` command for in-game portal creation. + +8. **@dig.** expand zone dimensions from in-game. grow the canvas in any + direction. + +9. **procedural generator as zone option.** ``--gen perlin`` on zone + creation. generate base terrain, allow painting over it. + +10. **the flower spawn.** hand-build the flower and treehouse zones. wire + the new-player experience to start in the flower instead of the + overworld center. + + +open questions +--------------- + +- should the overworld be a zone, or is it a special case? making it a + zone simplifies the code (everything goes through the same path) but + the overworld has unique properties (huge, procedural, wrapping). + probably: overworld IS a zone, just a large wrapping one with a + generator. + +- zone ownership and permissions. who can edit a zone? the creator? + anyone with builder role? co-ownership? defer this until the permission + model from things-and-building.rst is designed. + +- how big can a zone be before performance matters? a 1000x1000 zone is + 1MB of chars. loading, saving, and transmitting that is fine. but do + we want to support zones larger than that? probably not initially. + +- persistence model. are zones purely file-based (edit file, reload) or + do runtime changes (paint mode edits) persist automatically? leaning + toward: paint mode edits modify in-memory state AND write back to the + TOML file. the file is always the source of truth, and it stays + current. + +- what symbol is void/empty? tiles that haven't been painted yet. could + be space (invisible), could be a dim dot, could be configurable. needs + to be visually distinct from any palette symbol. + +- should portals be visible on the map? a special symbol, a color, a + blinking character? or do they look like their underlying tile (a door + looks like a door, not like a portal)? + +- layers vs separate zones for vertical space. layers are elegant but + add complexity. separate zones with portals (stairs) are simpler and + get the same result. start with separate zones. + + +relation to things-and-building.rst +------------------------------------- + +that doc covers the item/verb system (phase 1-2) and room system +(phase 3). zones and building here are the spatial foundation that +the item system lives on top of. + +zones provide the WHERE. things provide the WHAT. a zone has tiles +(terrain, walls, floor). things sit on tiles (items, furniture, NPCs). +portals are a zone-level concept. doors with locks are a thing-level +concept (the door is a @thing with an @verb for ``open`` that checks for +a key). + +build zones first (this doc), then populate them with things +(things-and-building.rst).