Session 16: Global 'Buy All Buildings' bulk-buy feature Added

Adds a global Buy All button to the Buildings panel that purchases as many
of every building type the player can afford at once, bringing Plants in line
with the Upgrades (Buy All) and Prestige (Buy Max) panels.

- game.js: Game.buyAllBuildings() loops buyMaxBuilding() per building type
- ui.js: UI.updateBuyAllBuildings() shows/hides + enables/disables live each tick
- index.html: Buy All button in Buildings panel header (reuses .upgrades-header/.buy-all-btn)
- Added headless test buy-all-buildings-test.mjs (31/31 pass); all existing suites green
This commit is contained in:
2026-08-24 18:00:27 +00:00
parent 44f55f0d24
commit cc1fa6bc4d
4 changed files with 96 additions and 1 deletions
+37
View File
@@ -132,6 +132,14 @@ const Game = {
});
}
// Buy All buildings button - buy as many of every building at once.
const buyAllBuildingsBtn = document.getElementById('buy-all-buildings');
if (buyAllBuildingsBtn) {
buyAllBuildingsBtn.addEventListener('click', () => {
Game.buyAllBuildings();
});
}
document.getElementById('reset-btn').addEventListener('click', () => {
if (confirm('Are you sure you want to reset all progress? This cannot be undone!')) {
this.reset();
@@ -395,6 +403,35 @@ const Game = {
return count;
},
/**
* Buy as many of EVERY building the player can currently afford at once,
* across all building types. Returns the total number purchased. Buildings
* cost-scales independently per type, so this loops until a full pass buys
* nothing (kept for symmetry with buyAllUpgrades / buyMaxPrestigeUpgrades
* and to stay safe if future buildings gain requirement gates); in practice
* a single pass suffices. Mirrors buyMaxBuilding per building.
*/
buyAllBuildings() {
let totalBought = 0;
// Loop until a full pass purchases nothing (buying one building type
// never unlocks another, but the loop keeps us safe against future
// requirement gates and matches the bulk-buy convention elsewhere).
let progress = true;
while (progress) {
progress = false;
for (const buildingId of Object.keys(BUILDINGS)) {
const bought = this.buyMaxBuilding(buildingId);
if (bought > 0) {
totalBought += bought;
progress = true;
}
}
}
return totalBought;
},
/**
* Buy an upgrade
*/
+29
View File
@@ -131,6 +131,35 @@ const UI = {
card.classList.toggle('locked', locked);
}
// Toggle the global "Buy All buildings" button: show it once at least
// one building type is currently affordable, and disable it otherwise.
this.updateBuyAllBuildings();
},
/**
* Show/hide and enable/disable the global "Buy All buildings" button based
* on whether at least one building type is currently affordable (at least
* one unit). Read of game state only; never mutates it. Mirrors
* Game.buyAllBuildings / buyMaxBuilding semantics.
*/
updateBuyAllBuildings() {
const btn = document.getElementById('buy-all-buildings');
if (!btn) return;
let affordableAny = false;
for (const buildingId of Object.keys(BUILDINGS)) {
const count = Game.state.buildings[buildingId] || 0;
const locked = Game.state.totalStardust < BUILDINGS[buildingId].unlockAt && count === 0;
if (locked) continue;
if (Game.getMaxAffordable(buildingId) > 0) {
affordableAny = true;
break;
}
}
btn.style.display = affordableAny ? '' : 'none';
btn.disabled = !affordableAny;
},
/**