aboutsummaryrefslogtreecommitdiff
path: root/AGENTS.md
diff options
context:
space:
mode:
Diffstat (limited to 'AGENTS.md')
-rw-r--r--AGENTS.md37
1 files changed, 30 insertions, 7 deletions
diff --git a/AGENTS.md b/AGENTS.md
index 8b65314..c2d420f 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -43,7 +43,7 @@ internal/
| `core_*.go` | Infrastructure — types, utils, login, production engine, skill XP, flags, courses, equipment, stations, messages, startup validation | 13 |
| `action_*.go` | Tick-based action lifecycles — gather, firemaking, talk, use, search, thieving, farming, agility, scavenging, assassin, fletching, cleaning, room scripts, targeting | 16 |
| `cmd_*.go` | Command handlers — one file per command or command group | 49 |
-| `sys_*.go` | Game subsystems — technology, science, combat (death + aggro), assassin tasks, buffs, construction | 6 |
+| `sys_*.go` | Game subsystems — technology, science, combat (death + aggro), assassin tasks, buffs, construction, hazards, labor (task mobs) | 8 |
| `ui_*.go` | Display/output — color, prompt, table, map, help | 5 |
| `hacking/` | Hacking sub-package — Minigame interface, TerminalDef, CalcXP, WumpusGame, MastermindGame, LiarsDiceGame | 4 |
@@ -81,15 +81,22 @@ The pattern is: lock, snapshot/unmarshal, unlock, then process. The engine creat
- **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.
+## Room Scripting
+
+- **`on_enter` steps** fire when a player enters. Each has a `message` + optional `condition`. A step may also have a `delay` (ticks) and/or `set_flags`/`set_player_flags`. If any surviving step is timed (has a delay or sets a flag) the sequence runs as a scheduled **cutscene** (driven by `EnterSeqTick`); otherwise messages print synchronously. Step conditions are snapshotted once at entry. A cutscene persists `Player.CutsceneRoom` and **resumes on reconnect** if interrupted; plain on_enter never runs on login.
+- **Conditional descriptions** (`descriptions: [{text, condition}]`) on rooms and objects pick the first variant whose condition passes (per-looker), else the base `description`. For an **object**, if it has `descriptions` and none match, the object is **absent** for that player (`look` falls through). Objects also support `aliases: [...]` for extra names. `look` lists candidates when multiple distinct objects match.
+- **Exits** support `set_flags`/`set_player_flags`, applied only on a successful traverse.
+
## Data Files
```
-data/rooms/<id>.yaml Room definitions (exits, objects, mobs, item_spawns, on_enter)
+data/rooms/<id>.yaml Room definitions (exits, objects, mobs, item_spawns, on_enter, descriptions)
data/rooms/player_housing/ Player house rooms
data/items/<id>.yaml Item definitions (stats, equip_slot, tool_type, craft, burn_ticks, search_table, etc.)
-data/mobs/<id>.yaml Mob definitions (combat stats, drops, behavior, steal config)
-data/objects/<id>.yaml Object definitions (name, behavior, hidden, inroom_description, removal_item)
+data/mobs/<id>.yaml Mob definitions (combat stats, drops, behavior, steal config; kind: task for worksites)
+data/objects/<id>.yaml Object definitions (name, aliases, behavior, hidden, inroom_description, descriptions, removal_item)
data/drops/<id>.yaml Shared drop tables (weighted item lists, sub-table references)
+data/hazards/<id>.yaml Shared room hazard definitions (attack_type, attack, max_hit, speed, messages, required_item)
data/help/<id>.yaml Help topics
data/modules/<id>.yaml Science module definitions (id, level, max_hit, base_xp, junk_cost, category)
data/courses/<id>.yaml Agility course definitions (name, required_level, start_room, obstacles)
@@ -99,7 +106,7 @@ data/players/characters/ Character YAML (gitignored)
Wander config (`wander_rooms`, `wander_interval`) is set per-instance in room YAML — mob defs are generic. Mobs wander via legal (unconditioned) room exits; objects teleport between rooms in their assigned list.
-See `worldbuilding_guide/` for full YAML format reference with examples.
+See `building_guide/` for full YAML format reference with examples.
## Startup Validation
@@ -217,6 +224,7 @@ The `verbSkill` map maps verb → skill name for default target resolution:
| `curing` | cure | Active |
| `traversing` | obstacle verbs (scramble/jump/etc.) | Active |
| `hacking` | jack/jackin | Active |
+| `working` | work/attack on a task mob (worksite) | Active |
### Behavior Types (YAML-driven in behavior.go)
@@ -286,12 +294,13 @@ clamped to [0, cfg.Cap]
### Condition System
-Used by exits, talk options, on-enter scripts, and use_interactions checks:
+Used by exits, talk options, on-enter scripts, and use_interactions checks. A bare `flag`/`player_flag` passes when the flag is set to a truthy value; `value` matches a specific value; `not` inverts.
| Field | Scope | Example |
|---|---|---|
| `flag` | World (shared by all) | `flag: gate_open` |
| `player_flag` | Per-character | `player_flag: finished_tutorial` |
+| `value` | Exact value to match (else truthy) | `value: 3` |
| `has_item` | Player inventory | `has_item: bronze_key` |
| `min_credits` | Player credits | `min_credits: 100` |
| `all_of` | All sub-conditions pass | Nested list |
@@ -341,6 +350,14 @@ Used by exits, talk options, on-enter scripts, and use_interactions checks:
**Mob DropTable:** `Remains` (guaranteed drop item), `Loot` (weighted DropEntry table).
+## Labor System (sys_labor.go, sys_hazard.go)
+
+A **non-violent reuse** of the entire combat engine for worksites — building solar panels, surveying flora, prospecting rocks — so combat skills/weapons train without the theme of killing.
+
+**Task mobs.** A `MobDef` with `kind: task` (default `combat`). Internally its `HP` drains to 0 to **complete** the work; the player sees a progress bar filling to 100% (`progressBar`, the inverse of `hpBar`). It reuses the whole pipeline: `startCombat`/`playerAttack`/`applyPlayerHit`/`endCombat`, all formulas, drops (= "payment"), respawn, the 1-worker `IsMobInCombat` lock. Differences: it **never attacks back** (`startCombat` skips the mob-attack subscription for tasks), display/messages are labor-flavored, and `ActionWorking` is used for `look`. Progress **decays** when unattended — this is the standard mob HP regen, unchanged, shown inverted. Commands `work` and `attack`/`kill` all route to `doAttack`, which auto-detects the kind. Flavor fields: `verb`, `progress_noun`, `complete_message`. Per-type defenses (`crush_defense`…`science_defense`) become **method efficiency** — every style works, designers steer which is efficient. XP/buffs are the normal style-based combat split (no change).
+
+**Hazards.** A room references a shared hazard by ID: `hazard: <id>` → `data/hazards/<id>.yaml` (`world.HazardDef`, cached via `World.LoadHazard`). `HazardTick()` (registered in `main.go`) rolls an attack against **everyone in a hazardous room every `speed` ticks** (cadence in non-persisted `Player.HazardTimer`, reset on room change) using the same `EffectiveRoll`/`HitCheck`/`MaxHit`/`RollDamage`. Player defends with Defense level + equip bonus selected by `attack_type`; `damageAfterTechProtection` applies the matching protect tech. `required_item` equipped negates it. A safespot blocks **all** hazard damage (`safespotBlocksHazard` = `isSafespotted`, type-agnostic). A lethal hazard hit calls `killPlayer` (extracted from `endCombat`). Hazards **do not interrupt movement** (no flee-abort), and stack with mobs. Entering a safe→dangerous room prompts `[Y/n]` (`StateDangerConfirm`) unless the `danger_warning` option is off.
+
## Technology System (tech.go)
25 hardcoded techs in 4 categories, unlocked by Technology level:
@@ -410,6 +427,7 @@ Account-wide options set via `option <name> <value>`. Stored in account YAML, sh
| `map_padding` | string | "none" | none/x/y/xy — blank-row stripping |
| `automap` | bool | false | Auto-show map after moving |
| `queue_silently` | bool | true | Suppress queue messages |
+| `danger_warning` | bool | true | Confirm `[Y/n]` before entering a hazardous area from a safe one |
| `room_desc_width` | int | 70 | Room desc line wrap width |
| `unicode` | bool | true | Unicode box-drawing characters |
| `run_countdown` | bool | false | Flee countdown messages |
@@ -454,6 +472,7 @@ Prompt variables: `%h` (HP), `%H` (max HP), `%b` (battery), `%B` (max battery),
| `StateShop` | Shop interface (buy, sell, browse, leave) |
| `StateBank` | Bank interface (deposit, withdraw, browse, leave) |
| `StateHacking` | Jacked into a terminal running a minigame |
+| `StateDangerConfirm` | Confirming `[Y/n]` entry into a hazardous room |
## ItemDef Fields (object/item.go)
@@ -500,6 +519,10 @@ Prompt variables: `%h` (HP), `%H` (max HP), `%b` (battery), `%B` (max battery),
- Cape of Agility makes movement instant (1 tick). Graceful pieces each reduce by 0.25 ticks; full set +0.5 bonus for 2 ticks total. Cape overrides Graceful.
- During combat, movement is a flee attempt. Mob hits during countdown abort the flee.
- Level-up messages output `*** You are now level N <skill>! ***` across all skills that gain XP.
+- Task mobs (`kind: task`) reuse the combat engine 1:1 — internally HP drains to 0 to complete; the bar is just displayed inverted. They never attack back; danger comes only from a room `hazard:`.
+- Hazard damage uses its own `applyHazardHit` path that deliberately omits the flee-abort (`MoveTicks`) logic, so hazards never interrupt walking. Mob hits still do.
+- A safespot blocks ALL hazard damage regardless of type (`safespotBlocksHazard`), but a melee work/attack step still forces you out of cover (so only ranged/science work keeps you sheltered).
+- `killPlayer` is the shared death path (extracted from `endCombat`); both combat death and lethal hazard hits go through it. `mob` may be nil for a hazard kill.
## Adding a New Skill
@@ -514,7 +537,7 @@ Prompt variables: `%h` (HP), `%H` (max HP), `%b` (battery), `%B` (max battery),
Production skills share a unified system in `core_production.go`:
-1. Create the output item YAML in `data/items/` with a `craft:` block. See `worldbuilding_guide/recipes.md`.
+1. Create the output item YAML in `data/items/` with a `craft:` block. See `building_guide/recipes.md`.
2. Create a station object in `data/objects/` if needed
3. Add a `cmd_<skill>.go` command handler following existing patterns
4. Add the command to `commandRegistry` in `cmd_registry.go` with the appropriate class