feat: New features (research, invest, gambling, new game+, trophies)

This commit is contained in:
gauvainboiche
2026-10-08 14:03:00 +02:00
parent 1caa4d92b9
commit fc0d5e3ba4
56 changed files with 4332 additions and 249 deletions
+51
View File
@@ -0,0 +1,51 @@
// Text helpers shared by the views: money, durations, effects and rewards.
import { t } from '../services/i18n.js';
/** Money in the theme's currency, e.g. "12.50 GAL". */
export const moneyFormatter = (fmt) => (n) => t('theme.fmt.funds', { value: fmt.money(n) });
export function formatDuration(seconds) {
const total = Math.max(0, Math.round(seconds));
const minutes = Math.floor(total / 60);
if (minutes < 1) return t('time.seconds', { value: total });
if (minutes < 60) return t('time.minutes', { value: minutes });
return t('time.hoursMinutes', { hours: Math.floor(minutes / 60), minutes: minutes % 60 });
}
/** "×1.5 production", "-20% generator cost"... from an effect object. */
export function effectText(effect, fmt) {
const params = { value: fmt.number(effect.value) };
if (effect.target) params.target = t(`theme.gen.${effect.target}.name`);
if (effect.type === 'batch_discount' || effect.type === 'generator_cost_mult') {
params.percent = fmt.number(Math.round((1 - effect.value) * 100));
}
if (effect.type === 'reliability_add' || effect.type === 'offline_add') {
params.percent = fmt.number(Math.round(effect.value * 100));
}
if (effect.type === 'start_funds') params.funds = moneyFormatter(fmt)(effect.value);
return t(`effect.${effect.type}`, params);
}
/** What a contract pays, e.g. "Reward: 1.2M GAL". */
export function rewardText(reward, fmt, seconds = 0) {
const money = moneyFormatter(fmt);
switch (reward.type) {
case 'funds':
return t('contracts.reward.funds', { amount: money(reward.amount) });
case 'boost':
return t('contracts.reward.boost', { value: fmt.number(reward.amount), duration: formatDuration(seconds) });
default: // research, chips
return t(`contracts.reward.${reward.type}`, { amount: fmt.number(reward.amount) });
}
}
export function setText(node, text) {
if (node.textContent !== text) node.textContent = text;
}
/** "+3.2%" / "-1.0%" */
export function signedPercent(fraction, fmt) {
const sign = fraction > 0 ? '+' : '';
return `${sign}${fmt.number(Math.round(fraction * 1000) / 10)}%`;
}