diff --git a/docs/plans/2026-03-07-npc-stats-design.md b/docs/plans/2026-03-07-npc-stats-design.md new file mode 100644 index 0000000..24308b7 --- /dev/null +++ b/docs/plans/2026-03-07-npc-stats-design.md @@ -0,0 +1,133 @@ +# NPC Statistics System Design + +## Overview + +Add a two-tier stat system to NPCs: Physical stats (RPG-rooted) and Personality stats (emotion/behavior-driven). Stats use GURPS-style 3d6 generation (range 3-18, bell curve centered ~10.5). Stats influence needs decay rates, brain decisions, and social interaction outcomes. + +## Stat Definitions + +### Physical Stats (3d6, range 3-18) + +| Stat | Governs | +|------|---------| +| **Strength** | Carry capacity, physical task output, melee outcomes | +| **Dexterity** | Movement speed modifier, dodge/craft precision | +| **Constitution** | Needs decay rates (high = slower drain), recovery speed | +| **Intelligence** | Learning rate (baseline drift speed), task efficiency | +| **Perception** | Awareness radius for social detection, noticing events | + +### Personality Stats (3d6, range 3-18) + +| Stat | Governs | +|------|---------| +| **Sociability** | Likelihood of initiating social interactions, cooldown reduction | +| **Courage** | Willingness to explore unknown areas, resistance to fleeing | +| **Curiosity** | Tendency to wander far vs. stay near, goal variety | +| **Empathy** | Social outcome bias (positive), responsiveness to others' needs | +| **Temperament** | Emotional stability; high = calm, low = volatile. Scales transient modifier magnitude | + +## Data Model + +### Stats Component + +```typescript +export interface Stats { + // Physical + strength: number; + dexterity: number; + constitution: number; + intelligence: number; + perception: number; + // Personality + sociability: number; + courage: number; + curiosity: number; + empathy: number; + temperament: number; +} +``` + +### Transient Modifiers Component + +```typescript +export interface StatModifier { + stat: keyof Stats; + value: number; // additive (+/-) + remaining: number; // ticks remaining +} + +export interface StatModifiers { + modifiers: StatModifier[]; +} +``` + +**Effective stat** = base stat + sum of active modifiers, clamped to 3-18. + +### Generation + +Roll 3d6 per stat at spawn. Pure bell curve, no rerolls or point-buy. + +### Baseline Drift + +- Base stats stored as floats internally, floored to integer for effective value +- Stat-relevant events shift base by tiny amounts (e.g., +0.05) +- Drift capped to 3-18 range +- Noticeable over hundreds of interactions, not minutes + +### Wire Protocol + +Stats sent as part of `EntityState` as effective (computed) integer values. Modifiers stay server-side only. + +## System Integration + +### New System: `statModifierSystem` + +Runs each tick **before** needsDecay. System order becomes: + +`statModifier` -> `needsDecay` -> `npcBrain` -> `social` -> `movement` -> `broadcast` + +Responsibilities per tick: +1. Decay modifiers (decrement `remaining`, remove expired) +2. Apply needs-based modifiers (replace, not stack) +3. Provide `getEffectiveStat()` helper for other systems + +### Needs Decay (Constitution) + +``` +effectiveDecay = BASE_DECAY * (1 - (constitution - 10) * 0.03) +``` + +CON 14 = 12% slower decay. CON 6 = 12% faster. CON 10 = unchanged. + +### NPC Brain (Curiosity, Courage) + +- **Curiosity** influences wander target selection (high = farther/more varied destinations) +- **Courage** is a future hook for threat response (no immediate behavior change) + +### Social System (Sociability, Empathy, Perception, Temperament) + +- **Perception** modifies awareness radius: `AWARENESS_RADIUS + (perception - 10)` +- **Sociability** modifies global cooldown: `SOCIAL_GLOBAL_COOLDOWN * (1 - (sociability - 10) * 0.04)` +- **Empathy** biases outcomes: `positiveChance = 0.5 + (empathy - 10) * 0.03` +- **Temperament** scales modifier magnitude: `modifierValue * (1 + (10 - temperament) * 0.05)` + +### Modifier Sources + +**Needs-based (ongoing, replaced each tick):** +- Low hunger (<30): Intelligence -2, Sociability -1 +- Low energy (<20): Dexterity -2, Temperament -2 + +**Event-based (decaying):** +- Positive social outcome: Sociability +1 for 100 ticks +- Negative social outcome: Sociability -1, Empathy -1 for 100 ticks + +### Baseline Drift Triggers + +- Successful social interaction: Sociability +0.05, Empathy +0.05 +- Negative social interaction: Temperament +0.02 +- Long wander completed: Curiosity +0.03, Courage +0.02 +- Eating/resting: Constitution +0.01 + +## UI + +Stats displayed numerically in the NpcInfoPanel alongside existing needs bars. Future iteration will move to descriptive labels (e.g., "Strong", "Shy").