feat: display NPC desires in info panel
Shows category-colored diamond bullets for active desires and placeholder slots in the Status tab, between backstory and thoughts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { EntityState, NarrationEvent, MemoryEvent, Stats, StatName } from '@dflike/shared';
|
||||
import type { EntityState, NarrationEvent, MemoryEvent, Stats, StatName, DesireCategory } from '@dflike/shared';
|
||||
import { attachTooltip } from './tooltip.js';
|
||||
|
||||
const ACTIVITY_LABELS: Record<string, string> = {
|
||||
@@ -32,6 +32,18 @@ const EB = {
|
||||
shine: 'rgba(200,200,255,0.08)', // Subtle window shine
|
||||
};
|
||||
|
||||
function desireCategoryColor(category: string): string {
|
||||
switch (category) {
|
||||
case 'material': return '#d4a574';
|
||||
case 'shelter': return '#c4956a';
|
||||
case 'comfort': return '#e8b87a';
|
||||
case 'social': return '#7ab8e8';
|
||||
case 'community': return '#7ae8a0';
|
||||
case 'creative': return '#c87ae8';
|
||||
default: return '#9898d0';
|
||||
}
|
||||
}
|
||||
|
||||
const STAT_FULL_NAMES: Record<string, string> = {
|
||||
STR: 'Strength', DEX: 'Dexterity', CON: 'Constitution', INT: 'Intelligence', PER: 'Perception',
|
||||
SOC: 'Sociability', COU: 'Courage', CUR: 'Curiosity', EMP: 'Empathy', TMP: 'Temperament',
|
||||
@@ -48,6 +60,7 @@ export class NpcInfoPanel {
|
||||
private needsBarsContainer: HTMLDivElement;
|
||||
private needsBars: Map<string, { wrapper: HTMLDivElement; fill: HTMLDivElement; valueEl: HTMLDivElement }> = new Map();
|
||||
private backstoryEl: HTMLDivElement;
|
||||
private desiresEl: HTMLDivElement;
|
||||
private statsContainer: HTMLDivElement;
|
||||
private statElements: Map<string, HTMLDivElement> = new Map();
|
||||
private statusTab!: HTMLDivElement;
|
||||
@@ -265,6 +278,16 @@ export class NpcInfoPanel {
|
||||
`;
|
||||
this.statusContent.appendChild(this.backstoryEl);
|
||||
|
||||
// Desires section
|
||||
this.desiresEl = document.createElement('div');
|
||||
this.desiresEl.style.cssText = `
|
||||
padding: 4px 8px;
|
||||
font-family: 'Press Start 2P', monospace;
|
||||
font-size: 10px;
|
||||
line-height: 1.8;
|
||||
`;
|
||||
this.statusContent.appendChild(this.desiresEl);
|
||||
|
||||
// Inner thought (italic first-person, shown above recent events)
|
||||
this.thoughtEl = document.createElement('div');
|
||||
this.thoughtEl.style.cssText = `
|
||||
@@ -441,6 +464,25 @@ export class NpcInfoPanel {
|
||||
this.backstoryEl.style.minHeight = '0';
|
||||
}
|
||||
|
||||
// Update desires
|
||||
const desires = entity.desires;
|
||||
if (desires && desires.length > 0) {
|
||||
let html = `<div style="color: ${EB.textMuted}; font-size: 9px; margin-bottom: 2px;">Desires</div>`;
|
||||
for (const desire of desires) {
|
||||
const color = desireCategoryColor(desire.category);
|
||||
html += `<div style="color: ${color}; padding: 1px 0;">◆ ${desire.description}</div>`;
|
||||
}
|
||||
const empty = 3 - desires.length;
|
||||
for (let i = 0; i < empty; i++) {
|
||||
html += `<div style="color: ${EB.textMuted}; font-style: italic; padding: 1px 0;">○ (daydreaming...)</div>`;
|
||||
}
|
||||
this.desiresEl.innerHTML = html;
|
||||
this.desiresEl.style.display = 'block';
|
||||
} else {
|
||||
this.desiresEl.innerHTML = `<div style="color: ${EB.textMuted}; font-size: 9px;">Content for now.</div>`;
|
||||
this.desiresEl.style.display = 'block';
|
||||
}
|
||||
|
||||
if (entity.needs) {
|
||||
this.updateNeeds(entity.needs);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user