Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add experience part 1 #448

Merged
merged 11 commits into from
Aug 30, 2023
32 changes: 10 additions & 22 deletions src/components/Farmhand/Farmhand.js
Original file line number Diff line number Diff line change
Expand Up @@ -590,29 +590,17 @@ export default class Farmhand extends FarmhandReducers {
})
const { isCombineEnabled, newDayNotifications } = sanitizedState

// saved games will likely have itemsSold but not experience since it's a new
// feature so this will "sync" them up
let { experience } = state
if (experience === 0) {
experience = Object.values(state.itemsSold).reduce(
(acc, value) => acc + value
)
}

this.setState(
{ ...sanitizedState, newDayNotifications: [], experience },
() => {
newDayNotifications.forEach(({ message, severity }) => {
// Defer these notifications so that notistack doesn't swallow all
// but the last one.
setTimeout(() => this.showNotification(message, severity), 0)
this.setState({ ...sanitizedState, newDayNotifications: [] }, () => {
newDayNotifications.forEach(({ message, severity }) => {
// Defer these notifications so that notistack doesn't swallow all
// but the last one.
setTimeout(() => this.showNotification(message, severity), 0)

if (isCombineEnabled) {
this.forRange(reducers.harvestPlot, Infinity, 0, 0)
}
})
}
)
if (isCombineEnabled) {
this.forRange(reducers.harvestPlot, Infinity, 0, 0)
}
})
})
} else {
// Initialize new game
await this.incrementDay(true)
Expand Down
5 changes: 3 additions & 2 deletions src/components/SettingsView/SettingsView.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState } from 'react'
import { bool, func } from 'prop-types'
import { bool, func, object } from 'prop-types'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
Expand All @@ -21,7 +21,7 @@ import './SettingsView.sass'

