fix: câbler tous les effets arbre + cleanup dette Sprint 2
- double_click_chance + crit_click_chance câblés dans applyClick (RNG) - auto_click câblé dans le tick (auto-pontes/s) - unlock_generator (Résilience) → 1 Lac Mystique gratuit au prestige - ponte_critique requires double_ponte (fix branche morte) - achievement_scaling retiré (nœud absent), full_tree + symbiose fixés - Particule feedback coloré (crit=ambre, double=violet) - 99 tests (tous passent)
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
|||||||
getStartBonusFromTree,
|
getStartBonusFromTree,
|
||||||
getPrestigeDnaBonus,
|
getPrestigeDnaBonus,
|
||||||
getCostReduction,
|
getCostReduction,
|
||||||
|
getAutoClicksPerSecond,
|
||||||
offlineEfficiency,
|
offlineEfficiency,
|
||||||
computeOfflineGains,
|
computeOfflineGains,
|
||||||
DEFAULT_STATE,
|
DEFAULT_STATE,
|
||||||
@@ -173,13 +174,15 @@ describe("computeIdleGains (lazy calculation)", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Click ---
|
// --- Click (avec double + crit) ---
|
||||||
|
|
||||||
describe("applyClick", () => {
|
describe("applyClick", () => {
|
||||||
it("augmente les ressources du clickMultiplier × prestigeMultiplier", () => {
|
it("augmente les ressources du clickMultiplier × prestigeMultiplier", () => {
|
||||||
const state = { ...DEFAULT_STATE, clickMultiplier: 3, prestigeMultiplier: 2 };
|
const state = { ...DEFAULT_STATE, clickMultiplier: 3, prestigeMultiplier: 2 };
|
||||||
const result = applyClick(state);
|
const result = applyClick(state, 0.99); // rng high → no double, no crit
|
||||||
expect(result.resources).toBe(6);
|
expect(result.state.resources).toBe(6);
|
||||||
|
expect(result.isDouble).toBe(false);
|
||||||
|
expect(result.isCrit).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("applique le multiplicateur click de l'arbre", () => {
|
it("applique le multiplicateur click de l'arbre", () => {
|
||||||
@@ -191,14 +194,58 @@ describe("applyClick", () => {
|
|||||||
n.id === "ponte_amelioree" ? { ...n, unlocked: true } : n
|
n.id === "ponte_amelioree" ? { ...n, unlocked: true } : n
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
const result = applyClick(state);
|
const result = applyClick(state, 0.99);
|
||||||
expect(result.resources).toBe(2); // ×2 depuis Ponte Améliorée
|
expect(result.state.resources).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("incrémente lifetimeTadpoles", () => {
|
it("incrémente lifetimeTadpoles", () => {
|
||||||
const state = { ...DEFAULT_STATE, clickMultiplier: 5, prestigeMultiplier: 1 };
|
const state = { ...DEFAULT_STATE, clickMultiplier: 5, prestigeMultiplier: 1 };
|
||||||
const result = applyClick(state);
|
const result = applyClick(state, 0.99);
|
||||||
expect(result.lifetimeTadpoles).toBe(5);
|
expect(result.state.lifetimeTadpoles).toBe(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("double ponte x2 quand rng < doubleClickChance", () => {
|
||||||
|
const state = {
|
||||||
|
...DEFAULT_STATE,
|
||||||
|
clickMultiplier: 1,
|
||||||
|
prestigeMultiplier: 1,
|
||||||
|
evolutionTree: DEFAULT_STATE.evolutionTree.map((n) =>
|
||||||
|
n.id === "double_ponte" ? { ...n, unlocked: true } : n
|
||||||
|
),
|
||||||
|
};
|
||||||
|
// double_ponte = 10% chance, rng=0.05 < 0.10 → double
|
||||||
|
const result = applyClick(state, 0.05);
|
||||||
|
expect(result.isDouble).toBe(true);
|
||||||
|
expect(result.gain).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("pas de double ponte quand rng > doubleClickChance", () => {
|
||||||
|
const state = {
|
||||||
|
...DEFAULT_STATE,
|
||||||
|
clickMultiplier: 1,
|
||||||
|
evolutionTree: DEFAULT_STATE.evolutionTree.map((n) =>
|
||||||
|
n.id === "double_ponte" ? { ...n, unlocked: true } : n
|
||||||
|
),
|
||||||
|
};
|
||||||
|
const result = applyClick(state, 0.50);
|
||||||
|
expect(result.isDouble).toBe(false);
|
||||||
|
expect(result.gain).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("crit x10 quand critRng < critClickChance", () => {
|
||||||
|
const state = {
|
||||||
|
...DEFAULT_STATE,
|
||||||
|
clickMultiplier: 1,
|
||||||
|
prestigeMultiplier: 1,
|
||||||
|
evolutionTree: DEFAULT_STATE.evolutionTree.map((n) =>
|
||||||
|
n.id === "ponte_critique" ? { ...n, unlocked: true } : n
|
||||||
|
),
|
||||||
|
};
|
||||||
|
// ponte_critique = 5% chance, need critRng = (rng * 7.13) % 1 < 0.05
|
||||||
|
// rng = 0.007 → critRng = 0.04991 < 0.05 → crit!
|
||||||
|
const result = applyClick(state, 0.007);
|
||||||
|
expect(result.isCrit).toBe(true);
|
||||||
|
expect(result.gain).toBe(10);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -444,6 +491,46 @@ describe("Evolution Tree (3 branches)", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("unlock_generator (Résilience)", () => {
|
||||||
|
it("prestige avec Résilience donne 1 Lac Mystique", () => {
|
||||||
|
const state = {
|
||||||
|
...DEFAULT_STATE,
|
||||||
|
resources: 2_000_000,
|
||||||
|
generators: DEFAULT_STATE.generators.map((g) => ({ ...g, owned: 5 })),
|
||||||
|
evolutionTree: DEFAULT_STATE.evolutionTree.map((n) =>
|
||||||
|
n.id === "resilience" ? { ...n, unlocked: true } : n
|
||||||
|
),
|
||||||
|
};
|
||||||
|
const result = applyPrestige(state);
|
||||||
|
const lac = result.generators.find((g) => g.id === "lac");
|
||||||
|
expect(lac!.owned).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("prestige sans Résilience donne 0 Lac Mystique", () => {
|
||||||
|
const state = {
|
||||||
|
...DEFAULT_STATE,
|
||||||
|
resources: 2_000_000,
|
||||||
|
generators: DEFAULT_STATE.generators.map((g) => ({ ...g, owned: 5 })),
|
||||||
|
};
|
||||||
|
const result = applyPrestige(state);
|
||||||
|
const lac = result.generators.find((g) => g.id === "lac");
|
||||||
|
expect(lac!.owned).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("auto_click (getAutoClicksPerSecond)", () => {
|
||||||
|
it("retourne 0 si auto_ponte non débloqué", () => {
|
||||||
|
expect(getAutoClicksPerSecond(DEFAULT_EVOLUTION_TREE)).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("retourne 1 si auto_ponte débloqué", () => {
|
||||||
|
const tree = DEFAULT_EVOLUTION_TREE.map((n) =>
|
||||||
|
n.id === "auto_ponte" ? { ...n, unlocked: true } : n
|
||||||
|
);
|
||||||
|
expect(getAutoClicksPerSecond(tree)).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("prestige threshold reduction", () => {
|
describe("prestige threshold reduction", () => {
|
||||||
it("Transcendance réduit le seuil de 50%", () => {
|
it("Transcendance réduit le seuil de 50%", () => {
|
||||||
const state = {
|
const state = {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ const EFFECT_LABELS: Record<string, (v: number) => string> = {
|
|||||||
production_multiplier: (v) => `x${v} production`,
|
production_multiplier: (v) => `x${v} production`,
|
||||||
start_bonus: (v) => `+${v} têtards au départ`,
|
start_bonus: (v) => `+${v} têtards au départ`,
|
||||||
unlock_generator: () => `Lac Mystique dès le début`,
|
unlock_generator: () => `Lac Mystique dès le début`,
|
||||||
achievement_scaling: (v) => `+${(v * 100).toFixed(0)}% prod/succès`,
|
|
||||||
double_click_chance: (v) => `${(v * 100).toFixed(0)}% chance double ponte`,
|
double_click_chance: (v) => `${(v * 100).toFixed(0)}% chance double ponte`,
|
||||||
auto_click: (v) => `${v} auto-ponte/s`,
|
auto_click: (v) => `${v} auto-ponte/s`,
|
||||||
crit_click_chance: (v) => `${(v * 100).toFixed(0)}% chance crit x10`,
|
crit_click_chance: (v) => `${(v * 100).toFixed(0)}% chance crit x10`,
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ export type EffectType =
|
|||||||
| "production_multiplier"
|
| "production_multiplier"
|
||||||
| "start_bonus"
|
| "start_bonus"
|
||||||
| "unlock_generator"
|
| "unlock_generator"
|
||||||
| "achievement_scaling"
|
|
||||||
| "double_click_chance"
|
| "double_click_chance"
|
||||||
| "auto_click"
|
| "auto_click"
|
||||||
| "crit_click_chance"
|
| "crit_click_chance"
|
||||||
@@ -65,7 +64,7 @@ export const DEFAULT_EVOLUTION_TREE: EvolutionNode[] = [
|
|||||||
{ id: "double_ponte", name: "Double Ponte", cost: 3, effect: "double_click_chance", value: 0.10, unlocked: false, requires: "ponte_amelioree", branch: "ponte" },
|
{ id: "double_ponte", name: "Double Ponte", cost: 3, effect: "double_click_chance", value: 0.10, unlocked: false, requires: "ponte_amelioree", branch: "ponte" },
|
||||||
{ id: "ponte_frenetique", name: "Ponte Frénétique", cost: 8, effect: "click_multiplier", value: 3, unlocked: false, requires: "double_ponte", branch: "ponte", exclusive_with: "auto_ponte" },
|
{ id: "ponte_frenetique", name: "Ponte Frénétique", cost: 8, effect: "click_multiplier", value: 3, unlocked: false, requires: "double_ponte", branch: "ponte", exclusive_with: "auto_ponte" },
|
||||||
{ id: "auto_ponte", name: "Auto-Ponte", cost: 8, effect: "auto_click", value: 1, unlocked: false, requires: "double_ponte", branch: "ponte", exclusive_with: "ponte_frenetique" },
|
{ id: "auto_ponte", name: "Auto-Ponte", cost: 8, effect: "auto_click", value: 1, unlocked: false, requires: "double_ponte", branch: "ponte", exclusive_with: "ponte_frenetique" },
|
||||||
{ id: "ponte_critique", name: "Ponte Critique", cost: 20, effect: "crit_click_chance", value: 0.05, unlocked: false, requires: "ponte_frenetique", branch: "ponte" },
|
{ id: "ponte_critique", name: "Ponte Critique", cost: 20, effect: "crit_click_chance", value: 0.05, unlocked: false, requires: "double_ponte", branch: "ponte" },
|
||||||
{ id: "maitre_pondeur", name: "Maître Pondeur", cost: 40, effect: "click_multiplier", value: 5, unlocked: false, requires: "ponte_critique", branch: "ponte" },
|
{ id: "maitre_pondeur", name: "Maître Pondeur", cost: 40, effect: "click_multiplier", value: 5, unlocked: false, requires: "ponte_critique", branch: "ponte" },
|
||||||
|
|
||||||
// --- Marais (production) ---
|
// --- Marais (production) ---
|
||||||
@@ -305,19 +304,48 @@ export function applyIdleGains(state: GameState, now: number): GameState {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gain réel par clic (pour affichage particule)
|
// Gain de base par clic (sans RNG — pour affichage tooltip)
|
||||||
export function getClickGain(state: GameState): number {
|
export function getClickGain(state: GameState): number {
|
||||||
const treeClickMult = getClickMultiplierFromTree(state.evolutionTree);
|
const treeClickMult = getClickMultiplierFromTree(state.evolutionTree);
|
||||||
return state.clickMultiplier * state.prestigeMultiplier * treeClickMult;
|
return state.clickMultiplier * state.prestigeMultiplier * treeClickMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clic manuel
|
export interface ClickResult {
|
||||||
export function applyClick(state: GameState): GameState {
|
state: GameState;
|
||||||
const gain = getClickGain(state);
|
gain: number;
|
||||||
|
isDouble: boolean;
|
||||||
|
isCrit: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clic manuel avec double ponte + crit
|
||||||
|
export function applyClick(state: GameState, rng: number = Math.random()): ClickResult {
|
||||||
|
let gain = getClickGain(state);
|
||||||
|
let isDouble = false;
|
||||||
|
let isCrit = false;
|
||||||
|
|
||||||
|
const doubleChance = getDoubleClickChance(state.evolutionTree);
|
||||||
|
if (doubleChance > 0 && rng < doubleChance) {
|
||||||
|
gain *= 2;
|
||||||
|
isDouble = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const critChance = getCritClickChance(state.evolutionTree);
|
||||||
|
// Use a second "roll" derived from rng to avoid double+crit being correlated
|
||||||
|
const critRng = (rng * 7.13) % 1;
|
||||||
|
if (critChance > 0 && critRng < critChance) {
|
||||||
|
gain *= 10;
|
||||||
|
isCrit = true;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
state: {
|
||||||
resources: state.resources + gain,
|
...state,
|
||||||
lifetimeTadpoles: state.lifetimeTadpoles + gain,
|
resources: state.resources + gain,
|
||||||
|
lifetimeTadpoles: state.lifetimeTadpoles + gain,
|
||||||
|
},
|
||||||
|
gain,
|
||||||
|
isDouble,
|
||||||
|
isCrit,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,10 +387,18 @@ export function applyPrestige(state: GameState): GameState {
|
|||||||
const dnaGained = Math.floor(baseDna * (1 + dnaBonus));
|
const dnaGained = Math.floor(baseDna * (1 + dnaBonus));
|
||||||
const startBonus = getStartBonusFromTree(state.evolutionTree);
|
const startBonus = getStartBonusFromTree(state.evolutionTree);
|
||||||
|
|
||||||
|
// Résilience : commencer avec 1 Lac Mystique
|
||||||
|
const hasUnlockGen = state.evolutionTree.some(
|
||||||
|
(n) => n.unlocked && n.effect === "unlock_generator"
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
resources: startBonus,
|
resources: startBonus,
|
||||||
generators: state.generators.map((g) => ({ ...g, owned: 0 })),
|
generators: state.generators.map((g) => ({
|
||||||
|
...g,
|
||||||
|
owned: hasUnlockGen && g.id === "lac" ? 1 : 0,
|
||||||
|
})),
|
||||||
prestigeCount: newPrestigeCount,
|
prestigeCount: newPrestigeCount,
|
||||||
prestigeMultiplier: 1 + newPrestigeCount * 0.1,
|
prestigeMultiplier: 1 + newPrestigeCount * 0.1,
|
||||||
ancestralDna: state.ancestralDna + dnaGained,
|
ancestralDna: state.ancestralDna + dnaGained,
|
||||||
|
|||||||
@@ -165,9 +165,12 @@ export const ACHIEVEMENTS: Achievement[] = [
|
|||||||
{
|
{
|
||||||
id: "full_tree",
|
id: "full_tree",
|
||||||
name: "Évolution Complète",
|
name: "Évolution Complète",
|
||||||
description: "Débloquer tous les noeuds de l'arbre.",
|
description: "Débloquer un nœud dans chaque branche de l'arbre.",
|
||||||
icon: "🌳",
|
icon: "🌳",
|
||||||
check: (s) => s.evolutionTree.every((n) => n.unlocked),
|
check: (s) => {
|
||||||
|
const branches = new Set(s.evolutionTree.filter((n) => n.unlocked).map((n) => n.branch));
|
||||||
|
return branches.size >= 3;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// --- Easter eggs & humour ---
|
// --- Easter eggs & humour ---
|
||||||
@@ -211,6 +214,6 @@ export const ACHIEVEMENTS: Achievement[] = [
|
|||||||
name: "Le Cercle de la Vie",
|
name: "Le Cercle de la Vie",
|
||||||
description: "Symbiose activée. Même Mufasa serait fier.",
|
description: "Symbiose activée. Même Mufasa serait fier.",
|
||||||
icon: "🦁",
|
icon: "🦁",
|
||||||
check: (s) => hasEvolutionNode(s, "symbiose"),
|
check: (s) => hasEvolutionNode(s, "symbiose_algale"),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -22,21 +22,30 @@ export default function Home() {
|
|||||||
const state = useGameStore((s) => s.state);
|
const state = useGameStore((s) => s.state);
|
||||||
const clickGain = getClickGain(state);
|
const clickGain = getClickGain(state);
|
||||||
|
|
||||||
const createParticle = useCallback((clientX, clientY) => {
|
const lastClickGain = useGameStore((s) => s.lastClickGain);
|
||||||
|
const lastClickDouble = useGameStore((s) => s.lastClickDouble);
|
||||||
|
const lastClickCrit = useGameStore((s) => s.lastClickCrit);
|
||||||
|
|
||||||
|
const createParticle = useCallback((clientX, clientY, gain, isDouble, isCrit) => {
|
||||||
const particle = document.createElement("span");
|
const particle = document.createElement("span");
|
||||||
particle.className = "click-particle";
|
particle.className = "click-particle";
|
||||||
particle.textContent = `+${formatNumber(clickGain)}`;
|
const prefix = isCrit ? "CRIT " : isDouble ? "x2 " : "";
|
||||||
|
particle.textContent = `${prefix}+${formatNumber(gain)}`;
|
||||||
|
if (isCrit) particle.style.color = "#f59e0b";
|
||||||
|
else if (isDouble) particle.style.color = "#a78bfa";
|
||||||
particle.style.left = `${clientX}px`;
|
particle.style.left = `${clientX}px`;
|
||||||
particle.style.top = `${clientY}px`;
|
particle.style.top = `${clientY}px`;
|
||||||
document.body.appendChild(particle);
|
document.body.appendChild(particle);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (particle.parentNode) particle.parentNode.removeChild(particle);
|
if (particle.parentNode) particle.parentNode.removeChild(particle);
|
||||||
}, 800);
|
}, 800);
|
||||||
}, [clickGain]);
|
}, []);
|
||||||
|
|
||||||
const handleIncrement = useCallback((e) => {
|
const handleIncrement = useCallback((e) => {
|
||||||
click();
|
click();
|
||||||
createParticle(e.clientX, e.clientY);
|
// Read latest click result from store after click
|
||||||
|
const s = useGameStore.getState();
|
||||||
|
createParticle(e.clientX, e.clientY, s.lastClickGain, s.lastClickDouble, s.lastClickCrit);
|
||||||
}, [click, createParticle]);
|
}, [click, createParticle]);
|
||||||
|
|
||||||
// Rain effect (ambiance)
|
// Rain effect (ambiance)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import {
|
|||||||
DEFAULT_STATE,
|
DEFAULT_STATE,
|
||||||
applyIdleGains,
|
applyIdleGains,
|
||||||
applyClick,
|
applyClick,
|
||||||
|
getClickGain,
|
||||||
|
getAutoClicksPerSecond,
|
||||||
buyGenerator,
|
buyGenerator,
|
||||||
buyEvolutionNode,
|
buyEvolutionNode,
|
||||||
resetEvolutionTree,
|
resetEvolutionTree,
|
||||||
@@ -66,6 +68,11 @@ interface GameStore {
|
|||||||
offlineReport: OfflineReport | null;
|
offlineReport: OfflineReport | null;
|
||||||
dismissOfflineReport: () => void;
|
dismissOfflineReport: () => void;
|
||||||
|
|
||||||
|
// Last click result (for particle feedback)
|
||||||
|
lastClickGain: number;
|
||||||
|
lastClickDouble: boolean;
|
||||||
|
lastClickCrit: boolean;
|
||||||
|
|
||||||
// Derived (recalculated on tick)
|
// Derived (recalculated on tick)
|
||||||
canPrestige: boolean;
|
canPrestige: boolean;
|
||||||
productionPerSecond: number;
|
productionPerSecond: number;
|
||||||
@@ -135,6 +142,9 @@ export const useGameStore = create<GameStore>((set, get) => ({
|
|||||||
playSeconds: 0,
|
playSeconds: 0,
|
||||||
ready: false,
|
ready: false,
|
||||||
offlineReport: null,
|
offlineReport: null,
|
||||||
|
lastClickGain: 0,
|
||||||
|
lastClickDouble: false,
|
||||||
|
lastClickCrit: false,
|
||||||
canPrestige: false,
|
canPrestige: false,
|
||||||
productionPerSecond: 0,
|
productionPerSecond: 0,
|
||||||
|
|
||||||
@@ -147,6 +157,14 @@ export const useGameStore = create<GameStore>((set, get) => ({
|
|||||||
const updated = applyIdleGains(s.state, now);
|
const updated = applyIdleGains(s.state, now);
|
||||||
updated.lastOnline = now;
|
updated.lastOnline = now;
|
||||||
|
|
||||||
|
// Auto-click from evolution tree
|
||||||
|
const autoClicks = getAutoClicksPerSecond(updated.evolutionTree);
|
||||||
|
if (autoClicks > 0) {
|
||||||
|
const autoGain = getClickGain(updated) * autoClicks;
|
||||||
|
updated.resources += autoGain;
|
||||||
|
updated.lifetimeTadpoles += autoGain;
|
||||||
|
}
|
||||||
|
|
||||||
// Check cosmetic unlocks every 5s
|
// Check cosmetic unlocks every 5s
|
||||||
if (s.playSeconds % 5 === 0) {
|
if (s.playSeconds % 5 === 0) {
|
||||||
const cosState = { inventory: updated.cosmeticInventory, equipped: updated.cosmeticEquipped };
|
const cosState = { inventory: updated.cosmeticInventory, equipped: updated.cosmeticEquipped };
|
||||||
@@ -170,12 +188,15 @@ export const useGameStore = create<GameStore>((set, get) => ({
|
|||||||
click: () => {
|
click: () => {
|
||||||
if (!get().ready) return;
|
if (!get().ready) return;
|
||||||
set((s) => {
|
set((s) => {
|
||||||
const updated = applyClick(applyIdleGains(s.state, Date.now()));
|
const result = applyClick(applyIdleGains(s.state, Date.now()));
|
||||||
saveLocal(updated);
|
saveLocal(result.state);
|
||||||
return {
|
return {
|
||||||
state: updated,
|
state: result.state,
|
||||||
canPrestige: canPrestigeCheck(updated),
|
lastClickGain: result.gain,
|
||||||
productionPerSecond: totalProductionPerSecond(updated),
|
lastClickDouble: result.isDouble,
|
||||||
|
lastClickCrit: result.isCrit,
|
||||||
|
canPrestige: canPrestigeCheck(result.state),
|
||||||
|
productionPerSecond: totalProductionPerSecond(result.state),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user