Session 9: Achievement Progress Tracking in Stats Panel
Added Next Achievement section to Statistics panel with progress bar. Tracks all 30 achievements across click, stardust, building, production, prestige, click power, and time categories. Shows closest unachieved milestone with percentage progress updating every tick.
This commit is contained in:
+129
-1
@@ -17,7 +17,7 @@ const Stats = {
|
||||
render() {
|
||||
const container = document.getElementById('stats-content');
|
||||
if (!container) return;
|
||||
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">Total Stardust Earned</div>
|
||||
@@ -51,6 +51,13 @@ const Stats = {
|
||||
<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">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">
|
||||
@@ -120,6 +127,127 @@ const Stats = {
|
||||
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;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user