const SettingsView = ({
allowCustomPeerCowNames,
features = {},
features,
handleAllowCustomPeerCowNamesChange,
handleClearPersistedDataClick,
handleExportDataClick,
Expand Down Expand Up @@ -215,6 +215,7 @@ const SettingsView = ({

SettingsView.propTypes = {
allowCustomPeerCowNames: bool.isRequired,
features: object.isRequired,
handleAllowCustomPeerCowNamesChange: func.isRequired,
handleClearPersistedDataClick: func.isRequired,
handleExportDataClick: func.isRequired,
Expand Down
11 changes: 1 addition & 10 deletions src/game-logic/reducers/addExperience.js
jeremyckahn marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import { levelAchieved } from '../../utils/levelAchieved'

import { processLevelUp } from './processLevelUp'

/**
* @param {farmhand.state} state
* @param {number} amount
* @returns {farmhand.state}
*/
export const addExperience = (state, amount) => {
const newExperience = state.experience + amount
const oldLevel = levelAchieved({ itemsSold: state.itemsSold })

state = processLevelUp(state, oldLevel)

return {
...state,
experience: newExperience,
experience: state.experience + amount,
}
}
13 changes: 2 additions & 11 deletions src/game-logic/reducers/addExperience.test.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import { addExperience } from './addExperience'
import { processLevelUp } from './processLevelUp'

jest.mock('./processLevelUp')

describe('addExperience', () => {
const gameState = { experience: 0, itemsSold: {} }

it('adds experience to current experience', () => {
const gameState = { experience: 0, itemsSold: {} }

const newState = addExperience(gameState, 100)

expect(newState.experience).toEqual(100)
})

it('will check for leveling up when experience is added', () => {
addExperience(gameState, 100)

expect(processLevelUp).toHaveBeenCalled()
})
})
13 changes: 8 additions & 5 deletions src/game-logic/reducers/sellItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ export const sellItem = (state, { id }, howMany = 1) => {
: getAdjustedItemValue(valueAdjustments, id)

const saleIsGarnished = isItemAFarmProduct(item)
let saleValue = 0
let saleValue = 0,
experienceGained = 0,
salePriceMultiplier = 1

for (let i = 0; i < howMany; i++) {
const loanGarnishment = saleIsGarnished
Expand All @@ -57,9 +59,10 @@ export const sellItem = (state, { id }, howMany = 1) => {
)
: 0

const salePriceMultiplier = isItemAFarmProduct(item)
? getSalePriceMultiplier(completedAchievements)
: 1
if (isItemAFarmProduct(item)) {
salePriceMultiplier = getSalePriceMultiplier(completedAchievements)
experienceGained += 1
}

const garnishedProfit =
adjustedItemValue * salePriceMultiplier - loanGarnishment
Expand All @@ -82,7 +85,7 @@ export const sellItem = (state, { id }, howMany = 1) => {
state = addRevenue({ ...state, money: initialMoney }, saleValue)
}

state = addExperience(state, howMany)
state = addExperience(state, experienceGained)

state = {
...state,
Expand Down
16 changes: 13 additions & 3 deletions src/game-logic/reducers/sellItem.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ describe('sellItem', () => {
test('sells item', () => {
const state = sellItem(
{
experience: 0,
inventory: [testItem({ id: 'sample-item-1', quantity: 1 })],
itemsSold: {},
loanBalance: 0,
Expand All @@ -23,7 +22,6 @@ describe('sellItem', () => {
testItem({ id: 'sample-item-1' })
)

expect(state.experience).toEqual(1)
expect(state.inventory).toEqual([])
expect(state.money).toEqual(101)
expect(state.revenue).toEqual(1)
Expand Down Expand Up @@ -130,9 +128,10 @@ describe('sellItem', () => {
let state

describe('item is not a farm product', () => {
test('sale is not garnished', () => {
beforeEach(() => {
state = sellItem(
{
experience: 0,
inventory: [testItem({ id: 'sample-crop-1-seed', quantity: 3 })],
itemsSold: {},
loanBalance: 100,
Expand All @@ -146,12 +145,18 @@ describe('sellItem', () => {
testItem({ id: 'sample-crop-1-seed' }),
3
)
})

test('sale is not garnished', () => {
expect(state.loanBalance).toEqual(100)
expect(state.money).toEqual(130)
expect(state.revenue).toEqual(0)
expect(state.todaysRevenue).toEqual(0)
})

test('experience is not gained', () => {
expect(state.experience).toEqual(0)
})
})

describe('item is a farm product', () => {
Expand Down Expand Up @@ -184,6 +189,7 @@ describe('sellItem', () => {
beforeEach(() => {
state = sellItem(
{
experience: 0,
inventory: [testItem({ id: 'sample-crop-1', quantity: 3 })],
itemsSold: {},
loanBalance: 1.5,
Expand Down Expand Up @@ -213,6 +219,10 @@ describe('sellItem', () => {
{ message: LOAN_PAYOFF``, severity: 'success' },
])
})

test('experience is gained', () => {
expect(state.experience).toEqual(3)
})
})
})
})
Expand Down
9 changes: 7 additions & 2 deletions src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,12 @@ import {
} from '../constants'
import { random } from '../common/utils'

import { memoize } from './memoize'
import { farmProductsSold } from './farmProductsSold'
import { getCropLifecycleDuration } from './getCropLifecycleDuration'
import { getItemBaseValue } from './getItemBaseValue'
import { getInventoryQuantityMap } from './getInventoryQuantityMap'
import { getItemBaseValue } from './getItemBaseValue'
import { getLevelEntitlements } from './getLevelEntitlements'
import { memoize } from './memoize'

const Jimp = configureJimp({
types: [jimpPng],
Expand Down Expand Up @@ -948,6 +949,10 @@ export const transformStateDataForImport = state => {
const rejectedKeys = ['version']
rejectedKeys.forEach(rejectedKey => delete sanitizedState[rejectedKey])

if (sanitizedState.experience === 0) {
sanitizedState.experience = farmProductsSold(sanitizedState.itemsSold)
}

return sanitizedState
}

Expand Down
50 changes: 50 additions & 0 deletions src/utils/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
moneyTotal,
percentageString,
randomChoice,
transformStateDataForImport,
} from './index'

jest.mock('../data/maps')
Expand Down Expand Up @@ -1046,3 +1047,52 @@ describe('getCowImage', () => {
expect(image).toEqual(animals.cow.rainbow)
})
})

describe('transformStateDataForImport', () => {
Copy link
Owner

Choose a reason for hiding this comment

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

Thank you for setting up test cases for this function! 🙏

let state

beforeEach(() => {
state = {
dayCount: 100,
experience: 10,
inventoryLimit: 1000,
loanBalance: 100,
money: 1234,
version: 1,
}
})

test('it returns a sanitized state without version', () => {
const sanitizedState = transformStateDataForImport(state)

expect(sanitizedState).toEqual({
dayCount: 100,
experience: 10,
inventoryLimit: 1000,
loanBalance: 100,
money: 1234,
})
})

test('it calculates experience from itemsSold if experience is 0', () => {
state.experience = 0
state.itemsSold = {
'sample-crop-1': 5,
'sample-crop-1-seed': 10,
}

const sanitizedState = transformStateDataForImport(state)

expect(sanitizedState).toEqual({
dayCount: 100,
experience: 5,
inventoryLimit: 1000,
itemsSold: {
'sample-crop-1': 5,
'sample-crop-1-seed': 10,
},
loanBalance: 100,
money: 1234,
})
})
})
8 changes: 3 additions & 5 deletions src/utils/isItemAFarmProduct.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import { itemType } from '../enums'

import { isItemAGrownCrop } from './isItemAGrownCrop'

const FARM_PRODUCT_TYPES = [itemType.MILK, itemType.CRAFTED_ITEM]

/**
* @param {farmhand.item} item
* @returns {boolean}
*/
export const isItemAFarmProduct = item =>
Boolean(
isItemAGrownCrop(item) ||
item.type === itemType.MILK ||
item.type === itemType.CRAFTED_ITEM
)
Boolean(isItemAGrownCrop(item) || FARM_PRODUCT_TYPES.includes(item.type))
Copy link
Owner

Choose a reason for hiding this comment

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

This is an excellent refactor! 💯

Loading