modified: index.html

modified:   js/config.js
	modified:   js/game.js
	modified:   js/ui.js
	modified:   style.css
This commit is contained in:
xbl
2026-02-15 02:45:20 +01:00
parent d744e59401
commit a1fd271811
5 changed files with 110 additions and 104 deletions

View File

@ -40,13 +40,12 @@ a1.7 1.7 0 0 0-1.5 1z"></path>
<div id="settings-menu">
<div class="menu-subtitle">Hoel</div>
<div class="menu-text">This game uses cookies to save your progress across sessions. By using this website, you consent to storing cookies on your device.</div>
<div class="menu-text">The game periodically sends pseudonymous information about your session to the server to populate the neighbour chart.</div>
<div class="menu-text">The game periodically sends anonymous information about your session to the server to populate the neighbour chart.</div>
<div class="menu-text">Sessions are hidden from the chart after 5 days and deleted from the database after 30 days of inactivity.</div>
<div class="menu-divider"></div>
<div class="menu-subtitle">Session Reset</div>
<div class="menu-text">Terminate progress, purge registers, annihilate archives, unweave circuits, shatter syntax, invert polarity, nullify existence, restart systems, initialize framework.</div>
<button id="reset-btn" class="menu-btn danger">Reset</button>
<div id="save-status" style="margin-top: 12px; font-size: 10px; color: rgba(100, 200, 100, 0.6);"></div>
<div class="menu-divider"></div>
<div class="menu-subtitle">Session Transfer</div>
<div class="menu-text">Duplicate progress, start migration, redirect access, shift registry, authorize device, clone instance, restore snapshot, deploy replica, mount payload, fuse endpoints.</div>

View File

