diff options
Diffstat (limited to 'AGENTS.md')
| -rw-r--r-- | AGENTS.md | 37 |
1 files changed, 30 insertions, 7 deletions
@@ -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 |
