Skip to content

Commit

Permalink
feat: [closes #408] Salt (#410)
Browse files Browse the repository at this point in the history
* refactor: make ResourceFactory private static variables fully private
* feat: add salt rock art
* feat: implement Salt Rock mining
* feat: make ore respawn logic more challenging
* refactor: improve ore code typing
* refactor: improve factory types
* fix: remove Twitter links
  - Badgen no longer supports Twitter badges.
* docs: explain interface system
* feat: add salt art
* feat: improve salt rock art
* feat: add salt recipe
* feat: add salt to various recipes
* test: improve expectation for minePlot
* refactor(StoneFactory): simplify generate method
* refactor(file naming): rename salt-rock.js to saltRock.js
  • Loading branch information
jeremyckahn authored Apr 29, 2023
1 parent d214631 commit 9e626f9
Show file tree
Hide file tree
Showing 28 changed files with 165 additions and 86 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
Community links:

- Discord link: [![Discord](https://img.shields.io/discord/714539345050075176?label=farmhand)](https://discord.gg/6cHEZ9H)
- Twitter link: [![@farmhandgame](https://badgen.net/twitter/follow/farmhandgame)](https://twitter.com/farmhandgame)
- Twitter link: [@farmhandgame](https://badgen.net/twitter/follow/farmhandgame)
- Reddit link: [![r/FarmhandGame](https://img.shields.io/reddit/subreddit-subscribers/FarmhandGame?style=social)](https://www.reddit.com/r/FarmhandGame/)

Storefront links:
Expand Down
2 changes: 1 addition & 1 deletion src/components/Home/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const Home = ({
source: `
Hi, you're playing **Farmhand**! This is an open source game project created by [Jeremy Kahn](https://github.com/jeremyckahn). The project has evolved over time and is now developed with the support of [a community of contributors](https://github.com/jeremyckahn/farmhand/blob/develop/CONTRIBUTORS.md).
[![Source code](https://badgen.net/badge/icon/github?icon=github&label)](https://github.com/jeremyckahn/farmhand) [![Discord](https://img.shields.io/discord/714539345050075176?label=farmhand+discord)](https://discord.gg/6cHEZ9H) [![@farmhandgame](https://badgen.net/twitter/follow/farmhandgame)](https://twitter.com/farmhandgame) [![r/FarmhandGame](https://img.shields.io/reddit/subreddit-subscribers/FarmhandGame?style=social)](https://www.reddit.com/r/FarmhandGame/)
[![Source code](https://badgen.net/badge/icon/github?icon=github&label)](https://github.com/jeremyckahn/farmhand) [![Discord](https://img.shields.io/discord/714539345050075176?label=farmhand+discord)](https://discord.gg/6cHEZ9H) [![r/FarmhandGame](https://img.shields.io/reddit/subreddit-subscribers/FarmhandGame?style=social)](https://www.reddit.com/r/FarmhandGame/) [Twitter: @farmhandgame](https://badgen.net/twitter/follow/farmhandgame)
Farmhand is a resource management game that puts a farm in your hand. It is designed to be both desktop and mobile-friendly and fun for 30 seconds or 30 minutes at a time. Can you build a thriving farming business? Give it a try and find out!
Expand Down
3 changes: 2 additions & 1 deletion src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ export const RESOURCE_SPAWN_CHANCE = 0.3
// todo: migrate these to an object called RESOURCE_SPAWN_CHANCES once reducers is refactored
export const ORE_SPAWN_CHANCE = 0.25
export const COAL_SPAWN_CHANCE = 0.15
export const STONE_SPAWN_CHANCE = 0.6
export const STONE_SPAWN_CHANCE = 0.4
export const SALT_ROCK_SPAWN_CHANCE = 0.3

// if spawning ore, which kind?
// note: these values end up being used relative to each other
Expand Down
10 changes: 9 additions & 1 deletion src/data/items.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,15 @@ export const weed = freeze({
type: WEED,
})

export { bronzeOre, coal, goldOre, ironOre, silverOre, stone } from './ores'
export {
bronzeOre,
coal,
goldOre,
ironOre,
silverOre,
stone,
saltRock,
} from './ores'

////////////////////////////////////////
//
Expand Down
1 change: 1 addition & 0 deletions src/data/ores/bronzeOre.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** @typedef {import("../../index").farmhand.item} farmhand.item */
import { itemType } from '../../enums'
import { BRONZE_SPAWN_CHANCE } from '../../constants'

Expand Down
1 change: 1 addition & 0 deletions src/data/ores/coal.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** @typedef {import("../../index").farmhand.item} farmhand.item */
import { itemType } from '../../enums'
import { COAL_SPAWN_CHANCE } from '../../constants'

Expand Down
1 change: 1 addition & 0 deletions src/data/ores/goldOre.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** @typedef {import("../../index").farmhand.item} farmhand.item */
import { itemType } from '../../enums'
import { GOLD_SPAWN_CHANCE } from '../../constants'

Expand Down
1 change: 1 addition & 0 deletions src/data/ores/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { goldOre } from './goldOre'
export { ironOre } from './ironOre'
export { silverOre } from './silverOre'
export { stone } from './stone'
export { saltRock } from './saltRock'
1 change: 1 addition & 0 deletions src/data/ores/ironOre.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** @typedef {import("../../index").farmhand.item} farmhand.item */
import { itemType } from '../../enums'
import { IRON_SPAWN_CHANCE } from '../../constants'

Expand Down
19 changes: 19 additions & 0 deletions src/data/ores/saltRock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** @typedef {import("../../index").farmhand.item} farmhand.item */
import { itemType } from '../../enums'
import { SALT_ROCK_SPAWN_CHANCE } from '../../constants'

const { freeze } = Object

/**
* @property farmhand.module:items.saltRock
* @type {farmhand.item}
*/
export const saltRock = freeze({
description: 'A large chunk of salt.',
doesPriceFluctuate: true,
id: 'salt-rock',
name: 'Salt Rock',
spawnChance: SALT_ROCK_SPAWN_CHANCE,
type: itemType.STONE,
value: 10,
})
1 change: 1 addition & 0 deletions src/data/ores/silverOre.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** @typedef {import("../../index").farmhand.item} farmhand.item */
import { itemType } from '../../enums'
import { SILVER_SPAWN_CHANCE } from '../../constants'

Expand Down
1 change: 1 addition & 0 deletions src/data/ores/stone.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** @typedef {import("../../index").farmhand.item} farmhand.item */
import { itemType } from '../../enums'
import { STONE_SPAWN_CHANCE } from '../../constants'

Expand Down
23 changes: 23 additions & 0 deletions src/data/recipes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import { itemType, fieldMode, recipeType } from '../enums'
import { RECIPE_INGREDIENT_VALUE_MULTIPLIER } from '../constants'
import { features } from '../config'

import * as items from './items'
import baseItemsMap from './items-map'
Expand All @@ -28,6 +29,23 @@ const itemify = recipe => {
return item
}

/**
* @property farmhand.module:recipes.salt
* @type {farmhand.item}
*/
export const salt = itemify({
id: 'salt',
name: 'Salt',
ingredients: {
[items.saltRock.id]: 1,
},
condition: state => state.itemsSold[items.saltRock.id] >= 30,
description: features.KEGS
? 'Useful for seasoning food and fermentation.'
: 'Useful for seasoning food.',
recipeType: recipeType.KITCHEN,
})

/**
* @property farmhand.module:recipes.bread
* @type {farmhand.recipe}
Expand Down Expand Up @@ -181,6 +199,7 @@ export const frenchOnionSoup = itemify({
ingredients: {
[items.onion.id]: 5,
[cheese.id]: 2,
[salt.id]: 2,
},
condition: state =>
state.itemsSold[items.onion.id] >= 15 && state.itemsSold[cheese.id] >= 10,
Expand Down Expand Up @@ -307,6 +326,7 @@ export const hotSauce = itemify({
name: 'Hot Sauce',
ingredients: {
[items.jalapeno.id]: 10,
[salt.id]: 1,
},
condition: state => state.itemsSold[items.jalapeno.id] >= 50,
recipeType: recipeType.KITCHEN,
Expand Down Expand Up @@ -408,6 +428,7 @@ export const garlicFries = itemify({
[items.potato.id]: 5,
[items.garlic.id]: 3,
[vegetableOil.id]: 1,
[salt.id]: 2,
},
condition: state =>
state.itemsSold[items.potato.id] >= 50 &&
Expand Down Expand Up @@ -512,6 +533,7 @@ export const sweetPotatoFries = itemify({
ingredients: {
[items.sweetPotato.id]: 10,
[vegetableOil.id]: 1,
[salt.id]: 1,
},
condition: state => state.itemsSold[items.sweetPotato.id] >= 100,
recipeType: recipeType.KITCHEN,
Expand All @@ -529,6 +551,7 @@ export const onionRings = itemify({
[vegetableOil.id]: 1,
[items.wheat.id]: 5,
[soyMilk.id]: 1,
[salt.id]: 3,
},
condition: state =>
state.itemsSold[items.onion.id] >= 50 &&
Expand Down
8 changes: 5 additions & 3 deletions src/factories/CoalFactory.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { chooseRandom } from '../utils'
/** @typedef {import("../index").farmhand.item} farmhand.item */
import { coal, stone } from '../data/ores'
import { Factory } from '../interfaces/Factory'
import { chooseRandom } from '../utils'

/**
* Resource factory used for spawning coal
* @constructor
*/
export default class CoalFactory {
export default class CoalFactory extends Factory {
/**
* Generate resources
* @returns {Array} an array of coal and stone resources
* @returns {Array.<farmhand.item>} an array of coal and stone resources
*/
generate() {
let spawns = []
Expand Down
8 changes: 6 additions & 2 deletions src/factories/OreFactory.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/** @typedef {import("../index").farmhand.item} farmhand.item */
import { goldOre, ironOre, bronzeOre, silverOre } from '../data/ores'
import { Factory } from '../interfaces/Factory'
import { randomChoice } from '../utils'

const SPAWNABLE_ORES = [goldOre, ironOre, bronzeOre, silverOre]
Expand All @@ -7,8 +9,10 @@ const SPAWNABLE_ORES = [goldOre, ironOre, bronzeOre, silverOre]
* Resource factory used for spawning ores
* @constructor
*/
export default class OreFactory {
export default class OreFactory extends Factory {
constructor() {
super()

this.oreOptions = []
for (let o of SPAWNABLE_ORES) {
this.oreOptions.push({
Expand All @@ -20,7 +24,7 @@ export default class OreFactory {

/**
* Generate resources
* @returns {Array} an array of ore resources
* @returns {Array.<farmhand.item>} an array of ore resources
*/
generate() {
return [this.spawn()]
Expand Down
56 changes: 28 additions & 28 deletions src/factories/ResourceFactory.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/** @typedef {import("../index").farmhand.item} farmhand.item */
/** @typedef {import("../enums").itemType} farmhand.itemType */
import { itemType, toolLevel } from '../enums'
import {
RESOURCE_SPAWN_CHANCE,
Expand All @@ -6,13 +8,26 @@ import {
STONE_SPAWN_CHANCE,
} from '../constants'
import { randomChoice } from '../utils'

import { randomNumberService } from '../common/services/randomNumber'
// eslint-disable-next-line no-unused-vars
import { Factory } from '../interfaces/Factory'

import OreFactory from './OreFactory'
import CoalFactory from './CoalFactory'
import StoneFactory from './StoneFactory'

/**
* Object for private cache of factory instances
* @type {Record.<string, Factory>}
*/
const factoryInstances = {}

/**
* Var for caching reference to instance of ResourceFactory
* @type {?ResourceFactory}
*/
let instance = null

/**
* Used for spawning mined resources
* @constructor
Expand All @@ -26,36 +41,23 @@ export default class ResourceFactory {
]
}

/**
* Object for internal cache of factory instances
* @static
*/
static _factoryInstances = {}

/**
* Var for caching reference to instance of ResourceFactory
* @static
*/
static _instance = null

/**
* Retrieve a reusable instance of ResourceFactory
* @returns {ResourceFactory}
* @static
*/
static instance() {
if (!ResourceFactory._instance) {
ResourceFactory._instance = new ResourceFactory()
if (!instance) {
instance = new ResourceFactory()
}

return ResourceFactory._instance
return instance
}

/**
* Generate an instance for specific factory
* @param {Number} type - an item type from itemType enum
* @returns {?Factory} returns a factory if one exists for type, default return is null
* @static
* @param {farmhand.itemType} type
* @returns {?Factory} A factory if one exists for type, default return is null
*/
static generateFactoryInstance(type) {
switch (type) {
Expand All @@ -76,26 +78,24 @@ export default class ResourceFactory {
/**
* Retrieve a specific factory for generating resources. Will create and cache
* a factory instance for reuse.
* @param {Number} type - an item type from itemType enum
* @return {Factory}
* @static
* @returns {?Factory}
*/
static getFactoryForItemType = type => {
if (!ResourceFactory._factoryInstances[type]) {
ResourceFactory._factoryInstances[
type
] = ResourceFactory.generateFactoryInstance(type)
if (!factoryInstances[type]) {
factoryInstances[type] = ResourceFactory.generateFactoryInstance(type)
}

return ResourceFactory._factoryInstances[type]
return factoryInstances[type]
}

/**
* Use dice roll and resource factories to generate resources at random
* @returns {Array} array of resource objects
* @returns {Array.<farmhand.item>} array of resource objects
*/
generateResources(shovelLevel) {
/** @type {Array.<farmhand.item>} */
let resources = []

let spawnChance = RESOURCE_SPAWN_CHANCE

switch (shovelLevel) {
Expand Down
46 changes: 20 additions & 26 deletions src/factories/StoneFactory.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,37 @@
import { coal, stone } from '../data/ores'
import { COAL_SPAWN_CHANCE } from '../constants'
/** @typedef {import("../index").farmhand.item} farmhand.item */
import { randomNumberService } from '../common/services/randomNumber'
import { Factory } from '../interfaces/Factory'
import { coal, saltRock, stone } from '../data/ores'
import {
COAL_SPAWN_CHANCE,
SALT_ROCK_SPAWN_CHANCE,
STONE_SPAWN_CHANCE,
} from '../constants'

const spawnableResources = [
[stone, STONE_SPAWN_CHANCE],
[saltRock, SALT_ROCK_SPAWN_CHANCE],
[coal, COAL_SPAWN_CHANCE],
]

/**
* Resource factory used for spawning stone
* @constructor
*/
export default class StoneFactory {
export default class StoneFactory extends Factory {
/**
* Generate resources
* @returns {Array} an array of stone and coal resources
* @returns {Array.<farmhand.item>} an array of stone and coal resources
*/
generate() {
let resources = []

resources.push(this.spawnStone())

if (randomNumberService.isRandomNumberLessThan(COAL_SPAWN_CHANCE)) {
resources.push(this.spawnCoal())
for (const [resource, spawnChance] of spawnableResources) {
if (randomNumberService.isRandomNumberLessThan(spawnChance)) {
resources.push(resource)
}
}

return resources
}

/**
* Spawn a piece of stone
* @returns {Object} stone item
* @private
*/
spawnStone() {
return stone
}

/**
* Spawn a piece of coal
* @returns {Object} coal item
* @private
*/
spawnCoal() {
return coal
}
}
Loading

0 comments on commit 9e626f9

Please sign in to comment.