From 120f4bedca257c2fca33a0c4aa9d2106a213246f Mon Sep 17 00:00:00 2001 From: Tetardtek Date: Sat, 28 Mar 2026 20:52:30 +0100 Subject: [PATCH] feat: buy x1/x5/x10/xMax + production preview per generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - buyGenerator() supports quantity param (multi-buy loop) - maxAffordable() / bulkCost() — compute max purchasable + total cost - GeneratorShop: mode selector (x1/x5/x10/MAX) - Each generator shows +X/s in amber — what the next purchase adds - Button shows total cost + quantity (e.g. "1.5k (x5)") --- .../src/lib/components/GeneratorShop.svelte | 47 ++++++++++++--- Frontend/src/lib/core/economy.ts | 60 +++++++++++++++---- Frontend/src/lib/stores/game.svelte.ts | 4 +- 3 files changed, 91 insertions(+), 20 deletions(-) diff --git a/Frontend/src/lib/components/GeneratorShop.svelte b/Frontend/src/lib/components/GeneratorShop.svelte index 3521246..7d81e44 100644 --- a/Frontend/src/lib/components/GeneratorShop.svelte +++ b/Frontend/src/lib/components/GeneratorShop.svelte @@ -2,9 +2,14 @@ import { scale } from 'svelte/transition'; import { quintOut } from 'svelte/easing'; import { game } from '$lib/stores/game.svelte'; - import { generatorEffectiveProduction } from '$lib/core/economy'; + import { generatorEffectiveProduction, maxAffordable, bulkCost } from '$lib/core/economy'; import { formatNumber } from '$lib/utils/formatNumber'; import CollapsiblePanel from './CollapsiblePanel.svelte'; + + type BuyMode = 1 | 5 | 10 | 'max'; + let buyMode = $state(1); + + const MODES: BuyMode[] = [1, 5, 10, 'max']; + +
+ {#each MODES as mode} + + {/each} +
+ {#each game.state.generators as gen, i} - {@const cost = game.generatorCostWithTree(gen)} - {@const canAfford = game.state.resources >= cost} + {@const qty = buyMode === 'max' ? maxAffordable(game.state, gen.id) : buyMode} + {@const cost = qty <= 1 ? game.generatorCostWithTree(gen) : bulkCost(game.state, gen.id, qty)} + {@const canAfford = game.state.resources >= cost && qty > 0} {@const effectiveProd = generatorEffectiveProduction(gen, game.state)} - {@const nextUnitProd = generatorEffectiveProduction({ ...gen, owned: 1 }, game.state)} + {@const nextGain = generatorEffectiveProduction({ ...gen, owned: qty || 1 }, game.state)} {@const share = game.productionPerSecond > 0 ? (effectiveProd / game.productionPerSecond * 100) : 0}
{formatNumber(effectiveProd)}/s · {share.toFixed(0)}% + · + +{formatNumber(nextGain)}/s
-
{:else} - +{formatNumber(nextUnitProd)}/s par unite + + +{formatNumber(nextGain)}/s par unite + {/if} {/each} diff --git a/Frontend/src/lib/core/economy.ts b/Frontend/src/lib/core/economy.ts index 3f1f36f..e8312cb 100644 --- a/Frontend/src/lib/core/economy.ts +++ b/Frontend/src/lib/core/economy.ts @@ -661,22 +661,62 @@ export function applyClick(state: GameState, rng: number = Math.random()): Click } // Achat d'un générateur (retourne null si fonds insuffisants) -export function buyGenerator(state: GameState, genId: string): GameState | null { +export function buyGenerator(state: GameState, genId: string, quantity = 1): GameState | null { const genIndex = state.generators.findIndex((g) => g.id === genId); if (genIndex === -1) return null; - const gen = state.generators[genIndex]; - const cost = generatorCost(gen, state.evolutionTree); - if (state.resources < cost) return null; + let gen = { ...state.generators[genIndex] }; + let resources = state.resources; + + let bought = 0; + for (let i = 0; i < quantity; i++) { + const cost = generatorCost(gen, state.evolutionTree); + if (resources < cost) break; + resources -= cost; + gen = { ...gen, owned: gen.owned + 1 }; + bought++; + } + + if (bought === 0) return null; const updatedGenerators = [...state.generators]; - updatedGenerators[genIndex] = { ...gen, owned: gen.owned + 1 }; + updatedGenerators[genIndex] = gen; - return { - ...state, - resources: state.resources - cost, - generators: updatedGenerators, - }; + return { ...state, resources, generators: updatedGenerators }; +} + +// Calcule combien d'unités on peut acheter avec les ressources actuelles +export function maxAffordable(state: GameState, genId: string): number { + const genIndex = state.generators.findIndex((g) => g.id === genId); + if (genIndex === -1) return 0; + + let gen = { ...state.generators[genIndex] }; + let resources = state.resources; + let count = 0; + + while (true) { + const cost = generatorCost(gen, state.evolutionTree); + if (resources < cost) break; + resources -= cost; + gen = { ...gen, owned: gen.owned + 1 }; + count++; + if (count > 1000) break; // safety + } + return count; +} + +// Cout total pour acheter N unités +export function bulkCost(state: GameState, genId: string, quantity: number): number { + const genIndex = state.generators.findIndex((g) => g.id === genId); + if (genIndex === -1) return Infinity; + + let gen = { ...state.generators[genIndex] }; + let total = 0; + for (let i = 0; i < quantity; i++) { + total += generatorCost(gen, state.evolutionTree); + gen = { ...gen, owned: gen.owned + 1 }; + } + return total; } // Prestige : reset run, gain ADN, arbre persiste diff --git a/Frontend/src/lib/stores/game.svelte.ts b/Frontend/src/lib/stores/game.svelte.ts index dec61ad..6959fd3 100644 --- a/Frontend/src/lib/stores/game.svelte.ts +++ b/Frontend/src/lib/stores/game.svelte.ts @@ -127,9 +127,9 @@ class Game { this.lastClickCrit = result.isCrit; } - buy(genId: string) { + buy(genId: string, quantity = 1) { if (!this.ready) return; - const updated = buyGenerator(applyIdleGains(this.state, Date.now()), genId); + const updated = buyGenerator(applyIdleGains(this.state, Date.now()), genId, quantity); if (updated) this.applyState(updated); }