@ -21,7 +21,7 @@ var CONFIG = {
BASE_PLANET_SPAWN_INTERVAL: 3600000, // 1 hour
BASE_GIANT_SPAWN_INTERVAL: 21600000, // 6 hours
BASE_MTYPE_SPAWN_INTERVAL: 86400000, // 1 day
BASE_KTYPE_SPAWN_INTERVAL: 259200000, // 3 days
BASE_KTYPE_SPAWN_INTERVAL: 172800000, // 2 days
// Rate tracking windows (in milliseconds)
RATE_WINDOWS: {

View File

@ -151,104 +151,95 @@ var Game = (function() {
function loadGameState() {
Server.loadGameState().then(function(savedState) {
if (savedState) {
state.blackHoleTotalMass = savedState.blackHoleTotalMass;
// Restore only what cannot be derived
state.blackHoleTotalMass = savedState.blackHoleTotalMass;
state.totalMassConsumedEver = savedState.totalMassConsumedEver;
state.totalMassConsumed = savedState.totalMassConsumed;
state.asteroidUpgradeLevel = savedState.asteroidUpgradeLevel;
state.asteroidUpgradeCost = savedState.asteroidUpgradeCost;
state.cometUpgradeLevel = savedState.cometUpgradeLevel;
state.cometUpgradeCost = savedState.cometUpgradeCost;
state.planetUpgradeLevel = savedState.planetUpgradeLevel;
state.planetUpgradeCost = savedState.planetUpgradeCost;
state.giantUpgradeLevel = savedState.giantUpgradeLevel;
state.giantUpgradeCost = savedState.giantUpgradeCost;
state.mtypeUpgradeLevel = savedState.mtypeUpgradeLevel || 0;
state.ktypeUpgradeLevel = savedState.ktypeUpgradeLevel || 0;
state.mtypeUpgradeCost = savedState.mtypeUpgradeCost || CONFIG.MTYPE_BASE_COST;
state.ktypeUpgradeCost = savedState.ktypeUpgradeCost || CONFIG.KTYPE_BASE_COST;
state.asteroidSpawnCount = savedState.asteroidSpawnCount;
state.totalMassConsumed = savedState.totalMassConsumed;
state.asteroidSpawnCount = savedState.asteroidSpawnCount;
// Load unlock states (with backward compatibility)
state.cometUnlocked = savedState.cometUnlocked !== undefined ? savedState.cometUnlocked : (savedState.asteroidUpgradeLevel >= 20);
state.planetUnlocked = savedState.planetUnlocked !== undefined ? savedState.planetUnlocked : (savedState.cometUpgradeLevel >= 15);
state.giantUnlocked = savedState.giantUnlocked !== undefined ? savedState.giantUnlocked : (savedState.planetUpgradeLevel >= 10);
state.mtypeUnlocked = savedState.mtypeUnlocked !== undefined ? savedState.mtypeUnlocked : (savedState.giantUpgradeLevel >= 5);
state.ktypeUnlocked = savedState.ktypeUnlocked !== undefined ? savedState.ktypeUnlocked : (savedState.mtypeUpgradeLevel >= 5);
// Upgrade levels — the only upgrade data we store
state.asteroidUpgradeLevel = savedState.asteroidUpgradeLevel || 0;
state.cometUpgradeLevel = savedState.cometUpgradeLevel || 0;
state.planetUpgradeLevel = savedState.planetUpgradeLevel || 0;
state.giantUpgradeLevel = savedState.giantUpgradeLevel || 0;
state.mtypeUpgradeLevel = savedState.mtypeUpgradeLevel || 0;
state.ktypeUpgradeLevel = savedState.ktypeUpgradeLevel || 0;
// Derive unlock states from levels
state.cometUnlocked = state.asteroidUpgradeLevel >= 20;
state.planetUnlocked = state.cometUpgradeLevel >= 15;
state.giantUnlocked = state.planetUpgradeLevel >= 10;
state.mtypeUnlocked = state.giantUpgradeLevel >= 5;
state.ktypeUnlocked = state.mtypeUpgradeLevel >= 5;
// Derive costs and intervals from levels + CONFIG
recalculateUpgradeCosts();
updateSpawnIntervals();
// Spawn timestamps
state.lastAsteroidSpawn = savedState.lastAsteroidSpawn || Date.now();
state.lastCometSpawn = savedState.lastCometSpawn || Date.now();
state.lastPlanetSpawn = savedState.lastPlanetSpawn || Date.now();
state.lastGiantSpawn = savedState.lastGiantSpawn || Date.now();
state.lastMtypeSpawn = savedState.lastMtypeSpawn || Date.now();
state.lastKtypeSpawn = savedState.lastKtypeSpawn || Date.now();
state.lastCometSpawn = savedState.lastCometSpawn || Date.now();
state.lastPlanetSpawn = savedState.lastPlanetSpawn || Date.now();
state.lastGiantSpawn = savedState.lastGiantSpawn || Date.now();
state.lastMtypeSpawn = savedState.lastMtypeSpawn || Date.now();
state.lastKtypeSpawn = savedState.lastKtypeSpawn || Date.now();
// Load consumption rates
// Consumption rates
state.sM = savedState.sM || 0;
state.mM = savedState.mM || 0;
state.lM = savedState.lM || 0;
var now = Date.now();
state.sT = savedState.sT || now;
state.mT = savedState.mT || now;
state.lT = savedState.lT || now;
state.rateShort = savedState.rateShort || 0;
state.rateShort = savedState.rateShort || 0;
state.rateShortTrend = savedState.rateShortTrend || 'same';
state.rateMedium = savedState.rateMedium || 0;
state.rateLong = savedState.rateLong || 0;
state.rateMedium = savedState.rateMedium || 0;
state.rateLong = savedState.rateLong || 0;
state.tabHiddenAt = savedState.tabHiddenAt || null;
state.tabHiddenAt = savedState.tabHiddenAt || null;
// Calculate offline progression ONLY if tab was actually hidden
var offlineTime = 0;
// Offline progression
var offlineTime = 0;
if (savedState.tabHiddenAt) {
offlineTime = now - savedState.tabHiddenAt;
}
if (savedState.tabHiddenAt) {
// Tab was hidden - calculate time between hiding and now
offlineTime = now - savedState.tabHiddenAt;
}
if (offlineTime > 1000) {
var rateToUse = 0;
if (state.rateLong > 0 && (now - state.lT) > 3600000) {
rateToUse = state.rateLong;
} else if (state.rateMedium > 0 && (now - state.mT) > 300000) {
rateToUse = state.rateMedium;
} else {
rateToUse = state.rateShort || 0;
}
if (offlineTime > 1000) {
var rateToUse = 0;
if (rateToUse > 0) {
var offlineMass = rateToUse * (offlineTime / 1000);
state.blackHoleTotalMass += offlineMass;
state.totalMassConsumedEver += offlineMass;
state.totalMassConsumed += offlineMass;
state.sM += offlineMass;
state.mM += offlineMass;
state.lM += offlineMass;
showOfflineNotification(
formatOfflineTime(offlineTime),
UI.formatMass(offlineMass),
'offline'
);
}
}
if (state.rateLong > 0 && (now - state.lT) > 3600000) {
rateToUse = state.rateLong;
} else if (state.rateMedium > 0 && (now - state.mT) > 300000) {
rateToUse = state.rateMedium;
} else {
rateToUse = state.rateShort || 0;
}
if (rateToUse > 0) {
var offlineMass = rateToUse * (offlineTime / 1000);
state.blackHoleTotalMass += offlineMass;
state.totalMassConsumedEver += offlineMass;
state.totalMassConsumed += offlineMass;
state.sM += offlineMass;
state.mM += offlineMass;
state.lM += offlineMass;
showOfflineNotification(
formatOfflineTime(offlineTime),
UI.formatMass(offlineMass),
'offline'
);
}
}
// Clear the hidden timestamp after processing
state.tabHiddenAt = null;
updateSpawnIntervals();
state.tabHiddenAt = null;
// Restore black hole size
blackHole.radius = 0.5 * (state.blackHoleTotalMass / CONFIG.SOLAR_MASS_KG)
blackHole.radius = 0.5 * (state.blackHoleTotalMass / CONFIG.SOLAR_MASS_KG);
// Send checkpoint after loading
Server.checkpoint(state).then(function() {
state.isReady = true; // Mark as ready after checkpoint
state.isReady = true;
});
} else {
// No saved state - send initial checkpoint for new player
@ -276,6 +267,15 @@ var Game = (function() {
(1 + state.ktypeUpgradeLevel * CONFIG.UPGRADE_BONUS_PER_LEVEL_KTYPE);
}
function recalculateUpgradeCosts() {
state.asteroidUpgradeCost = Math.floor(CONFIG.ASTEROID_BASE_COST * Math.pow(CONFIG.UPGRADE_COST_MULTIPLIER_ASTER, state.asteroidUpgradeLevel));
state.cometUpgradeCost = Math.floor(CONFIG.COMET_BASE_COST * Math.pow(CONFIG.UPGRADE_COST_MULTIPLIER_COMET, state.cometUpgradeLevel));
state.planetUpgradeCost = Math.floor(CONFIG.PLANET_BASE_COST * Math.pow(CONFIG.UPGRADE_COST_MULTIPLIER_PLANT, state.planetUpgradeLevel));
state.giantUpgradeCost = Math.floor(CONFIG.GIANT_BASE_COST * Math.pow(CONFIG.UPGRADE_COST_MULTIPLIER_GIANT, state.giantUpgradeLevel));
state.mtypeUpgradeCost = Math.floor(CONFIG.MTYPE_BASE_COST * Math.pow(CONFIG.UPGRADE_COST_MULTIPLIER_MTYPE, state.mtypeUpgradeLevel));
state.ktypeUpgradeCost = Math.floor(CONFIG.KTYPE_BASE_COST * Math.pow(CONFIG.UPGRADE_COST_MULTIPLIER_KTYPE, state.ktypeUpgradeLevel));
}
function handleAsteroidUpgrade() {
if (state.totalMassConsumed >= state.asteroidUpgradeCost) {
state.totalMassConsumed -= state.asteroidUpgradeCost;

View File

@ -391,9 +391,10 @@ var UI = {
},
updateAsteroidUpgrade: function(gameState) {
var rate = (1 / gameState.currentAsteroidSpawnInterval * 1000).toFixed(2);
var bonusPercent = (gameState.asteroidUpgradeLevel * 10);
var tooltipText = 'Rate: ' + rate + '/sec <br>Bonus: ' + bonusPercent + '%';
var rate = (1000 / gameState.currentAsteroidSpawnInterval).toFixed(2);
var bonusPercent = (gameState.asteroidUpgradeLevel * CONFIG.UPGRADE_BONUS_PER_LEVEL_ASTER * 100).toFixed(0);
var tooltipText = 'Asteroids are rocky, airless bodies that range in size from tiny pebbles to hundreds of kilometers across. Some asteroids have moons or even binary companions.<br><br>Rate: ' + rate + '/sec<br>Bonus: ' + bonusPercent + '%';
if (!gameState.cometUnlocked) tooltipText += '<br>Unlocks Comets at level 20';
this.elements.asteroidLevel.innerHTML = '<span class="tooltip-trigger">Asteroids: Level ' +
gameState.asteroidUpgradeLevel +
@ -407,9 +408,10 @@ var UI = {
},
updateCometUpgrade: function(gameState) {
var rate = (1 / gameState.currentCometSpawnInterval * 60000).toFixed(2);
var bonusPercent = (gameState.cometUpgradeLevel * 10);
var tooltipText = 'Rate: ' + rate + '/min <br>Bonus: ' + bonusPercent + '%';
var rate = (60000 / gameState.currentCometSpawnInterval).toFixed(2);
var bonusPercent = (gameState.cometUpgradeLevel * CONFIG.UPGRADE_BONUS_PER_LEVEL_COMET * 100).toFixed(0);
var tooltipText = 'Comets are small icy bodies that typically release gas and dust, forming a glowing coma and often a tail. They are composed mainly of ice, rock, and organic compounds.<br><br>Rate: ' + rate + '/min<br>Bonus: ' + bonusPercent + '%';
if (!gameState.planetUnlocked) tooltipText += '<br>Unlocks Planets at level 15';
this.elements.cometLevel.innerHTML = '<span class="tooltip-trigger">Comets: Level ' +
gameState.cometUpgradeLevel +
@ -423,9 +425,10 @@ var UI = {
},
updatePlanetUpgrade: function(gameState) {
var rate = (3600000 / gameState.currentPlanetSpawnInterval).toFixed(2);
var bonusPercent = (gameState.planetUpgradeLevel * 10);
var tooltipText = 'Rate: ' + rate + '/hour <br>Bonus: ' + bonusPercent + '%';
var rate = (CONFIG.BASE_PLANET_SPAWN_INTERVAL / gameState.currentPlanetSpawnInterval).toFixed(2);
var bonusPercent = (gameState.planetUpgradeLevel * CONFIG.UPGRADE_BONUS_PER_LEVEL_PLANT * 100).toFixed(0);
var tooltipText = 'Planets are roughly spherical accumulations of rock and metal, with solid surfaces and relatively thin atmospheres. Local examples include Mercury, Venus, Earth, and Mars. They may vary greatly in size.<br><br>Rate: ' + rate + '/hour<br>Bonus: ' + bonusPercent + '%';
if (!gameState.giantUnlocked) tooltipText += '<br>Unlocks Giants at level 10';
this.elements.planetLevel.innerHTML = '<span class="tooltip-trigger">Planets: Level ' +
gameState.planetUpgradeLevel +
@ -439,9 +442,10 @@ var UI = {
},
updateGiantUpgrade: function(gameState) {
var rate = (21600000 / gameState.currentGiantSpawnInterval).toFixed(2);
var bonusPercent = (gameState.giantUpgradeLevel * 10);
var tooltipText = 'Spawn Rate: ' + rate + '/6hours <br>Bonus: ' + bonusPercent + '%';
var rate = (CONFIG.BASE_GIANT_SPAWN_INTERVAL / gameState.currentGiantSpawnInterval).toFixed(2);
var bonusPercent = (gameState.giantUpgradeLevel * CONFIG.UPGRADE_BONUS_PER_LEVEL_GIANT * 100).toFixed(0);
var tooltipText = 'Gas giants are large planets made mostly of hydrogen and helium, with thick atmospheres and no solid surface; Jupiter and Saturn are examples.<br>Ice giants are similar but contain higher amounts of frozen materials like water, ammonia, and methane beneath their atmospheres; Uranus and Neptune fall into this category.<br><br>Spawn Rate: ' + rate + '/6hours<br>Bonus: ' + bonusPercent + '%';
if (!gameState.mtypeUnlocked) tooltipText += '<br>Unlocks M-Type at level 5';
this.elements.giantLevel.innerHTML = '<span class="tooltip-trigger">Giants: Level ' +
gameState.giantUpgradeLevel +
@ -455,9 +459,11 @@ var UI = {
},
updateMtypeUpgrade: function(gameState) {
var rate = (86400000 / gameState.currentMtypeSpawnInterval).toFixed(2);
var bonusPercent = (gameState.mtypeUpgradeLevel * 0.5);
var tooltipText = 'Spawn Rate: ' + rate + '/day <br>Bonus: ' + bonusPercent + '%';
var rate = (CONFIG.BASE_MTYPE_SPAWN_INTERVAL / gameState.currentMtypeSpawnInterval).toFixed(2);
var bonusPercent = (gameState.mtypeUpgradeLevel * CONFIG.UPGRADE_BONUS_PER_LEVEL_MTYPE * 100).toFixed(0);
var tooltipText = 'M-types, also known as red dwarfs, are the smallest and coolest stars with masses ranging from about 0.08 to 0.45 M☉.<br>They are the most common star in the universe, making up roughly three quarters of all main-sequence stars, but are not easily visible due to their low luminosity.<br><br>Spawn Rate: ' + rate + '/day<br>Bonus: ' + bonusPercent + '%';
if (!gameState.ktypeUnlocked) tooltipText += '<br>Unlocks K-Type at level 5';
this.elements.mtypeLevel.innerHTML = '<span class="tooltip-trigger">M-Type: Level ' +
gameState.mtypeUpgradeLevel +
'<span class="tooltip">' + tooltipText + '</span></span>';
@ -468,9 +474,10 @@ var UI = {
},
updateKtypeUpgrade: function(gameState) {
var rate = (259200000 / gameState.currentKtypeSpawnInterval).toFixed(2);
var bonusPercent = (gameState.ktypeUpgradeLevel * 3);
var tooltipText = 'Spawn Rate: ' + rate + '/3days <br>Bonus: ' + bonusPercent + '%';
var rate = (CONFIG.BASE_KTYPE_SPAWN_INTERVAL / gameState.currentKtypeSpawnInterval).toFixed(2);
var bonusPercent = (gameState.ktypeUpgradeLevel * CONFIG.UPGRADE_BONUS_PER_LEVEL_KTYPE * 100).toFixed(0);
var tooltipText = 'K-types, also known as orange dwarfs, are medium-sized stars that are cooler than the Sun, with masses ranging from about 0.45 to 0.8 M☉. They are known for their stability and long lifespans (20 to 70 billion years) making them potential candidates for supporting inhabited planets.<br><br>Spawn Rate: ' + rate + '/2days<br>Bonus: ' + bonusPercent + '%';
this.elements.ktypeLevel.innerHTML = '<span class="tooltip-trigger">K-Type: Level ' +
gameState.ktypeUpgradeLevel +
'<span class="tooltip">' + tooltipText + '</span></span>';

View File

@ -47,7 +47,7 @@ canvas {
.tooltip {
display: none;
position: absolute;
background: rgba(20, 20, 30, 0.3);
background: rgba(20, 20, 30, 0.69);
backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.2);
padding: 8px 12px;