feat: add ring emoji for proposals and partner bond display

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-03-07 19:36:37 +00:00
parent 03f837f95f
commit 61e37bd2db
2 changed files with 21 additions and 12 deletions
+11 -4
View File
@@ -2,6 +2,7 @@ import type { EntityState } from '@dflike/shared';
const EMOJI_POSITIVE = '\u{1F60A}';
const EMOJI_NEGATIVE = '\u{1F620}';
const EMOJI_PROPOSAL = '\u{1F48D}';
export class InteractionEmojiManager {
private activeEmojis: Map<number, HTMLDivElement> = new Map();
@@ -18,10 +19,10 @@ export class InteractionEmojiManager {
const emoting = new Set<number>();
for (const entity of entities) {
if (entity.socialState?.phase === 'emoting' && entity.socialState.outcome) {
if ((entity.socialState?.phase === 'emoting' || entity.socialState?.phase === 'proposing') && entity.socialState.outcome) {
emoting.add(entity.id);
if (!this.activeEmojis.has(entity.id)) {
this.createEmoji(entity.id, entity.socialState.outcome);
this.createEmoji(entity.id, entity.socialState.outcome, entity.socialState.phase);
}
}
}
@@ -37,7 +38,7 @@ export class InteractionEmojiManager {
}
}
private createEmoji(entityId: number, outcome: string): void {
private createEmoji(entityId: number, outcome: string, phase?: string): void {
const div = document.createElement('div');
div.style.cssText = `
position: fixed;
@@ -47,7 +48,13 @@ export class InteractionEmojiManager {
transform: translate(-50%, -100%);
`;
div.style.animation = 'emoji-float 2s ease-out forwards';
div.textContent = outcome === 'positive' ? EMOJI_POSITIVE : EMOJI_NEGATIVE;
let emoji: string;
if (phase === 'proposing') {
emoji = EMOJI_PROPOSAL;
} else {
emoji = outcome === 'positive' ? EMOJI_POSITIVE : EMOJI_NEGATIVE;
}
div.textContent = emoji;
// Self-cleanup when animation completes
div.addEventListener('animationend', () => {
+10 -8
View File
@@ -483,7 +483,7 @@ export class NpcInfoPanel {
return;
}
const tierOrder = ['Partner', 'Close Friend', 'Friend', 'Acquaintance', 'Stranger', 'Wary', 'Rival', 'Enemy', 'Nemesis'];
const tierOrder = ['Partner', 'Devoted', 'Close Friend', 'Friend', 'Acquaintance', 'Stranger', 'Wary', 'Rival', 'Enemy', 'Nemesis'];
const groups = new Map<string, typeof relationships>();
const memories: typeof relationships = [];
@@ -500,7 +500,7 @@ export class NpcInfoPanel {
this.relationshipsContent.innerHTML = '';
const tierIcons: Record<string, string> = {
'Partner': '\u2665', 'Close Friend': '\u2605', 'Friend': '\u25C6',
'Partner': '\u2665', 'Devoted': '\u2764', 'Close Friend': '\u2605', 'Friend': '\u25C6',
'Acquaintance': '\u25CB', 'Stranger': '\u00B7',
'Wary': '\u25B2', 'Rival': '\u2716', 'Enemy': '\u2620', 'Nemesis': '\u2620',
};
@@ -525,7 +525,7 @@ export class NpcInfoPanel {
tierEl.appendChild(tierLabel);
for (const rel of shown) {
tierEl.appendChild(this.createRelSlider(rel.name, rel.value, tier));
tierEl.appendChild(this.createRelSlider(rel.name, rel.value, tier, rel.bond));
}
if (hidden.length > 0) {
@@ -533,7 +533,7 @@ export class NpcInfoPanel {
const overflow = document.createElement('div');
overflow.style.cssText = isExpanded ? '' : 'display: none;';
for (const rel of hidden) {
overflow.appendChild(this.createRelSlider(rel.name, rel.value, tier));
overflow.appendChild(this.createRelSlider(rel.name, rel.value, tier, rel.bond));
}
tierEl.appendChild(overflow);
@@ -579,7 +579,7 @@ export class NpcInfoPanel {
const memHidden = memories.slice(2);
for (const rel of memShown) {
memEl.appendChild(this.createRelSlider(rel.name + ' \u2020', rel.value, 'memory'));
memEl.appendChild(this.createRelSlider(rel.name + ' \u2020', rel.value, 'memory', rel.bond));
}
if (memHidden.length > 0) {
@@ -588,7 +588,7 @@ export class NpcInfoPanel {
const overflow = document.createElement('div');
overflow.style.cssText = isExpanded ? '' : 'display: none;';
for (const rel of memHidden) {
overflow.appendChild(this.createRelSlider(rel.name + ' \u2020', rel.value, 'memory'));
overflow.appendChild(this.createRelSlider(rel.name + ' \u2020', rel.value, 'memory', rel.bond));
}
memEl.appendChild(overflow);
@@ -623,7 +623,7 @@ export class NpcInfoPanel {
}
}
private createRelSlider(name: string, value: number, tier: string): HTMLDivElement {
private createRelSlider(name: string, value: number, tier: string, bond?: string | null): HTMLDivElement {
const row = document.createElement('div');
row.style.cssText = `
display: flex;
@@ -635,7 +635,8 @@ export class NpcInfoPanel {
const nameEl = document.createElement('span');
nameEl.style.cssText = `color: ${EB.textPrimary}; min-width: 70px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;`;
nameEl.textContent = name;
const bondIcon = bond === 'partner' ? ' \u{1F48D}' : bond === 'former_partner' ? ' \u{1F48D}\u{FE0E}' : '';
nameEl.textContent = name + bondIcon;
const slider = document.createElement('div');
slider.style.cssText = `
@@ -682,6 +683,7 @@ export class NpcInfoPanel {
private getRelColor(tier: string): string {
switch (tier) {
case 'Partner': return '#ff69b4';
case 'Devoted': return '#ff69b4';
case 'Close Friend': return '#58d858';
case 'Friend': return '#40b840';
case 'Acquaintance': return '#6868a8';