feat(sprint1-step2): core economy TS + useEconomy hook (lazy calc) + 13 tests vitest
This commit is contained in:
111
Frontend/src/core/economy.ts
Normal file
111
Frontend/src/core/economy.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
// economy.ts — Core clicker logic (lazy calculation pattern)
|
||||
// Jamais de timer actif : tout est calculé au read depuis lastTick
|
||||
|
||||
export interface Generator {
|
||||
id: string;
|
||||
name: string;
|
||||
baseCost: number;
|
||||
baseProduction: number; // ressource/s
|
||||
owned: number;
|
||||
}
|
||||
|
||||
export interface GameState {
|
||||
resources: number;
|
||||
clickMultiplier: number;
|
||||
generators: Generator[];
|
||||
lastTick: number; // timestamp ms — lazy calc reference
|
||||
prestigeCount: number;
|
||||
prestigeMultiplier: number; // 1 + prestigeCount * 0.1
|
||||
}
|
||||
|
||||
// Coût d'achat du N-ième générateur : baseCost × 1.15^owned
|
||||
export function generatorCost(gen: Generator): number {
|
||||
return Math.floor(gen.baseCost * Math.pow(1.15, gen.owned));
|
||||
}
|
||||
|
||||
// Production totale par seconde de tous les générateurs
|
||||
export function totalProductionPerSecond(state: GameState): number {
|
||||
const base = state.generators.reduce(
|
||||
(sum, gen) => sum + gen.baseProduction * gen.owned,
|
||||
0
|
||||
);
|
||||
return base * state.prestigeMultiplier;
|
||||
}
|
||||
|
||||
// Lazy calculation : ressources accumulées depuis lastTick
|
||||
export function computeIdleGains(state: GameState, now: number): number {
|
||||
const elapsedSeconds = (now - state.lastTick) / 1000;
|
||||
return totalProductionPerSecond(state) * elapsedSeconds;
|
||||
}
|
||||
|
||||
// Applique les gains idle et met à jour lastTick
|
||||
export function applyIdleGains(state: GameState, now: number): GameState {
|
||||
const gains = computeIdleGains(state, now);
|
||||
return {
|
||||
...state,
|
||||
resources: state.resources + gains,
|
||||
lastTick: now,
|
||||
};
|
||||
}
|
||||
|
||||
// Clic manuel
|
||||
export function applyClick(state: GameState): GameState {
|
||||
return {
|
||||
...state,
|
||||
resources: state.resources + state.clickMultiplier * state.prestigeMultiplier,
|
||||
};
|
||||
}
|
||||
|
||||
// Achat d'un générateur (retourne null si fonds insuffisants)
|
||||
export function buyGenerator(state: GameState, genId: string): 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);
|
||||
if (state.resources < cost) return null;
|
||||
|
||||
const updatedGenerators = [...state.generators];
|
||||
updatedGenerators[genIndex] = { ...gen, owned: gen.owned + 1 };
|
||||
|
||||
return {
|
||||
...state,
|
||||
resources: state.resources - cost,
|
||||
generators: updatedGenerators,
|
||||
};
|
||||
}
|
||||
|
||||
// Prestige : reset ressources + générateurs, +0.1× multiplicateur permanent
|
||||
export function canPrestige(state: GameState): boolean {
|
||||
return state.resources >= 1_000_000;
|
||||
}
|
||||
|
||||
export function applyPrestige(state: GameState): GameState {
|
||||
const newPrestigeCount = state.prestigeCount + 1;
|
||||
return {
|
||||
...state,
|
||||
resources: 0,
|
||||
generators: state.generators.map((g) => ({ ...g, owned: 0 })),
|
||||
prestigeCount: newPrestigeCount,
|
||||
prestigeMultiplier: 1 + newPrestigeCount * 0.1,
|
||||
lastTick: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
// Valeurs par défaut — 5 tiers alignés GDD (x10 coût / tier, x5 production)
|
||||
export const DEFAULT_GENERATORS: Generator[] = [
|
||||
{ id: "manic", name: "Manic", baseCost: 10, baseProduction: 0.1, owned: 0 },
|
||||
{ id: "coffee", name: "Tasse à café", baseCost: 100, baseProduction: 0.5, owned: 0 },
|
||||
{ id: "sugar", name: "Sucre", baseCost: 1_000, baseProduction: 3, owned: 0 },
|
||||
{ id: "factory", name: "Usine", baseCost: 10_000, baseProduction: 20, owned: 0 },
|
||||
{ id: "portal", name: "Portail", baseCost: 100_000, baseProduction: 150, owned: 0 },
|
||||
];
|
||||
|
||||
export const DEFAULT_STATE: GameState = {
|
||||
resources: 0,
|
||||
clickMultiplier: 1,
|
||||
generators: DEFAULT_GENERATORS,
|
||||
lastTick: Date.now(),
|
||||
prestigeCount: 0,
|
||||
prestigeMultiplier: 1,
|
||||
};
|
||||
Reference in New Issue
Block a user