Skip to content

Commit

Permalink
Merge patch commit
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Jun 6, 2023
2 parents 188cef7 + f0dbebc commit bf81e73
Show file tree
Hide file tree
Showing 12 changed files with 200 additions and 15 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jeremyckahn/farmhand",
"version": "1.17.0",
"version": "1.17.1",
"publishConfig": {
"access": "public"
},
Expand Down
23 changes: 14 additions & 9 deletions src/components/Cellar/Keg.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { FERMENTED_CROP_NAME } from '../../templates'
import AnimatedNumber from '../AnimatedNumber'

import './Keg.sass'
import { getKegSpoilageRate } from '../../utils/getKegSpoilageRate'

/**
* @param {Object} props
Expand Down Expand Up @@ -54,6 +55,9 @@ export function Keg({ keg }) {
const kegValue =
getKegValue(keg) * getSalePriceMultiplier(completedAchievements)

const spoilageRate = getKegSpoilageRate(keg)
const spoilageRateDisplayValue = Number((spoilageRate * 100).toPrecision(2))

return (
<Card className="Keg">
<CardHeader
Expand All @@ -69,18 +73,19 @@ export function Keg({ keg }) {
subheader={
<>
{canBeSold ? (
<p>Days since ready: {Math.abs(keg.daysUntilMature)}</p>
<>
<p>Days since ready: {Math.abs(keg.daysUntilMature)}</p>
<p>
Current value:{' '}
<AnimatedNumber
{...{ number: kegValue, formatter: moneyString }}
/>
</p>
<p>Potential for spoilage: {spoilageRateDisplayValue}%</p>
</>
) : (
<p>Days until ready: {keg.daysUntilMature}</p>
)}
{canBeSold ? (
<p>
Current value:{' '}
<AnimatedNumber
{...{ number: kegValue, formatter: moneyString }}
/>
</p>
) : null}
</>
}
></CardHeader>
Expand Down
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,4 @@ export const COW_TRADE_TIMEOUT = 10000
export const WEEDS_SPAWN_CHANCE = 0.15

export const KEG_INTEREST_RATE = 0.02
export const KEG_SPOILAGE_RATE_MULTIPLIER = 0.001
6 changes: 4 additions & 2 deletions src/data/crops/carrot.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/** @typedef {import("../../index").farmhand.item} item */

import { crop, fromSeed } from '../crop'
import { cropLifeStage, cropType } from '../../enums'

const { SEED, GROWING } = cropLifeStage

