Add gape seeds and god modal
This commit is contained in:
parent
9edb030079
commit
5eda5c158b
16
src/App.tsx
16
src/App.tsx
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
|
|
@ -13,6 +13,7 @@ import Temple from './components/Temple'
|
|||
import { ActionCooldown } from './components/ActionCooldown'
|
||||
import { useSaveSystem } from './store/useSaveSystem'
|
||||
import { Console } from './components/Console'
|
||||
import { GodModal } from './components/GodModal'
|
||||
|
||||
const appContainerStyle: React.CSSProperties = {
|
||||
maxWidth: '1200px',
|
||||
|
|
@ -29,6 +30,18 @@ const tabsListStyles: React.CSSProperties = {
|
|||
function App() {
|
||||
useGameTick()
|
||||
useSaveSystem()
|
||||
const [isGodModalOpen, setIsGodModalOpen] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyPress = (event: KeyboardEvent) => {
|
||||
if (event.key.toLowerCase() === 'g') {
|
||||
setIsGodModalOpen(prev => !prev)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', handleKeyPress)
|
||||
return () => window.removeEventListener('keydown', handleKeyPress)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -56,6 +69,7 @@ function App() {
|
|||
</Tabs>
|
||||
<Console />
|
||||
</div>
|
||||
{isGodModalOpen && <GodModal onClose={() => setIsGodModalOpen(false)} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,35 +59,6 @@ const getCropButtonStyle = (active: boolean): React.CSSProperties => ({
|
|||
cursor: 'pointer',
|
||||
})
|
||||
|
||||
const speedSelectorContainerStyle: React.CSSProperties = {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
marginBottom: '1rem',
|
||||
padding: '0.5rem',
|
||||
backgroundColor: '#f9fafb',
|
||||
borderRadius: '0.5rem',
|
||||
border: '1px solid #e5e7eb',
|
||||
}
|
||||
|
||||
const speedSelectorLabelStyle: React.CSSProperties = {
|
||||
fontWeight: 500,
|
||||
marginBottom: '0.5rem',
|
||||
}
|
||||
|
||||
const speedButtonsContainerStyle: React.CSSProperties = {
|
||||
display: 'flex',
|
||||
gap: '0.5rem',
|
||||
}
|
||||
|
||||
const getSpeedButtonStyle = (active: boolean): React.CSSProperties => ({
|
||||
padding: '0.5rem 1rem',
|
||||
borderRadius: '0.25rem',
|
||||
border: '1px solid #ccc',
|
||||
backgroundColor: active ? '#4ade80' : '#f3f4f6',
|
||||
cursor: 'pointer',
|
||||
})
|
||||
|
||||
const getFieldGridStyle = (size: number): React.CSSProperties => ({
|
||||
display: 'grid',
|
||||
gridTemplateColumns: `repeat(${size}, 1fr)`,
|
||||
|
|
@ -220,8 +191,6 @@ const FieldComponent: React.FC = () => {
|
|||
harvest,
|
||||
remove,
|
||||
assignCrop,
|
||||
gameSpeed,
|
||||
setGameSpeed,
|
||||
actionCooldown,
|
||||
} = useGameStore()
|
||||
|
||||
|
|
@ -276,8 +245,6 @@ const FieldComponent: React.FC = () => {
|
|||
return `rgb(${r}, ${g}, ${b})`
|
||||
}
|
||||
|
||||
const availableSpeeds = [1, 2, 4, 8, 16, 32, 64]
|
||||
|
||||
const tools: { id: FieldTool; label: string; icon: string }[] = [
|
||||
{ id: 'mark', label: 'Mark', icon: '🎯' },
|
||||
{ id: 'plant', label: 'Plant', icon: '🌱' },
|
||||
|
|
@ -291,21 +258,6 @@ const FieldComponent: React.FC = () => {
|
|||
<div style={fieldContainerStyle}>
|
||||
<h2 style={titleStyle}>Fields</h2>
|
||||
|
||||
<div style={speedSelectorContainerStyle}>
|
||||
<p style={speedSelectorLabelStyle}>Game Speed:</p>
|
||||
<div style={speedButtonsContainerStyle}>
|
||||
{availableSpeeds.map((speed) => (
|
||||
<button
|
||||
style={getSpeedButtonStyle(gameSpeed === speed)}
|
||||
onClick={() => setGameSpeed(speed)}
|
||||
key={speed}
|
||||
>
|
||||
{speed}x
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={toolbarStyle}>
|
||||
{tools.map((tool) => (
|
||||
<button
|
||||
|
|
|
|||
96
src/components/GodModal.tsx
Normal file
96
src/components/GodModal.tsx
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import React from 'react'
|
||||
import { styled } from '@linaria/react'
|
||||
import { useGameStore } from '../store/useGameStore'
|
||||
import Modal from './Modal'
|
||||
|
||||
const Section = styled.div`
|
||||
margin-bottom: 1.5rem;
|
||||
`
|
||||
|
||||
const SectionTitle = styled.h3`
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.5rem;
|
||||
`
|
||||
|
||||
const SpeedButtonsContainer = styled.div`
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
`
|
||||
|
||||
const SpeedButton = styled.button<{ active?: boolean }>`
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.25rem;
|
||||
border: 1px solid #ccc;
|
||||
background-color: ${props => props.active ? '#4ade80' : '#f3f4f6'};
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: ${props => props.active ? '#4ade80' : '#e5e7eb'};
|
||||
}
|
||||
`
|
||||
|
||||
const AddCashButton = styled.button`
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.375rem;
|
||||
background-color: #4f46e5;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
width: 100%;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
&:hover {
|
||||
background-color: #4338ca;
|
||||
}
|
||||
`
|
||||
|
||||
interface GodModalProps {
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
export const GodModal: React.FC<GodModalProps> = ({ onClose }) => {
|
||||
const { gameSpeed, setGameSpeed, addCash } = useGameStore()
|
||||
|
||||
const availableSpeeds = [1, 2, 4, 8, 16, 32, 64]
|
||||
const presetAmounts = [5, 10, 100]
|
||||
|
||||
const handleAddCashClick = (amount: number) => {
|
||||
addCash(amount)
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal onClose={onClose} title="God Controls">
|
||||
<Section>
|
||||
<SectionTitle>Game Speed</SectionTitle>
|
||||
<SpeedButtonsContainer>
|
||||
{availableSpeeds.map((speed) => (
|
||||
<SpeedButton
|
||||
key={speed}
|
||||
active={gameSpeed === speed}
|
||||
onClick={() => setGameSpeed(speed)}
|
||||
>
|
||||
{speed}x
|
||||
</SpeedButton>
|
||||
))}
|
||||
</SpeedButtonsContainer>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<SectionTitle>Add Cash</SectionTitle>
|
||||
{presetAmounts.map((amount) => (
|
||||
<AddCashButton
|
||||
key={amount}
|
||||
onClick={() => handleAddCashClick(amount)}
|
||||
>
|
||||
${amount}
|
||||
</AddCashButton>
|
||||
))}
|
||||
</Section>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
|
@ -46,6 +46,18 @@ export const CROPS: CropDefinitions = {
|
|||
isPerennial: true,
|
||||
regrowthProgress: 150, // Resets to 150 ticks after harvest
|
||||
},
|
||||
grape_vine: {
|
||||
id: 'grape_vine',
|
||||
name: 'Grape Vine',
|
||||
growthTicks: 250,
|
||||
waterPerTick: 1 / 45,
|
||||
yield: 2,
|
||||
yieldType: 'grape',
|
||||
fertilityDepletion: 0.15,
|
||||
seedType: 'grape_seed',
|
||||
isPerennial: true,
|
||||
regrowthProgress: 200, // Resets to 200 ticks after harvest
|
||||
},
|
||||
}
|
||||
|
||||
export const INITIAL_INVENTORY = {
|
||||
|
|
@ -172,6 +184,13 @@ export const ITEMS: Record<string, Item> = {
|
|||
buyPrice: 5,
|
||||
sellPrice: null,
|
||||
},
|
||||
grape_seed: {
|
||||
id: 'grape_seed',
|
||||
name: 'Grape Seeds',
|
||||
emoji: '🌰',
|
||||
buyPrice: 25,
|
||||
sellPrice: null,
|
||||
},
|
||||
celery: {
|
||||
id: 'celery',
|
||||
name: 'Celery',
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ export const useGameStore = create<
|
|||
buyEquipment: (equipmentId: string) => void
|
||||
configureEquipment: (equipmentId: string, recipeId: string) => void
|
||||
useEquipment: (equipmentId: string) => void
|
||||
addCash: (amount: number) => void
|
||||
}
|
||||
>((set, get) => ({
|
||||
cash: INITIAL_CASH,
|
||||
|
|
@ -132,6 +133,7 @@ export const useGameStore = create<
|
|||
piety: 50,
|
||||
landPurchases: 0,
|
||||
equipment: {},
|
||||
milestones: {},
|
||||
|
||||
assignCrop: (row, col, cropId) => {
|
||||
set(
|
||||
|
|
@ -266,6 +268,10 @@ export const useGameStore = create<
|
|||
state.plots[row][col].fertility - crop.fertilityDepletion,
|
||||
)
|
||||
state.actionCooldown = COOLDOWN_DURATION
|
||||
|
||||
// Track milestone for crop harvest
|
||||
const milestoneKey = `crops_harvested_${crop.id}`
|
||||
state.milestones[milestoneKey] = (state.milestones[milestoneKey] || 0) + yieldAmount
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
@ -662,4 +668,10 @@ export const useGameStore = create<
|
|||
}),
|
||||
)
|
||||
},
|
||||
|
||||
addCash: (amount) => {
|
||||
set(
|
||||
produce((state) => { state.cash += amount }),
|
||||
)
|
||||
},
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ export interface GameState {
|
|||
piety: number
|
||||
landPurchases: number
|
||||
equipment: EquipmentState
|
||||
milestones: Partial<Record<string, number>>
|
||||
}
|
||||
|
||||
export interface MarketTransaction {
|
||||
|
|
|
|||
Loading…
Reference in a new issue