From 936f7fc4e82e6855455c040470bc822a07c73a7a Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Mon, 24 Aug 2026 09:43:38 +0000 Subject: [PATCH] Session 15: Buy Max Prestige Upgrades (bulk-buy for prestige upgrades) + fix missing Stellar Essence spend --- css/game.css | 17 +++++++++++++++++ dev-journal.md | 28 ++++++++++++++++++++++++++++ index.html | 4 ++++ js/game.js | 47 +++++++++++++++++++++++++++++++++++++++++++++++ js/prestigeUI.js | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 143 insertions(+), 1 deletion(-) diff --git a/css/game.css b/css/game.css index dc3faba..0814732 100644 --- a/css/game.css +++ b/css/game.css @@ -363,6 +363,23 @@ h2, h3 { opacity: 0.4; } +/* Prestige Upgrades header + Buy Max button */ +.prestige-upgrades-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 10px; +} + +.prestige-upgrades-header h3 { + margin: 0; +} + +.prestige-buy-all { + background: var(--accent-gold); + color: var(--bg-primary, #1a1035); +} + /* Side Panel Tabs */ .tabs { display: flex; diff --git a/dev-journal.md b/dev-journal.md index 53339de..092c6e3 100644 --- a/dev-journal.md +++ b/dev-journal.md @@ -414,3 +414,31 @@ Wrote a headless Node.js test (`/opt/data/idle-game-test/buy-all-upgrades-test.m - Consider adding a "Buy Max" button to the prestige upgrades list as well. - Potential new building tiers or prestige milestones. - Sound variations or background music. + +--- + +### Session 15 - 2026-08-24 (Morning) +**Status:** ✅ Buy Max Prestige Upgrades (bulk-buy for prestige upgrades) Added + +#### What was done: +- Followed up on Session 14's own "next goal" by adding a **Buy Max** button to the **Prestige Upgrades** list. Previously one-time prestige upgrades could only be purchased individually (one click each), which was tedious once several were available — buildings had Buy Max (Session 10) and regular upgrades had Buy All (Session 14), but prestige upgrades did not. This brings prestige upgrades in line with that established bulk-buy convention. +- Added `Game.buyMaxPrestigeUpgrades()` to `js/game.js`. It loops through every entry in `PRESTIGE_UPGRADES`, skips owned ones, respects each upgrade's (optional) `requirements` building-count gate, and buys everything affordable at once from **Stellar Essence**. It runs until a full pass purchases nothing (loop kept for symmetry with `buyAllUpgrades` and to stay safe if future prestige upgrades gain requirement gates), then decrements `stellarEssence` per purchase (mirroring `PRESTIGE.buyUpgrade`) and returns `{ bought: count, ids: [...] }`. +- Wired the button into the Prestige tab in `index.html` (`#buy-all-prestige`, placed alongside a left-aligned header row mirroring the Upgrades tab's Buy All layout). Added a click listener in `PrestigeUI.setupEventListeners()`. +- Added `PrestigeUI.updateBuyMaxPrestigeButton()` (called from `PrestigeUI.update()` each tick) which shows/hides and enables/disables the button based on whether any unowned, requirement-met prestige upgrade is currently affordable with Stellar Essence — a read-only state check, exactly mirroring `UI.updateBuyAllButton()`. +- Added CSS for `.prestige-upgrades-header` (flex layout) and `.prestige-buy-all` (gold accent theme reusing the existing `.buy-all-btn` base, matching the Upgrades tab's Buy All button). +- **Bug found & fixed during testing:** the first implementation of `buyMaxPrestigeUpgrades()` added upgrades to the list but never decremented `stellarEssence`, which would have let players prestige-buy unlimited upgrades for free. The headless test asserted essence depletion and caught it; added the missing `this.state.stellarEssence -= upgrade.cost` line so spend mirrors `PRESTIGE.buyUpgrade`. + +#### Files modified: +- `js/game.js` - added `buyMaxPrestigeUpgrades()` method (with correct Stellar Essence spend) +- `js/prestigeUI.js` - added click listener for the Buy Max button + `updateBuyMaxPrestigeButton()`; called from `update()` each tick +- `index.html` - added Buy Max button to the Prestige Upgrades header +- `css/game.css` - `.prestige-upgrades-header`, `.prestige-buy-all` styles +- `dev-journal.md` - appended Session 15 entry + +#### Verification: +Wrote a headless Node.js test (`/opt/data/idle-game-test/prestige-buy-max-test.mjs`) that loads the real `game.js`, `prestige.js`, and `prestigeUI.js` in-process with DOM/audio/particle stubs. **22/22 checks pass**, covering: no-op when nothing affordable, bulk purchase deducting Stellar Essence correctly, ungated-upgrade behavior (real prestige upgrades have no requirement gates), idempotent second call, already-owned upgrade skipping, notification-on-purchase vs silence on no-op, the missing-essence-spend regression (now fixed), and the real `PrestigeUI.updateBuyMaxPrestigeButton()` show/hide/enabled state against actual `PRESTIGE_UPGRADES` data. All existing suites re-ran clean with no regressions: buy-all-upgrades 24/24, buy-max 6/6, golden-bloom 22/22, slot-preview 22/22. All modified JS files pass `node --check`. + +#### Next goals: +- Potential new building tiers or prestige milestones / new prestige upgrades. +- Sound variations or background music. +- Consider a global "Buy Max" for buildings across all types at once (currently per-building). diff --git a/index.html b/index.html index e7ba9dc..6394988 100644 --- a/index.html +++ b/index.html @@ -99,6 +99,10 @@

Prestige Upgrades

+
+ + +
diff --git a/js/game.js b/js/game.js index f363cf7..755d0e8 100644 --- a/js/game.js +++ b/js/game.js @@ -469,6 +469,53 @@ const Game = { return { bought: bought.length, ids: bought }; }, + /** + * Buy every prestige upgrade the player can currently afford at once, + * paid from Stellar Essence. Returns an object describing what happened: + * { bought: count, ids: [...] }. Prestige upgrades are one-time purchases, + * so we loop until a full pass buys nothing (purchasing one never unlocks + * another, but the loop is kept for symmetry with buyAllUpgrades and to + * stay safe should future prestige upgrades gain requirement gates). + */ + buyMaxPrestigeUpgrades() { + const bought = []; + let progress = true; + while (progress) { + progress = false; + for (const [id, upgrade] of Object.entries(PRESTIGE_UPGRADES)) { + if ((this.state.prestigeUpgrades || []).includes(id)) continue; + // Respect requirements before attempting purchase, mirroring + // PRESTIGE.buyUpgrade semantics. + if (upgrade.requirements) { + let met = true; + for (const [reqId, reqCount] of Object.entries(upgrade.requirements)) { + if ((this.state.buildings[reqId] || 0) < reqCount) { + met = false; + break; + } + } + if (!met) continue; + } + if ((this.state.stellarEssence || 0) >= upgrade.cost) { + this.state.prestigeUpgrades = this.state.prestigeUpgrades || []; + this.state.prestigeUpgrades.push(id); + // Spend Stellar Essence, mirroring PRESTIGE.buyUpgrade. + this.state.stellarEssence -= upgrade.cost; + bought.push(id); + progress = true; + } + } + } + + if (bought.length > 0) { + UI.showNotification(`Bought ${bought.length} prestige upgrade(s)!`, 'achievement'); + Audio.playPurchase(); + UI.update(); + } + + return { bought: bought.length, ids: bought }; + }, + /** * Golden Starbloom - random event system. * A rare, time-limited bloom occasionally appears on screen. Clicking it diff --git a/js/prestigeUI.js b/js/prestigeUI.js index 9a91fb2..e1bd7d9 100644 --- a/js/prestigeUI.js +++ b/js/prestigeUI.js @@ -43,6 +43,15 @@ const PrestigeUI = { } }); }); + + // Buy Max prestige upgrades button - buy every affordable prestige + // upgrade at once, paid from Stellar Essence. + const buyMaxBtn = document.getElementById('buy-all-prestige'); + if (buyMaxBtn) { + buyMaxBtn.addEventListener('click', () => { + Game.buyMaxPrestigeUpgrades(); + }); + } }, /** @@ -119,7 +128,44 @@ const PrestigeUI = { if (prestigeTab?.classList.contains('active')) { this.renderPrestigeUpgrades(); } - } + + // Show/hide the "Buy Max" button based on whether any unowned prestige + // upgrade is currently affordable with Stellar Essence. Read-only. + this.updateBuyMaxPrestigeButton(); + }, + + /** + * Show/hide and enable/disable the "Buy Max" prestige-upgrades button + * depending on whether at least one unowned, requirement-met prestige + * upgrade is currently affordable with Stellar Essence. Read of game state + * only; never mutates it. Mirrors Game.buyMaxPrestigeUpgrades / + * PRESTIGE.buyUpgrade semantics. + */ + updateBuyMaxPrestigeButton() { + const btn = document.getElementById('buy-all-prestige'); + if (!btn) return; + + let affordableAny = false; + for (const [id, upgrade] of Object.entries(PRESTIGE_UPGRADES)) { + if ((Game.state.prestigeUpgrades || []).includes(id)) continue; + if ((Game.state.stellarEssence || 0) < upgrade.cost) continue; + if (upgrade.requirements) { + let met = true; + for (const [reqId, reqCount] of Object.entries(upgrade.requirements)) { + if ((Game.state.buildings[reqId] || 0) < reqCount) { + met = false; + break; + } + } + if (!met) continue; + } + affordableAny = true; + break; + } + + btn.style.display = affordableAny ? '' : 'none'; + btn.disabled = !affordableAny; + }, }; window.PrestigeUI = PrestigeUI;