docs(sprints): add Sprint 15 React briefings
Server (7), client (5), copy (2) tickets. Goal: player acts and world reacts — follow/examine, dialogue access layers, server-side monologue events, personality and tell system. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# Sprint 15: React — Client Tasks
|
||||
|
||||
**Goal:** The player acts and the world reacts — follow and examine mechanics connect the player to the living NPC simulation; the dialogue system's first two access layers open up information gating; server-side monologue events fire in context; and the personality/tell system completes the NPC data model.
|
||||
|
||||
**Branch:** `client`
|
||||
**Agents:** Stig (UI/rendering dev), Tyre (architect), Hoshe (QA)
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #71 | Tilemap rendering system | — |
|
||||
| #72 | Entity sprite system | — |
|
||||
| #73 | Input capture system | — |
|
||||
| #74 | Basic UI framework | — |
|
||||
| #117 | Smooth camera movement | #116 (done) |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/perception.md` — D-015 (camera locked to character, fixed-north for v0.1), D-019 (top-down confirmed, ~15-20° from vertical "the angle", sprite art convention not camera setting), D-033 (entity color = relationship to player), D-049 (8-layer z-stack), D-059 (fog shader five layers)
|
||||
- `decisions/architecture.md` — D-020 (Godot client = pure renderer, no game logic in GDScript), D-066 (dual-scale grid: 0.5m simulation, 1m visual, 64x64px visual tile), D-010 (deterministic simulation — client renders what server sends)
|
||||
- `decisions/perception.md` — D-043 (functional warmth art style), D-044 (entity > object > structure visual hierarchy), D-046 (three-reference lighting: Darkwood/BR2049/Hopper), D-056 (insert-styled cursor states)
|
||||
|
||||
## Notes
|
||||
|
||||
- **#71 Tilemap rendering system:** `client/scripts/rendering/tile_renderer.gd` exists and is referenced in `world_renderer.gd` as `$FogGroup/FloorTiles` (a TileMapLayer node). The current implementation may be a stub — this ticket must deliver: TileMap node with atlas management, multi-layer support for floor/walls/objects matching D-049 z-stack layers 0 (FloorTiles), 1 (FloorObjects), 2 (furniture in YSortGroup). Tile size is `Constants.TILE_SIZE` (32px visual, per D-066 dual-scale grid where 1 visual tile = 1m = 64x64 source, scaled to 32px runtime). Wall rendering follows D-019 amendment: Option B for structural walls (visible top + face), Option A (boundary lines) for interior partitions. Atlas must accept tiles from `ObserverSnapshot.visible_tiles` (format: `[{x, y, z, type}]`). `world_renderer.gd` already calls `tile_renderer.update_tiles(GameState.visible_tiles)` — ensure `update_tiles()` is the correct entry point.
|
||||
|
||||
- **#72 Entity sprite system:** `client/scripts/rendering/entity_renderer.gd` is substantially implemented — it handles D-033 color derivation (Phase 1 defaults by kind, Phase 2 from RelationshipState), position lerp with `LERP_SPEED = 12.0`, and 0.5s color fade for relationship transitions (#521). This ticket must validate and complete: ensure all entity kinds from `ObserverSnapshot.entities` render correctly, including the `kind.variant` field dispatching to correct sprite/shape, the 24x32 entity footprint within 64x64 visual tiles (D-044), and y-sort ordering within `YSortGroup`. If placeholder shapes (ColorRect) are used, that is correct for v0.1 per D-014. Integration check: `world_renderer.gd` drives entity updates through the same `update_from_state()` path — confirm entity renderer is wired there. Follow-mode UI state (#241, server) will need a new field on `GameState` — stub a `follow_target_id: int = -1` for when the server ticket lands.
|
||||
|
||||
- **#73 Input capture system:** `client/scripts/autoloads/input_mapper.gd` is implemented with WASD movement (D-054 mouse-relative), stance toggles, Interact, and semantic action dispatch. `InputMapper.Action` enum covers: `MOVE_*` (8 directions), `INTERACT`, `USE_PERCEPTION_MODE`, `OPEN_MENU`, `PAUSE`/`UNPAUSE`, `TOGGLE_STANCE_*`, `SET_FACING`. This ticket must validate the full pipeline: physical key → `Action` enum → `input_queue` → message serialized and sent to server. Verify: movement throttle per stance (Sprint=5/s, Walk=2.5/s, Careful=1.7/s, Crouch=1.25/s) is active, facing angle updates every frame, `InputMapper` correctly suppresses movement when `GameState.dialogue_active == true` (D-061 walk-away via WASD). If any semantic actions are stubbed out or missing from the protocol send path, complete them. The `Follow` verb (#241 server) will arrive via `nearby_interactions` — confirm the client can dispatch an `Interact` action with a specific `response_id` corresponding to Follow.
|
||||
|
||||
- **#74 Basic UI framework:** `main.gd` reveals the current HUD structure — `$UILayer/HUD`, `$UILayer/MonologueDisplay`, `$InsertOverlay/InteractionList`, `$InsertOverlay/DialogueBox`, `$UILayer/StanceIndicator`, and more are already wired. This ticket must ensure the HUD structural layout is complete and stable: monologue display area (top of screen or floating, z-layer 7 per D-049), placeholder area for insert/minimap (D-013, not yet implemented), stance indicator visible, and the overall scene hierarchy matches D-049's 8-layer z-stack. The `$InsertOverlay` is z-layer 6 (insert overlay), `$UILayer` is z-layer 7 (UI/monologue). Confirm `GameState.insert_active` controls visibility of z-layer 6 elements per D-056/D-057 OQ-07 resolution. This is a completion + validation ticket — identify gaps in the existing HUD structure rather than building from scratch.
|
||||
|
||||
- **#117 Smooth camera movement:** Camera lock to character is done (#116) — `camera` in `main.gd` is a `Camera2D`. `_camera_anchored` and `_teleport_in_progress` flags exist for init sequencing. This ticket adds interpolated camera tracking: instead of snapping `camera.position` to `GameState.player_position` each frame, use exponential smoothing (same pattern as `entity_renderer.gd`'s `LERP_SPEED`). Configurable smoothing: expose a constant or project setting for the smoothing factor. Edge cases to handle — camera must snap immediately on teleport (the `_teleport_in_progress` flag already exists for exactly this), and must not smooth during initial camera anchor (`_camera_anchored` flag). Camera is always fixed-north per D-015 v0.1 scope — no rotation logic.
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
#71 (Tilemap rendering) ─────────────────────────────────────────────┐
|
||||
#72 (Entity sprite system) ──────────────────────────────────────────┤→ integrated in world_renderer.gd
|
||||
#73 (Input capture system) → feeds server #241 (Follow), #242 (Examine)│
|
||||
#74 (Basic UI framework) ────────────────────────────────────────────┘
|
||||
|
||||
#117 (Smooth camera) → standalone, parallel track
|
||||
```
|
||||
|
||||
## PR Workflow
|
||||
|
||||
When ready to submit, create a PR with the `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): sprint 15 react — client deliverables" --description "body" --base main --head client
|
||||
```
|
||||
@@ -0,0 +1,54 @@
|
||||
# Sprint 15: React — Copy Tasks
|
||||
|
||||
**Goal:** The player acts and the world reacts — follow and examine mechanics connect the player to the living NPC simulation; the dialogue system's first two access layers open up information gating; server-side monologue events fire in context; and the personality/tell system completes the NPC data model.
|
||||
|
||||
**Branch:** `copy`
|
||||
**Agents:** Mellanie (lead author), Paula (narrative design), Gestalt (systems/content architecture)
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #299 | Opening hook content — smuggler first 5 minutes | all blockers done |
|
||||
| #300 | Opening hook content — detective first 5 minutes | all blockers done |
|
||||
| #169 | Layer 1: Access tier filtering (content for dialogue system) | — |
|
||||
| #170 | Layer 2: Relationship history (content for dialogue system) | — |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/content.md` — D-016 (internal monologue functions: perception bridge, atmosphere, diegetic tutorial, unreliable narrator), D-024 (10-axis NPC model; personality traits, tell system), D-028 (dialogue 4-layer architecture: access tiers → relationship history → trust gossip → unprompted disclosure), D-032 (separate monologue pools per character — hard partition), D-034 (THE FRIEND pattern: Kael Davan / Sera Venn), D-035 (converged tag taxonomy — 6 structural + 3 selection tags; 9 mood states post Sprint 14 amendment), D-036 (Sova Transit District setting, Krenn System naming conventions), D-075 (dialogue filtering: KnowledgeConfidence gates TrustTier, not AccessTier)
|
||||
- `decisions/perception.md` — D-060 (cognitive delay 0.6s / 0.3s), D-061 (unified dialogue log, bottom screen, max 20% height, max 640px wide), D-062 (invisible locked options — no lock icons), D-063 (confrontation: same box, different weight — italicized first-person voice), D-064 (walk-away: three-phase consequences, KG records incompleteness), D-078 (overheard NPC conversation — passive panel with occlusion filter; monologue reacts via `witness_interaction` trigger)
|
||||
|
||||
## Notes
|
||||
|
||||
- **#299 Opening hook — smuggler first 5 minutes:** All blockers are done: Dual Lens Authoring Guide (#261), character voice speech patterns (#310), knowledge state vocabulary (#309), monologue display visual spec (#315). This is the single most important content deliverable in the game — it blocks all playtest feedback and defines first impressions. Deliver 10-15 tightly sequenced monologue lines structured as a diegetic tutorial arc: (1) station hum as opening sensation, (2) spatial orientation — NPCs already moving, fog boundary visible, (3) first sight of Kael (warm, trusted — D-033 green entity), (4) news ticker glance (optional environmental text moment), (5) first fog-edge sound ping noticed (teaches sound channel). Voice: smuggler is working-class pragmatic, warm but watchful, compact consonant-heavy Krenn naming in references (D-036). Prerequisite tags (`knowledge_state` gates) must be `null` for this sequence — these lines fire on first encounter, before any knowledge graph state exists. Use `trigger: enter_location` for spatial lines, `trigger: observe_npc` for Kael sighting. File structure: `monologue-smuggler.yaml` per D-032. This ticket blocks #330 (diegetic tutorial lines), so prioritize it early.
|
||||
|
||||
- **#300 Opening hook — detective first 5 minutes:** Same blockers done, same urgency. Different emotional register: detective arrives into established rhythm (mid-morning, D-036 Sova atmosphere). The detective is an institutional outsider with analytical lattice — sharper, more detached voice. Tutorial pathway differs: detective's insert HUD is denser (D-048), first NPC contact mediated by institutional insert overlay (Authority access relationship by default). 10-15 lines structured as: (1) institutional orientation — commission kiosk visible, cool-lit corridors (D-046), (2) analytical lattice flagging ambient data (teaches insert channel), (3) first sight of Sera Venn (THE FRIEND, D-034 — currently Unknown/Neutral teal per D-033), (4) cargo manifest anomaly observation (sets detective motivation). Voice: analytical, institutional, controlled. Krenn naming in observations (D-036). File structure: `monologue-detective.yaml` per D-032.
|
||||
|
||||
- **#169 Layer 1: Access tier filtering:** D-028 Layer 1 is the foundational gate on the dialogue system. Every dialogue line in the content files must carry an `access` tag (list): values are `public`, `insider`, `authority`, `peer`, `hostile`. This ticket's content deliverable is: (a) audit all existing line pool files under `content/` for correct `access` tagging — flag any lines missing the tag, (b) author the Layer 1 filter logic design spec if one does not exist (how does `RelationshipState` map to `access` tier? see D-075: AccessTier is gated by `RelationshipState` only, not `KnowledgeConfidence`), (c) ensure the existing Kael and Sera line pools (authored in earlier sprints) have correct `access` tags on every line. The dialogue selection pipeline (`server/src/simulation/dialogue.rs`, #305 done) already implements Layer 1 filtering — this ticket is the content-side completion: all lines properly tagged, authoring guide updated for Line Layer 1 rules, Gestalt to confirm tag schema is consistent with D-035 structural tags. Cross-reference: the detective gets Authority access naturally from institutional role; the smuggler gets Insider/Peer access from social network — no archetype tag needed on the pipeline (D-075 emergent design).
|
||||
|
||||
- **#170 Layer 2: Relationship history:** D-028 Layer 2 modifies greeting and topic selection based on the interaction log per NPC pair. Content deliverable: (a) define the situation tags that encode relationship history context — D-035 lists 13 situations for v0.1, with `greeting` added in Sprint 8 amendment as the 14th; specify which situations encode first_meeting, established, tense, post_confrontation, post_walkaway states, (b) author `situation: greeting` variants for Kael and Sera line pools — first meeting line (situation: greeting, access: [public]) vs repeat visit line (situation: greeting, access: [peer]) should differ meaningfully, (c) document how the engine maps `InteractionMemory` (#325, done) interaction log to Layer 2 situation tags — Gestalt to write or verify this mapping in the authoring guide. The dialogue selection pipeline already calls Layer 2 filtering; this ticket completes the content to exercise it. Result: Kael greets the smuggler differently on first vs third encounter. Sera greets the detective differently before and after the detective has spoken to her colleagues.
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
#299 (Smuggler opening hook) ──┐
|
||||
↓
|
||||
#330 (Diegetic tutorial lines — deferred sprint 16)
|
||||
#300 (Detective opening hook) ─┘
|
||||
|
||||
#169 (Layer 1: Access tier filtering) → must complete before Layer 3 work (#171, sprint 16)
|
||||
#170 (Layer 2: Relationship history) → must complete before Layer 3 work (#171, sprint 16)
|
||||
|
||||
#299 and #300 are parallel. #169 and #170 are parallel.
|
||||
```
|
||||
|
||||
## PR Workflow
|
||||
|
||||
When ready to submit, create a PR with the `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): sprint 15 react — opening hooks + dialogue layer 1-2" --description "body" --base main --head copy
|
||||
```
|
||||
@@ -0,0 +1,100 @@
|
||||
# Sprint 15: React — Joint Coordination
|
||||
|
||||
**Goal:** The player acts and the world reacts — follow and examine mechanics connect the player to the living NPC simulation; the dialogue system's first two access layers open up information gating; server-side monologue events fire in context; and the personality/tell system completes the NPC data model.
|
||||
|
||||
**Agents:** All teams — coordination reference
|
||||
|
||||
---
|
||||
|
||||
## Pre-Sprint Decisions
|
||||
|
||||
No blocking open questions identified for this sprint. All decisions required by Sprint 15 tickets are confirmed.
|
||||
|
||||
| Decision | Status | Required by |
|
||||
|----------|--------|-------------|
|
||||
| D-024 (NPC 10-axis model, tell system) | Confirmed | #90, #92 |
|
||||
| D-028 (dialogue 4-layer architecture) | Confirmed | #169, #170 |
|
||||
| D-035 (tag taxonomy, 9 moods post S14 amendment) | Confirmed | #119, #169, #170 |
|
||||
| D-075 (confidence gates trust tier, not access tier) | Confirmed | #169 |
|
||||
| D-016 (monologue triggers) | Confirmed | #119 |
|
||||
| D-010 (deterministic simulation) | Confirmed | #92, #340 |
|
||||
| D-015 (camera locked, fixed-north v0.1) | Confirmed | #117 |
|
||||
| D-019 (top-down, "the angle") | Confirmed | #71 |
|
||||
| D-049 (8-layer z-stack) | Confirmed | #71, #74 |
|
||||
|
||||
---
|
||||
|
||||
## Cross-Team Dependencies
|
||||
|
||||
```
|
||||
Server #119 (monologue event generation)
|
||||
→ content pool selector reads D-035 trigger tags authored by copy team
|
||||
→ fires on observe_npc, hear_sound, observe_anomaly, witness_interaction, post_conversation
|
||||
→ output appears in ObserverSnapshot.current_monologue (existing field, GameState v5)
|
||||
→ client #74 (UI framework) must display it via MonologueDisplay
|
||||
|
||||
Server #241 (follow mechanic)
|
||||
→ emits follow_target_id in ObserverSnapshot
|
||||
→ client #73 (input capture) must dispatch Interact→Follow verb via nearby_interactions
|
||||
→ client #72 (entity sprite) can highlight follow target entity
|
||||
|
||||
Server #90 (personality & tell system)
|
||||
→ tell state on ObserverSnapshot entity field
|
||||
→ client #72 may render tell state (stub field now, visual in sprint 16)
|
||||
|
||||
Copy #169 (Layer 1 access tier tagging)
|
||||
→ requires server dialogue.rs (#305, done) to be running Layer 1 filter
|
||||
→ copy team audits content files; server team does not need to change code
|
||||
|
||||
Copy #299/#300 (opening hooks)
|
||||
→ requires MonologueDisplay (#122, done) and monologue event triggers (#119, this sprint)
|
||||
→ content ready before engine = acceptable; engine ready before content = also acceptable
|
||||
→ they are parallel workstreams that meet at playtest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sprint Completion Proof
|
||||
|
||||
Sprint 15 is done when all of the following are observable:
|
||||
|
||||
1. **Follow mechanic end-to-end:** Player right-clicks an NPC and selects Follow. The server tracks proximity and LOS. Observation events fire while following. NPC suspicion accumulates if the player is within 2 tiles for 60+ ticks. The follow ends naturally when the NPC enters deep fog or detects the player. No client crash. Server logs emit follow-state transitions.
|
||||
|
||||
2. **Monologue fires on observation events:** When the player enters a location, observes an NPC, or hears a sound at medium range, a contextually tagged monologue line appears in the MonologueDisplay. Line selection uses D-035 trigger tags. The cooldown (300 ticks) prevents spam. `observe_anomaly` fires when a routine deviation is detected (#243).
|
||||
|
||||
3. **Routine deviation detected:** An NPC breaks their routine (wrong location for day phase, or absent from expected location). The server emits a `RoutineDeviationEvent`. This feeds the monologue trigger above (observe_anomaly).
|
||||
|
||||
4. **NPC generation pipeline produces valid NPCs:** `generate_npc()` takes a role, outputs a fully-seeded ECS entity with all 10 axes populated. Constraint validation passes. Personality traits (2-3) and tell state are present.
|
||||
|
||||
5. **Layer 1 access filtering active:** The dialogue system filters lines by `RelationshipState` → `access` tier. A player with Unknown relationship sees only `public`-tagged lines. A player with Known/Friendly relationship also sees `insider`/`peer` lines. The filter is invisible — no locked indicators (D-062).
|
||||
|
||||
6. **Layer 2 relationship history active:** Kael (or Sera) greets the player differently on first vs subsequent encounters. The `greeting` situation tag drives this. `InteractionMemory` from Sprint 14 (#325) is the data source.
|
||||
|
||||
7. **Tilemap + entity + input + UI all render cleanly:** Game boots, tiles render from snapshot data, entity sprites move with lerp, input sends semantic actions to server, HUD displays monologue and stance. No regressions on Sprint 14 functionality (fog, dialogue box, NPC-to-NPC conversation panel).
|
||||
|
||||
8. **Smooth camera movement:** Camera tracks player position with interpolated smoothing. No jarring snaps during movement. Snap-on-teleport still works. Camera stays fixed-north (D-015).
|
||||
|
||||
9. **Opening hooks authored:** Both `monologue-smuggler.yaml` and `monologue-detective.yaml` contain the 10-15 opening sequence lines. Lines carry correct D-035 structural tags: character partition, trigger type, situation, prerequisite null.
|
||||
|
||||
---
|
||||
|
||||
## Test Plan Alignment (D-030)
|
||||
|
||||
Sprint 15 is in the integration-and-behavior phase. Testing priorities:
|
||||
|
||||
- **Server unit tests (Hoshe):** `PersonalityTraits` derivation (correct tell state from axis values), `RoutineDeviationEvent` emission timing, `ToleranceThreshold` breach at correct stress level, `SpatialIndex` naive impl correctness (entities_in_range, entities_at, update)
|
||||
- **Integration test (Hoshe):** Follow mechanic end-to-end — simulate player issuing Follow verb, advance N ticks with NPC moving, verify observation event frequency increase, verify suspicion accumulation rate
|
||||
- **Content validation (CI):** Cross-reference check on new monologue files — character partition, required tags present, trigger enum values valid (extends existing `content-cross-reference` CI check, #464)
|
||||
- **Client regression (Hoshe):** Verify all Sprint 14 integration proofs still pass after #71/#72/#73/#74 changes — fog renders, dialogue box appears, NPC-to-NPC conversation panel shows
|
||||
|
||||
---
|
||||
|
||||
## Carry-over Risk
|
||||
|
||||
No Sprint 14 carry-overs. Sprint 14 was 100% complete (22/22 done).
|
||||
|
||||
The highest carry-over risks in Sprint 15:
|
||||
|
||||
- **#299/#300 (opening hooks):** Content authoring on the critical path — Mellanie leads, Paula consults. If these slip, they carry to sprint 16 with no downstream blocking (the system will run without them, using time_idle and enter_location monologue from existing pools).
|
||||
- **#169/#170 (dialogue layers 1-2):** These are content-side auditing and authoring tasks. The pipeline code (#305) is done. Carry-over has no server code impact.
|
||||
- **#241 (follow mechanic):** Depends on interaction dispatcher (#240, done) but adds new system logic. Medium complexity. Carry-over defers NPC suspicion mechanics but does not block other sprint tickets.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Sprint 15: React — Server Tasks
|
||||
|
||||
**Goal:** The player acts and the world reacts — follow and examine mechanics connect the player to the living NPC simulation; the dialogue system's first two access layers open up information gating; server-side monologue events fire in context; and the personality/tell system completes the NPC data model.
|
||||
|
||||
**Branch:** `server`
|
||||
**Agents:** Dudley (simulation dev), Tyre (architect), Hoshe (QA)
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #119 | Monologue event generation — server | #239 (done) |
|
||||
| #92 | NPC generation pipeline | #86 (done) |
|
||||
| #90 | Personality & tell system | #89 (cancelled — blocker resolved) |
|
||||
| #241 | Follow mechanic | #240 (done) |
|
||||
| #243 | Routine deviation detection | #88 (done) |
|
||||
| #105 | Tolerance threshold triggers | — |
|
||||
| #340 | Define SpatialIndex trait with naive Vec implementation | — |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/perception.md` — D-011 (fog of perception universal to all entities), D-016 (internal monologue as perception bridge), D-060 (cognitive delay), D-067 (recognition chime onset)
|
||||
- `decisions/content.md` — D-024 (10-axis NPC generation model + tell system), D-028 (dialogue 4-layer architecture), D-035 (converged tag taxonomy, 9 mood states), D-075 (dialogue filtering: confidence gates trust tier, not access tier)
|
||||
- `decisions/architecture.md` — D-010 (information boundaries first-class), D-026 (simulation tiers), D-041 (knowledge graph: KnowsOf / KnowsDetails confidence levels)
|
||||
|
||||
## Notes
|
||||
|
||||
- **#119 Monologue event generation — server:** `server/src/simulation/monologue.rs` already handles `enter_location` and `time_idle` triggers. This ticket extends the system to fire on `observe_npc`, `hear_sound`, `observe_anomaly`, `witness_interaction`, and `post_conversation` triggers — all enumerated in D-035 tag taxonomy. The `ObservationEvent` struct from `server/src/simulation/interaction.rs` (completed in #239) is the input source. Each trigger must emit a `MonologueEvent` into `MonologueBuffer` with context tags (`location`, `situation`, `character_state`) so the content pool selector can match against D-035 structural tags. Respect the `COOLDOWN_TICKS = 300` anti-spam guard already in the file. The `witness_interaction` trigger (D-078) fires after overheard NPC-to-NPC conversation is displayed — coordinate with the passive dialogue system in `server/src/simulation/conversation.rs` and `server/src/simulation/listening.rs`.
|
||||
|
||||
- **#92 NPC generation pipeline:** Core NPC ECS components (Want, Secret, Relationships, Tolerance, Routine, Contentment) are done in `server/src/npc/mod.rs` (#86). This ticket wires procedural generation: takes a role definition as input, seeds all 10 axes using the sim RNG (`server/src/simulation/rng.rs`), applies constraint validation, and spawns a fully-populated NPC entity. Use the `SimRng` resource for all randomness — determinism is non-negotiable (D-010 principle 4). Constraint validation must catch: relationship graph cycles, tolerance values that would immediately trigger, routines that conflict spatially. Output: a function `generate_npc(role: &RoleDefinition, world: &mut World, rng: &mut SimRng)` or equivalent ECS command. Personality traits (2-3 per NPC) must be populated — they feed #90.
|
||||
|
||||
- **#90 Personality & tell system:** The blocker (#89, Information inventory) was cancelled; the knowledge graph (D-041, completed in Sprint 12) supersedes it. `PersonalityTraits` component holds 2-3 traits drawn from a trait set. `TellSystem` covers 5 categories: `nervous`, `angry`, `friendly`, `guarded`, `routine_deviation`. Tell state is derived each tick from NPC axis values — not authored per NPC. Derivation rules: `Secret + low Tolerance → nervous`, `low Contentment + Hostile mood → angry`, `high Contentment + Friendly relationship → friendly`, `high Secret weight → guarded`, deviation from routine → `routine_deviation`. `NpcMood` is already available from `server/src/npc/mood.rs` (#323). The `mood.rs` header comment explicitly flags `Tell system (#337, deferred to Sprint 15) → reads MoodState`. The v0.1 renderer for tells is **monologue text**, not visual animation — emit tell state into `ObserverSnapshot` as a field on the entity's tell status; the client reads it for future use. `server/src/npc/` is the correct home for new components.
|
||||
|
||||
- **#241 Follow mechanic:** Player uses Interact verb on an NPC to designate a follow target. The interaction dispatcher in `server/src/simulation/interaction.rs` (#240, done) must be extended with a `Follow` verb. Server tracks: target NPC entity ID, current distance (tile-based), LOS state (from the existing shadowcasting system in `server/src/perception/`). Observation events (`observe_npc` trigger) fire at double frequency while following. NPC suspicion increases via `ToleranceThreshold` stress if the player maintains close proximity + LOS for sustained ticks. Define "too close too long" as a configurable threshold (start: within 2 tiles for 60+ ticks). Follow ends when: target enters deep fog (LOS lost for N ticks), target detects player (suspicion threshold crossed, feeds `NpcPlayerAwareness`), or player issues a different action. Emit follow-state events into `ObserverSnapshot` so the client can show follow-mode UI state.
|
||||
|
||||
- **#243 Routine deviation detection:** `server/src/npc/routine.rs` tracks `ActivityState` (set when NPC arrives at routine destination) and `DailyRoutine` (schedule of phase → location). Compare the NPC's current `TilePosition` and `ActivityState` against what `DailyRoutine` specifies for the current `DayPhase`. Emit `RoutineDeviationEvent` when: NPC is in wrong location for phase, NPC is absent from expected location (has been out of expected zone for N ticks), NPC is performing wrong activity. Absence detection covers the case where the player expects an NPC at a known location and they are not there. `RoutineDeviationEvent` feeds the observation event generator (#239, done), which will route it to `observe_anomaly` monologue triggers (#119, this sprint). This is the primary detective mechanic per D-027 criterion 4.
|
||||
|
||||
- **#105 Tolerance threshold triggers:** `ToleranceThreshold` component exists (part of NPC data model). This ticket adds the monitoring system: each tick, check all Active-tier NPCs' tolerance against accumulated stress. When stress exceeds threshold, emit a `ToleranceBreachEvent` and apply behavioral state changes (mood shift, potential confrontation-initiation, avoidance behavior). Threshold value varies per NPC seed — do not hardcode. This unblocks #250 (Triangle escalation system) in a later sprint, which needs tolerance breach events as input. Integrate with `server/src/npc/mood.rs` — a tolerance breach should push mood toward `Hostile` or `Anxious` per the FSM.
|
||||
|
||||
- **#340 SpatialIndex trait:** XS effort task. Define a trait in `server/src/` (suggest `server/src/simulation/spatial.rs`) with three methods: `entities_in_range(position, radius)`, `entities_at(position)`, `update(entity_id, position)`. Implement a naive `Vec`-backed backend (`NaiveSpatialIndex`). This is called from the follow mechanic (#241) for proximity queries and from the NPC vision system (#115, deferred). The trait abstraction means a grid/quadtree can replace the naive impl later without touching callers. Register as a Bevy resource.
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
#340 (SpatialIndex) ─────────────────────────────────┐
|
||||
↓
|
||||
#92 (NPC generation pipeline) → #90 (Personality & tell) → future: #337 (tell state derivation)
|
||||
|
||||
#243 (Routine deviation detection) ──────────────────┐
|
||||
↓
|
||||
#119 (Monologue event generation) ← also feeds from #241 (Follow mechanic)
|
||||
↑
|
||||
#241 (Follow mechanic) → feeds NPC suspicion → future: #115 (NPC vision)
|
||||
|
||||
#105 (Tolerance threshold triggers) → future: #250 (Triangle escalation)
|
||||
```
|
||||
|
||||
## PR Workflow
|
||||
|
||||
When ready to submit, create a PR with the `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): sprint 15 react — server deliverables" --description "body" --base main --head server
|
||||
```
|
||||
Reference in New Issue
Block a user