/**
* @property farmhand.module:items.carrotSeed
* @type {farmhand.item}
* @type {item}
*/
export const carrotSeed = crop({
cropType: cropType.CARROT,
Expand All @@ -21,7 +23,7 @@ export const carrotSeed = crop({

/**
* @property farmhand.module:items.carrot
* @type {farmhand.item}
* @type {item}
*/
export const carrot = crop({
...fromSeed(carrotSeed, { canBeFermented: true }),
Expand Down
3 changes: 3 additions & 0 deletions src/game-logic/reducers/processCellar.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
/** @typedef {import("../../components/Farmhand/Farmhand").farmhand.state} state */

import { processCellarSpoilage } from './processCellarSpoilage'

/**
* @param {state} state
* @returns state
*/
export const processCellar = state => {
state = processCellarSpoilage(state)
const { cellarInventory } = state

const newCellarInventory = [...cellarInventory]
Expand Down
40 changes: 40 additions & 0 deletions src/game-logic/reducers/processCellarSpoilage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/** @typedef {import("../../components/Farmhand/Farmhand").farmhand.state} state */

import { randomNumberService } from '../../common/services/randomNumber'
import { KEG_SPOILED_MESSAGE } from '../../templates'
import { getKegSpoilageRate } from '../../utils/getKegSpoilageRate'

import { removeKegFromCellar } from './removeKegFromCellar'

/**
* @param {state} state
* @returns state
*/
export const processCellarSpoilage = state => {
const { cellarInventory } = state

const newCellarInventory = [...cellarInventory]

for (let i = newCellarInventory.length - 1; i > -1; i--) {
const keg = newCellarInventory[i]
const spoilageRate = getKegSpoilageRate(keg)

if (randomNumberService.isRandomNumberLessThan(spoilageRate)) {
state = removeKegFromCellar(state, keg.id)
state = {
...state,
newDayNotifications: [
...state.newDayNotifications,
{
message: KEG_SPOILED_MESSAGE`${keg}`,
severity: 'error',
},
],
}
}
}

state = { ...state }

return state
}
60 changes: 60 additions & 0 deletions src/game-logic/reducers/processCellarSpoilage.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { randomNumberService } from '../../common/services/randomNumber'
import { KEG_SPOILED_MESSAGE } from '../../templates'
import { getKegStub } from '../../test-utils/stubs/getKegStub'

import { processCellarSpoilage } from './processCellarSpoilage'

describe('processCellarSpoilage', () => {
test('does not remove kegs that have not spoiled', () => {
jest
.spyOn(randomNumberService, 'isRandomNumberLessThan')
.mockReturnValueOnce(false)

const keg = getKegStub()
const cellarInventory = [keg]
const newDayNotifications = []
const expectedState = processCellarSpoilage({
cellarInventory,
newDayNotifications,
})

expect(expectedState.cellarInventory).toHaveLength(1)
})

test('removes kegs that have spoiled', () => {
jest
.spyOn(randomNumberService, 'isRandomNumberLessThan')
.mockReturnValueOnce(true)

const keg = getKegStub()
const cellarInventory = [keg]
const newDayNotifications = []
const expectedState = processCellarSpoilage({
cellarInventory,
newDayNotifications,
})

expect(expectedState.cellarInventory).toHaveLength(0)
})

test('shows notification for kegs that have spoiled', () => {
jest
.spyOn(randomNumberService, 'isRandomNumberLessThan')
.mockReturnValueOnce(true)

const keg = getKegStub()
const cellarInventory = [keg]
const newDayNotifications = []
const expectedState = processCellarSpoilage({
cellarInventory,
newDayNotifications,
})

expect(expectedState.newDayNotifications).toEqual([
{
message: KEG_SPOILED_MESSAGE`${keg}`,
severity: 'error',
},
])
})
})
13 changes: 12 additions & 1 deletion src/templates.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/** @typedef {import("./index").farmhand.item} farmhand.item */
/**
* @typedef {import("./index").farmhand.item} farmhand.item
* @typedef {import("./index").farmhand.keg} keg
*/

/**
* @module farmhand.templates
Expand Down Expand Up @@ -335,3 +338,11 @@ export const SHOVELED_PLOT = (_, item) => `Shoveled plot of ${item.name}`
* @returns {string}
*/
export const FERMENTED_CROP_NAME = (_, item) => `Fermented ${item.name}`

/**
* @param {string} _
* @param {keg} keg
* @returns {string}
*/
export const KEG_SPOILED_MESSAGE = (_, keg) =>
`Oh no! Your ${FERMENTED_CROP_NAME`${itemsMap[keg.itemId]}`} has spoiled!`
18 changes: 18 additions & 0 deletions src/test-utils/stubs/getKegStub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/** @typedef {import("../../index").farmhand.keg} keg */

import { v4 as uuid } from 'uuid'

import { carrot } from '../../data/crops'

/**
* @param {Partial<keg>} overrides
* @returns keg
*/
export const getKegStub = overrides => {
return {
id: uuid(),
itemId: carrot.id,
daysUntilMature: carrot.daysToFerment,
...overrides,
}
}
18 changes: 18 additions & 0 deletions src/utils/getKegSpoilageRate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/** @typedef {import("../index").farmhand.keg} keg */

import { KEG_SPOILAGE_RATE_MULTIPLIER } from '../constants'

/**
* @param {keg} keg
* @returns number
*/
export const getKegSpoilageRate = keg => {
if (keg.daysUntilMature > 0) {
return 0
}

const spoilageRate =
Math.abs(keg.daysUntilMature) * KEG_SPOILAGE_RATE_MULTIPLIER

return spoilageRate
}
27 changes: 27 additions & 0 deletions src/utils/getKegSpoilageRate.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getKegStub } from '../test-utils/stubs/getKegStub'

import { getKegSpoilageRate } from './getKegSpoilageRate'

describe('getKegSpoilageRate', () => {
test('handles kegs that are not mature', () => {
const keg = getKegStub()
expect(getKegSpoilageRate(keg)).toEqual(0)
})

test('handles kegs that are mature', () => {
const keg = getKegStub({ daysUntilMature: 0 })
expect(getKegSpoilageRate(keg)).toEqual(0)
})

test.each([
[-1, 0.001],
[-10, 0.01],
[-100, 0.1],
])(
'handles kegs that are beyond mature',
(daysUntilMature, expectedSpoilageRate) => {
const keg = getKegStub({ daysUntilMature })
expect(getKegSpoilageRate(keg)).toEqual(expectedSpoilageRate)
}
)
})

1 comment on commit bf81e73

@vercel
Copy link

@vercel vercel bot commented on bf81e73 Jun 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.