feat: More bonus (exponential) and method to list icons needed

This commit is contained in:
gauvainboiche
2026-10-08 14:20:58 +02:00
parent fc0d5e3ba4
commit a88b8f5f14
25 changed files with 977 additions and 40 deletions
+123
View File
@@ -0,0 +1,123 @@
// Endless upgrades: families of upgrades that continue forever, level after level.
import { endlessQuote, lineAvailable, lineLevel } from '../engine/endless.js';
import { t } from '../services/i18n.js';
import { h, icon } from './dom.js';
import { effectText, moneyFormatter, setText } from './text.js';
const AMOUNTS = [1, 10, 100, 'max'];
export function createEndlessView(root, actions) {
let ctx;
let fmt;
let money;
let amount = 1;
const rows = new Map();
const lineName = (line) =>
line.effect.target
? t('endless.name.generator', { target: t(`theme.gen.${line.effect.target}.name`) })
: t(`endless.name.${line.id}`);
function rowFor(line) {
const level = h('span', { class: 'badge' });
const total = h('p', { class: 'card__meta' });
const label = h('span', { class: 'btn__label' });
const cost = h('small');
const buy = h(
'button',
{ class: 'btn btn--buy', type: 'button', onclick: () => actions.buy(line.id, amount) },
label,
cost,
);
const li = h(
'li',
{ class: 'card', hidden: true },
icon(`endless.${line.id}`),
h(
'div',
{ class: 'card__body' },
h('h3', { class: 'card__title' }, h('span', { text: lineName(line) }), level),
h('p', { class: 'card__desc', text: t('endless.perLevel', { effect: effectText(line.effect, fmt) }) }),
total,
),
buy,
);
return { li, level, total, label, cost, buy, line };
}
function rebuild(newCtx, formatter) {
ctx = newCtx;
fmt = formatter;
money = moneyFormatter(fmt);
rows.clear();
const list = h('ul', { class: 'cards cards--grid' });
for (const line of ctx.endless) {
const row = rowFor(line);
rows.set(line.id, row);
list.append(row.li);
}
const amountGroup = h(
'fieldset',
{ class: 'segmented' },
h('legend', { class: 'sr-only', text: t('endless.amount') }),
...AMOUNTS.map((a) =>
h(
'label',
{},
h('input', {
type: 'radio',
name: 'endless-amount',
value: String(a),
checked: a === amount,
onchange: () => {
amount = a;
},
}),
h('span', { text: a === 'max' ? t('ui.max') : `×${a}` }),
),
),
);
root.replaceChildren(
h(
'div',
{ class: 'panel__head' },
h('h2', { class: 'panel__title', text: t('endless.title') }),
amountGroup,
),
h('p', { class: 'hint', text: t('endless.intro') }),
list,
);
}
function update(state) {
let any = false;
for (const { li, level, total, label, cost, buy, line } of rows.values()) {
const open = lineAvailable(state, line);
li.hidden = !open;
if (!open) continue;
any = true;
const lv = lineLevel(state, line.id);
const maxed = lv >= line.maxLevel;
let quote = endlessQuote(state, ctx, line.id, amount);
if (quote.count <= 0) quote = endlessQuote(state, ctx, line.id, 1);
setText(level, t('endless.level', { level: fmt.number(lv) }));
setText(
total,
lv > 0
? t('endless.total', { effect: effectText({ ...line.effect, value: line.effect.value ** lv }, fmt) })
: t('endless.none'),
);
setText(label, maxed ? t('endless.maxed') : t('endless.buy', { count: fmt.number(quote.count) }));
setText(cost, maxed ? '' : money(quote.cost));
buy.disabled = maxed || quote.count <= 0 || !(state.funds >= quote.cost);
}
root.hidden = !any;
}
return { rebuild, update };
}