aboutsummaryrefslogtreecommitdiff
path: root/AGENTS.md
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-14 22:38:23 -0400
committerhistoria <[not public]>2026-06-14 22:38:23 -0400
commita6f0ad79e2e3a5b7c11eef1ffc3233f3a2766f77 (patch)
tree89601a502bbfcb50302cf03f09b6febc6040eeb0 /AGENTS.md
parent1aba2bdd23aebed4032333e74aa553c40a31fcbd (diff)
downloadthehouseoficarus-a6f0ad79e2e3a5b7c11eef1ffc3233f3a2766f77.tar.gz
feat: fractional ticks and server game_speed implemented. potentially insanely janky.
Diffstat (limited to 'AGENTS.md')
-rw-r--r--AGENTS.md39
1 files changed, 37 insertions, 2 deletions
diff --git a/AGENTS.md b/AGENTS.md
index 2897be8..0b829a5 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -15,6 +15,13 @@ make vet # go vet ./...
Binary accepts `--config <path>` (defaults to `config.yaml`). If no config found, starts telnet on :4000.
+Config options:
+```yaml
+game:
+ tick_length: 600 # ms per game tick (default 600, min 50)
+ game_speed: 1.0 # multiplier for all tick timers (default 1.0)
+```
+
Dependencies: `gopkg.in/yaml.v3`, `github.com/gorilla/websocket`.
## Package Map
@@ -42,7 +49,8 @@ internal/engine/ Tick scheduler — 600ms interval, subscriber pattern +
| `cmd_*.go` | Command handlers (see Adding a New Command below) |
| `action.go` | StartAction, CancelAction, AdvanceActions, checkCondition |
| `action_*.go` | Action lifecycle per behavior type (gather, talk, use, toggle, burn) |
-| `tick.go` | DisconnectTick, RegenTick, WanderTick, WoodcuttingTick |
+| `action_state.go` | ActionState type, ActionType consts, Description for look display |
+| `tick.go` | DisconnectTick, RegenTick, WanderTick, SharedDepletionTick |
| `map.go` | BFS graph builder, tiny map, full map, display utilities (strip, trim) |
| `types.go` | Shared types (EquipSlots, itemMatch, xpGain, deathDrop) |
| `utils.go` | Helper functions (plural, parseQty, parseChoiceIndex, formatPickupList, etc.) |
@@ -62,6 +70,8 @@ internal/engine/ Tick scheduler — 600ms interval, subscriber pattern +
**Tick-driven.** The world runs on a 600ms tick. Combat, gathering, regen, wandering, respawns, shared depletion, woodcutting timers all advance per tick. See `cmd/mud/main.go` for the subscription loop.
+**Fractional ticks.** All YAML timer fields (tool_speed, speed, base_wait, deplete_timer, etc.) accept `float64` values. `engine.FractionalTicks(base, speed)` probabilistically rounds to an integer — a tool_speed of 4.5 means each action cycle has a 50% chance of 4 ticks and 50% of 5 ticks. The `game_speed` config option scales all timers uniformly via `g.computeTicks()`.
+
## Two State Systems
- **World flags** (`set_flags` / checked with `flag`): Shared by all players. A door opened by one player is open for everyone.
@@ -148,7 +158,7 @@ Firemaking is implemented as standalone actions (not behavior-YAML-driven) in `i
**Per-drop depletion** (mining, regular trees): Set `depletes: true` on a drop entry. The resource depletes on first successful gather of that drop. Rocks don't show despawn timers when not depleted.
-**Shared depletion** (higher-tier trees): Set `deplete_timer: <ticks>` on the behavior. A shared timer counts down while anyone is chopping; when it hits 0, the next successful gather depletes the tree for all players. The timer regenerates back to max when no one is chopping. `WoodcuttingTick` manages this in `internal/game/tick.go`.
+**Shared depletion** (higher-tier trees): Set `deplete_timer: <ticks>` on the behavior. A shared timer counts down while anyone is chopping; when it hits 0, the next successful gather depletes the tree for all players. If multiple players succeed on the depletion tick, all get their drops. The timer regenerates back to max when no one is chopping. `SharedDepletionTick` manages this in `internal/game/tick.go`.
## Data Files
@@ -168,6 +178,31 @@ Wander config (`wander_rooms`, `wander_interval`) is set per-instance in room YA
See `WORLDBUILDING.md` for full YAML format reference with examples.
+## Tick-Based Action Queue
+
+All gameplay commands are queued for the next 600ms game tick instead of executing immediately. Commands are classified into three types:
+
+| Class | Behavior | Commands |
+|---|---|---|
+| Instant | Execute immediately, no queue | `say`, `score`, `inventory`, `equipment`, `look`, `exits`, `help`, `map`, `option`, `alias`, `unalias`, `description`, `queued` |
+| Free | Stackable, execute in order before active | `wear`/`wield`, `remove`/`unwear`, `style` |
+| Active | Only the last active per player survives | Everything else: move, attack, mine/chop/fish/cut, use, talk, burn, stoke, get, drop, search, quit |
+
+Each 600ms tick, `ProcessQueuedCommands` in `internal/game/game.go`:
+1. Clears stale ActionState from one-tick actions (move, get, drop, etc.)
+2. Executes all free commands per player in queued order
+3. Executes all active commands sorted globally by real-time timestamp
+4. Flushes any pending shared resource depletions
+
+**Conflict resolution:**
+- Multi-player attack on same mob: first player to queue wins (timestamp-order).
+- Multi-player get on same item: first player to queue wins.
+- Multi-player shared depletion: defer depletion, award all successful gatherers.
+
+**ActionState** (`internal/game/action_state.go`) tracks what a player is doing for `look` display. Timed actions (gather, combat, burn, stoke, use) persist the state until interrupted. One-tick actions (move, get, drop) clear after one tick.
+
+Queue feedback is controlled by the `queue_actions_silently` player option (default on).
+
## Places to Be Careful
- `StartAction` searches objects first, then mobs. A mob must have `behavior:` set on its YAML def to be interactable.