feat: New theme + wire price adjustement

This commit is contained in:
gauvainboiche
2026-10-08 12:25:45 +02:00
parent aa9721ac2a
commit 1734487f1e
19 changed files with 348 additions and 88 deletions
+40 -20
View File
@@ -16,7 +16,15 @@ import { fetchLocales, fetchThemes, loadGameContext } from './services/data.js';
import { createFormatter } from './services/format.js';
import { applyTranslations, fetchThemeName, FALLBACK_LOCALE, loadDictionary, t } from './services/i18n.js';
import { buildExport, parseImport } from './services/saveio.js';
import { cookiesAvailable, loadGameText, loadPrefs, saveGameText, savePrefs, deleteGame } from './services/storage.js';
import {
cookiesAvailable,
deleteGame,
loadGameText,
loadPrefs,
saveGameText,
savePrefs,
takeLegacySaves,
} from './services/storage.js';
import { applyThemeStyles } from './services/themes.js';
import { $, refreshStaticIcons, setThemeAssets } from './ui/dom.js';
import { createSettings } from './ui/settings.js';
@@ -44,7 +52,7 @@ function persist() {
if (!state) return;
state.savedAt = Date.now();
try {
saveGameText(themeId, serializeState(state));
saveGameText(serializeState(state));
} catch {
if (Date.now() - lastSaveError > SAVE_ERROR_COOLDOWN_MS) {
lastSaveError = Date.now();
@@ -53,9 +61,7 @@ function persist() {
}
}
function loadSavedState() {
const text = loadGameText(themeId);
if (!text) return null;
function parseSaved(text) {
try {
return sanitizeState(JSON.parse(text), ctx);
} catch {
@@ -63,6 +69,19 @@ function loadSavedState() {
}
}
/**
* The shared game from cookies. Falls back to the per-theme saves of the first
* version: the most advanced one becomes the shared game, the others are dropped.
*/
function loadSavedState() {
const text = loadGameText();
if (text) return parseSaved(text);
const legacy = takeLegacySaves(themes.map((th) => th.id)).map(parseSaved).filter(Boolean);
legacy.sort((a, b) => b.totalProduced - a.totalProduced);
return legacy[0] ?? null;
}
function persistPrefs() {
savePrefs({ theme: themeId, lang: locale });
}
@@ -107,16 +126,13 @@ async function refreshTexts() {
await fillSelects();
}
async function enterTheme(id) {
persist(); // keep the theme we are leaving
/** Change the skin only: the game state is shared by every theme. */
async function setTheme(id) {
themeId = id;
await applyThemeStyles(id);
await refreshTexts();
state = loadSavedState() ?? createState(ctx);
income = 0;
catchUp((Date.now() - state.savedAt) / 1000);
persistPrefs();
render();
if (state) render();
}
// ------------------------------------------------------------------ the loop
@@ -181,18 +197,17 @@ const view = createView({
createSettings({
getExport: () => ({
text: buildExport(themeId, state),
name: `idle-clicker-${themeId}-${new Date().toISOString().slice(0, 10)}`,
text: buildExport(state),
name: `idle-clicker-${new Date().toISOString().slice(0, 10)}`,
}),
async importText(text) {
const imported = parseImport(text, ctx, themes.map((th) => th.id)); // throws before any change
if (imported.themeId !== themeId) await enterTheme(imported.themeId);
state = imported.state;
importText(text) {
state = parseImport(text, ctx); // throws before anything changes
income = 0;
persist();
render();
},
reset() {
deleteGame(themeId);
deleteGame();
state = createState(ctx);
income = 0;
persist();
@@ -216,7 +231,7 @@ async function boot() {
const initialTheme = themes.find((th) => th.id === prefs.theme) ?? themes[0];
$('#cookie-warning').hidden = cookiesAvailable();
$('#theme-select').addEventListener('change', (e) => enterTheme(e.target.value));
$('#theme-select').addEventListener('change', (e) => setTheme(e.target.value));
$('#locale-select').addEventListener('change', async (e) => {
locale = e.target.value;
persistPrefs();
@@ -224,9 +239,14 @@ async function boot() {
render();
});
await enterTheme(initialTheme.id);
await setTheme(initialTheme.id);
refreshStaticIcons();
state = loadSavedState() ?? createState(ctx);
catchUp((Date.now() - state.savedAt) / 1000);
persist();
render();
lastFrame = Date.now();
setInterval(frame, TICK_MS);
setInterval(persist, ctx.rules.autosaveSeconds * 1000);