// Achievements tab: milestones with a small permanent bonus each. import { statValue } from '../engine/achievements.js'; import { t } from '../services/i18n.js'; import { h, icon } from './dom.js'; import { effectText, setText } from './text.js'; export function createAchievementsView(root) { let ctx; let fmt; let summary; const rows = new Map(); function rebuild(newCtx, formatter) { ctx = newCtx; fmt = formatter; rows.clear(); summary = h('p', { class: 'hint' }); const list = h('ul', { class: 'cards cards--grid' }); for (const a of ctx.achievements) { const progress = h('p', { class: 'card__meta' }); const li = h( 'li', { class: 'card' }, icon(`ach.${a.id}`), h( 'div', { class: 'card__body' }, h('h3', { class: 'card__title', text: t(`ach.title.${a.id}`) }), h('p', { class: 'card__desc', text: t(`ach.cond.${a.condition.stat}`, { value: fmt.number(a.condition.min) }) }), h('p', { class: 'card__meta', text: effectText(a.effect, fmt) }), progress, ), ); list.append(li); rows.set(a.id, { a, li, progress }); } root.replaceChildren( h('section', { class: 'panel panel--wide' }, h('h2', { class: 'panel__title', text: t('tab.achievements') }), summary, list), ); } function update(state) { const bonus = state.achievements.reduce((product, id) => product * ctx.achievementsById.get(id).effect.value, 1); setText(summary, t('ach.summary', { done: state.achievements.length, total: ctx.achievements.length, bonus: fmt.number(bonus) })); for (const { a, li, progress } of rows.values()) { const done = state.achievements.includes(a.id); li.classList.toggle('card--done', done); li.classList.toggle('card--locked', !done); const value = Math.min(statValue(state, a.condition.stat), a.condition.min); setText(progress, done ? t('ach.done') : `${fmt.number(Math.floor(value))} / ${fmt.number(a.condition.min)}`); } } return { rebuild, update }; }