import Phaser from 'phaser'; import type { DoorDressCodeRule } from '../../rules/dressCode'; import { DOOR_UI } from '../../data/strings/door'; import { DOOR_PALETTE, MONO, panel, text } from './ui'; // The laminated card on the desk. Rules land the moment Dazza's text arrives // (design §3.1), so the NEW badge is the only warning the player gets that the // punter they are already looking at just became a violation. const NEW_BADGE_MS = 12_000; interface Row { rule: DoorDressCodeRule; label: Phaser.GameObjects.Text; badge: Phaser.GameObjects.Text; addedAt: number; } export class DressCodeCard { private readonly root: Phaser.GameObjects.Container; private readonly emptyText: Phaser.GameObjects.Text; private readonly rows: Row[] = []; private readonly x: number; private readonly y: number; constructor(scene: Phaser.Scene, x: number, y: number, w: number, h: number) { this.x = x; this.y = y; this.root = scene.add.container(0, 0).setDepth(50); this.root.add(panel(scene, x, y, w, h, 0x1a2018, 0x3c4a38)); this.root.add(text(scene, x + 5, y + 4, DOOR_UI.dressCode, 8, '#c8d8b0')); this.root.add(scene.add.rectangle(x + w / 2, y + 15, w - 8, 1, 0x3c4a38)); this.emptyText = text(scene, x + 5, y + 21, DOOR_UI.dressCodeEmpty, 7, DOOR_PALETTE.inkDim); this.root.add(this.emptyText); } add(scene: Phaser.Scene, rule: DoorDressCodeRule, nowMs: number): void { if (this.rows.some((r) => r.rule.id === rule.id)) return; this.emptyText.setVisible(false); const y = this.y + 20 + this.rows.length * 11; const label = scene.add.text(this.x + 5, y, `· ${rule.short}`, { fontFamily: MONO, fontSize: '7px', color: '#e0e8c8', wordWrap: { width: 150 }, }); const badge = scene.add.text(this.x + 5, y, 'NEW', { fontFamily: MONO, fontSize: '7px', color: '#ffd050', }); badge.x = this.x + 5 + label.width + 4; this.root.add([label, badge]); // A flash on arrival — the card is peripheral vision, it has to shout once. scene.tweens.add({ targets: badge, alpha: { from: 1, to: 0.25 }, duration: 400, yoyo: true, repeat: 8 }); this.rows.push({ rule, label, badge, addedAt: nowMs }); } /** Highlight the rules the patron currently in front of you is breaking. */ highlight(violatedIds: readonly string[]): void { for (const r of this.rows) { const hit = violatedIds.includes(r.rule.id); r.label.setColor(hit ? '#ff9090' : '#e0e8c8'); } } update(nowMs: number): void { for (const r of this.rows) { if (r.badge.visible && nowMs - r.addedAt > NEW_BADGE_MS) r.badge.setVisible(false); } } destroy(): void { this.root.destroy(); } }