diff --git a/src/components/Farmhand/Farmhand.js b/src/components/Farmhand/Farmhand.js
index 2688cf3c4..f769d6060 100644
--- a/src/components/Farmhand/Farmhand.js
+++ b/src/components/Farmhand/Farmhand.js
@@ -2,7 +2,9 @@
* @typedef {import("../../index").farmhand.item} farmhand.item
* @typedef {import("../../index").farmhand.cow} farmhand.cow
* @typedef {import("../../index").farmhand.cowBreedingPen} farmhand.cowBreedingPen
+ * @typedef {import("../../index").farmhand.forestForageable} farmhand.forestForageable
* @typedef {import("../../index").farmhand.keg} farmhand.keg
+ * @typedef {import("../../index").farmhand.plantedTree} farmhand.plantedTree
* @typedef {import("../../index").farmhand.plotContent} farmhand.plotContent
* @typedef {import("../../index").farmhand.peerMessage} farmhand.peerMessage
* @typedef {import("../../index").farmhand.peerMetadata} farmhand.peerMetadata
@@ -93,6 +95,7 @@ import {
STANDARD_LOAN_AMOUNT,
Z_INDEX,
STANDARD_VIEW_LIST,
+ UNLOCK_FOREST_LEVEL,
} from '../../constants'
import {
HEARTBEAT_INTERVAL_PERIOD,
@@ -215,7 +218,7 @@ const applyPriceEvents = (valueAdjustments, priceCrashes, priceSurges) => {
* @property {number} experience
* @property {string} farmName
* @property {(?farmhand.plotContent)[][]} field
- * @property {(?farmhand.plotContent)[][]} forest
+ * @property {(farmhand.plantedTree | farmhand.forestForageable | null)[][]} forest
* @property {farmhand.fieldMode} fieldMode
* @property {Function?} getCowAccept https://github.com/dmotz/trystero#receiver
* @property {Function?} getCowReject https://github.com/dmotz/trystero#receiver
@@ -374,7 +377,7 @@ export default class Farmhand extends FarmhandReducers {
viewList.unshift(HOME)
}
- if (this.state.purchasedForest && features.FOREST) {
+ if (this.isForestUnlocked && features.FOREST) {
viewList.push(FOREST)
}
@@ -416,6 +419,10 @@ export default class Farmhand extends FarmhandReducers {
return isOnline && room !== DEFAULT_ROOM
}
+ get isForestUnlocked() {
+ return levelAchieved(this.state.experience) >= UNLOCK_FOREST_LEVEL
+ }
+
/**
* @returns {farmhand.state}
*/
diff --git a/src/components/Forest/Forest.js b/src/components/Forest/Forest.js
index ea92e77b3..176b34afe 100644
--- a/src/components/Forest/Forest.js
+++ b/src/components/Forest/Forest.js
@@ -1,17 +1,5 @@
import React from 'react'
-import FarmhandContext from '../Farmhand/Farmhand.context'
-
export const Forest = () => {
return
'welcome to da forest'
}
-
-export default function Consumer(props) {
- return (
-
- {({ gameState, handlers }) => (
-
- )}
-
- )
-}
diff --git a/src/components/Forest/index.js b/src/components/Forest/index.js
index 7951550e3..f8db3e650 100644
--- a/src/components/Forest/index.js
+++ b/src/components/Forest/index.js
@@ -1 +1 @@
-export { default } from './Forest'
+export { Forest } from './Forest'
diff --git a/src/components/Shop/Shop.js b/src/components/Shop/Shop.js
index 299e678ce..b0e25deca 100644
--- a/src/components/Shop/Shop.js
+++ b/src/components/Shop/Shop.js
@@ -12,6 +12,7 @@ import Typography from '@mui/material/Typography'
import FarmhandContext from '../Farmhand/Farmhand.context'
import { features } from '../../config'
import { moneyString } from '../../utils/moneyString'
+import { levelAchieved } from '../../utils/levelAchieved'
import {
dollarString,
getCostOfNextStorageExpansion,
@@ -30,6 +31,7 @@ import {
PURCHASABLE_FOREST_SIZES,
PURCHASEABLE_SMELTERS,
STORAGE_EXPANSION_AMOUNT,
+ UNLOCK_FOREST_LEVEL,
} from '../../constants'
import Inventory from '../Inventory'
import TierPurchase from '../TierPurchase'
@@ -56,6 +58,7 @@ const categorizeShopInventory = memoize(shopInventory =>
)
export const Shop = ({
+ experience,
handleCombinePurchase,
handleComposterPurchase,
handleCowPenPurchase,
@@ -82,6 +85,8 @@ export const Shop = ({
const { seeds, fieldTools } = categorizeShopInventory(shopInventory)
+ const isForestUnlocked = levelAchieved(experience) >= UNLOCK_FOREST_LEVEL
+
return (
) : null}
- {features.FOREST ? (
+ {features.FOREST && isForestUnlocked ? (
`${dollarString(price)}: ${columns} x ${rows}`,
tiers: PURCHASABLE_FOREST_SIZES,
- title: purchasedForest ? 'Expand Forest' : 'Purchase Forest',
+ title: 'Expand Forest',
}}
/>
diff --git a/src/components/Stage/Stage.js b/src/components/Stage/Stage.js
index 9bf096bf7..88ef48da5 100644
--- a/src/components/Stage/Stage.js
+++ b/src/components/Stage/Stage.js
@@ -4,7 +4,7 @@ import { array, arrayOf, string } from 'prop-types'
import FarmhandContext from '../Farmhand/Farmhand.context'
import Field from '../Field'
-import Forest from '../Forest'
+import { Forest } from '../Forest'
import Home from '../Home'
import CowPen from '../CowPen'
import Shop from '../Shop'
diff --git a/src/constants.js b/src/constants.js
index 07c9c71b3..f326f943f 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -313,3 +313,5 @@ export const STANDARD_VIEW_LIST = [stageFocusType.SHOP, stageFocusType.FIELD]
export const Z_INDEX = {
END_DAY_BUTTON: 1100,
}
+
+export const UNLOCK_FOREST_LEVEL = 15
diff --git a/src/game-logic/reducers/processLevelUp.js b/src/game-logic/reducers/processLevelUp.js
index 7793bc57b..cc2442ad4 100644
--- a/src/game-logic/reducers/processLevelUp.js
+++ b/src/game-logic/reducers/processLevelUp.js
@@ -6,8 +6,9 @@ import {
unlockTool,
} from '../../utils'
import { getLevelEntitlements } from '../../utils/getLevelEntitlements'
-import { SPRINKLER_ITEM_ID } from '../../constants'
+import { SPRINKLER_ITEM_ID, UNLOCK_FOREST_LEVEL } from '../../constants'
import { LEVEL_GAINED_NOTIFICATION } from '../../templates'
+import { FOREST_AVAILABLE_NOTIFICATION } from '../../strings'
import { addItemToInventory } from './addItemToInventory'
import { showNotification } from './showNotification'
@@ -61,6 +62,10 @@ export const processLevelUp = (state, oldLevel) => {
LEVEL_GAINED_NOTIFICATION`${i}${randomCropSeed}`,
'success'
)
+
+ if (i === UNLOCK_FOREST_LEVEL) {
+ state = showNotification(state, FOREST_AVAILABLE_NOTIFICATION, 'success')
+ }
}
return state
diff --git a/src/game-logic/reducers/purchaseForest.test.js b/src/game-logic/reducers/purchaseForest.test.js
index 5fbe4adfb..947490e9b 100644
--- a/src/game-logic/reducers/purchaseForest.test.js
+++ b/src/game-logic/reducers/purchaseForest.test.js
@@ -4,6 +4,13 @@ import { FOREST_AVAILABLE_NOTIFICATION } from '../../strings'
import { purchaseForest } from './purchaseForest'
+const tree = () => {
+ return {
+ daysOld: 0,
+ itemId: 'test-tree',
+ }
+}
+
describe('purchaseForest', () => {
test('updates purchasedForest', () => {
const { purchasedForest } = purchaseForest({ purchasedForest: 0 }, 0)
@@ -60,15 +67,15 @@ describe('purchaseForest', () => {
{
todaysNotifications: [],
forest: [
- [testCrop(), null],
- [null, testCrop()],
+ [tree(), null],
+ [null, tree()],
],
},
1
)
- expectedForest[0][0] = testCrop()
- expectedForest[1][1] = testCrop()
+ expectedForest[0][0] = tree()
+ expectedForest[1][1] = tree()
expect(forest).toEqual(expectedForest)
})
diff --git a/src/index.js b/src/index.js
index 28ae1aaa2..a969917e9 100644
--- a/src/index.js
+++ b/src/index.js
@@ -64,6 +64,20 @@
* @typedef {farmhand.plotContent & farmhand.cropType} farmhand.crop
*/
+/**
+ * Represents a tree
+ * @typedef farmhand.plantedTree
+ * @property {number} daysOld
+ * @property {string} itemId
+ */
+
+/**
+ * Represents a forageable item that grows in the forest
+ * @typedef farmhand.forestForageable
+ * @property {number} daysOld
+ * @property {'mushroom' | 'acorn'} forageableId
+ */
+
/**
* Represents a shoveled plot
* @typedef farmhand.shoveledPlot