Compare commits
2 commits
6d72c8c0f9
...
23c312299c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23c312299c | ||
|
|
ba9b26ff64 |
|
|
@ -40,4 +40,4 @@ export const Console: React.FC = () => {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useRef } from 'react'
|
import React, { useRef } from 'react'
|
||||||
import { useGameStore } from '../store/useGameStore'
|
import { useGameStore } from '../store/useGameStore'
|
||||||
import { MARKET_ITEMS } from '../constants'
|
import { MARKET_ITEMS, MarketItem } from '../constants'
|
||||||
import FloatingMessage, { FloatingMessagesHandle } from './FloatingMessages'
|
import FloatingMessage, { FloatingMessagesHandle } from './FloatingMessages'
|
||||||
import { styled } from '@linaria/react'
|
import { styled } from '@linaria/react'
|
||||||
|
|
||||||
|
|
@ -72,12 +72,20 @@ const ActionButton = styled.button<{ disabled?: boolean }>`
|
||||||
`
|
`
|
||||||
|
|
||||||
const MarketComponent: React.FC = () => {
|
const MarketComponent: React.FC = () => {
|
||||||
const { inventory, cash, buyItem, sellItem } = useGameStore()
|
const { inventory, cash, buyItem, sellItem, landPurchases } = useGameStore()
|
||||||
const floatingMessagesRef = useRef<FloatingMessagesHandle>(null)
|
const floatingMessagesRef = useRef<FloatingMessagesHandle>(null)
|
||||||
|
|
||||||
|
const getItemPrice = (item: MarketItem) => {
|
||||||
|
if (item.id === 'additional_land') {
|
||||||
|
return Math.floor(100 * Math.pow(1.5, landPurchases))
|
||||||
|
}
|
||||||
|
return item.buyPrice
|
||||||
|
}
|
||||||
|
|
||||||
const handleBuy = (itemId: string, e: React.MouseEvent) => {
|
const handleBuy = (itemId: string, e: React.MouseEvent) => {
|
||||||
const item = MARKET_ITEMS[itemId]
|
const item = MARKET_ITEMS[itemId]
|
||||||
if (!item || item.buyPrice === null || cash < item.buyPrice) return
|
const price = getItemPrice(item)
|
||||||
|
if (!item || price === null || cash < price) return
|
||||||
|
|
||||||
buyItem(itemId)
|
buyItem(itemId)
|
||||||
|
|
||||||
|
|
@ -182,11 +190,13 @@ const MarketComponent: React.FC = () => {
|
||||||
<ItemIcon>{item.emoji}</ItemIcon>
|
<ItemIcon>{item.emoji}</ItemIcon>
|
||||||
{item.name}
|
{item.name}
|
||||||
</MarketItemCell>
|
</MarketItemCell>
|
||||||
<MarketItemCell>${item.buyPrice}</MarketItemCell>
|
<MarketItemCell>${getItemPrice(item)}</MarketItemCell>
|
||||||
<MarketItemCell>
|
<MarketItemCell>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
onClick={(e) => handleBuy(item.id, e)}
|
onClick={(e) => handleBuy(item.id, e)}
|
||||||
disabled={item.buyPrice ? cash < item.buyPrice : true}
|
disabled={
|
||||||
|
getItemPrice(item) ? cash < getItemPrice(item)! : true
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Buy
|
Buy
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||||
import { useGameStore } from '../store/useGameStore'
|
import { useGameStore } from '../store/useGameStore'
|
||||||
import { UPGRADES } from '../constants'
|
import { UPGRADES } from '../constants'
|
||||||
import { styled } from '@linaria/react'
|
import { styled } from '@linaria/react'
|
||||||
import type { UpgradeCost } from '../types'
|
import type { UpgradeCost, Upgrade } from '../types'
|
||||||
|
|
||||||
const TempleContainer = styled.div`
|
const TempleContainer = styled.div`
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
|
@ -15,6 +15,46 @@ const Title = styled.h2`
|
||||||
text-align: center;
|
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`
|
const UpgradesGrid = styled.div`
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
|
@ -23,7 +63,7 @@ const UpgradesGrid = styled.div`
|
||||||
`
|
`
|
||||||
|
|
||||||
const UpgradeCard = styled.div<{ purchased?: boolean }>`
|
const UpgradeCard = styled.div<{ purchased?: boolean }>`
|
||||||
background-color: ${props => props.purchased ? '#e5e7eb' : '#f3f4f6'};
|
background-color: ${(props) => (props.purchased ? '#e5e7eb' : '#f3f4f6')};
|
||||||
border: 1px solid #d1d5db;
|
border: 1px solid #d1d5db;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
|
@ -59,35 +99,91 @@ const CostItem = styled.div`
|
||||||
const PurchaseButton = styled.button<{ disabled?: boolean }>`
|
const PurchaseButton = styled.button<{ disabled?: boolean }>`
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
background-color: ${props => props.disabled ? '#9ca3af' : '#3b82f6'};
|
background-color: ${(props) => (props.disabled ? '#9ca3af' : '#3b82f6')};
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
|
cursor: ${(props) => (props.disabled ? 'not-allowed' : 'pointer')};
|
||||||
border: none;
|
border: none;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
`
|
`
|
||||||
|
|
||||||
const TempleComponent: React.FC = () => {
|
const TempleComponent: React.FC = () => {
|
||||||
const { inventory, purchasedUpgrades, purchaseUpgrade } = useGameStore()
|
const {
|
||||||
|
inventory,
|
||||||
|
purchasedUpgrades,
|
||||||
|
purchaseUpgrade,
|
||||||
|
pray,
|
||||||
|
piety,
|
||||||
|
actionCooldown,
|
||||||
|
} = useGameStore()
|
||||||
|
|
||||||
const handlePurchase = (upgradeId: string) => {
|
const handlePurchase = (upgradeId: string) => {
|
||||||
purchaseUpgrade(upgradeId)
|
purchaseUpgrade(upgradeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
const canAffordUpgrade = (costs: UpgradeCost[]) => {
|
const canAffordUpgrade = (costs: UpgradeCost[]) => {
|
||||||
return costs.every(cost =>
|
return costs.every(
|
||||||
inventory[cost.itemId] !== undefined &&
|
(cost) =>
|
||||||
inventory[cost.itemId] >= cost.amount
|
inventory[cost.itemId] !== undefined &&
|
||||||
|
inventory[cost.itemId] >= cost.amount,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (
|
return (
|
||||||
<TempleContainer>
|
<TempleContainer>
|
||||||
<Title>Temple</Title>
|
<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>
|
<UpgradesGrid>
|
||||||
{Object.values(UPGRADES).map((upgrade) => {
|
{Object.values(UPGRADES).map((upgrade) => {
|
||||||
const isPurchased = purchasedUpgrades.includes(upgrade.id)
|
const isPurchased = purchasedUpgrades.includes(upgrade.id)
|
||||||
const canAfford = canAffordUpgrade(upgrade.cost)
|
const canPurchase = canPurchaseUpgrade(upgrade)
|
||||||
|
const status = getUpgradeStatus(upgrade)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UpgradeCard key={upgrade.id} purchased={isPurchased}>
|
<UpgradeCard key={upgrade.id} purchased={isPurchased}>
|
||||||
|
|
@ -97,18 +193,18 @@ const TempleComponent: React.FC = () => {
|
||||||
<span>Cost:</span>
|
<span>Cost:</span>
|
||||||
{upgrade.cost.map((cost, index) => (
|
{upgrade.cost.map((cost, index) => (
|
||||||
<CostItem key={index}>
|
<CostItem key={index}>
|
||||||
<span>{cost.amount} {cost.itemId}</span>
|
|
||||||
<span>
|
<span>
|
||||||
(You have: {inventory[cost.itemId] || 0})
|
{cost.amount} {cost.itemId}
|
||||||
</span>
|
</span>
|
||||||
|
<span>(You have: {inventory[cost.itemId] || 0})</span>
|
||||||
</CostItem>
|
</CostItem>
|
||||||
))}
|
))}
|
||||||
</UpgradeCost>
|
</UpgradeCost>
|
||||||
<PurchaseButton
|
<PurchaseButton
|
||||||
onClick={() => handlePurchase(upgrade.id)}
|
onClick={() => handlePurchase(upgrade.id)}
|
||||||
disabled={isPurchased || !canAfford}
|
disabled={!canPurchase}
|
||||||
>
|
>
|
||||||
{isPurchased ? 'Purchased' : 'Purchase'}
|
{status}
|
||||||
</PurchaseButton>
|
</PurchaseButton>
|
||||||
</UpgradeCard>
|
</UpgradeCard>
|
||||||
)
|
)
|
||||||
|
|
@ -118,4 +214,4 @@ const TempleComponent: React.FC = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TempleComponent
|
export default TempleComponent
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,25 @@ export const UPGRADES: Record<string, Upgrade> = {
|
||||||
id: 'aqueous_vigor_1',
|
id: 'aqueous_vigor_1',
|
||||||
name: 'Aqueous Vigor I',
|
name: 'Aqueous Vigor I',
|
||||||
description: 'Reduces watering cooldown by 25%',
|
description: 'Reduces watering cooldown by 25%',
|
||||||
cost: [{
|
cost: [
|
||||||
itemId: 'celery',
|
{
|
||||||
amount: 10
|
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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MarketItem {
|
export interface MarketItem {
|
||||||
|
|
@ -59,6 +73,13 @@ export interface MarketItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MARKET_ITEMS: Record<string, MarketItem> = {
|
export const MARKET_ITEMS: Record<string, MarketItem> = {
|
||||||
|
additional_land: {
|
||||||
|
id: 'additional_land',
|
||||||
|
name: 'Additional Land',
|
||||||
|
emoji: '🌱',
|
||||||
|
buyPrice: 100,
|
||||||
|
sellPrice: null,
|
||||||
|
},
|
||||||
celery_seed: {
|
celery_seed: {
|
||||||
id: 'celery_seed',
|
id: 'celery_seed',
|
||||||
name: 'Celery Seeds',
|
name: 'Celery Seeds',
|
||||||
|
|
|
||||||
|
|
@ -54,17 +54,46 @@ export const hasSaveInSlot = (slot: number): boolean => {
|
||||||
return !!localStorage.getItem(`${SAVE_SLOT_PREFIX}${slot}`)
|
return !!localStorage.getItem(`${SAVE_SLOT_PREFIX}${slot}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const addConsoleMessage = (state: GameState, text: string) => (
|
const addConsoleMessage = (state: GameState, text: string) =>
|
||||||
state.consoleMessages = [
|
(state.consoleMessages = [
|
||||||
{
|
{
|
||||||
id: Math.random().toString(36).substring(7),
|
id: Math.random().toString(36).substring(7),
|
||||||
text,
|
text,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
},
|
},
|
||||||
...state.consoleMessages,
|
...state.consoleMessages,
|
||||||
].slice(0, 50)
|
].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<
|
export const useGameStore = create<
|
||||||
GameState & {
|
GameState & {
|
||||||
|
|
@ -81,6 +110,7 @@ export const useGameStore = create<
|
||||||
saveToSlot: (slot: number) => void
|
saveToSlot: (slot: number) => void
|
||||||
loadFromSlot: (slot: number) => void
|
loadFromSlot: (slot: number) => void
|
||||||
purchaseUpgrade: (upgradeId: string) => void
|
purchaseUpgrade: (upgradeId: string) => void
|
||||||
|
pray: () => void
|
||||||
}
|
}
|
||||||
>((set, get) => ({
|
>((set, get) => ({
|
||||||
cash: INITIAL_CASH,
|
cash: INITIAL_CASH,
|
||||||
|
|
@ -94,6 +124,8 @@ export const useGameStore = create<
|
||||||
tickCount: 0,
|
tickCount: 0,
|
||||||
consoleMessages: [],
|
consoleMessages: [],
|
||||||
purchasedUpgrades: [],
|
purchasedUpgrades: [],
|
||||||
|
piety: 50,
|
||||||
|
landPurchases: 0,
|
||||||
|
|
||||||
assignCrop: (row, col, cropId) => {
|
assignCrop: (row, col, cropId) => {
|
||||||
set(
|
set(
|
||||||
|
|
@ -140,16 +172,16 @@ export const useGameStore = create<
|
||||||
|
|
||||||
const plot = plots[row][col]
|
const plot = plots[row][col]
|
||||||
if (plot.current && plot.moisture < 1) {
|
if (plot.current && plot.moisture < 1) {
|
||||||
// Calculate cooldown reduction from upgrades
|
// Calculate cooldown reduction from upgrades (multiplicative)
|
||||||
let cooldownReduction = 0
|
let cooldownMultiplier = 1
|
||||||
if (purchasedUpgrades.includes('aqueous_vigor_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(
|
const finalCooldown = Math.max(0, COOLDOWN_DURATION * cooldownMultiplier)
|
||||||
0,
|
|
||||||
COOLDOWN_DURATION * (1 - cooldownReduction)
|
|
||||||
)
|
|
||||||
|
|
||||||
set(
|
set(
|
||||||
produce((state) => {
|
produce((state) => {
|
||||||
|
|
@ -231,7 +263,7 @@ export const useGameStore = create<
|
||||||
state.plots[rowIndex][colIndex].moisture =
|
state.plots[rowIndex][colIndex].moisture =
|
||||||
plot.moisture - waterNeeded
|
plot.moisture - waterNeeded
|
||||||
state.plots[rowIndex][colIndex].current.progress = newProgress
|
state.plots[rowIndex][colIndex].current.progress = newProgress
|
||||||
|
|
||||||
// If the plot just became mature, add a message
|
// If the plot just became mature, add a message
|
||||||
if (mature && !plot.current.mature) {
|
if (mature && !plot.current.mature) {
|
||||||
addConsoleMessage(
|
addConsoleMessage(
|
||||||
|
|
@ -239,7 +271,7 @@ export const useGameStore = create<
|
||||||
`Plot (${rowIndex + 1},${colIndex + 1}) ${crop.name} is ready to harvest!`,
|
`Plot (${rowIndex + 1},${colIndex + 1}) ${crop.name} is ready to harvest!`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
state.plots[rowIndex][colIndex].current.mature = mature
|
state.plots[rowIndex][colIndex].current.mature = mature
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -290,21 +322,57 @@ export const useGameStore = create<
|
||||||
},
|
},
|
||||||
|
|
||||||
buyItem: (itemId) => {
|
buyItem: (itemId) => {
|
||||||
const { cash } = get()
|
const { cash, landPurchases, plots, fieldSize } = get()
|
||||||
const item = MARKET_ITEMS[itemId]
|
const item = MARKET_ITEMS[itemId]
|
||||||
|
|
||||||
if (!item || item.buyPrice === null || item.buyPrice === undefined) {
|
if (!item || item.buyPrice === null || item.buyPrice === undefined) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cash < item.buyPrice) {
|
// Calculate price for Additional Land based on number of purchases
|
||||||
|
let price = item.buyPrice
|
||||||
|
if (itemId === 'additional_land') {
|
||||||
|
price = Math.floor(100 * Math.pow(1.5, landPurchases))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cash < price) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
set(
|
set(
|
||||||
produce((state) => {
|
produce((state) => {
|
||||||
state.cash -= item.buyPrice!
|
state.cash -= price
|
||||||
state.inventory[itemId] = (state.inventory[itemId] || 0) + 1
|
|
||||||
|
// Special handling for Additional Land
|
||||||
|
if (itemId === 'additional_land') {
|
||||||
|
state.landPurchases += 1
|
||||||
|
if (state.fieldSize < state.maxFieldSize) {
|
||||||
|
const newSize = state.fieldSize + 1
|
||||||
|
|
||||||
|
// Add a new row
|
||||||
|
state.plots.push(
|
||||||
|
Array(newSize)
|
||||||
|
.fill(0)
|
||||||
|
.map(() => ({
|
||||||
|
moisture: 0,
|
||||||
|
fertility: 1,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add a new column to each existing row
|
||||||
|
state.plots.forEach((row: PlotState[]) => {
|
||||||
|
row.push({
|
||||||
|
moisture: 0,
|
||||||
|
fertility: 1,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
state.fieldSize = newSize
|
||||||
|
addConsoleMessage(state, 'Field size increased!')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.inventory[itemId] = (state.inventory[itemId] || 0) + 1
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -346,6 +414,7 @@ export const useGameStore = create<
|
||||||
saveToSlot,
|
saveToSlot,
|
||||||
loadFromSlot,
|
loadFromSlot,
|
||||||
purchaseUpgrade,
|
purchaseUpgrade,
|
||||||
|
pray,
|
||||||
...gameState
|
...gameState
|
||||||
} = state
|
} = state
|
||||||
saveGame(slot, gameState)
|
saveGame(slot, gameState)
|
||||||
|
|
@ -368,7 +437,9 @@ export const useGameStore = create<
|
||||||
|
|
||||||
// Check if player can afford all costs
|
// Check if player can afford all costs
|
||||||
const canAfford = upgrade.cost.every(
|
const canAfford = upgrade.cost.every(
|
||||||
cost => inventory[cost.itemId] !== undefined && inventory[cost.itemId] >= cost.amount
|
(cost) =>
|
||||||
|
inventory[cost.itemId] !== undefined &&
|
||||||
|
inventory[cost.itemId] >= cost.amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!canAfford) {
|
if (!canAfford) {
|
||||||
|
|
@ -378,14 +449,50 @@ export const useGameStore = create<
|
||||||
set(
|
set(
|
||||||
produce((state) => {
|
produce((state) => {
|
||||||
// Deduct all costs
|
// Deduct all costs
|
||||||
upgrade.cost.forEach(cost => {
|
upgrade.cost.forEach((cost) => {
|
||||||
state.inventory[cost.itemId] -= cost.amount
|
state.inventory[cost.itemId] -= cost.amount
|
||||||
})
|
})
|
||||||
state.purchasedUpgrades.push(upgradeId)
|
state.purchasedUpgrades.push(upgradeId)
|
||||||
addConsoleMessage(
|
addConsoleMessage(state, `Purchased upgrade: ${upgrade.name}`)
|
||||||
state,
|
}),
|
||||||
`Purchased upgrade: ${upgrade.name}`
|
)
|
||||||
)
|
},
|
||||||
|
|
||||||
|
pray: () => {
|
||||||
|
const { actionCooldown, piety } = 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,8 @@ export interface GameState {
|
||||||
actionCooldown: number
|
actionCooldown: number
|
||||||
consoleMessages: ConsoleMessage[]
|
consoleMessages: ConsoleMessage[]
|
||||||
purchasedUpgrades: string[]
|
purchasedUpgrades: string[]
|
||||||
|
piety: number
|
||||||
|
landPurchases: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MarketTransaction {
|
export interface MarketTransaction {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue