feat: display NPC stats in info panel with EarthBound styling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,8 @@ export class NpcInfoPanel {
|
||||
private separatorEl: HTMLDivElement;
|
||||
private needsBarsContainer: HTMLDivElement;
|
||||
private needsBars: Map<string, { wrapper: HTMLDivElement; fill: HTMLDivElement; valueEl: HTMLDivElement }> = new Map();
|
||||
private statsContainer: HTMLDivElement;
|
||||
private statElements: Map<string, HTMLDivElement> = new Map();
|
||||
private visible = false;
|
||||
|
||||
constructor() {
|
||||
@@ -119,8 +121,8 @@ export class NpcInfoPanel {
|
||||
|
||||
this.portraitImg = document.createElement('img');
|
||||
this.portraitImg.style.cssText = `
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
width: 192px;
|
||||
height: 192px;
|
||||
image-rendering: pixelated;
|
||||
display: block;
|
||||
opacity: 1;
|
||||
@@ -188,6 +190,29 @@ export class NpcInfoPanel {
|
||||
`;
|
||||
infoSection.appendChild(this.needsBarsContainer);
|
||||
|
||||
// Stats separator
|
||||
const statsSeparator = document.createElement('div');
|
||||
statsSeparator.style.cssText = `
|
||||
text-align: center;
|
||||
font-size: 5px;
|
||||
color: ${EB.textMuted};
|
||||
padding: 4px 0;
|
||||
letter-spacing: 6px;
|
||||
user-select: none;
|
||||
`;
|
||||
statsSeparator.textContent = '\u25C6\u25C6\u25C6';
|
||||
infoSection.appendChild(statsSeparator);
|
||||
|
||||
// Stats container - two columns
|
||||
this.statsContainer = document.createElement('div');
|
||||
this.statsContainer.style.cssText = `
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3px 8px;
|
||||
font-family: 'Press Start 2P', monospace;
|
||||
`;
|
||||
infoSection.appendChild(this.statsContainer);
|
||||
|
||||
this.container.appendChild(infoSection);
|
||||
this.outerFrame.appendChild(this.container);
|
||||
document.body.appendChild(this.outerFrame);
|
||||
@@ -219,6 +244,10 @@ export class NpcInfoPanel {
|
||||
if (entity.needs) {
|
||||
this.updateNeeds(entity.needs);
|
||||
}
|
||||
|
||||
if (entity.stats) {
|
||||
this.updateStats(entity.stats);
|
||||
}
|
||||
}
|
||||
|
||||
updateNeeds(needs: { hunger: number; energy: number }): void {
|
||||
@@ -322,6 +351,45 @@ export class NpcInfoPanel {
|
||||
}
|
||||
}
|
||||
|
||||
updateStats(stats: Record<string, number>): void {
|
||||
const physicalKeys = ['STR', 'DEX', 'CON', 'INT', 'PER'];
|
||||
const personalityKeys = ['SOC', 'COU', 'CUR', 'EMP', 'TMP'];
|
||||
const mapping: Record<string, string> = {
|
||||
STR: 'strength', DEX: 'dexterity', CON: 'constitution', INT: 'intelligence', PER: 'perception',
|
||||
SOC: 'sociability', COU: 'courage', CUR: 'curiosity', EMP: 'empathy', TMP: 'temperament',
|
||||
};
|
||||
for (const key of [...physicalKeys, ...personalityKeys]) {
|
||||
const value = stats[mapping[key]];
|
||||
if (value !== undefined) {
|
||||
this.setStatDisplay(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private setStatDisplay(label: string, value: number): void {
|
||||
let el = this.statElements.get(label);
|
||||
if (!el) {
|
||||
el = document.createElement('div');
|
||||
el.style.cssText = `
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 6px;
|
||||
`;
|
||||
const labelEl = document.createElement('span');
|
||||
labelEl.style.cssText = `color: ${EB.textSecondary}; text-transform: uppercase; letter-spacing: 0.5px;`;
|
||||
labelEl.textContent = label;
|
||||
const valueEl = document.createElement('span');
|
||||
valueEl.style.cssText = `color: ${EB.textPrimary}; text-shadow: 1px 1px 0 rgba(0,0,0,0.5);`;
|
||||
valueEl.dataset.role = 'value';
|
||||
el.appendChild(labelEl);
|
||||
el.appendChild(valueEl);
|
||||
this.statsContainer.appendChild(el);
|
||||
this.statElements.set(label, el);
|
||||
}
|
||||
const valueEl = el.querySelector('[data-role="value"]') as HTMLSpanElement;
|
||||
valueEl.textContent = String(value);
|
||||
}
|
||||
|
||||
isVisible(): boolean {
|
||||
return this.visible;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user