From a1b6613c6c6a2f8d6e1ecd47e766bd40f92ac295 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Sun, 28 Jun 2026 02:40:30 -0400 Subject: feat: admin accounts, god mode, OLC commands like dig/room, 'inline' objects changed to 'local' objects --- building_guide/admin.md | 204 +++++++++++++++++++++++++++++++++++++++++++++ building_guide/objects.md | 24 +++--- building_guide/triggers.md | 2 +- 3 files changed, 217 insertions(+), 13 deletions(-) create mode 100644 building_guide/admin.md (limited to 'building_guide') diff --git a/building_guide/admin.md b/building_guide/admin.md new file mode 100644 index 0000000..4ec36c1 --- /dev/null +++ b/building_guide/admin.md @@ -0,0 +1,204 @@ +## Admin Commands + +Admin commands are available to accounts with `admin: true` set in their account YAML file +(`data/players/accounts/.yaml`). Non-admin players see "Unknown command." when +attempting these, so their existence is hidden. + +### Enabling Admin + +Edit the account YAML and add `admin: true`: +```yaml +name: yourname +password_hash: sha256:... +characters: [...] +aliases: {} +colors: {} +options: {} +admin: true +``` + +The character must log out and back in for the change to take effect. + +### Commands + +#### goto +``` +goto +``` +Instantly teleports you to the specified room by numeric ID. Cancels any active combat, +action, rest, enter sequence, or safespot. Your departure and arrival are broadcast to +players in both rooms. + +#### summon +``` +summon +``` +Teleports a player to your current room. Their active state is cleaned up (combat, actions, +etc.) and they receive a notification. Case-insensitive name matching. + +#### dig +``` +dig [name] +``` +Creates a new room in the given direction (north/south/east/west/up/down) from your +current room. The new room ID is auto-generated as the lowest available integer at-or-above +the minimum room ID in the same directory as your current room's YAML file. + +Both the new room and your current room are updated with reciprocal exits. The admin is +teleported into the new room. The new room starts with a generic "A featureless room." +description and no spawns, mobs, or objects — edit its YAML file to flesh it out. + +If the direction would place the new room on a grid cell already occupied by an existing +room (a grid overlap), no new room is created. Instead, a two-way link is automatically +established between your current room and the existing room. + +Examples: +- `dig north` — creates a room north of you with auto-generated ID and name "New Room" +- `dig east "Dark Forest"` — creates a room east of you named "Dark Forest" + +#### undig +``` +undig +``` +Deletes the room in the given direction and removes all exits leading to it from +every room. Requires confirmation — type `UNDIG ` to proceed, anything +else to cancel. The target room's name and ID are shown before deletion. A warning +is displayed if deleting the room would create orphaned (unreachable) rooms. + +Any players currently in the deleted room are teleported to your current room. + +#### close +``` +close +``` +Deletes an exit in the given direction from your current room. Also removes the +reciprocal exit from the target room if it points back to your room. + +#### swapid +``` +swapid +swapid +``` +Swaps the numeric IDs of two rooms. The first form swaps your current room with +the given room ID. The second form swaps two arbitrary rooms. All exit references +across the entire world are updated automatically to keep the world consistent. + +#### room +``` +room [args...] +``` +Modify the current room's data directly from inside the game. Type `room` alone +to see all available actions: + +| Action | Usage | Description | +|--------|-------|-------------| +| `name` | `room name ` | Set the room's name | +| `desc` | `room desc ` | Set the room's description | +| `addobj` | `room addobj ` | Add a referenced object (must exist in data/objects/) | +| `remobj` | `room remobj ` | Remove a referenced object | +| `addlocalobj` | `room addlocalobj ` | Add a local object | +| `remlocalobj` | `room remlocalobj ` | Remove a local object | +| `hide` | `room hide ` | Hide all matching objects (referenced or local) | +| `unhide` | `room unhide ` | Unhide all matching objects (referenced or local) | +| `addmob` | `room addmob ` | Add a mob spawn (must exist in data/mobs/) | +| `remmob` | `room remmob ` | Remove a mob spawn | +| `addspawn` | `room addspawn [qty] [respawn]` | Add an item spawn (must exist in data/items/) | +| `remspawn` | `room remspawn ` | Remove an item spawn | + +All room commands are admin-only. Referenced objects, mobs, and items are validated +before being added. + +#### god +``` +god +``` +Temporarily sets all your skills to level 99, prevents mobs from aggressing you, +allows walking through blocked exits, and makes you immune to hazard damage and +death. Does NOT persist across reconnects — your original stats are restored +automatically when you quit, disconnect, or use the `ungod` command. + +#### ungod +``` +ungod +``` +Restores your original skills and removes god-mode privileges. This also happens +automatically if you disconnect or quit while in god mode, so your inflated stats +are never saved to disk. + +#### setflag +``` +setflag [value] +``` +Sets a world flag. World flags are shared by all players and stored in memory (lost on +server restart). Setting a flag fires any triggers watching that flag. Values default to +`true` if omitted. Accepted value types: `true`/`false` (bool), integer, or string. + +#### setplayerflag +``` +setplayerflag [value] +``` +Sets a player-specific flag on a character. Player flags are persisted to the character +YAML file and survive restarts. Setting a flag fires any triggers watching that flag. +The character is saved immediately. Values work the same as setflag. + +#### reload +``` +reload +``` +Reloads all data caches from disk. Use this after editing YAML files (items, objects, +mobs, drops, techs, modules, courses, hazards, triggers) to pick up changes without +restarting the server. Rooms already hot-reload automatically. + +The reload process: +1. Clears item, object, and mob definition caches +2. Rebuilds path indices for items, objects, mobs, drops, and rooms +3. Rebuilds the craft index +4. Reloads techs and modules +5. Reloads courses +6. Clears hazard caches +7. Clears and re-seeds triggers from disk + +Live state (mob instances, player data, ground items, active sequences) is NOT affected. + +#### shutdown +``` +shutdown +shutdown cancel +``` +Schedules a graceful shutdown announcement. All online players receive a message every +30 seconds with the remaining time. When the countdown reaches zero, the server exits +immediately. Use `shutdown cancel` to abort a pending shutdown. + +#### inspect +``` +inspect +``` +Dumps detailed diagnostic information about your current room: +- Room ID, name, color, hazard, BlockTransport status +- All exits with conditions noted +- Objects (with local/global, hidden, and wander status) +- Mobs with wander intervals +- Item spawns with respawn timers +- On-enter step and trigger counts +- All world flags +- Your player flags +- Connected players in the room +- Live mob instances with HP + +### Workflow + +The typical admin worldbuilding workflow: + +1. **Lay out rooms:** Use `dig` to create connected rooms quickly. If `dig` would create a + grid overlap, a two-way link is created instead — no duplicate rooms. +2. **Flesh out rooms:** Use `room` commands to set names, descriptions, add objects/mobs/spawns + directly from inside the game. For deeper edits, edit the YAML files directly in + `data/rooms/` to add on-enter scripts, triggers, hazards, etc. +3. **Rearrange:** Use `swapid` to renumber rooms and `undig` to delete rooms you no longer want + (with full exit cleanup). Use `close` to remove individual exits. +4. **Reload:** Run `reload` to pick up YAML changes without restarting (rooms auto-reload). +5. **Test:** Use `goto` to jump around while debugging room connections and content. +6. **God mode:** Use `god` to test dangerous areas safely — full stats, no aggro, pass through + blocked exits. `ungod` restores normal state. +7. **Debug:** Use `setflag` / `setplayerflag` to test quest logic and conditional content. + Use `inspect` to check room state, flags, and triggers. diff --git a/building_guide/objects.md b/building_guide/objects.md index 37b8e23..d8761ae 100644 --- a/building_guide/objects.md +++ b/building_guide/objects.md @@ -16,8 +16,8 @@ and is still required there.) - **Generic, shared objects** (rocks, trees, altars, stations) use a semantic name and live flat in `data/objects/` — e.g. `data/objects/copper_rock.yaml`. - **Room-specific one-offs** (signs, set-dressing, scenery for a single room): if they are - description-only (the passive subset), prefer defining them **inline in the room** (see - [Inline objects](#inline-objects-defined-in-the-room) below). If a one-off needs + description-only (the passive subset), prefer defining them **locally in the room** (see + [Local objects](#local-objects-defined-in-the-room) below). If a one-off needs interactable behavior (`gather`/`talk`/`use`/etc.) it must be a file — prefix it with the room number and place it in `data/objects/unique/`, e.g. `data/objects/unique/1002_sign.yaml` (ID `1002_sign`, referenced from room `1002`). @@ -27,20 +27,20 @@ need no changes to room references when a file is moved. They do **not** namespa filename stem must be globally unique across all of `data/objects/`. Use `hidden: true` for signage/scenery so it doesn't appear in room listings. -### Inline objects (defined in the room) +### Local objects (defined in the room) Room-specific **description / scenery** objects can be defined directly inside the room's `objects:` list instead of as separate files in `data/objects/unique/`. An entry in the list -is treated as **inline** when it carries a `name:` (or any other content field — +is treated as **local** when it carries a `name:` (or any other content field — `description`, `aliases`, `inroom_description`, `color`, `hidden`, `on_look`). An entry with only `- id: ` is a plain **reference** to a file object, as before. `id:` is reserved -for references; **inline objects do not take an `id:`** — their identity comes from the name. +for references; **local objects do not take an `id:`** — their identity comes from the name. ```yaml # in data/rooms/intro/1001.yaml objects: - id: workbench # reference: resolves to data/objects/workbench.yaml - - name: window # inline: identity derived from the name, no file + - name: window # local: identity derived from the name, no file hidden: true description: "A thick trim with rounded bolt heads frames the tiny window." - name: sign @@ -55,26 +55,26 @@ objects: - **Identity comes from `name`.** Internally the object's id is the name, normalized (lowercased, surrounding/redundant spaces trimmed, spaces kept — `"Instrument Panel"` → - `instrument panel`). You never write an `id:`; doing so on an inline entry is ignored and + `instrument panel`). You never write an `id:`; doing so on a local entry is ignored and warned about at startup. - **Identity is room-scoped.** Two different rooms may each have an object named `sign` without conflict — no room-number prefixing needed (unlike the old `data/objects/unique/` files). - **Each object in a room must have a unique name.** Two *distinct* objects in the same room - with the same exact name — whether both inline, both file references, or one of each — is a + with the same exact name — whether both local, both file references, or one of each — is a startup **error** (the player could not disambiguate them). Multiple instances of the *same* object are still fine via repeated references (e.g. two `- id: copper_rock`). - **Partial-name siblings are fine.** `rusty sign` and `shiny sign` can coexist; `look sign` matches both and prompts *"which one?"*, while `look rusty sign` resolves directly. -- Inline objects support only the **passive subset**: `name`, `aliases`, `color`, `hidden`, +- Local objects support only the **passive subset**: `name`, `aliases`, `color`, `hidden`, `inroom_description`, `description` (including conditional variants), and `on_look`. - Interactable / stateful behavior (`gather`, `talk`, `use`, `safespot`, `steal`, `guard_mob`, `removal_item`, `use_interactions`, craft stations) **must** be a standalone object file; - startup validation errors if those appear inline. -- Inline objects are re-read from the room file on every access, so edits take effect + startup validation errors if those appear locally. +- Local objects are re-read from the room file on every access, so edits take effect immediately (file objects are cached after first load). -Prefer inline for one-room flavor; keep generic/reusable/interactable objects as files. +Prefer local for one-room flavor; keep generic/reusable/interactable objects as files. Gathering object (mining): diff --git a/building_guide/triggers.md b/building_guide/triggers.md index 8d6454c..b88f16d 100644 --- a/building_guide/triggers.md +++ b/building_guide/triggers.md @@ -32,7 +32,7 @@ triggers: ``` The sign object itself is unchanged — its `on_look` simply sets the flag. The trigger -and the object are cleanly separated. The sign is an inline object in room `1001`: +and the object are cleanly separated. The sign is a local object in room `1001`: ```yaml # data/rooms/intro/1001.yaml -- cgit v1.2.3