// „🎨 Realm“: Aussehen wählen (Farbe, Volk, Thema, Banner). Gesperrtes zeigt seine Bedingung – das lockt zum // Wiederkommen. Gespeichert wird in Redis (localStorage leert Devvit bei jedem App-Update). import {showLoginPrompt} from '@devvit/web/client' import {spriteUrl} from '../engine/app/board/atlas.ts' import { bannerPreview, pieceSpriteName, setBoardBanners, setBoardLook, setBoardTheme, } from '../engine/app/board/BoardView.ts' import {TEAM_HEX} from '../engine/core/avatars.ts' import {Endpoint, type SetLookRsp} from '../shared/api.ts' import { BANNER_OPTIONS, COLORS, FACTION_OPTIONS, isUnlocked, type Look, type Progress, THEME_OPTIONS, type Unlock, unlockText, } from '../shared/look.ts' import {h} from './dom.ts' /** Aussehen auf alle Bretter anwenden (vor setBoard/update aufrufen) */ export function applyLook(look: Look): void { setBoardTheme(look.theme) setBoardBanners([look.banner, look.banner]) setBoardLook([look.color, look.color], [look.faction, look.faction]) } const NAMES: Record = { red: 'Red', cyan: 'Cyan', lime: 'Green', purple: 'Purple', kingdom: 'Kingdom', orc: 'Orcs', pirate: 'Pirates', classic: 'Classic', autumn: 'Autumn', winter: 'Winter', night: 'Night', winterfest: 'Winterfest', pennant: 'Pennant', swallowtail: 'Swallowtail', hanging: 'Hanging', stripe: 'Stripe', cross: 'Cross', star: 'Star', crown: 'Crown', snowflake: 'Snowflake', } function img(src: string): HTMLImageElement { const el = h('img.realm-img') el.src = src el.alt = '' return el } function themeTile(theme: string): HTMLImageElement { return img( theme === 'classic' ? spriteUrl('grass0') : `/sprites/themes/${theme}/grass0.png`, ) } export function openRealm(opts: { look: Look progress: Progress day: string loggedIn: boolean onChange: (look: Look) => void }): void { let look = opts.look const body = h('div.realm-rows') const close = h('button.primary', 'Done') const overlay = h( 'div.overlay', h( 'div.panel.realm', h('h2', 'Your realm'), h( 'p.muted.small', opts.loggedIn ? 'Play daily to unlock more: themes come with your streak, banners and peoples with your stars.' : 'Log in to customise your realm and keep your unlocks.', ), body, h('div.row.end', close), ), ) close.addEventListener('click', () => overlay.remove()) const row = ( title: string, options: readonly {id: T; unlock: Unlock}[], key: keyof Look, preview: (id: T) => Node, ) => { const items = h('div.realm-items') for (const o of options) { const open = isUnlocked(o.unlock, opts.progress, opts.day) const btn = h( 'button.realm-item', preview(o.id), h('span.realm-name', NAMES[o.id] ?? o.id), open ? null : h('span.realm-lock', `🔒 ${unlockText(o.unlock)}`), ) btn.classList.toggle('selected', look[key] === o.id) btn.classList.toggle('locked', !open) btn.disabled = !open btn.addEventListener('click', () => void choose({...look, [key]: o.id})) items.append(btn) } return h('section.realm-row', h('h3', title), items) } const render = () => { body.replaceChildren( row('Colour', COLORS, 'color', c => img(spriteUrl(pieceSpriteName('HIVEMOTHER', c, look.faction))), ), row('People', FACTION_OPTIONS, 'faction', f => img(spriteUrl(pieceSpriteName('HIVEMOTHER', look.color, f))), ), row('Board', THEME_OPTIONS, 'theme', t => themeTile(t)), row('Banner', BANNER_OPTIONS, 'banner', b => bannerPreview(b, TEAM_HEX[look.color]), ), ) } async function choose(next: Look): Promise { if (!opts.loggedIn) { showLoginPrompt() return } look = next render() try { const rsp = await fetch(Endpoint.SetLook, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify({look: next}), }) if (rsp.ok) look = ((await rsp.json()) as SetLookRsp).look } catch { // offline o. Ä.: Auswahl gilt bis zum Neuladen } render() opts.onChange(look) } render() document.body.append(overlay) }