# AGENTS.md Third Collapse — a Runescape-like sci-fi MUD written in Go. Data-driven via YAML files. No database, no ORM. ## Build & Run ```bash make build # go build -o tc ./cmd/mud make run # build + run with DATA_DIR=./data make test # go test ./... make vet # go vet ./... ``` Single dependency: `gopkg.in/yaml.v3`. ## Package Map ``` cmd/mud/main.go Entry point — wires server, game, tick engine internal/net/ Telnet server, TCP session state machine, room hub internal/game/ Session handler, login, command dispatch, all game logic internal/action/ Behavior structs (GatherConfig, TalkConfig, etc.), Action, drop tables internal/player/ Player struct, skills, inventory, XP, Account YAML persistence internal/world/ Room, MobDef, MobInstance, ObjState, ground items, wandering internal/combat/ Combat state tracking, OSRS-style combat formulas internal/object/ ItemDef, ObjectDef, item/object YAML loaders internal/engine/ Tick scheduler — 600ms interval, subscriber pattern ``` `internal/game/` is the largest package and contains most command implementations as `cmd_*.go` files. ## Key Conventions **YAML-driven.** Rooms, items, objects, mobs, behaviors, drops are all YAML files under `data/`. Read from disk on every access — edit a room description and it takes effect immediately, no restart. **Live state.** Player data (characters, accounts) is written to YAML on every state change. Ground items, mob instances, and object states live in memory only and are lost on restart. **No database.** Everything is flat YAML files. Account passwords use sha256 + 16-byte random salt. **Tick-driven.** The world runs on a 600ms tick. Combat, gathering, regen, wandering, respawns all advance per tick. See `cmd/mud/main.go` for the subscription loop. ## Two State Systems - **World flags** (`set_flags` / checked with `flag`): Shared by all players. A door opened by one player is open for everyone. - **Player flags** (`set_player_flags` / checked with `player_flag`): Per-character, saved to character YAML. Quest progress, dialog history. ## Command Dispatch `internal/game/game.go` — `handleGameCommand()`: 1. Cancel rest timer 2. Resolve account aliases (alias expansion happens BEFORE command lookup) 3. Switch on command word 4. Most commands call into `cmd_*.go` files Commands that need an object/mob interaction route through `StartAction()` in `action.go`, which: 1. Normalizes verb (mine/chop/fish → gather, talk/speak/ask → talk, pull/push → toggle) 2. Searches object instances in room 3. Falls back to mob instances if no object matches 4. Loads the behavior from YAML 5. Routes to type-specific handler (startGather, startTalk, startUse, startToggle) ## Adding a New Skill 1. Add `SkillName` constant + entry in `AllSkills` + `SkillAbbr` in `internal/player/player.go` 2. Create a gather behavior YAML in `data/behaviors/` 3. Create an object YAML referencing that behavior in `data/objects/` 4. Create an item for the tool in `data/items/` (with `tool_type`) 5. Place the object in a room YAML in `data/rooms/` 6. Create any resource items in `data/items/` Woodcutting is the next planned gathering skill — same pattern as mining (see `data/behaviors/mine_copper.yaml`). ## Adding a New Production Skill Same as gathering but use `type: use` behavior (see `UseConfig` in `internal/action/behavior.go`). Smithing is the reference example planned. ## Adding a New Command 1. Add a `cmd_*.go` file in `internal/game/` with the handler 2. Add a case in `handleGameCommand()` in `internal/game/game.go` 3. Update `data/help/` YAML files ## Data Files ``` data/rooms/.yaml Room definitions (exits, objects, mobs, spawns, on_enter) data/items/.yaml Item definitions (stats, equip slot, tool type, speed) data/mobs/.yaml Mob definitions (combat stats, drops, behavior, wandering) data/objects/.yaml Object definitions (name, behavior, hidden) data/behaviors/.yaml Behaviors (gather, talk, use, toggle configs) data/drops/.yaml Shared drop tables (weighted item lists) data/help/.yaml Help topics data/players/accounts/ Account YAML (gitignored) data/players/characters/ Character YAML (gitignored) ``` See `WORLDBUILDING.md` for full YAML format reference with examples. ## Current State - 21 skills defined, 2 implemented (Mining, Fishing) - 4 behavior types: gather, use, talk, toggle - Combat system complete (melee only — Ranged not implemented yet) - 11 rooms with conditional exits and on-enter scripts - Talk system: dialog trees with conditions, item give/take, flag setting, teleport, heal - Account-wide alias system - No shops, banks, or quest system yet (though talk + flags already supports quest logic) ## Places to Be Careful - `StartAction` searches objects first, then mobs. A mob must have `behavior:` set on its YAML def to be interactable. - Exits changed from `map[ExitDir]int` to `map[ExitDir]ExitDef` — old `north: 2` still works via custom `UnmarshalYAML`. - `CheckExitCondition` was unified into `checkCondition` — there's only one condition evaluator now. - Object `Hidden: true` means the object doesn't appear in room listings but is still interactable. - Alias expansion happens before command dispatch. An alias can shadow a built-in command. - `say` preserves case in the message (alias expansion preserves case, and the dispatch extracts the original input text for say).