Add remove tool, fix the way olives are presented in the warehouse tab.

This commit is contained in:
Ryan Lanny Jenkins 2025-05-26 14:24:56 -05:00
parent c11a2dde94
commit 5724da535a
6 changed files with 74 additions and 60 deletions

View file

@ -256,6 +256,7 @@ const FieldComponent: React.FC = () => {
plant, plant,
water, water,
harvest, harvest,
remove,
assignCrop, assignCrop,
gameSpeed, gameSpeed,
setGameSpeed, setGameSpeed,
@ -288,6 +289,9 @@ const FieldComponent: React.FC = () => {
case 'harvest': case 'harvest':
harvest(row, col) harvest(row, col)
break break
case 'remove':
remove(row, col)
break
case 'inspect': case 'inspect':
setInspectedPlot({ plot: plots[row][col], row, col }) setInspectedPlot({ plot: plots[row][col], row, col })
break break
@ -317,6 +321,7 @@ const FieldComponent: React.FC = () => {
{ id: 'plant', label: 'Plant', icon: '🌱' }, { id: 'plant', label: 'Plant', icon: '🌱' },
{ id: 'water', label: 'Water', icon: '💧' }, { id: 'water', label: 'Water', icon: '💧' },
{ id: 'harvest', label: 'Harvest', icon: '✂️' }, { id: 'harvest', label: 'Harvest', icon: '✂️' },
{ id: 'remove', label: 'Remove', icon: '🗑️' },
{ id: 'inspect', label: 'Inspect', icon: '🔍' }, { id: 'inspect', label: 'Inspect', icon: '🔍' },
] ]

View file

@ -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, MarketItem } from '../constants' import { ITEMS, Item } from '../constants'
import FloatingMessage, { FloatingMessagesHandle } from './FloatingMessages' import FloatingMessage, { FloatingMessagesHandle } from './FloatingMessages'
import { styled } from '@linaria/react' import { styled } from '@linaria/react'
@ -75,7 +75,7 @@ const MarketComponent: React.FC = () => {
const { inventory, cash, buyItem, sellItem, landPurchases } = useGameStore() const { inventory, cash, buyItem, sellItem, landPurchases } = useGameStore()
const floatingMessagesRef = useRef<FloatingMessagesHandle>(null) const floatingMessagesRef = useRef<FloatingMessagesHandle>(null)
const getItemPrice = (item: MarketItem) => { const getItemPrice = (item: Item) => {
if (item.id === 'additional_land') { if (item.id === 'additional_land') {
return Math.floor(100 * Math.pow(1.5, landPurchases)) return Math.floor(100 * Math.pow(1.5, landPurchases))
} }
@ -83,7 +83,7 @@ const MarketComponent: React.FC = () => {
} }
const handleBuy = (itemId: string, e: React.MouseEvent) => { const handleBuy = (itemId: string, e: React.MouseEvent) => {
const item = MARKET_ITEMS[itemId] const item = ITEMS[itemId]
const price = getItemPrice(item) const price = getItemPrice(item)
if (!item || price === null || cash < price) return if (!item || price === null || cash < price) return
@ -99,7 +99,7 @@ const MarketComponent: React.FC = () => {
} }
const handleSell = (itemId: string, e: React.MouseEvent) => { const handleSell = (itemId: string, e: React.MouseEvent) => {
const item = MARKET_ITEMS[itemId] const item = ITEMS[itemId]
if ( if (
!item || !item ||
item.sellPrice === null || item.sellPrice === null ||
@ -119,14 +119,14 @@ const MarketComponent: React.FC = () => {
) )
} }
const sellableItems = Object.entries(MARKET_ITEMS) const sellableItems = Object.entries(ITEMS)
.filter( .filter(
([_, item]) => ([_, item]) =>
item.sellPrice !== null && inventory[item.id] && inventory[item.id] > 0, item.sellPrice !== null && inventory[item.id] && inventory[item.id] > 0,
) )
.map(([_, item]) => item) .map(([_, item]) => item)
const buyableItems = Object.entries(MARKET_ITEMS) const buyableItems = Object.entries(ITEMS)
.filter(([_, item]) => item.buyPrice !== null) .filter(([_, item]) => item.buyPrice !== null)
.map(([_, item]) => item) .map(([_, item]) => item)
@ -174,37 +174,41 @@ const MarketComponent: React.FC = () => {
</> </>
)} )}
<SectionTitle>Buy Items</SectionTitle> {buyableItems.length > 0 && (
<MarketTable> <>
<thead> <SectionTitle>Buy Items</SectionTitle>
<tr> <MarketTable>
<TableHeader>Item</TableHeader> <thead>
<TableHeader>Buy Price</TableHeader> <tr>
<TableHeader>Action</TableHeader> <TableHeader>Item</TableHeader>
</tr> <TableHeader>Buy Price</TableHeader>
</thead> <TableHeader>Action</TableHeader>
<tbody> </tr>
{buyableItems.map((item) => ( </thead>
<MarketItemRow key={`buy-${item.id}`}> <tbody>
<MarketItemCell> {buyableItems.map((item) => (
<ItemIcon>{item.emoji}</ItemIcon> <MarketItemRow key={`buy-${item.id}`}>
{item.name} <MarketItemCell>
</MarketItemCell> <ItemIcon>{item.emoji}</ItemIcon>
<MarketItemCell>${getItemPrice(item)}</MarketItemCell> {item.name}
<MarketItemCell> </MarketItemCell>
<ActionButton <MarketItemCell>${getItemPrice(item)}</MarketItemCell>
onClick={(e) => handleBuy(item.id, e)} <MarketItemCell>
disabled={ <ActionButton
getItemPrice(item) ? cash < getItemPrice(item)! : true onClick={(e) => handleBuy(item.id, e)}
} disabled={
> getItemPrice(item) ? cash < getItemPrice(item)! : true
Buy }
</ActionButton> >
</MarketItemCell> Buy
</MarketItemRow> </ActionButton>
))} </MarketItemCell>
</tbody> </MarketItemRow>
</MarketTable> ))}
</tbody>
</MarketTable>
</>
)}
<FloatingMessage ref={floatingMessagesRef} /> <FloatingMessage ref={floatingMessagesRef} />
</MarketContainer> </MarketContainer>

View file

@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import { useGameStore } from '../store/useGameStore' import { useGameStore } from '../store/useGameStore'
import { CROPS } from '../constants' import { ITEMS } from '../constants'
const warehouseContainerStyle: React.CSSProperties = { const warehouseContainerStyle: React.CSSProperties = {
padding: '1rem', padding: '1rem',
@ -65,25 +65,11 @@ const itemNameStyle: React.CSSProperties = {
} }
const formatItemName = (id: string) => { const formatItemName = (id: string) => {
if (id.endsWith('_seed')) { return ITEMS[id]?.name || id
const cropId = id.replace('_seed', '')
return `${CROPS[cropId]?.name || cropId} Seeds`
}
return CROPS[id]?.name || id
} }
const getItemIcon = (id: string) => { const getItemIcon = (id: string) => {
if (id.endsWith('_seed')) { return ITEMS[id]?.emoji || '📦'
return '🌰'
}
const cropIcons: Record<string, string> = {
celery: '🥬',
corn: '🌽',
}
return cropIcons[id] || '📦'
} }
const WarehouseComponent: React.FC = () => { const WarehouseComponent: React.FC = () => {

View file

@ -108,7 +108,7 @@ export const UPGRADES: Record<string, Upgrade> = {
}, },
} }
export interface MarketItem { export interface Item {
id: string id: string
name: string name: string
emoji: string emoji: string
@ -116,7 +116,7 @@ export interface MarketItem {
sellPrice: number | null // null means not sellable sellPrice: number | null // null means not sellable
} }
export const MARKET_ITEMS: Record<string, MarketItem> = { export const ITEMS: Record<string, Item> = {
additional_land: { additional_land: {
id: 'additional_land', id: 'additional_land',
name: 'Additional Land', name: 'Additional Land',

View file

@ -8,7 +8,7 @@ import {
CROPS, CROPS,
INITIAL_GAME_SPEED, INITIAL_GAME_SPEED,
COOLDOWN_DURATION, COOLDOWN_DURATION,
MARKET_ITEMS, ITEMS,
UPGRADES, UPGRADES,
} from '../constants' } from '../constants'
import { GameState, PlotState } from '../types' import { GameState, PlotState } from '../types'
@ -100,6 +100,7 @@ export const useGameStore = create<
plant: (row: number, col: number) => void plant: (row: number, col: number) => void
water: (row: number, col: number) => void water: (row: number, col: number) => void
harvest: (row: number, col: number) => void harvest: (row: number, col: number) => void
remove: (row: number, col: number) => void
tick: () => void tick: () => void
assignCrop: (row: number, col: number, cropId: string) => void assignCrop: (row: number, col: number, cropId: string) => void
upgradeField: () => void upgradeField: () => void
@ -265,6 +266,24 @@ export const useGameStore = create<
} }
}, },
remove: (row, col) => {
const { plots, actionCooldown } = get()
if (actionCooldown > 0) {
return
}
const plot = plots[row][col]
if (plot.current) {
set(
produce((state) => {
state.plots[row][col].current = undefined
state.actionCooldown = COOLDOWN_DURATION
}),
)
}
},
tick: () => { tick: () => {
set( set(
produce((state) => { produce((state) => {
@ -368,7 +387,7 @@ export const useGameStore = create<
buyItem: (itemId) => { buyItem: (itemId) => {
const { cash, landPurchases, plots, fieldSize } = get() const { cash, landPurchases, plots, fieldSize } = get()
const item = MARKET_ITEMS[itemId] const item = ITEMS[itemId]
if (!item || item.buyPrice === null || item.buyPrice === undefined) { if (!item || item.buyPrice === null || item.buyPrice === undefined) {
return return
@ -424,7 +443,7 @@ export const useGameStore = create<
sellItem: (itemId) => { sellItem: (itemId) => {
const { inventory } = get() const { inventory } = get()
const item = MARKET_ITEMS[itemId] const item = ITEMS[itemId]
if ( if (
!item || !item ||

View file

@ -31,7 +31,7 @@ export interface InventoryItem {
count: number count: number
} }
export type FieldTool = 'mark' | 'plant' | 'water' | 'harvest' | 'inspect' export type FieldTool = 'mark' | 'plant' | 'water' | 'harvest' | 'inspect' | 'remove'
export interface ConsoleMessage { export interface ConsoleMessage {
id: string id: string