feat: New theme + wire price adjustement
This commit is contained in:
+40
-20
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user