docs(sprints): add Sprint 18: Touch briefings
14 tickets across server (9), client (3), copy (2). Examine mechanic, NPC awareness, social propagation, minimap, dialogue UI, save state data model, and blocker-clearing work for Sprint 19. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
# Sprint 18: Touch — Client Tasks
|
||||
|
||||
**Goal:** The player can examine entities and objects to generate character-filtered observations; NPCs detect and react when watched; social actions propagate through the relationship graph; minimap renders POIs on the client.
|
||||
|
||||
**Branch:** `client`
|
||||
**Agents:** Stig (UI/rendering), Tyre (architecture), Hoshe (QA)
|
||||
|
||||
## Carry-over from Sprint 17
|
||||
|
||||
None. Sprint 17 closed 19/19.
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #151 | Minimap rendering | #148/#149 (both done in Sprint 17) |
|
||||
| #174 | Dialogue UI — client (D-061 spec) | #434 (done) |
|
||||
| #264 | Knowledge/journal display | — |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/architecture.md` — D-020 (client is pure renderer, no game logic in GDScript), D-041 (knowledge graph — client displays KG data from snapshot), D-042 (UI microcopy format — YAML via UIStrings autoload)
|
||||
- `decisions/perception.md` — D-013 (diegetic insert/POI system — minimap is insert-layer UI), D-061 (dialogue box spec — 20% max height, no portraits)
|
||||
- `decisions/content.md` — D-028 (dialogue architecture — client renders options, server selects), D-062 (invisible locked options), D-064 (walk-away — WASD during dialogue)
|
||||
- `decisions/scope.md` — D-027 (vertical slice — dual-character POI and knowledge display)
|
||||
|
||||
## Notes
|
||||
|
||||
### #151 — Minimap rendering
|
||||
|
||||
POI data infrastructure (`PointOfInterest` component, discovery events) landed on the server in Sprint 17 (#148, #149). The `ObserverSnapshot` will carry POI data for discovered points. This ticket wires that data into a rendered minimap overlay.
|
||||
|
||||
What this ticket must deliver:
|
||||
- A `MinimapRenderer` scene or node attached to the insert HUD layer (z-layer 6, diegetic insert per D-049)
|
||||
- Nearby POIs rendered as colored dots at their relative compass position from player origin
|
||||
- Distant POIs (beyond minimap radius) rendered as directional arrows at the minimap border
|
||||
- POI dot color and shape vary by category (the server sends `poi_category` in snapshot — use it)
|
||||
- Player is always centered; minimap does not scroll or rotate (fixed-north, D-015)
|
||||
- Minimap must be diegetically framed — it reads as a neural insert overlay, not a traditional game HUD
|
||||
- If no POIs discovered: minimap is empty but the insert frame still renders (the frame is diegetic, always present)
|
||||
|
||||
Existing infrastructure to build on:
|
||||
- `client/scripts/autoloads/game_state.gd` — holds `current_snapshot` which will include POI array from server
|
||||
- `client/scripts/autoloads/ui_strings.gd` — minimap label strings (add to `client/data/ui-strings.yaml` per D-042)
|
||||
- `client/scripts/rendering/world_renderer.gd` — reference for how snapshot data drives rendered output
|
||||
|
||||
Gotcha: POI positions are in simulation tile coordinates. The minimap renders relative compass direction and distance, not absolute tile positions. Convert server tile positions to player-relative vectors in GDScript.
|
||||
|
||||
### #174 — Dialogue UI — client (implement to D-061 spec)
|
||||
|
||||
The dialogue box spec (#434, D-061) was delivered in Sprint 7 and is done. This ticket (#174) is the older "Dialogue UI" story whose description has been updated to reference the D-061 spec. Given that the dialogue box, response selection, and walk-away mechanic are already implemented (#434, #435, #437), this ticket now covers the remaining dialogue UI surface not yet wired.
|
||||
|
||||
What this ticket must deliver — audit first, then implement gaps:
|
||||
- Verify the existing dialogue box correctly uses `game_state.current_dialogue` field (set in Sprint 14+)
|
||||
- **Examine result display**: the examine verb (#242 server) returns a character-filtered text description. The client needs a display path for this — it should appear as a non-interactive overlay (not a dialogue box, no options), floating above the examined entity or in a dedicated "observation" panel. Design to spec: brief, diegetic, auto-dismisses after 4-6 seconds
|
||||
- **Dialogue UI hardening**: confirm invisible locked options (D-062) — no grayed-out elements, no lock icons anywhere in the dialogue tree
|
||||
- **Confrontation styling** (#436, D-063): verify italic first-person voice for confrontation options is rendering correctly; confirm the 1-2 second pre-delivery monologue beat fires before the option triggers
|
||||
|
||||
Integration point: `client/scripts/autoloads/game_state.gd` holds `current_dialogue`. The rendering layer reads this each frame. Examine result will come through a new `current_examine_result` field (coordinate field name with server team).
|
||||
|
||||
### #264 — Knowledge/journal display
|
||||
|
||||
Client UI for reviewing accumulated KG facts. The player character's `KnowledgeGraph` is populated server-side and sent down in snapshot as a structured object. This ticket creates the review panel.
|
||||
|
||||
What this ticket must deliver:
|
||||
- A journal/insert panel — toggle key (TBD, coordinate with server team for any keybind — likely `J` or dedicated insert shortcut)
|
||||
- Displays accumulated facts grouped by entity: "What I know about Kael Davan", then fact entries with confidence level and source
|
||||
- Fact entries show: fact text, `KnowledgeConfidence` level (Suspects / KnowsOf / KnowsDetails / Direct), source (`DirectObservation` / `ToldBy` / `Heard`), and `last_observed_tick` timestamp converted to game-time string
|
||||
- `Contradicted` facts rendered with a visual distinction (strikethrough or amber tint) — these are the moments where THE FRIEND arc surfaces in the UI
|
||||
- `Stale` facts rendered more dimly than `Active` facts
|
||||
- The display is read-only — no player interaction with entries beyond scrolling
|
||||
- Diegetic frame: the panel reads as neural insert memory recall. Use `UIStrings` (D-042) for all labels (`client/data/ui-strings.yaml`)
|
||||
|
||||
Integration with `game_state.gd`: the snapshot does not currently carry a full KG dump — coordinate with server team. The server team will need to add a `player_knowledge` field to `ObserverSnapshot` (or a separate periodic message). Define the wire format jointly before implementation.
|
||||
|
||||
Key gotcha: the journal panel must close when dialogue opens and vice versa — they cannot be open simultaneously. Both compete for insert-layer attention.
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
#151 (minimap) → POI data in snapshot (#148/#149 done) — start immediately
|
||||
|
||||
#174 (dialogue UI hardening + examine result display) → examine field from server #242
|
||||
→ coordinate wire format week 1, implement week 2
|
||||
|
||||
#264 (knowledge/journal display) → player_knowledge field in snapshot (coordinate with server)
|
||||
→ start design week 1, implement after wire format agreed
|
||||
```
|
||||
|
||||
Parallel tracks: #151 can start immediately. #174 and #264 both need a brief coordination with server team on wire format additions — block 30 minutes in week 1 to agree those field names, then implement in parallel.
|
||||
|
||||
## PR Workflow
|
||||
|
||||
When ready to submit, create a PR with `tea` CLI. **All flags are required** to avoid TTY prompts (see CLAUDE.md "Gitea access" section):
|
||||
```bash
|
||||
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(client): description" --description "body" --base main --head client
|
||||
```
|
||||
@@ -0,0 +1,90 @@
|
||||
# Sprint 18: Touch — Copy Tasks
|
||||
|
||||
**Goal:** The player can examine entities and objects to generate character-filtered observations; NPCs detect and react when watched; social actions propagate through the relationship graph; minimap renders POIs on the client.
|
||||
|
||||
**Branch:** `copy`
|
||||
**Agents:** Mellanie (author), Paula (narrative lead), Gestalt (systems)
|
||||
|
||||
## Carry-over from Sprint 17
|
||||
|
||||
None. Sprint 17 closed 19/19.
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #544 | Design: collision-resistant line IDs for auto-generated NPCs | — |
|
||||
| #158 | Tier 1 drama module schema | — |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/content.md` — D-023 (three-tier content model — Tier 1 is drama modules), D-024 (NPC generation — hundreds of auto-generated NPCs per D-029 population model), D-028 (dialogue line pool format), D-035 (line ID scheme — Amendment Sprint 15: NPC-scoped IDs; D-029 auto-generated NPCs need collision-resistant variant)
|
||||
- `decisions/scope.md` — D-027 (vertical slice scope — Tier 1 modules activate for the smuggler/detective scenario)
|
||||
|
||||
## Notes
|
||||
|
||||
### #544 — Design: collision-resistant line IDs for auto-generated NPCs
|
||||
|
||||
**Context (Q-028):** The current line ID scheme (D-035 Amendment Sprint 15) uses `{npc-slug}_{d|m}_{###}` — e.g., `kael-davan_d_001`. For hand-authored NPCs with unique slugs this works. But D-029 specifies hundreds of procedurally generated NPCs (the 70% mundane majority), each with a generated slug like `dock-worker`. A district with 40 dock workers all using `dock-worker_d_001` produces immediate collision.
|
||||
|
||||
**What this ticket must deliver:**
|
||||
- A design document (output to `docs/design/` or as a decision record) specifying the collision-resistant scheme for auto-generated NPC line IDs
|
||||
- Evaluation of at least three options:
|
||||
1. **Short UUID suffix on NPC slug** — `dock-worker-a3f2_d_001`. Human-readable, unique per NPC, but IDs are not stable across seed changes
|
||||
2. **StableId prefix** — `npc-00042_d_001`. Machine-readable, stable if `StableId` persists. Less author-friendly
|
||||
3. **Role slug + instance counter** — `dock-worker-03_d_001`. Human-readable, author can write role-scoped lines used by all instances of that role. Requires a clear definition of "role" as the ID namespace
|
||||
4. **Slug registry with collision resolution** — same slug gets `dock-worker`, `dock-worker-2`, etc. at generation time, recorded in content registry
|
||||
|
||||
- The chosen scheme must satisfy:
|
||||
- Hand-authored NPCs (Kael, Sera, etc.) retain their current human-readable slugs — no migration
|
||||
- Auto-generated NPCs can be distinguished from one another in line IDs
|
||||
- The scheme is implementable in the content registry (`server/src/knowledge/registry.rs`) without breaking existing authored content
|
||||
- Authors can still write role-scoped lines that apply to all dock workers (shared content), distinct from instance-specific authored lines
|
||||
|
||||
- **Gestalt owns this ticket** — it resolves Q-028. Output: a decision record (D-NNN) or documented convention added to `docs/design/`. Once the scheme is chosen, update `docs/design/interaction-verbs-v0.1.md` or the content authoring guide if needed.
|
||||
|
||||
Timeline: resolve by end of week 1 so server/ci teams can implement the registry change in Sprint 18 or Sprint 19.
|
||||
|
||||
### #158 — Tier 1 drama module schema
|
||||
|
||||
Tier 1 content (D-023) is authored drama modules drawn from a pool at game start. The smuggler/detective vertical slice (D-027) IS a Tier 1 module. This ticket defines the structure every Tier 1 module must follow so the storyteller can activate and manage them consistently.
|
||||
|
||||
**What this ticket must deliver:**
|
||||
- A YAML schema definition file at `content/schemas/drama_module.schema.yaml` (or extend existing schema files in `content/schemas/`)
|
||||
- The schema must cover:
|
||||
- **Entry conditions**: what world-state must be true for this module to be activatable (NPC present, player relationship threshold, location accessible, etc.)
|
||||
- **NPC requirements**: which NPC slots the module requires (protagonist, antagonist, witness, etc.) and what axes they must satisfy (e.g., "protagonist must have Major secret")
|
||||
- **Event sequences**: ordered or unordered events the module can fire, with storyteller trigger conditions for each (proximity, tick threshold, player action)
|
||||
- **Outcomes**: resolution states the module can reach (exposed, escaped, ambiguous, abandoned)
|
||||
- **Pool format**: how multiple modules coexist in the pool — each module is a YAML file in `content/modules/tier1/`
|
||||
- A stub Tier 1 module file for the smuggling ring scenario at `content/modules/tier1/smuggling_ring_v0_1.yaml` — this is the vertical slice module
|
||||
- Coordinate with server team: the storyteller module stub (`server/src/storyteller/`) will eventually activate modules by reading this schema. Schema design choices constrain implementation — agree on the top-level structure with Tyre before finalizing
|
||||
|
||||
**Paula owns the dramatic structure design** (entry conditions, event sequences, outcomes). **Gestalt owns the schema implementation** (YAML format, field names, validation rules). **Mellanie reviews** for authoring ergonomics — can a writer actually fill this template?
|
||||
|
||||
Output: schema file + stub module file + brief authoring notes in `docs/design/tier1-module-authoring.md` explaining the fields to future writers.
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
#544 (line ID design) → standalone — Gestalt starts week 1
|
||||
→ output unblocks server/ci registry implementation (Sprint 19)
|
||||
|
||||
#158 (drama module schema) → standalone — Paula + Gestalt start week 1
|
||||
→ output unblocks storyteller activation (future sprint)
|
||||
```
|
||||
|
||||
Both tickets are design-first — produce documents and schema files, not code. Both run in parallel from day 1.
|
||||
|
||||
## Open Questions to Resolve Early
|
||||
|
||||
- **Q-028: collision-resistant line IDs** — #544 IS the resolution ticket. Gestalt must produce a concrete decision by end of week 1. The decision should be registered as D-NNN via the standard decision record format in `decisions/content.md`.
|
||||
|
||||
## PR Workflow
|
||||
|
||||
When ready to submit, create a PR with `tea` CLI. **All flags are required** to avoid TTY prompts (see CLAUDE.md "Gitea access" section):
|
||||
```bash
|
||||
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(copy): description" --description "body" --base main --head copy
|
||||
```
|
||||
@@ -0,0 +1,88 @@
|
||||
# Sprint 18: Touch — Joint Tasks
|
||||
|
||||
**Goal:** The player can examine entities and objects to generate character-filtered observations; NPCs detect and react when watched; social actions propagate through the relationship graph; minimap renders POIs on the client.
|
||||
|
||||
## Pre-Sprint
|
||||
|
||||
No blocking decisions required before implementation starts. All architectural decisions for Sprint 18 scope are confirmed.
|
||||
|
||||
| Decision | Status | Impact |
|
||||
|----------|--------|--------|
|
||||
| D-011 (NPCs use same LOS system) | Confirmed | #115 (NPC vision) — no new LOS mechanism needed |
|
||||
| D-026 (simulation tiers) | Confirmed | #95 (background state machines) — `BackgroundSim` marker exists |
|
||||
| D-041 (knowledge graph data model) | Confirmed | #242 (examine), #264 (journal display) — KG is the output format |
|
||||
| D-062 (invisible locked options) | Confirmed | #174 (dialogue UI audit) — no grayed-out options anywhere |
|
||||
| D-035 Amendment Sprint 15 (NPC-scoped line IDs) | Confirmed | #544 (ID design) extends this for auto-generated NPCs |
|
||||
| Q-028 (collision-resistant line IDs) | **Open** | #544 resolves this — copy team, week 1 |
|
||||
|
||||
## Cross-Team Integration Points
|
||||
|
||||
### Server → Client wire format additions (week 1 coordination)
|
||||
|
||||
Two new snapshot fields must be agreed before client implementation begins:
|
||||
|
||||
| New field | Server ticket | Client ticket | Format notes |
|
||||
|-----------|--------------|---------------|--------------|
|
||||
| `examine_result` | #242 | #174 | `{entity_id, text, confidence}` or null — character-filtered observation text |
|
||||
| `player_knowledge` | #256 (stub) / #242 | #264 | Partial KG dump: `{entities: [{id, name, confidence, source, state, last_tick}], facts: [...]}` |
|
||||
| `poi_list` | #148/#149 (done) | #151 | Already in snapshot from Sprint 17 — verify field name with server |
|
||||
|
||||
Action: server team (Tyre/Dudley) and client team (Stig) align on field names and wire format on **day 1**. No code needed — just agreed field names written to a `.tmp/` file or directly into `server/src/bridge/types.rs` as stub structs.
|
||||
|
||||
### Server → Copy dependency
|
||||
|
||||
| Server ticket | Copy output | Integration |
|
||||
|---------------|-------------|-------------|
|
||||
| #91 (skill system) | #544 (ID scheme) | Auto-generated NPC skills will need line IDs once the NPC pool is large. ID scheme must work for skill-bearing generated NPCs. |
|
||||
| #115 (NPC vision) | #248 (pressure framework) | Awareness events from #244 drive `exposure_pressure` in #248 — copy team's monologue lines with `mood: [anxious]` are the output surface. |
|
||||
|
||||
### Copy → Server dependency
|
||||
|
||||
| Copy output | Server ticket | Integration |
|
||||
|-------------|--------------|-------------|
|
||||
| #544 (ID scheme decision) | Content registry | Server team cannot implement collision-resistant registry until scheme is decided. Sprint 19 work. |
|
||||
| #158 (drama module schema) | Storyteller activation | Schema design constrains the storyteller module interface. Server team should review #158 output before storyteller implementation begins. |
|
||||
|
||||
## Sprint Completion Proof
|
||||
|
||||
Sprint 18 is **DONE** when:
|
||||
|
||||
1. **Examine fires and is character-filtered** — Player uses Examine on an NPC at close range. The client displays a short observation text. The smuggler and detective receive different text for the same NPC — same entity, different perspective.
|
||||
2. **NPC notices the player** — An NPC with the player in its LOS for ≥N consecutive ticks changes behavior: route deviation, posture shift, or tell state update. The player can observe this response.
|
||||
3. **Social ripple is observable** — Player action toward NPC A (e.g., a trust-positive dialogue) causes a measurable trust delta on NPC B (second-order relationship). Verify via server state inspection or the WRONG button (F12) snapshot.
|
||||
4. **Tell states wire to snapshot** — Active-tier NPCs with Major secrets show `Nervous` or `Guarded` tell in the `ObserverSnapshot`. The client renders this (monologue trigger or entity tint — verify whichever is wired).
|
||||
5. **Minimap renders POIs** — Discovered POIs appear as dots/arrows on the insert minimap overlay. Player position is centered. Minimap is present when at least one POI has been discovered.
|
||||
6. **Journal panel opens** — Player opens journal panel. At least one KG fact entry is visible with confidence level, source, and game-time timestamp.
|
||||
7. **Background NPCs tick** — A Background-tier NPC's schedule, mood, relationship, and job state visibly change over game-time (verify via WRONG button or server log). Tick rate is once per game-minute (10 ticks per D-031).
|
||||
8. **Skill system exists** — Generated NPCs have a `SkillSet` component. At least one NPC is spawned with `combat_trained` skill, resulting in a `CombatCapability` marker component attached.
|
||||
9. **Save data model stubs round-trip** — A `SaveStateV1` struct serializes and deserializes without data loss. Test coverage confirms roundtrip fidelity for: entity positions, KG entries, relationship graph, simulation tick.
|
||||
10. **Line ID scheme is decided** — Q-028 is resolved. A decision record (D-NNN) exists in `decisions/content.md`. The scheme is documented clearly enough for a writer to apply it immediately.
|
||||
|
||||
## Test Plan (D-030 alignment)
|
||||
|
||||
Sprint 18 is in the **integration testing** phase (ongoing from Sprint 3 per D-030). The gauntlet infrastructure from Sprint 17 is the primary test harness for server-side verification.
|
||||
|
||||
| Ticket | Test approach |
|
||||
|--------|---------------|
|
||||
| #242 (examine) | Unit test: `process_examine_interaction` with mock KG → confirm character-filtered output differs between smuggler and detective KG states. Integration test: examine verb from player action → KG entry written via event queue. |
|
||||
| #244 (NPC awareness) | Unit test: NPC with player in LOS for N ticks → `PlayerAwareness` component threshold crossed → routine deviation fired. |
|
||||
| #248 (pressure framework) | Unit test: high awareness events → `exposure_pressure` rises. Integration: pressure visible in snapshot HUD data. |
|
||||
| #249 (social propagation) | Unit test: trust delta +5 to NPC A → NPC B (strong relationship to A) receives delta ~+2. Cycle test: A→B→A propagation terminates cleanly. |
|
||||
| #337 (tell state wiring) | Integration test: `TellCategory::Nervous` for NPC with Major secret + stress past midpoint → confirmed in snapshot `entities[].tell_state`. |
|
||||
| #91 (skill system) | Unit test: NPC with `combat_trained` skill in `SkillSet` → `CombatCapability` component present after spawn. Unit test: NPC without `combat_trained` → no `CombatCapability`. |
|
||||
| #115 (NPC vision) | Unit test: NPC placed adjacent to player (within LOS, no walls) → `NpcVisionState` contains player `StableId`. Wall-blocked: player not visible. |
|
||||
| #256 (save state) | Unit test: serialize `SaveStateV1` with known state → deserialize → all fields match. Round-trip for `KnowledgeGraph` (already serializable). |
|
||||
| #95 (background ticks) | Unit test: NPC with `BackgroundSim`, advance 10 ticks → schedule state machine advances. Unit test: mood drift toward neutral after 10 ticks. |
|
||||
| #151 (minimap) | Manual: POI discovered → minimap dot appears. Distant POI: directional arrow appears at minimap border. |
|
||||
| #174 (dialogue UI) | Manual: examine result appears as overlay, auto-dismisses. Dialogue options confirmed: no locked/grayed options visible. Confrontation option in italic voice. |
|
||||
| #264 (journal) | Manual: journal panel opens, KG facts listed with correct metadata. Contradicted facts visually distinct. |
|
||||
| #544 (ID scheme) | Decision review: scheme handles all four population categories (hand-authored, role-based, generated unique, generated shared). |
|
||||
| #158 (drama module schema) | Schema review: stub `smuggling_ring_v0_1.yaml` validates against `drama_module.schema.yaml`. |
|
||||
|
||||
## Teams
|
||||
|
||||
| Team | Branch | Agents | Tickets |
|
||||
|------|--------|--------|---------|
|
||||
| server | `server` | Dudley, Tyre, Hoshe | #242, #244, #248, #249, #337, #91, #115, #256, #95 |
|
||||
| client | `client` | Stig, Tyre, Hoshe | #151, #174, #264 |
|
||||
| copy | `copy` | Mellanie, Paula, Gestalt | #544, #158 |
|
||||
@@ -0,0 +1,175 @@
|
||||
# Sprint 18: Touch — Server Tasks
|
||||
|
||||
**Goal:** The player can examine entities and objects to generate character-filtered observations; NPCs detect and react when watched; social actions propagate through the relationship graph; minimap renders POIs on the client.
|
||||
|
||||
**Branch:** `server`
|
||||
**Agents:** Dudley (simulation), Tyre (architecture), Hoshe (QA)
|
||||
|
||||
## Carry-over from Sprint 17
|
||||
|
||||
None. Sprint 17 closed 19/19.
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #242 | Examine mechanic | #240 (done) |
|
||||
| #244 | NPC player-awareness behavior | — |
|
||||
| #248 | Character goal/pressure framework | — |
|
||||
| #249 | Player-action social propagation | — |
|
||||
| #337 | Tell state derivation system | #323 (done) |
|
||||
| #91 | Skill system & combat flag | — |
|
||||
| #115 | NPC vision system | — |
|
||||
| #256 | Save state data model | — |
|
||||
| #95 | Background tier state machines | — |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/architecture.md` — D-010 (information boundaries), D-020 (IPC architecture), D-026 (simulation tiers), D-041 (knowledge graph data model)
|
||||
- `decisions/perception.md` — D-011 (fog of perception — NPCs use same LOS), D-035 (symmetric shadowcasting)
|
||||
- `decisions/content.md` — D-024 (NPC 10-axis model, skill set axis, combat component), D-028 (dialogue architecture — examine verb is a dialogue layer entry point)
|
||||
- `decisions/scope.md` — D-027 (vertical slice criteria — character-specific observation)
|
||||
|
||||
## Notes
|
||||
|
||||
### #242 — Examine mechanic
|
||||
|
||||
The interaction dispatcher (`server/src/simulation/interaction.rs`) already computes `VerbKind::ExamineNpc` and `VerbKind::ExamineObject` in the `NearbyInteractionBuffer`. The examine verb appears at close range (≤2 tiles, `CLOSE_RANGE`). `PlayerAction` dispatch and `process_player_input` are the entry points in `server/src/simulation/input.rs`.
|
||||
|
||||
What this ticket must deliver:
|
||||
- A `process_examine_interaction` system that handles `PlayerAction::Examine { entity_id }` (or equivalent)
|
||||
- Generates a detailed `ObservationEvent` with low uncertainty for the target entity
|
||||
- Applies character-specific filtering via the observer's `KnowledgeGraph` (same NPC looks different to smuggler vs detective — smuggler reads cargo-handling posture, detective reads procedural tells)
|
||||
- Result is written to the observer's `KnowledgeGraph` via `KnowledgeEventQueue` as a `DirectObservation` entry with `KnowledgeConfidence::Direct`
|
||||
- Emits an examine result field in `ObserverSnapshot` so the client can display character-filtered detail text
|
||||
|
||||
Integration points: `server/src/simulation/interaction.rs` (verb dispatch), `server/src/knowledge/graph.rs` (`KnowledgeGraph` write), `server/src/perception/observation.rs` (observation event pattern), `server/src/simulation/dialogue.rs` (examine result mirrors dialogue result pattern).
|
||||
|
||||
### #244 — NPC player-awareness behavior
|
||||
|
||||
NPCs use the same LOS system as the player (D-011). The awareness system detects when an NPC's LOS query includes the player's `TilePosition`, and generates a behavioral response.
|
||||
|
||||
What this ticket must deliver:
|
||||
- A new `PlayerAwareness` component on Active-tier NPCs tracking: whether the player is in this NPC's LOS, for how many consecutive ticks, and accumulated suspicion level
|
||||
- A `detect_player_awareness` system running after `compute_observer_snapshot` — iterate Active-tier NPCs, run a simplified LOS check or piggyback on existing shadowcast state
|
||||
- When awareness crosses threshold: routine deviation behavior (NPC changes path or posture), fed into the `DerivedTellState` pipeline (already exists in `server/src/npc/tell_state.rs`)
|
||||
- Feeds follow-verb suspicion in `server/src/simulation/follow.rs`
|
||||
|
||||
Key file: `server/src/simulation/follow.rs` already has proximity + attention logic for follow suspicion — awareness system reuses this infrastructure. New system lives in `server/src/simulation/` or `server/src/npc/`.
|
||||
|
||||
### #248 — Character goal/pressure framework
|
||||
|
||||
Defines systemic pressures per character that modulate monologue salience and observation priority. Not scripted arcs — emergent from interaction of existing axes (D-024).
|
||||
|
||||
What this ticket must deliver:
|
||||
- A `CharacterPressure` component on the player character entity: `exposure_pressure: i32` (smuggler), `institutional_pressure: i32` (detective), `relationship_pressure: i32` (both)
|
||||
- Pressure inputs: exposure rises when NPCs notice the player (feeds from #244), relationship pressure from trust changes in `server/src/npc/relationships.rs`, institutional pressure from detective-specific interaction patterns
|
||||
- Pressure outputs: written into `ObserverSnapshot` HUD widget data; high pressure raises monologue trigger weight for anxiety-tagged lines
|
||||
- Coordinate with copy team — monologue lines using `mood: [anxious]` or `mood: [frustrated]` tags (D-035) are the output surface
|
||||
|
||||
This is a design-and-implement ticket — start by defining the pressure struct, then wire inputs from existing systems. Monologue salience weighting is the primary v0.1 output.
|
||||
|
||||
### #249 — Player-action social propagation
|
||||
|
||||
Player actions toward one NPC ripple through the relationship graph at three decay orders (D-029 topology principle). The `RelationshipGraph` resource (`server/src/npc/relationships.rs`) and `TrustEventQueue` are the integration points.
|
||||
|
||||
What this ticket must deliver:
|
||||
- A `propagate_social_actions` system triggered when a `TrustEventQueue` event fires from player action
|
||||
- First-order: immediate full delta to the directly affected NPC
|
||||
- Second-order: `delta * 0.4` to NPCs with strong relationships to the first-order NPC (trust > 3 in `RelationshipGraph`)
|
||||
- Third-order: `delta * 0.15` to NPCs one further hop away, delayed by configurable ticks
|
||||
- Propagation topology varies per seed (D-029 anti-metagaming) — the same action produces different cascades depending on who knows whom
|
||||
- Write propagated trust changes back to `TrustEventQueue` or directly to `Relationships` components with a `PropagatedTrust` marker
|
||||
|
||||
Gotcha: propagation must not loop (A affects B affects A). Visited-entity set per propagation pass prevents cycles.
|
||||
|
||||
### #337 — Tell state derivation system
|
||||
|
||||
The `derive_tell_state` system already exists and is fully tested in `server/src/npc/tell_state.rs`. This ticket existed in the backlog because the mood state machine (#323) it depends on was not yet done. #323 is now done.
|
||||
|
||||
What this ticket must deliver:
|
||||
- Verify `derive_tell_state` runs correctly in the current schedule (it is already registered in `server/src/npc/mod.rs` after `mood::update_mood`)
|
||||
- Wire `DerivedTellState` into the observer snapshot output — confirm `ObserverSnapshot.entities[].tell_state` is populated for visible entities
|
||||
- Integration test: NPC with Major secret + stress past midpoint shows `TellCategory::Nervous` in snapshot
|
||||
- This ticket is mostly verification + integration wiring, not new code — the system is complete, the sprint task is closing the loop into the snapshot
|
||||
|
||||
### #91 — Skill system & combat flag
|
||||
|
||||
What this ticket must deliver:
|
||||
- A `SkillSet` component: `BTreeMap<String, u8>` of named skills with level values (BTreeMap per D-010 determinism requirement)
|
||||
- When a `SkillSet` contains `"combat_trained"` with value ≥ 1, the ECS system attaches a `CombatCapability` marker component to that NPC at spawn time
|
||||
- `SkillSet` added to the NPC generation pipeline in `server/src/npc/generate.rs` (already sets other D-024 axes)
|
||||
- The `CombatCapability` component is a zero-sized marker for now — future sprints add stats
|
||||
|
||||
NPC skill sets are generated from content YAML at startup. The content loader in `server/src/content/` reads NPC definitions — add `skills: {}` as a YAML field on NPC templates.
|
||||
|
||||
### #115 — NPC vision system
|
||||
|
||||
NPCs must use the same LOS shadowcasting system as the player (D-011 — "Applies to ALL entities"). The shadowcast machinery lives in `server/src/perception/shadowcast.rs`.
|
||||
|
||||
What this ticket must deliver:
|
||||
- NPC vision is computed via `compute_los` (or equivalent call) for Active-tier NPCs each tick
|
||||
- Results stored in an `NpcVisionState` component: set of `StableId` values currently visible to this NPC, plus the player entity if visible
|
||||
- NPC memory: `NpcMemory` component tracking last-known-position of the player even after leaving LOS ("saw you enter building → knows you're inside" per D-011)
|
||||
- Inference stub: if player was seen entering a room, NPC `KnowledgeGraph` records `DirectObservation` of player at that room's zone, degrading to `KnowsOf` after configurable ticks
|
||||
|
||||
This feeds #244 (awareness) — the `detect_player_awareness` system reads `NpcVisionState` rather than running its own LOS query.
|
||||
|
||||
Performance note: only run LOS for NPCs whose `TilePosition` is within `ACTIVE_RADIUS` (already guaranteed by `ActiveSim` marker). Full shadowcast per NPC per tick is feasible at 30-80 active NPCs — Tyre has confirmed the budget.
|
||||
|
||||
### #256 — Save state data model
|
||||
|
||||
Define the serialization format for full game state. Shares architecture with #96 (state serialization system, still backlog — this ticket is the data model design, not the save/load implementation).
|
||||
|
||||
What this ticket must deliver:
|
||||
- A `SaveStateV1` struct (versioned from day one) covering: entity state, `KnowledgeGraph` per entity (already serializable via `serde` in `server/src/knowledge/graph.rs`), `RelationshipGraph`, game clock position (`SimulationTime`), seed value
|
||||
- Write format: MessagePack (consistent with IPC protocol per D-020) or RON for human-readable debugging — decide and document
|
||||
- The struct must roundtrip cleanly: serialize + deserialize produces identical ECS world state
|
||||
- Stub tests proving the roundtrip; full save/load flow is #257 (future sprint)
|
||||
|
||||
The `KnowledgeGraph` is already `Serialize + Deserialize`. The main design work is enumerating which ECS components must be captured and in what order (deterministic serialization per D-010).
|
||||
|
||||
### #95 — Background tier state machines
|
||||
|
||||
Background-tier NPCs (marked `BackgroundSim` in `server/src/simulation/tier.rs`) currently receive no simulation — tier markers exist but no background tick systems run. This ticket adds the four D-026 state machines for background NPCs.
|
||||
|
||||
What this ticket must deliver:
|
||||
- A `background_tick` system gated by `With<BackgroundSim>` that fires once per game-minute (every 10 ticks per D-031)
|
||||
- Four mini state machines per background NPC:
|
||||
1. **Schedule**: advance NPC to next routine activity based on `DayPhase` (reads `DayPhase` from `server/src/simulation/time.rs`, updates `Routine` component)
|
||||
2. **Mood**: simple mood drift toward neutral; significant events (stress > threshold) can shift from neutral
|
||||
3. **Relationships**: trust drift toward baseline over time; no events-driven trust changes for background NPCs
|
||||
4. **Job**: job performance score drift based on contentment (lower contentment → lower performance)
|
||||
- Background tick does NOT run pathfinding, LOS, or dialogue — those are Active-tier only
|
||||
- Background NPCs promoted to Active receive their current state machine state (no reset on promotion)
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
#95 (background tier state machines) → standalone, no blockers
|
||||
|
||||
#115 (NPC vision system) → #244 (player-awareness behavior)
|
||||
↓
|
||||
#248 (character goal/pressure framework) ← feeds from awareness events
|
||||
|
||||
#337 (tell state wiring) → standalone, verify + wire into snapshot
|
||||
|
||||
#242 (examine mechanic) → standalone (dispatcher already exists)
|
||||
|
||||
#249 (social propagation) → standalone (relationships already exist)
|
||||
|
||||
#91 (skill system & combat flag) → standalone
|
||||
|
||||
#256 (save state data model) → standalone (design + stub)
|
||||
```
|
||||
|
||||
Parallel tracks: #95, #91, #337, #256, #249, and #242 can all start in week 1. #244 starts after #115 is in review.
|
||||
|
||||
## PR Workflow
|
||||
|
||||
When ready to submit, create a PR with `tea` CLI. **All flags are required** to avoid TTY prompts (see CLAUDE.md "Gitea access" section):
|
||||
```bash
|
||||
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(simulation): description" --description "body" --base main --head server
|
||||
```
|
||||
Reference in New Issue
Block a user