219 lines
7.9 KiB
TypeScript

import { ResourceDisplay } from './components/ResourceDisplay'
import { BuildingButton } from './components/BuildingButton'
import { MultiplierShop } from './components/MultiplierShop'
import { NextBuildingPreview } from './components/NextBuildingPreview'
import { ResetButton } from './components/ResetButton'
import { useGameStore } from './store/gameStore'
import {
ChakraProvider,
Box,
Container,
Heading,
Text,
VStack,
SimpleGrid,
Button,
Flex
} from '@chakra-ui/react'
import theme from './theme'
import { useEffect } from 'react'
type BuildingId = 'mouseFarms' | 'keyboardFactories' | 'monitorDisplays' | 'officeSpace' | 'serverRooms' | 'dataCenters' |
'dataCities' | 'dataCountries' | 'dataContinents' | 'dataWorlds' | 'dataMoons' |
'dataSolarSystems' | 'dataGalaxies' | 'dataUniverses' | 'dataGods'
type BuildingLevelKey = `${BuildingId}Level`
const BUILDING_INFO = {
mouseFarms: {
title: 'Mouse Farm',
description: 'A basic facility that produces computer mice. Each mouse farm generates points automatically.',
production: { points: 0.1 }
},
keyboardFactories: {
title: 'Keyboard Factory',
description: 'Manufactures mechanical keyboards and generates tech parts. Essential for advanced upgrades.',
production: { techParts: 0.05 }
},
monitorDisplays: {
title: 'Monitor Display',
description: 'High-resolution displays that generate both points and tech parts. A balanced production facility.',
production: { points: 0.2, techParts: 0.1 }
},
serverRooms: {
title: 'Server Room',
description: 'A powerful facility that generates significant amounts of both resources. Requires proper cooling.',
production: { points: 1, techParts: 0.5 }
},
dataCenters: {
title: 'Data Center',
description: 'The ultimate production facility. Generates massive amounts of resources but requires significant investment.',
production: { points: 5, techParts: 2 }
},
dataCities: {
title: 'Data City',
description: 'A massive network of data centers spanning an entire city. Requires level 5 to unlock.',
production: { points: 25, techParts: 10 }
},
dataCountries: {
title: 'Data Country',
description: 'A country-wide network of data cities. Requires level 10 to unlock.',
production: { points: 100, techParts: 40 }
},
dataContinents: {
title: 'Data Continent',
description: 'A continent-spanning network of data countries. Requires level 20 to unlock.',
production: { points: 500, techParts: 200 }
},
dataWorlds: {
title: 'Data World',
description: 'A world-wide network of data continents. Requires level 30 to unlock.',
production: { points: 2500, techParts: 1000 }
},
dataMoons: {
title: 'Data Moon',
description: 'A moon-sized data processing facility. Requires level 40 to unlock.',
production: { points: 10000, techParts: 4000 }
},
dataSolarSystems: {
title: 'Data Solar System',
description: 'A solar system-wide network of data moons. Requires level 50 to unlock.',
production: { points: 50000, techParts: 20000 }
},
dataGalaxies: {
title: 'Data Galaxy',
description: 'A galaxy-spanning network of data solar systems. Requires level 60 to unlock.',
production: { points: 250000, techParts: 100000 }
},
dataUniverses: {
title: 'Data Universe',
description: 'A universe-wide network of data galaxies. Requires level 70 to unlock.',
production: { points: 1000000, techParts: 400000 }
},
dataGods: {
title: 'Data God',
description: 'The ultimate data processing entity. Requires level 80 to unlock.',
production: { points: 5000000, techParts: 2000000 }
}
}
function App() {
const {
points,
playerLevel,
getAvailableBuildings,
tick,
clickPower,
click
} = useGameStore()
const availableBuildings = getAvailableBuildings()
// Set up game tick interval
useEffect(() => {
const interval = setInterval(tick, 100) // 100ms = 10 ticks per second
return () => clearInterval(interval)
}, [tick])
// Handle clicks anywhere in the game
const handleClick = (e: React.MouseEvent) => {
// Don't count clicks on buttons or interactive elements
if (e.target instanceof HTMLElement &&
(e.target.tagName === 'BUTTON' ||
e.target.closest('button') ||
e.target.closest('[role="button"]'))) {
return
}
click()
}
return (
<ChakraProvider theme={theme}>
<Box
minH="100vh"
bg="gray.900"
color="white"
onClick={handleClick}
cursor="pointer"
>
<ResourceDisplay />
<Box pt="180px">
<Container maxW="container.xl">
<VStack spacing={8}>
<Box textAlign="center" w="full">
<Flex justify="space-between" align="center" mb={4}>
<Heading as="h1" size="2xl">Clicker Clicker 2</Heading>
<ResetButton />
</Flex>
<Text fontSize="xl" color="yellow.400" mb={4}>Level {playerLevel}</Text>
</Box>
<VStack spacing={8} w="full">
{/* Shop Section */}
<Box bg="gray.800" p={6} borderRadius="lg" w="full">
<Heading as="h2" size="xl" mb={6} color="blue.400">Shop</Heading>
<SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} gap={4}>
{availableBuildings.map((building) => (
<BuildingButton
key={building.id}
title={building.title}
cost={building.cost}
owned={useGameStore.getState()[building.id as BuildingId]}
level={useGameStore.getState()[`${building.id}Level` as BuildingLevelKey] as number}
onClick={() => useGameStore.getState().buyBuilding(building.id as BuildingId)}
description={building.description}
production={building.production}
buildingType={building.id}
levelRequirement={building.levelRequirement}
/>
))}
<NextBuildingPreview />
</SimpleGrid>
</Box>
<Box h="1px" bg="gray.600" w="full" />
{/* Upgrades Section */}
<Box bg="gray.800" p={6} borderRadius="lg" w="full">
<Heading as="h2" size="xl" mb={6} color="green.400">Upgrades</Heading>
<SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} gap={4}>
<Box
bg="gray.700"
p={4}
borderRadius="lg"
border="1px"
borderColor="gray.600"
>
<VStack align="stretch" spacing={2}>
<Box display="flex" justifyContent="space-between" alignItems="center">
<Text fontWeight="bold">Click Power</Text>
<Text>Level {clickPower}</Text>
</Box>
<Text fontSize="sm" color="gray.400">
Each click generates {clickPower} points
</Text>
<Button
onClick={() => useGameStore.getState().buyUpgrade('clickPower')}
isDisabled={points < 20}
bg="gray.600"
_hover={{ bg: 'gray.500' }}
>
Upgrade (20 points)
</Button>
</VStack>
</Box>
</SimpleGrid>
</Box>
</VStack>
<MultiplierShop />
</VStack>
</Container>
</Box>
</Box>
</ChakraProvider>
)
}
export default App