324 lines
15 KiB
JavaScript
324 lines
15 KiB
JavaScript
/**
|
|
* Cosmic Garden - Statistics Panel
|
|
* Tracks and displays game statistics
|
|
*/
|
|
|
|
const Stats = {
|
|
/**
|
|
* Initialize the stats panel
|
|
*/
|
|
init() {
|
|
this.render();
|
|
},
|
|
|
|
/**
|
|
* Render the stats panel
|
|
*/
|
|
render() {
|
|
const container = document.getElementById('stats-content');
|
|
if (!container) return;
|
|
|
|
container.innerHTML = `
|
|
<div class="stat-item">
|
|
<div class="stat-label">Total Stardust Earned</div>
|
|
<div class="stat-value" id="stat-total-stardust">0 ✨</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Current Production</div>
|
|
<div class="stat-value" id="stat-production">0 ✨/sec</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Total Clicks</div>
|
|
<div class="stat-value" id="stat-clicks">0</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Click Power</div>
|
|
<div class="stat-value" id="stat-click-power">1 ✨</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Time Played</div>
|
|
<div class="stat-value" id="stat-time-played">0:00:00</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Buildings Owned</div>
|
|
<div class="stat-value" id="stat-buildings">0</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Upgrades Purchased</div>
|
|
<div class="stat-value" id="stat-upgrades">0/${Object.keys(UPGRADES).length}</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Achievements Unlocked</div>
|
|
<div class="stat-value" id="stat-achievements">0/${Object.keys(ACHIEVEMENTS).length}</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Total Golden Blooms Claimed</div>
|
|
<div class="stat-value" id="stat-golden-blooms">0</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Production Boost</div>
|
|
<div class="stat-value" id="stat-production-boost">Inactive</div>
|
|
<div class="stat-bar">
|
|
<div class="stat-bar-fill" id="stat-boost-progress" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Next Achievement</div>
|
|
<div id="stat-next-achievement" style="font-size:0.85rem; color:var(--text-secondary); margin-top:4px">Loading...</div>
|
|
<div class="stat-bar">
|
|
<div class="stat-bar-fill" id="stat-achievement-progress" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-label">Game Progress</div>
|
|
<div class="stat-bar">
|
|
<div class="stat-bar-fill" id="stat-progress-bar" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
},
|
|
|
|
/**
|
|
* Update stats display
|
|
*/
|
|
update() {
|
|
// Total stardust
|
|
const totalStardustEl = document.getElementById('stat-total-stardust');
|
|
if (totalStardustEl) {
|
|
totalStardustEl.textContent = `${Game.formatNumber(Game.state.totalStardust)} ✨`;
|
|
}
|
|
|
|
// Current production
|
|
const productionEl = document.getElementById('stat-production');
|
|
if (productionEl) {
|
|
productionEl.textContent = `${Game.formatNumber(Game.getProductionPerSecond())} ✨/sec`;
|
|
}
|
|
|
|
// Total clicks
|
|
const clicksEl = document.getElementById('stat-clicks');
|
|
if (clicksEl) {
|
|
clicksEl.textContent = Game.formatNumber(Game.state.totalClicks);
|
|
}
|
|
|
|
// Click power
|
|
const clickPowerEl = document.getElementById('stat-click-power');
|
|
if (clickPowerEl) {
|
|
clickPowerEl.textContent = `${Game.formatNumber(Game.getClickPower())} ✨`;
|
|
}
|
|
|
|
// Time played
|
|
const timePlayedEl = document.getElementById('stat-time-played');
|
|
if (timePlayedEl) {
|
|
const elapsed = Math.floor((Date.now() - Game.state.startTime) / 1000);
|
|
timePlayedEl.textContent = this.formatTime(elapsed);
|
|
}
|
|
|
|
// Buildings owned
|
|
const buildingsEl = document.getElementById('stat-buildings');
|
|
if (buildingsEl) {
|
|
const total = Object.values(Game.state.buildings).reduce((a, b) => a + b, 0);
|
|
buildingsEl.textContent = total;
|
|
}
|
|
|
|
// Upgrades purchased
|
|
const upgradesEl = document.getElementById('stat-upgrades');
|
|
if (upgradesEl) {
|
|
upgradesEl.textContent = `${Game.state.upgrades.length}/${Object.keys(UPGRADES).length}`;
|
|
}
|
|
|
|
// Achievements unlocked
|
|
const achievementsEl = document.getElementById('stat-achievements');
|
|
if (achievementsEl) {
|
|
achievementsEl.textContent = `${Achievements.getCount()}/${Achievements.getTotal()}`;
|
|
}
|
|
|
|
// Total Golden Blooms claimed
|
|
const goldenBloomsEl = document.getElementById('stat-golden-blooms');
|
|
if (goldenBloomsEl) {
|
|
goldenBloomsEl.textContent = Game.state.goldenBlooms.totalClaimed || 0;
|
|
}
|
|
|
|
// Production boost status + progress bar
|
|
const boostInfo = Game.getProductionBoostInfo();
|
|
const boostEl = document.getElementById('stat-production-boost');
|
|
const boostProgressEl = document.getElementById('stat-boost-progress');
|
|
if (boostEl) {
|
|
if (boostInfo.active) {
|
|
boostEl.textContent = `Active (${boostInfo.remaining}s)`;
|
|
if (boostProgressEl) {
|
|
boostProgressEl.style.width = `${Math.min(100, (boostInfo.remaining / 30) * 100)}%`;
|
|
}
|
|
} else {
|
|
boostEl.textContent = 'Inactive';
|
|
if (boostProgressEl) {
|
|
boostProgressEl.style.width = '0%';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Game progress (based on total stardust milestones)
|
|
const progressBarEl = document.getElementById('stat-progress-bar');
|
|
if (progressBarEl) {
|
|
const progress = this.calculateProgress();
|
|
progressBarEl.style.width = `${progress}%`;
|
|
}
|
|
|
|
// Next achievement tracking
|
|
this.updateNextAchievement();
|
|
},
|
|
|
|
/**
|
|
* Update the next achievement display with progress bar
|
|
*/
|
|
updateNextAchievement() {
|
|
const nextEl = document.getElementById('stat-next-achievement');
|
|
const progressEl = document.getElementById('stat-achievement-progress');
|
|
if (!nextEl) return;
|
|
|
|
// Find the closest unachieved milestone
|
|
let closest = null;
|
|
let closestProgress = -1;
|
|
|
|
for (const [id, achievement] of Object.entries(ACHIEVEMENTS)) {
|
|
if (Game.state.achievements.includes(id)) continue;
|
|
|
|
const result = this.calculateAchievementProgress(achievement);
|
|
if (result && result.progress > closestProgress) {
|
|
closestProgress = result.progress;
|
|
closest = { ...result, name: achievement.name, icon: achievement.icon };
|
|
}
|
|
}
|
|
|
|
if (closest) {
|
|
nextEl.textContent = `${closest.icon} ${closest.name}`;
|
|
if (progressEl) {
|
|
progressEl.style.width = `${Math.min(100, Math.max(0, closest.progress))}%`;
|
|
}
|
|
} else {
|
|
nextEl.textContent = 'All achievements unlocked! 🎉';
|
|
if (progressEl) {
|
|
progressEl.style.width = '100%';
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Calculate progress toward a specific achievement
|
|
*/
|
|
calculateAchievementProgress(achievement) {
|
|
const state = Game.state;
|
|
|
|
// Click achievements
|
|
if (achievement.id === 'firstClick') return { current: state.totalClicks, target: 1, progress: Math.min(100, (state.totalClicks / 1) * 100) };
|
|
if (achievement.id === 'clicker') return { current: state.totalClicks, target: 100, progress: Math.min(100, (state.totalClicks / 100) * 100) };
|
|
if (achievement.id === 'spammer') return { current: state.totalClicks, target: 1000, progress: Math.min(100, (state.totalClicks / 1000) * 100) };
|
|
if (achievement.id === 'clickMaster') return { current: state.totalClicks, target: 10000, progress: Math.min(100, (state.totalClicks / 10000) * 100) };
|
|
|
|
// Stardust achievements
|
|
if (achievement.id === 'dustCollector') return { current: state.totalStardust, target: 1000, progress: Math.min(100, (state.totalStardust / 1000) * 100) };
|
|
if (achievement.id === 'stardustMagnate') return { current: state.totalStardust, target: 100000, progress: Math.min(100, (state.totalStardust / 100000) * 100) };
|
|
if (achievement.id === 'cosmicTycoon') return { current: state.totalStardust, target: 10000000, progress: Math.min(100, (state.totalStardust / 10000000) * 100) };
|
|
if (achievement.id === 'galaxyBaron') return { current: state.totalStardust, target: 1000000000, progress: Math.min(100, (state.totalStardust / 1000000000) * 100) };
|
|
|
|
// Building achievements
|
|
if (achievement.id === 'firstPlant') {
|
|
const totalBuildings = Object.values(state.buildings).reduce((a, b) => a + b, 0);
|
|
return { current: totalBuildings, target: 1, progress: Math.min(100, (totalBuildings / 1) * 100) };
|
|
}
|
|
if (achievement.id === 'gardenStart') {
|
|
const totalBuildings = Object.values(state.buildings).reduce((a, b) => a + b, 0);
|
|
return { current: totalBuildings, target: 10, progress: Math.min(100, (totalBuildings / 10) * 100) };
|
|
}
|
|
if (achievement.id === 'gardenCenter') {
|
|
const totalBuildings = Object.values(state.buildings).reduce((a, b) => a + b, 0);
|
|
return { current: totalBuildings, target: 50, progress: Math.min(100, (totalBuildings / 50) * 100) };
|
|
}
|
|
if (achievement.id === 'cosmicGarden') {
|
|
const totalBuildings = Object.values(state.buildings).reduce((a, b) => a + b, 0);
|
|
return { current: totalBuildings, target: 100, progress: Math.min(100, (totalBuildings / 100) * 100) };
|
|
}
|
|
|
|
// Specific building achievements
|
|
if (achievement.id === 'sproutFarmer') return { current: state.buildings.starSprout || 0, target: 25, progress: Math.min(100, ((state.buildings.starSprout || 0) / 25) * 100) };
|
|
if (achievement.id === 'bloomGarden') return { current: state.buildings.moonBloom || 0, target: 25, progress: Math.min(100, ((state.buildings.moonBloom || 0) / 25) * 100) };
|
|
if (achievement.id === 'solarPowered') return { current: state.buildings.solarLeaf || 0, target: 25, progress: Math.min(100, ((state.buildings.solarLeaf || 0) / 25) * 100) };
|
|
if (achievement.id === 'voidWeaver') return { current: state.buildings.voidFern || 0, target: 25, progress: Math.min(100, ((state.buildings.voidFern || 0) / 25) * 100) };
|
|
if (achievement.id === 'supernovaGrowth') return { current: state.buildings.supernovaSeed || 0, target: 25, progress: Math.min(100, ((state.buildings.supernovaSeed || 0) / 25) * 100) };
|
|
|
|
// Production achievements
|
|
if (achievement.id === 'steadyStream') {
|
|
const prod = Game.getProductionPerSecond();
|
|
return { current: prod, target: 100, progress: Math.min(100, (prod / 100) * 100) };
|
|
}
|
|
if (achievement.id === 'rushingRiver') {
|
|
const prod = Game.getProductionPerSecond();
|
|
return { current: prod, target: 1000, progress: Math.min(100, (prod / 1000) * 100) };
|
|
}
|
|
if (achievement.id === 'cosmicFlood') {
|
|
const prod = Game.getProductionPerSecond();
|
|
return { current: prod, target: 100000, progress: Math.min(100, (prod / 100000) * 100) };
|
|
}
|
|
|
|
// Prestige achievements
|
|
if (achievement.id === 'firstPrestige') return { current: state.prestigeCount || 0, target: 1, progress: Math.min(100, ((state.prestigeCount || 0) / 1) * 100) };
|
|
if (achievement.id === 'stellarAdaptation') return { current: state.prestigeCount || 0, target: 5, progress: Math.min(100, ((state.prestigeCount || 0) / 5) * 100) };
|
|
if (achievement.id === 'cosmicAscension') return { current: state.prestigeCount || 0, target: 10, progress: Math.min(100, ((state.prestigeCount || 0) / 10) * 100) };
|
|
if (achievement.id === 'eternalGardener') return { current: state.totalPrestigeEssence || 0, target: 100, progress: Math.min(100, ((state.totalPrestigeEssence || 0) / 100) * 100) };
|
|
if (achievement.id === 'quantumGrowth') return { current: state.totalPrestigeEssence || 0, target: 1000, progress: Math.min(100, ((state.totalPrestigeEssence || 0) / 1000) * 100) };
|
|
|
|
// Click power achievements
|
|
if (achievement.id === 'powerfulHarvester') {
|
|
const cp = Game.getClickPower();
|
|
return { current: cp, target: 1000, progress: Math.min(100, (cp / 1000) * 100) };
|
|
}
|
|
if (achievement.id === 'divineTouch') {
|
|
const cp = Game.getClickPower();
|
|
return { current: cp, target: 10000, progress: Math.min(100, (cp / 10000) * 100) };
|
|
}
|
|
|
|
// Time-based achievement
|
|
if (achievement.id === 'dedicatedGardener') {
|
|
const elapsed = Date.now() - state.startTime;
|
|
return { current: elapsed, target: 3600000, progress: Math.min(100, (elapsed / 3600000) * 100) };
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
/**
|
|
* Format elapsed time as HH:MM:SS
|
|
*/
|
|
formatTime(seconds) {
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
const secs = seconds % 60;
|
|
|
|
if (hours > 0) {
|
|
return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
|
}
|
|
return `${minutes}:${secs.toString().padStart(2, '0')}`;
|
|
},
|
|
|
|
/**
|
|
* Calculate game progress percentage
|
|
* Based on total stardust earned vs all building costs combined
|
|
*/
|
|
calculateProgress() {
|
|
let totalCost = 0;
|
|
for (const building of Object.values(BUILDINGS)) {
|
|
// Approximate cost to buy one of each building
|
|
totalCost += building.baseCost;
|
|
}
|
|
|
|
// Add upgrade costs
|
|
for (const upgrade of Object.values(UPGRADES)) {
|
|
totalCost += upgrade.cost;
|
|
}
|
|
|
|
const progress = Math.min(100, (Game.state.totalStardust / totalCost) * 100);
|
|
return Math.round(progress);
|
|
}
|
|
};
|
|
|
|
window.Stats = Stats;
|