Add prayer action to the temple.
This commit is contained in:
parent
6d72c8c0f9
commit
ba9b26ff64
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||
import { useGameStore } from '../store/useGameStore'
|
||||
import { UPGRADES } from '../constants'
|
||||
import { styled } from '@linaria/react'
|
||||
import type { UpgradeCost } from '../types'
|
||||
import type { UpgradeCost, Upgrade } from '../types'
|
||||
|
||||
const TempleContainer = styled.div`
|
||||
padding: 1rem;
|
||||
|
|
@ -15,6 +15,46 @@ const Title = styled.h2`
|
|||
text-align: center;
|
||||
`
|
||||
|
||||
const PrayerSection = styled.div`
|
||||
background-color: #f8fafc;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
`
|
||||
|
||||
const PietyDisplay = styled.div`
|
||||
font-size: 1.25rem;
|
||||
color: #4b5563;
|
||||
margin-bottom: 1rem;
|
||||
`
|
||||
|
||||
const PrayerButton = styled.button<{ disabled?: boolean }>`
|
||||
padding: 1rem 2rem;
|
||||
font-size: 1.25rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: ${props => props.disabled ? '#9ca3af' : '#8b5cf6'};
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
|
||||
border: none;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin: 0 auto;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background-color: #7c3aed;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&:active:not(:disabled) {
|
||||
transform: translateY(0);
|
||||
}
|
||||
`
|
||||
|
||||
const UpgradesGrid = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
|
|
@ -68,7 +108,7 @@ const PurchaseButton = styled.button<{ disabled?: boolean }>`
|
|||
`
|
||||
|
||||
const TempleComponent: React.FC = () => {
|
||||
const { inventory, purchasedUpgrades, purchaseUpgrade } = useGameStore()
|
||||
const { inventory, purchasedUpgrades, purchaseUpgrade, pray, piety, actionCooldown } = useGameStore()
|
||||
|
||||
const handlePurchase = (upgradeId: string) => {
|
||||
purchaseUpgrade(upgradeId)
|
||||
|
|
@ -81,13 +121,58 @@ const TempleComponent: React.FC = () => {
|
|||
)
|
||||
}
|
||||
|
||||
const canPurchaseUpgrade = (upgrade: Upgrade) => {
|
||||
// Check if already purchased
|
||||
if (purchasedUpgrades.includes(upgrade.id)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if can afford
|
||||
if (!canAffordUpgrade(upgrade.cost)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check requirements
|
||||
if (upgrade.id === 'aqueous_vigor_2' && !purchasedUpgrades.includes('aqueous_vigor_1')) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const getUpgradeStatus = (upgrade: Upgrade) => {
|
||||
if (purchasedUpgrades.includes(upgrade.id)) {
|
||||
return 'Purchased'
|
||||
}
|
||||
if (upgrade.id === 'aqueous_vigor_2' && !purchasedUpgrades.includes('aqueous_vigor_1')) {
|
||||
return 'Requires Aqueous Vigor I'
|
||||
}
|
||||
if (!canAffordUpgrade(upgrade.cost)) {
|
||||
return 'Cannot Afford'
|
||||
}
|
||||
return 'Purchase'
|
||||
}
|
||||
|
||||
return (
|
||||
<TempleContainer>
|
||||
<Title>Temple</Title>
|
||||
|
||||
<PrayerSection>
|
||||
<PietyDisplay>Piety Level: {piety}</PietyDisplay>
|
||||
<PrayerButton
|
||||
onClick={() => pray()}
|
||||
disabled={actionCooldown > 0}
|
||||
>
|
||||
🙏 Pray to the Gods
|
||||
{actionCooldown > 0 && ` (${(actionCooldown / 1000).toFixed(1)}s)`}
|
||||
</PrayerButton>
|
||||
</PrayerSection>
|
||||
|
||||
<UpgradesGrid>
|
||||
{Object.values(UPGRADES).map((upgrade) => {
|
||||
const isPurchased = purchasedUpgrades.includes(upgrade.id)
|
||||
const canAfford = canAffordUpgrade(upgrade.cost)
|
||||
const canPurchase = canPurchaseUpgrade(upgrade)
|
||||
const status = getUpgradeStatus(upgrade)
|
||||
|
||||
return (
|
||||
<UpgradeCard key={upgrade.id} purchased={isPurchased}>
|
||||
|
|
@ -106,9 +191,9 @@ const TempleComponent: React.FC = () => {
|
|||
</UpgradeCost>
|
||||
<PurchaseButton
|
||||
onClick={() => handlePurchase(upgrade.id)}
|
||||
disabled={isPurchased || !canAfford}
|
||||
disabled={!canPurchase}
|
||||
>
|
||||
{isPurchased ? 'Purchased' : 'Purchase'}
|
||||
{status}
|
||||
</PurchaseButton>
|
||||
</UpgradeCard>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,15 @@ export const UPGRADES: Record<string, Upgrade> = {
|
|||
itemId: 'celery',
|
||||
amount: 10
|
||||
}]
|
||||
},
|
||||
aqueous_vigor_2: {
|
||||
id: 'aqueous_vigor_2',
|
||||
name: 'Aqueous Vigor II',
|
||||
description: 'Reduces watering cooldown by an additional 25% (requires Aqueous Vigor I)',
|
||||
cost: [{
|
||||
itemId: 'celery',
|
||||
amount: 25
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,32 @@ const addConsoleMessage = (state: GameState, text: string) => (
|
|||
].slice(0, 50)
|
||||
)
|
||||
|
||||
const progressRandomImmaturePlot = (state: GameState, growthAmount: number): boolean => {
|
||||
// Find all immature plants
|
||||
const immaturePlots: { row: number; col: number }[] = []
|
||||
state.plots.forEach((row, rowIndex) => {
|
||||
row.forEach((plot, colIndex) => {
|
||||
if (plot.current && !plot.current.mature) {
|
||||
immaturePlots.push({ row: rowIndex, col: colIndex })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (immaturePlots.length > 0) {
|
||||
// Select a random immature plot and progress it
|
||||
const randomPlot = immaturePlots[Math.floor(Math.random() * immaturePlots.length)]
|
||||
const plot = state.plots[randomPlot.row][randomPlot.col]
|
||||
|
||||
const crop = CROPS[plot.current!.cropId]
|
||||
const actualGrowthAmount = crop.growthTicks * growthAmount
|
||||
plot.current!.progress = Math.min(
|
||||
crop.growthTicks,
|
||||
plot.current!.progress + actualGrowthAmount
|
||||
)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const useGameStore = create<
|
||||
GameState & {
|
||||
|
|
@ -81,6 +107,7 @@ export const useGameStore = create<
|
|||
saveToSlot: (slot: number) => void
|
||||
loadFromSlot: (slot: number) => void
|
||||
purchaseUpgrade: (upgradeId: string) => void
|
||||
pray: () => void
|
||||
}
|
||||
>((set, get) => ({
|
||||
cash: INITIAL_CASH,
|
||||
|
|
@ -94,6 +121,7 @@ export const useGameStore = create<
|
|||
tickCount: 0,
|
||||
consoleMessages: [],
|
||||
purchasedUpgrades: [],
|
||||
piety: 50,
|
||||
|
||||
assignCrop: (row, col, cropId) => {
|
||||
set(
|
||||
|
|
@ -140,15 +168,18 @@ export const useGameStore = create<
|
|||
|
||||
const plot = plots[row][col]
|
||||
if (plot.current && plot.moisture < 1) {
|
||||
// Calculate cooldown reduction from upgrades
|
||||
let cooldownReduction = 0
|
||||
// Calculate cooldown reduction from upgrades (multiplicative)
|
||||
let cooldownMultiplier = 1
|
||||
if (purchasedUpgrades.includes('aqueous_vigor_1')) {
|
||||
cooldownReduction += 0.25 // 25% reduction
|
||||
cooldownMultiplier *= 0.75 // 25% reduction
|
||||
}
|
||||
if (purchasedUpgrades.includes('aqueous_vigor_2')) {
|
||||
cooldownMultiplier *= 0.75 // Additional 25% reduction
|
||||
}
|
||||
|
||||
const finalCooldown = Math.max(
|
||||
0,
|
||||
COOLDOWN_DURATION * (1 - cooldownReduction)
|
||||
COOLDOWN_DURATION * cooldownMultiplier
|
||||
)
|
||||
|
||||
set(
|
||||
|
|
@ -346,6 +377,7 @@ export const useGameStore = create<
|
|||
saveToSlot,
|
||||
loadFromSlot,
|
||||
purchaseUpgrade,
|
||||
pray,
|
||||
...gameState
|
||||
} = state
|
||||
saveGame(slot, gameState)
|
||||
|
|
@ -389,4 +421,43 @@ export const useGameStore = create<
|
|||
}),
|
||||
)
|
||||
},
|
||||
|
||||
pray: () => {
|
||||
const { actionCooldown, piety, plots } = get()
|
||||
|
||||
if (actionCooldown > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
set(
|
||||
produce((state) => {
|
||||
const roll = Math.random()
|
||||
const result = roll * piety
|
||||
|
||||
if (result < 50 || roll < 0.3) {
|
||||
state.piety += 1
|
||||
addConsoleMessage(
|
||||
state,
|
||||
"Nothing happens, but you feel the approval of the gods"
|
||||
)
|
||||
} else if (result > 100) {
|
||||
if (progressRandomImmaturePlot(state, 0.3)) {
|
||||
addConsoleMessage(
|
||||
state,
|
||||
"The gods have bestowed a significant blessing on one of your crops"
|
||||
)
|
||||
}
|
||||
} else if (result > 50) {
|
||||
if (progressRandomImmaturePlot(state, 0.1)) {
|
||||
addConsoleMessage(
|
||||
state,
|
||||
"The gods have bestowed a minor blessing on one of your crops"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
state.actionCooldown = 3000
|
||||
})
|
||||
)
|
||||
},
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ export interface GameState {
|
|||
actionCooldown: number
|
||||
consoleMessages: ConsoleMessage[]
|
||||
purchasedUpgrades: string[]
|
||||
piety: number
|
||||
}
|
||||
|
||||
export interface MarketTransaction {
|
||||
|
|
|
|||
Loading…
Reference in a new issue