Spring-cleaning accumulated v0.1 vertical-slice residue across the wiki. Scope per Jeroen's pre-decisions on 2026-04-21: - Delete outright: wiki/star-systems/GJ-35/sova/ subtree (5 files + 2 dirs) — v0.1 Station Sova / Transit District content. - Strip example blocks in authoring guides and _templates/ that cited dropped v0.1 NPCs (Kael Davan, Sera Venn, Nils Davan, Devra, Torek, Renn, Pell, Tav, Lera Sessik, Sabel). Replaced with short "v0.1 examples removed — D-122" notes pointing authors to the active NPC roster. - Rewrite canonical-lore references file-by-file: faction pages, technology pages, contraband pages, concepts pages, corp pages that cited v0.1 names/places. Preserve institutional/structural content, drop specific-name citations. - Commission name drift: replace "Concord Commission" and "Assembly Commission" with "the Lattice Commission" (D-193) throughout. - Van Maanen's Star cultural references: the canonical in-game name is Vuurkloof. "Van Maanen's Star" is retained only as an astronomical designation (glossary + GJ-35 Calibration Note). All cultural/system references converted to Vuurkloof across culture-authoring-guide, cultural-generation-guide, founder-gates, and star-system adjacent-system descriptions. - Strip `v0.1` from faction/triangle frontmatter tags (8 files). - wiki/triangles/hub-power.md and wiki/factions/the-ring.md: rewritten using role-name exemplars (Ring Coordinator / Shift Supervisor / THE FRIEND) instead of named v0.1 NPCs. Triangle pattern preserved as a structural reference. Also applies drive-by Commission drift fixes and minor cross-ref updates to canonical corps (gate-corporation, mastroianni-vehicle-group, stalownia-kowalski, prometheus-labs, ferreira-monteiro, vins-de-grand-vide, and 13 others). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
347 lines
15 KiB
Markdown
347 lines
15 KiB
Markdown
---
|
|
title: "Relationship States and Transitions"
|
|
description: "Five RelationshipState values, THE FRIEND contradiction arcs, KnowledgeState integration, and dialogue access tier filtering"
|
|
slug: relationship-states
|
|
category: concept
|
|
status: canonical
|
|
created: 2026-02-12
|
|
updated: 2026-02-13
|
|
concept_type: mechanical
|
|
tags: []
|
|
decision_refs: [D-041]
|
|
cross_refs: []
|
|
---
|
|
|
|
# Relationship States and Transitions
|
|
|
|
How `RelationshipState` (defined in `server/src/knowledge/types.rs`) evolves during gameplay, with specific patterns for THE FRIEND contradictions and KnowledgeState integration.
|
|
|
|
## Canonical States
|
|
|
|
From `server/src/knowledge/types.rs`:
|
|
|
|
```rust
|
|
pub enum RelationshipState {
|
|
Unknown, // Teal #4a9ebb
|
|
Known, // Soft green #6bc9a6
|
|
Friendly, // Soft green #6bc9a6 (same color, different semantics)
|
|
PersonOfInterest, // Amber #e8c547
|
|
Hostile, // Red #d45d5d
|
|
}
|
|
```
|
|
|
|
**Visual rendering**: D-033 entity color system. The client maps these states to colors. The knowledge graph determines the state.
|
|
|
|
---
|
|
|
|
## State Semantics
|
|
|
|
### Unknown
|
|
|
|
**What it means**: No prior knowledge of this entity. First encounter.
|
|
|
|
**Monologue tone**: Observational, neutral. "Who's that?"
|
|
|
|
**Dialogue availability**: Public-tier only. No trust-gated content.
|
|
|
|
**Color**: Teal — visually distinct from all other states.
|
|
|
|
**Typical duration**: First 30 seconds to 2 minutes of gameplay (until first direct interaction or lattice query).
|
|
|
|
---
|
|
|
|
### Known
|
|
|
|
**What it means**: Recognized, neutral-to-positive. Not a threat, not a close ally.
|
|
|
|
**Monologue tone**: Casual acknowledgment. "There's Drin. Maintenance tech."
|
|
|
|
**Dialogue availability**: Public + peer-tier (if appropriate). No insider/secret content yet.
|
|
|
|
**Color**: Soft green — "safe enough."
|
|
|
|
**Typical entities**: Coworkers (smuggler), routine contacts (detective), flat NPCs, bar regulars.
|
|
|
|
---
|
|
|
|
### Friendly
|
|
|
|
**What it means**: Positive relationship, trusted. Emotional connection or reliable professional rapport.
|
|
|
|
**Monologue tone**: Warm, personal. "Good to see them. Always reliable."
|
|
|
|
**Dialogue availability**: Public + peer + insider-tier. Trust-gated content unlocks. Some secret-tier content if relationship deepens.
|
|
|
|
**Color**: Soft green (same as Known — the distinction is semantic, not visual).
|
|
|
|
**Typical entities**: THE FRIEND NPCs, close colleagues, trusted contacts.
|
|
|
|
**Why same color as Known**: Visual simplicity in early implementation. Future refinement could add subtle shader variation (warmth, pulse, saturation).
|
|
|
|
---
|
|
|
|
### PersonOfInterest
|
|
|
|
**What it means**: Flagged. Something's wrong. Under observation or suspicion.
|
|
|
|
**Monologue tone**: Analytical, cautious. "{THE FRIEND}'s meeting someone I don't recognize. That's not normal."
|
|
|
|
**Dialogue availability**: Shifts. Trust-gated content may become unavailable. Confrontation options unlock.
|
|
|
|
**Color**: Amber — "pay attention."
|
|
|
|
**Typical entities**: NPCs caught in contradictions, suspects under investigation, people who've triggered tells.
|
|
|
|
**THE FRIEND trigger**: When THE FRIEND's contradiction is discovered, they transition from Friendly → PersonOfInterest. This is the emotional gut-punch moment.
|
|
|
|
---
|
|
|
|
### Hostile
|
|
|
|
**What it means**: Character KNOWS there is danger. Threat confirmed.
|
|
|
|
**Monologue tone**: Alarm, threat assessment. "That's security. They're moving toward me."
|
|
|
|
**Dialogue availability**: Hostile-tier only (threats, demands, final warnings). All trust content locked.
|
|
|
|
**Color**: Red — "danger."
|
|
|
|
**Typical entities**: NPCs who've turned on the player, authority figures during a confrontation gone bad, exposed ring members cornered by the detective.
|
|
|
|
**Rare**: Most NPCs don't reach Hostile. It's the endgame state for failed social maneuvering.
|
|
|
|
---
|
|
|
|
## Transition Paths
|
|
|
|
### Standard Progression (No Contradiction)
|
|
|
|
```
|
|
Unknown → Known → Friendly
|
|
```
|
|
|
|
**Triggers**:
|
|
- Unknown → Known: First direct interaction OR lattice query identifies them.
|
|
- Known → Friendly: Repeated positive interactions, shared drinks at bar, successful cooperation, trust-building dialogue.
|
|
|
|
**Example**: Detective meets a bar regular. Unknown (first visit) → Known (second visit, exchanged names) → Friendly (third visit, regular offers unprompted gossip).
|
|
|
|
---
|
|
|
|
### Investigation Progression (Detective)
|
|
|
|
```
|
|
Unknown → Known → PersonOfInterest → Hostile (if confrontation fails)
|
|
```
|
|
|
|
**Triggers**:
|
|
- Unknown → Known: Lattice query, case file match, first observation.
|
|
- Known → PersonOfInterest: Behavioral flags accumulate, tells observed, manifest discrepancy linked to this NPC.
|
|
- PersonOfInterest → Hostile: Confrontation attempt rejected, NPC realizes they're under investigation, escalation.
|
|
|
|
**Example**: Detective observes a cargo handler. Unknown (first sight) → Known (lattice query: "dock worker, logistics") → PersonOfInterest (observed in restricted corridor, evasive answers) → Hostile (confrontation: "I know you're involved. You need to cooperate." / handler: "Stay away from me.").
|
|
|
|
---
|
|
|
|
### THE FRIEND Contradiction Arc (Smuggler's Perspective)
|
|
|
|
```
|
|
Friendly → PersonOfInterest → [resolution: Friendly-but-contaminated OR Hostile]
|
|
```
|
|
|
|
**Phase 1: Friendly (baseline)**
|
|
- {THE FRIEND} is the smuggler's trusted colleague.
|
|
- Monologue: fond, casual.
|
|
- Color: soft green.
|
|
- Dialogue: insider-tier, warm.
|
|
|
|
**Phase 2: First Crack (still Friendly, but flags accumulating)**
|
|
- Behavioral flags: `lattice_checking,distracted`.
|
|
- Monologue shifts slightly: "{THE FRIEND}'s been quiet lately."
|
|
- State unchanged (still Friendly), but `EntityKnowledge.known_attributes["behavior_flags"]` updates.
|
|
|
|
**Phase 3: The Contradiction (Friendly → PersonOfInterest)**
|
|
- Trigger: Direct observation of {THE FRIEND} meeting an unknown contact off-route.
|
|
- `EntityKnowledge.known_attributes["contradiction_flagged"] = "meeting_unknown_contact"`.
|
|
- `RelationshipState` transitions to `PersonOfInterest`.
|
|
- Color shifts: soft green → amber.
|
|
- Monologue: "That wasn't anyone from our rotation. {THE FRIEND}, what are you doing?"
|
|
- Dialogue options change: confrontation unlocks, trust-tier content locks ({THE FRIEND} is evasive).
|
|
|
|
**Phase 4: Post-Confrontation**
|
|
- **Path A (understanding)**: Smuggler confronts {THE FRIEND} gently. {THE FRIEND} confesses: trying to exit the ring to protect someone close to them. `RelationshipState` remains `PersonOfInterest` but monologue tone shifts to conflicted sympathy. Color stays amber (still a problem), but dialogue reflects empathy.
|
|
- **Path B (betrayal)**: Smuggler reports {THE FRIEND} to ring leadership or applies harsh pressure. {THE FRIEND} turns defensive. `RelationshipState` → `Hostile`. Color → red. {THE FRIEND} avoids the smuggler, might actively obstruct.
|
|
|
|
**THE FRIEND pattern**: Friendly → PersonOfInterest is the emotional core. The player trusted {THE FRIEND}. Now {THE FRIEND} is amber. That color shift IS the narrative moment.
|
|
|
|
---
|
|
|
|
### THE FRIEND Contradiction Arc (Detective's Perspective)
|
|
|
|
```
|
|
Friendly → PersonOfInterest → [resolution: Friendly-but-contaminated OR Known-distanced OR Hostile]
|
|
```
|
|
|
|
**Phase 1: Friendly (baseline)**
|
|
- {THE FRIEND} is the detective's institutional contact and social anchor.
|
|
- Monologue: professional warmth, relief.
|
|
- Color: soft green.
|
|
- Dialogue: peer-tier, cooperative, helpful.
|
|
|
|
**Phase 2: Pattern Observation (still Friendly, but flags accumulating)**
|
|
- Behavioral flags: `avoidance_pattern` ({THE FRIEND} leaves when a suspect arrives).
|
|
- Monologue: "That's the third time. {THE FRIEND} leaves when that person shows up."
|
|
- State unchanged (still Friendly), but `EntityKnowledge.known_attributes["behavior_flags"]` updates.
|
|
|
|
**Phase 3: The Contradiction (Friendly → PersonOfInterest)**
|
|
- Trigger: Detective asks {THE FRIEND} directly about their avoidance. {THE FRIEND} deflects unconvincingly.
|
|
- `EntityKnowledge.known_attributes["contradiction_flagged"] = "avoidance_inconsistency"`.
|
|
- `EntityKnowledge.known_attributes["secret_held"] = "unreported evidence"` (detective's inference).
|
|
- `RelationshipState` transitions to `PersonOfInterest`.
|
|
- Color shifts: soft green → amber.
|
|
- Monologue: "They're not lying. But they're not telling me everything. {THE FRIEND}, what do you know?"
|
|
- Dialogue options change: pressing questions unlock, casual warmth diminishes.
|
|
|
|
**Phase 4: Post-Confrontation**
|
|
- **Path A (loyalty test)**: Detective confronts {THE FRIEND} about concealment. {THE FRIEND} confesses: sitting on evidence to protect a third party. Detective can choose: report {THE FRIEND} (Hostile), use the information without reporting them (PersonOfInterest → Known, relationship damaged), or protect {THE FRIEND} and accept the information gap (PersonOfInterest → Friendly-but-contaminated).
|
|
- **Path B (institutional)**: Detective reports {THE FRIEND} immediately. `RelationshipState` → `Hostile`. {THE FRIEND} is reprimanded or reassigned. Color → red. The detective loses their only local ally.
|
|
|
|
**THE FRIEND pattern**: The detective's trust in {THE FRIEND} is tested. Amber means "my contact is hiding something." The resolution determines whether the friendship survives.
|
|
|
|
---
|
|
|
|
## Contradiction Patterns: Smuggler vs. Detective Paths
|
|
|
|
Both THE FRIEND NPCs follow the same structural arc, but the **nature of the contradiction differs**:
|
|
|
|
| Dimension | {THE FRIEND} — Smuggler Path | {THE FRIEND} — Detective Path |
|
|
|-----------|------------------------------|-------------------------------|
|
|
| **Contradiction type** | Spatial deviation (meeting unknown contact) | Behavioral avoidance (leaving when a suspect arrives) |
|
|
| **Discovery method** | Direct observation in restricted area | Pattern recognition over multiple visits |
|
|
| **What they're hiding** | Attempt to exit the ring (protect someone close) | Unreported evidence (protect a third party) |
|
|
| **Sympathetic motivation** | Personal protection (someone they care about) | Friendship loyalty (mutual third-party connection) |
|
|
| **Third-party connection** | {THE FRIEND}'s personal life | {THE FRIEND}'s social network |
|
|
| **Color shift timing** | Single observation event (immediate) | Third occurrence (cumulative) |
|
|
| **Confrontation stakes** | Ring security vs. personal loyalty | Institutional duty vs. personal loyalty |
|
|
| **Resolution spectrum** | Understanding ↔ Betrayal | Protect friend ↔ Report corruption |
|
|
|
|
**Common structure**: Both contradictions involve a **shared third party** as the emotional anchor — someone both THE FRIEND NPCs are trying to protect, approached from opposite sides of the case.
|
|
|
|
---
|
|
|
|
## KnowledgeState Integration
|
|
|
|
`RelationshipState` (social assessment) is **orthogonal to** `KnowledgeState` (logical validity).
|
|
|
|
### Active (default)
|
|
|
|
**What it means**: The knowledge is currently believed true.
|
|
|
|
**Effect on relationship**: None directly. A Friendly NPC with Active knowledge remains Friendly.
|
|
|
|
**Example**: Smuggler's knowledge of {THE FRIEND} as "trusted colleague" is Active until the contradiction.
|
|
|
|
---
|
|
|
|
### Contradicted
|
|
|
|
**What it means**: Conflicting information exists. Both the original belief and the contradiction receive this state.
|
|
|
|
**Effect on relationship**: **This is the trigger for Friendly → PersonOfInterest.**
|
|
|
|
When `KnowledgeState` becomes `Contradicted`, the system:
|
|
1. Sets `EntityKnowledge.state = KnowledgeState::Contradicted` on the conflicting knowledge entries.
|
|
2. Triggers a monologue event: "Wait, that doesn't match what I thought I knew."
|
|
3. Evaluates `RelationshipState` transition. If the contradicted knowledge is about a Friendly NPC, transition to PersonOfInterest.
|
|
|
|
**Example**: Smuggler's knowledge "{THE FRIEND} operates within ring protocol" contradicts with new observation "{THE FRIEND} meeting unauthorized contact." Both entries become `Contradicted`. Monologue fires. {THE FRIEND}'s `RelationshipState` → `PersonOfInterest`.
|
|
|
|
---
|
|
|
|
### Stale
|
|
|
|
**What it means**: Knowledge has aged beyond the stale threshold (default 3600 ticks = 6 game-hours).
|
|
|
|
**Effect on relationship**: Degrades confidence but doesn't change relationship state. A Friendly NPC remains Friendly, but positional knowledge becomes unreliable.
|
|
|
|
**Example**: Smuggler last saw {THE FRIEND} at the hub 7 hours ago. `last_known_position` becomes Stale. Monologue: "{THE FRIEND} should be off-shift by now. Probably at the bar, but I haven't seen them."
|
|
|
|
---
|
|
|
|
## Relationship State and Dialogue Selection
|
|
|
|
The dialogue system (D-028, D-035) uses `RelationshipState` as a filter:
|
|
|
|
| Dialogue `access` tag | Unknown | Known | Friendly | PersonOfInterest | Hostile |
|
|
|-----------------------|---------|-------|----------|------------------|---------|
|
|
| `public` | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
| `peer` | ✗ | ✓ | ✓ | ✗ | ✗ |
|
|
| `insider` | ✗ | ✗ | ✓ | ✗ | ✗ |
|
|
| `authority` | ✓ (if detective) | ✓ (if detective) | ✗ | ✓ (if detective) | ✗ |
|
|
| `hostile` | ✗ | ✗ | ✗ | ✗ | ✓ |
|
|
|
|
**Key insight**: `PersonOfInterest` **locks out peer and insider content**. When THE FRIEND transitions to PersonOfInterest, trust-gated dialogue disappears. The NPC becomes guarded. This is mechanically expressed through access-tier filtering.
|
|
|
|
---
|
|
|
|
## Monologue Tone Shifts per State
|
|
|
|
### Unknown → Known
|
|
|
|
- **Before**: "Who's that?"
|
|
- **After**: "That's the maintenance tech."
|
|
|
|
**Shift**: Identification. Observer now has context.
|
|
|
|
---
|
|
|
|
### Known → Friendly
|
|
|
|
- **Before**: "They're over there."
|
|
- **After**: "Good to see them. Always fixes things without making a fuss."
|
|
|
|
**Shift**: Warmth. Personal regard.
|
|
|
|
---
|
|
|
|
### Friendly → PersonOfInterest (THE FRIEND)
|
|
|
|
- **Before**: "There's {THE FRIEND}. Good — I was starting to worry."
|
|
- **After**: "{THE FRIEND}'s here. But they've been acting strange. What's going on?"
|
|
|
|
**Shift**: Doubt contaminates warmth. The fond observation is now analytical.
|
|
|
|
---
|
|
|
|
### PersonOfInterest → Hostile
|
|
|
|
- **Before**: "{THE FRIEND}'s avoiding me. Something's wrong."
|
|
- **After**: "{THE FRIEND} just signaled security. They've turned on me."
|
|
|
|
**Shift**: Assessment → alarm.
|
|
|
|
---
|
|
|
|
## Implementation Notes for Content Authors
|
|
|
|
- **Contradiction discovery** sets `EntityKnowledge.state = KnowledgeState::Contradicted` AND triggers `RelationshipState` transition if applicable.
|
|
- **Monologue lines** should reference `RelationshipState` in prerequisites:
|
|
```yaml
|
|
prerequisite:
|
|
relationship_state: PersonOfInterest
|
|
subject: {npc_id}
|
|
```
|
|
- **Dialogue lines** filter on `access` tier, which is derived from `RelationshipState` + character type (smuggler/detective/NPC role).
|
|
- **Color shifts** are client-side rendering, but the knowledge graph determines the state. Content authors write to the state; the client handles the color.
|
|
- **THE FRIEND arc** requires:
|
|
- Friendly baseline (relationship history)
|
|
- Observable contradiction (spatial deviation or behavioral pattern)
|
|
- `contradiction_flagged` attribute set
|
|
- Monologue shift (analytical doubt)
|
|
- Dialogue shift (confrontation options unlock, trust options lock)
|
|
- Resolution paths (multiple endings based on player choice)
|
|
|
|
---
|
|
|
|
**Total states**: 5. **Load-bearing transitions**: Unknown → Known (universal), Known/Friendly → PersonOfInterest (THE FRIEND), PersonOfInterest → Hostile (confrontation failure). Other transitions exist but are less structurally critical.
|