aboutsummaryrefslogtreecommitdiff
path: root/AGENTS.md
blob: 6834676bb5119790ab8271857437f005fa7737ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 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/<id>.yaml      Room definitions (exits, objects, mobs, spawns, on_enter)
data/items/<id>.yaml      Item definitions (stats, equip slot, tool type, speed)
data/mobs/<id>.yaml        Mob definitions (combat stats, drops, behavior, wandering)
data/objects/<id>.yaml     Object definitions (name, behavior, hidden)
data/behaviors/<id>.yaml   Behaviors (gather, talk, use, toggle configs)
data/drops/<id>.yaml       Shared drop tables (weighted item lists)
data/help/<id>.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).