src/App.tsx (view raw)
1import { useEffect, useState } from 'react';
2import Header from './components/Header';
3import ClickArea from './components/ClickArea';
4import UpgradeShop from './components/UpgradeShop';
5import PrestigePanel from './components/PrestigePanel';
6import { GameState } from './types';
7import { initialUpgrades, initialPrestigeUpgrades } from './data/gameData';
8import { formatNumber } from './utils/formatters';
9import { saveGame, loadGame } from './utils/storage';
10import './App.css';
11
12function App() {
13 const [gameState, setGameState] = useState<GameState>({
14 currency: 0,
15 totalCurrency: 0,
16 clickValue: 1,
17 passiveIncome: 0,
18 autoClickRate: 0,
19 prestigePoints: 0,
20 prestigeMultiplier: 1,
21 lastSaveTime: Date.now(),
22 upgrades: initialUpgrades,
23 prestigeUpgrades: initialPrestigeUpgrades
24 });
25
26 // Load saved game on startup
27 useEffect(() => {
28 const savedGame = loadGame();
29 if (savedGame) {
30 // Calculate offline progress
31 const currentTime = Date.now();
32 const timeDiff = (currentTime - savedGame.lastSaveTime) / 1000; // in seconds
33 const offlineEarnings = Math.floor(savedGame.passiveIncome * timeDiff);
34
35 if (offlineEarnings > 0) {
36 savedGame.currency += offlineEarnings;
37 savedGame.totalCurrency += offlineEarnings;
38 alert(`Welcome back! You earned ${formatNumber(offlineEarnings)} while away.`);
39 }
40
41 savedGame.lastSaveTime = currentTime;
42 setGameState(savedGame);
43 }
44 }, []);
45
46 // Save game periodically
47 useEffect(() => {
48 const saveInterval = setInterval(() => {
49 saveGame({...gameState, lastSaveTime: Date.now()});
50 }, 10000); // Save every 10 seconds
51
52 return () => clearInterval(saveInterval);
53 }, [gameState]);
54
55 // Passive income logic
56 useEffect(() => {
57 const incomeInterval = setInterval(() => {
58 if (gameState.passiveIncome > 0) {
59 setGameState(prev => ({
60 ...prev,
61 currency: prev.currency + prev.passiveIncome,
62 totalCurrency: prev.totalCurrency + prev.passiveIncome
63 }));
64 }
65 }, 1000); // Every second
66
67 return () => clearInterval(incomeInterval);
68 }, [gameState.passiveIncome]);
69
70 // Auto click logic
71 useEffect(() => {
72 if (gameState.autoClickRate <= 0) return;
73
74 const clickInterval = setInterval(() => {
75 handleCurrencyClick();
76 }, 1000 / gameState.autoClickRate);
77
78 return () => clearInterval(clickInterval);
79 }, [gameState.autoClickRate, gameState.clickValue]);
80
81 const handleCurrencyClick = () => {
82 const value = gameState.clickValue * gameState.prestigeMultiplier;
83 setGameState(prev => ({
84 ...prev,
85 currency: prev.currency + value,
86 totalCurrency: prev.totalCurrency + value
87 }));
88 };
89
90 const purchaseUpgrade = (upgradeId: string) => {
91 const upgrade = gameState.upgrades.find(u => u.id === upgradeId);
92 if (!upgrade || gameState.currency < upgrade.cost) return;
93
94 const updatedUpgrades = gameState.upgrades.map(u => {
95 if (u.id === upgradeId) {
96 const newLevel = u.level + 1;
97 const newCost = Math.floor(u.baseCost * Math.pow(u.costMultiplier, newLevel));
98
99 return { ...u, level: newLevel, cost: newCost };
100 }
101 return u;
102 });
103
104 let newClickValue = gameState.clickValue;
105 let newPassiveIncome = gameState.passiveIncome;
106 let newAutoClickRate = gameState.autoClickRate;
107
108 switch (upgrade.type) {
109 case 'clickValue':
110 newClickValue += upgrade.value;
111 break;
112 case 'passive':
113 newPassiveIncome += upgrade.value;
114 break;
115 case 'autoClick':
116 newAutoClickRate += upgrade.value;
117 break;
118 }
119
120 setGameState(prev => ({
121 ...prev,
122 currency: prev.currency - upgrade.cost,
123 clickValue: newClickValue,
124 passiveIncome: newPassiveIncome,
125 autoClickRate: newAutoClickRate,
126 upgrades: updatedUpgrades
127 }));
128 };
129
130 const purchasePrestigeUpgrade = (upgradeId: string) => {
131 const upgrade = gameState.prestigeUpgrades.find(u => u.id === upgradeId);
132 if (!upgrade || gameState.prestigePoints < upgrade.cost || upgrade.purchased) return;
133
134 const updatedUpgrades = gameState.prestigeUpgrades.map(u => {
135 if (u.id === upgradeId) {
136 return { ...u, purchased: true };
137 }
138 return u;
139 });
140
141 let newPrestigeMultiplier = gameState.prestigeMultiplier;
142 newPrestigeMultiplier += upgrade.multiplierBonus;
143
144 setGameState(prev => ({
145 ...prev,
146 prestigePoints: prev.prestigePoints - upgrade.cost,
147 prestigeMultiplier: newPrestigeMultiplier,
148 prestigeUpgrades: updatedUpgrades
149 }));
150 };
151
152 const performPrestige = () => {
153 // Calculate prestige points based on total currency earned
154 const newPrestigePoints = Math.floor(Math.sqrt(gameState.totalCurrency / 1000000));
155
156 if (newPrestigePoints <= 0) {
157 alert("You need to earn more currency before prestiging!");
158 return;
159 }
160
161 if (!window.confirm(`Are you sure you want to prestige? You'll earn ${newPrestigePoints} prestige points but will lose all progress except prestige upgrades.`)) {
162 return;
163 }
164
165 // Reset game but keep prestige upgrades and add prestige points
166 setGameState(prev => ({
167 ...prev,
168 currency: 0,
169 totalCurrency: 0,
170 clickValue: 1,
171 passiveIncome: 0,
172 autoClickRate: 0,
173 prestigePoints: prev.prestigePoints + newPrestigePoints,
174 lastSaveTime: Date.now(),
175 upgrades: initialUpgrades
176 // Note: prestigeUpgrades and prestigeMultiplier are kept
177 }));
178 };
179
180 return (
181 <div className="app-container">
182 <Header
183 currency={gameState.currency}
184 clickValue={gameState.clickValue * gameState.prestigeMultiplier}
185 passiveIncome={gameState.passiveIncome}
186 autoClickRate={gameState.autoClickRate}
187 prestigePoints={gameState.prestigePoints}
188 prestigeMultiplier={gameState.prestigeMultiplier}
189 />
190
191 <main>
192 <ClickArea onCurrencyClick={handleCurrencyClick} />
193
194 <div className="game-sections">
195 <UpgradeShop
196 upgrades={gameState.upgrades}
197 currency={gameState.currency}
198 onPurchase={purchaseUpgrade}
199 prestigeMultiplier={gameState.prestigeMultiplier}
200 />
201
202 <PrestigePanel
203 totalCurrency={gameState.totalCurrency}
204 prestigePoints={gameState.prestigePoints}
205 prestigeUpgrades={gameState.prestigeUpgrades}
206 onPrestige={performPrestige}
207 onPurchaseUpgrade={purchasePrestigeUpgrade}
208 />
209 </div>
210 </main>
211 </div>
212 );
213}
214
215export default App;