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>
12 KiB
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_interactionsystem that handlesPlayerAction::Examine { entity_id }(or equivalent) - Generates a detailed
ObservationEventwith 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
KnowledgeGraphviaKnowledgeEventQueueas aDirectObservationentry withKnowledgeConfidence::Direct - Emits an examine result field in
ObserverSnapshotso 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
PlayerAwarenesscomponent 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_awarenesssystem running aftercompute_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
DerivedTellStatepipeline (already exists inserver/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
CharacterPressurecomponent 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
ObserverSnapshotHUD widget data; high pressure raises monologue trigger weight for anxiety-tagged lines - Coordinate with copy team — monologue lines using
mood: [anxious]ormood: [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_actionssystem triggered when aTrustEventQueueevent fires from player action - First-order: immediate full delta to the directly affected NPC
- Second-order:
delta * 0.4to NPCs with strong relationships to the first-order NPC (trust > 3 inRelationshipGraph) - Third-order:
delta * 0.15to 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
TrustEventQueueor directly toRelationshipscomponents with aPropagatedTrustmarker
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_stateruns correctly in the current schedule (it is already registered inserver/src/npc/mod.rsaftermood::update_mood) - Wire
DerivedTellStateinto the observer snapshot output — confirmObserverSnapshot.entities[].tell_stateis populated for visible entities - Integration test: NPC with Major secret + stress past midpoint shows
TellCategory::Nervousin 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
SkillSetcomponent:BTreeMap<String, u8>of named skills with level values (BTreeMap per D-010 determinism requirement) - When a
SkillSetcontains"combat_trained"with value ≥ 1, the ECS system attaches aCombatCapabilitymarker component to that NPC at spawn time SkillSetadded to the NPC generation pipeline inserver/src/npc/generate.rs(already sets other D-024 axes)- The
CombatCapabilitycomponent 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
NpcVisionStatecomponent: set ofStableIdvalues currently visible to this NPC, plus the player entity if visible - NPC memory:
NpcMemorycomponent 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
KnowledgeGraphrecordsDirectObservationof player at that room's zone, degrading toKnowsOfafter 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
SaveStateV1struct (versioned from day one) covering: entity state,KnowledgeGraphper entity (already serializable viaserdeinserver/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_ticksystem gated byWith<BackgroundSim>that fires once per game-minute (every 10 ticks per D-031) - Four mini state machines per background NPC:
- Schedule: advance NPC to next routine activity based on
DayPhase(readsDayPhasefromserver/src/simulation/time.rs, updatesRoutinecomponent) - Mood: simple mood drift toward neutral; significant events (stress > threshold) can shift from neutral
- Relationships: trust drift toward baseline over time; no events-driven trust changes for background NPCs
- Job: job performance score drift based on contentment (lower contentment → lower performance)
- Schedule: advance NPC to next routine activity based on
- 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):
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(simulation): description" --description "body" --base main --head server