From d37d41073867da6a8dbfa65048c0b008b303a9f5 Mon Sep 17 00:00:00 2001 From: Jeremy Kahn Date: Sun, 27 Aug 2023 15:07:15 -0500 Subject: [PATCH 1/6] chore(package): rebuild package-lock.json (#447) --- package-lock.json | 1233 --------------------------------------------- 1 file changed, 1233 deletions(-) diff --git a/package-lock.json b/package-lock.json index b87803fbf..09ea170d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2658,246 +2658,6 @@ "version": "0.8.0", "license": "MIT" }, - "node_modules/@esbuild/android-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", - "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", - "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", - "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", - "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", - "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", - "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", - "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", - "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", - "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", - "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", - "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", - "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", - "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", - "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", - "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/linux-x64": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", @@ -2914,102 +2674,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", - "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", - "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", - "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", - "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", - "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", - "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "dev": true, @@ -6909,17 +6573,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/plist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz", - "integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*", - "xmlbuilder": ">=11.0.1" - } - }, "node_modules/@types/prettier": { "version": "2.7.2", "dev": true, @@ -7068,13 +6721,6 @@ "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", "dev": true }, - "node_modules/@types/verror": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.6.tgz", - "integrity": "sha512-NNm+gdePAX1VGvPcGZCDKQZKYSiAWigKhKaz5KF94hG6f2s8de9Ow5+7AbXoeKxL8gavZfk4UquSAygOF2duEQ==", - "dev": true, - "optional": true - }, "node_modules/@types/ws": { "version": "8.5.4", "dev": true, @@ -10430,23 +10076,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "optional": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/clipboardy": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", @@ -11037,41 +10666,6 @@ "node": ">=10" } }, - "node_modules/crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, - "optional": true, - "dependencies": { - "buffer": "^5.1.0" - } - }, - "node_modules/crc/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -12133,32 +11727,6 @@ "node": ">= 10.0.0" } }, - "node_modules/dmg-license": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", - "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "@types/plist": "^3.0.1", - "@types/verror": "^1.10.3", - "ajv": "^6.10.0", - "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.7", - "plist": "^3.0.4", - "smart-buffer": "^4.0.2", - "verror": "^1.10.0" - }, - "bin": { - "dmg-license": "bin/dmg-license.js" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dns-equal": { "version": "1.0.0", "dev": true, @@ -13142,118 +12710,6 @@ "esbuild-windows-arm64": "0.14.47" } }, - "node_modules/esbuild-android-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz", - "integrity": "sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz", - "integrity": "sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", - "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz", - "integrity": "sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz", - "integrity": "sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz", - "integrity": "sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz", - "integrity": "sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/esbuild-linux-64": { "version": "0.14.47", "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz", @@ -13270,198 +12726,6 @@ "node": ">=12" } }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz", - "integrity": "sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz", - "integrity": "sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz", - "integrity": "sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz", - "integrity": "sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz", - "integrity": "sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz", - "integrity": "sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz", - "integrity": "sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz", - "integrity": "sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz", - "integrity": "sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz", - "integrity": "sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz", - "integrity": "sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz", - "integrity": "sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/escalade": { "version": "3.1.1", "license": "MIT", @@ -15366,19 +14630,6 @@ "node": ">=0.4" } }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/fun-animal-names": { "version": "0.1.1", "license": "MIT", @@ -16646,23 +15897,6 @@ "version": "1.0.4", "license": "BSD-3-Clause" }, - "node_modules/iconv-corefoundation": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", - "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "cli-truncate": "^2.1.0", - "node-addon-api": "^1.6.3" - }, - "engines": { - "node": "^8.11.2 || >=10" - } - }, "node_modules/iconv-lite": { "version": "0.6.3", "license": "MIT", @@ -23691,13 +22925,6 @@ "version": "1.2.14", "license": "MIT" }, - "node_modules/node-addon-api": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", - "dev": true, - "optional": true - }, "node_modules/node-environment-flags": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", @@ -30190,21 +29417,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "optional": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "dev": true, @@ -33165,38 +32377,6 @@ "node": ">= 14" } }, - "node_modules/verror": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", - "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", - "dev": true, - "optional": true, - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/verror/node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true, - "optional": true - }, "node_modules/vfile": { "version": "2.3.0", "license": "MIT", @@ -35883,111 +35063,6 @@ "@emotion/hash": { "version": "0.8.0" }, - "@esbuild/android-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", - "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", - "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", - "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", - "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", - "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", - "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", - "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", - "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", - "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", - "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", - "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", - "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", - "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", - "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", - "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", - "dev": true, - "optional": true - }, "@esbuild/linux-x64": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", @@ -35995,48 +35070,6 @@ "dev": true, "optional": true }, - "@esbuild/netbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", - "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", - "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", - "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", - "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", - "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", - "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", - "dev": true, - "optional": true - }, "@eslint/eslintrc": { "version": "0.4.3", "dev": true, @@ -38850,17 +37883,6 @@ "version": "4.0.0", "dev": true }, - "@types/plist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz", - "integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==", - "dev": true, - "optional": true, - "requires": { - "@types/node": "*", - "xmlbuilder": ">=11.0.1" - } - }, "@types/prettier": { "version": "2.7.2", "dev": true @@ -38995,13 +38017,6 @@ "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", "dev": true }, - "@types/verror": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.6.tgz", - "integrity": "sha512-NNm+gdePAX1VGvPcGZCDKQZKYSiAWigKhKaz5KF94hG6f2s8de9Ow5+7AbXoeKxL8gavZfk4UquSAygOF2duEQ==", - "dev": true, - "optional": true - }, "@types/ws": { "version": "8.5.4", "dev": true, @@ -41286,17 +40301,6 @@ "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", "dev": true }, - "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "optional": true, - "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - } - }, "clipboardy": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", @@ -41703,29 +40707,6 @@ "yaml": "^1.10.0" } }, - "crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, - "optional": true, - "requires": { - "buffer": "^5.1.0" - }, - "dependencies": { - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "optional": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - } - } - }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -42405,23 +41386,6 @@ } } }, - "dmg-license": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", - "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", - "dev": true, - "optional": true, - "requires": { - "@types/plist": "^3.0.1", - "@types/verror": "^1.10.3", - "ajv": "^6.10.0", - "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.7", - "plist": "^3.0.4", - "smart-buffer": "^4.0.2", - "verror": "^1.10.0" - } - }, "dns-equal": { "version": "1.0.0", "dev": true @@ -43134,55 +42098,6 @@ "esbuild-windows-arm64": "0.14.47" } }, - "esbuild-android-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz", - "integrity": "sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz", - "integrity": "sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", - "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz", - "integrity": "sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz", - "integrity": "sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz", - "integrity": "sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz", - "integrity": "sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==", - "dev": true, - "optional": true - }, "esbuild-linux-64": { "version": "0.14.47", "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz", @@ -43190,90 +42105,6 @@ "dev": true, "optional": true }, - "esbuild-linux-arm": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz", - "integrity": "sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz", - "integrity": "sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz", - "integrity": "sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz", - "integrity": "sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz", - "integrity": "sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz", - "integrity": "sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz", - "integrity": "sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz", - "integrity": "sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz", - "integrity": "sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz", - "integrity": "sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz", - "integrity": "sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz", - "integrity": "sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==", - "dev": true, - "optional": true - }, "escalade": { "version": "3.1.1" }, @@ -44557,12 +43388,6 @@ "fs.realpath": { "version": "1.0.0" }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, "fun-animal-names": { "version": "0.1.1" }, @@ -45418,17 +44243,6 @@ "hyphenate-style-name": { "version": "1.0.4" }, - "iconv-corefoundation": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", - "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", - "dev": true, - "optional": true, - "requires": { - "cli-truncate": "^2.1.0", - "node-addon-api": "^1.6.3" - } - }, "iconv-lite": { "version": "0.6.3", "requires": { @@ -50509,13 +49323,6 @@ "noble-secp256k1": { "version": "1.2.14" }, - "node-addon-api": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", - "dev": true, - "optional": true - }, "node-environment-flags": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", @@ -54638,18 +53445,6 @@ "version": "3.0.0", "dev": true }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, "smart-buffer": { "version": "4.2.0", "dev": true @@ -56689,34 +55484,6 @@ "@vercel/static-build": "1.3.0" } }, - "verror": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", - "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true, - "optional": true - } - } - }, "vfile": { "version": "2.3.0", "requires": { From 99b42124c9c19545152e1788c8831b0c1d9fffd0 Mon Sep 17 00:00:00 2001 From: Luke Stebner Date: Wed, 30 Aug 2023 09:17:42 -0700 Subject: [PATCH 2/6] add experience based leveling part 1 (#448) The goal of this PR is to lay some groundwork for an experience based level system as outlined in #371 - add 'experience' to farmhand state - add 'useLegacyLevelingSystem' to farmhand state and settings screen (only shown when the EXPERIENCE feature is enabled) - update `levelAchieved` to be more flexible about how level is calculated based on which leveling system is being used - update all calls to `levelAchieved` - update utils unit tests for levelAchieved to test both systems - add 'EXPERIENCE' feature flag - add reducer for adding experience + unit test - some utils were moved into their own files to make them easier to work with (mostly to avoid circular dependencies when one util relies on another util) and imports across the codebase were updated - initialize `experience` value to match number of items sold when loading a saved game - add 1 experience point per farm item sold (crops, milks, and crafted or forged items) - items that are not farm items should not reward the player with any experience (seeds, weeds, other supplies) - importing a save without experience should calculate experience based on items sold --- .env.development.local | 1 + src/components/Farmhand/Farmhand.js | 7 +- src/components/Field/Field.js | 10 +- src/components/Navigation/Navigation.js | 6 +- .../OnlinePeersView/OnlinePeer/OnlinePeer.js | 13 +-- .../OnlinePeersView/OnlinePeersView.js | 5 +- src/components/Recipe/Recipe.js | 2 +- src/components/SettingsView/SettingsView.js | 20 +++- src/components/StatsView/StatsView.js | 6 +- .../UpgradePurchase/UpgradePurchase.js | 7 +- src/constants.js | 2 + src/game-logic/reducers/addExperience.js | 11 +++ src/game-logic/reducers/addExperience.test.js | 11 +++ .../reducers/generatePriceEvents.js | 5 +- src/game-logic/reducers/processLevelUp.js | 7 +- src/game-logic/reducers/processSprinklers.js | 12 +-- src/game-logic/reducers/sellItem.js | 21 ++-- src/game-logic/reducers/sellItem.test.js | 14 ++- src/game-logic/reducers/sellKeg.js | 11 +-- src/handlers/ui-events.js | 7 ++ src/utils/farmProductsSold.js | 17 ++++ src/utils/index.js | 49 ++-------- src/utils/index.test.js | 98 +++++++++++++++++-- src/utils/isItemAFarmProduct.js | 12 +++ src/utils/isItemAGrownCrop.js | 8 ++ src/utils/levelAchieved.js | 23 +++++ src/utils/totalIngredientsInRecipe.js | 2 +- src/utils/totalIngredientsInRecipe.test.js | 2 +- 28 files changed, 268 insertions(+), 121 deletions(-) create mode 100644 src/game-logic/reducers/addExperience.js create mode 100644 src/game-logic/reducers/addExperience.test.js create mode 100644 src/utils/farmProductsSold.js create mode 100644 src/utils/isItemAFarmProduct.js create mode 100644 src/utils/isItemAGrownCrop.js create mode 100644 src/utils/levelAchieved.js diff --git a/.env.development.local b/.env.development.local index 09062c3e0..18006bc20 100644 --- a/.env.development.local +++ b/.env.development.local @@ -1,2 +1,3 @@ REACT_APP_API_ROOT=http://localhost:3001/ REACT_APP_ENABLE_KEGS=true +REACT_APP_ENABLE_EXPERIENCE=true diff --git a/src/components/Farmhand/Farmhand.js b/src/components/Farmhand/Farmhand.js index aec94fdf5..c32cc48cb 100644 --- a/src/components/Farmhand/Farmhand.js +++ b/src/components/Farmhand/Farmhand.js @@ -56,17 +56,16 @@ import NotificationSystem, { } from '../NotificationSystem' import DebugMenu from '../DebugMenu' import theme from '../../mui-theme' +import { levelAchieved } from '../../utils/levelAchieved' import { computeMarketPositions, createNewField, doesMenuObstructStage, - farmProductsSold, generateCow, getAvailableShopInventory, getItemCurrentValue, getPeerMetadata, inventorySpaceRemaining, - levelAchieved, moneyTotal, nullArray, reduceByPersistedKeys, @@ -381,7 +380,7 @@ export default class Farmhand extends FarmhandReducers { get levelEntitlements() { return getLevelEntitlements( - levelAchieved(farmProductsSold(this.state.itemsSold)) + levelAchieved({ itemsSold: this.state.itemsSold }) ) } @@ -425,6 +424,7 @@ export default class Farmhand extends FarmhandReducers { cowTradeTimeoutId: -1, cropsHarvested: {}, dayCount: 0, + experience: 0, farmName: 'Unnamed', field: createNewField(), fieldMode: OBSERVE, @@ -497,6 +497,7 @@ export default class Farmhand extends FarmhandReducers { [toolType.WATERING_CAN]: toolLevel.DEFAULT, }, useAlternateEndDayButtonPosition: false, + useLegacyLevelingSystem: true, valueAdjustments: {}, version: process.env.REACT_APP_VERSION ?? '', } diff --git a/src/components/Field/Field.js b/src/components/Field/Field.js index f4c8dca7c..24f779d5e 100644 --- a/src/components/Field/Field.js +++ b/src/components/Field/Field.js @@ -18,12 +18,8 @@ import Plot from '../Plot' import QuickSelect from '../QuickSelect' import { fieldMode } from '../../enums' import tools from '../../data/tools' -import { - doesInventorySpaceRemain, - farmProductsSold, - levelAchieved, - nullArray, -} from '../../utils' +import { levelAchieved } from '../../utils/levelAchieved' +import { doesInventorySpaceRemain, nullArray } from '../../utils' import { getLevelEntitlements } from '../../utils/getLevelEntitlements' import './Field.sass' @@ -74,7 +70,7 @@ export const isInHoverRange = ({ switch (fieldMode) { case SET_SPRINKLER: hoveredPlotRangeSizeToRender = getLevelEntitlements( - levelAchieved(farmProductsSold(itemsSold)) + levelAchieved({ itemsSold }) ).sprinklerRange break diff --git a/src/components/Navigation/Navigation.js b/src/components/Navigation/Navigation.js index a08f63940..41fadf4ee 100644 --- a/src/components/Navigation/Navigation.js +++ b/src/components/Navigation/Navigation.js @@ -27,13 +27,13 @@ import Typography from '@material-ui/core/Typography' import { array, bool, func, number, object, string } from 'prop-types' import FarmhandContext from '../Farmhand/Farmhand.context' +import { farmProductsSold } from '../../utils/farmProductsSold' +import { levelAchieved } from '../../utils/levelAchieved' import { doesInventorySpaceRemain, farmProductSalesVolumeNeededForLevel, - farmProductsSold, integerString, inventorySpaceConsumed, - levelAchieved, scaleNumber, } from '../../utils' import { dialogView } from '../../enums' @@ -225,7 +225,7 @@ export const Navigation = ({ viewList, totalFarmProductsSold = farmProductsSold(itemsSold), - currentLevel = levelAchieved(totalFarmProductsSold), + currentLevel = levelAchieved({ itemsSold }), levelPercent = scaleNumber( totalFarmProductsSold, farmProductSalesVolumeNeededForLevel(currentLevel), diff --git a/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.js b/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.js index 4a520e836..0bfa309ff 100644 --- a/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.js +++ b/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.js @@ -7,12 +7,8 @@ import CardHeader from '@material-ui/core/CardHeader' import CowCard from '../../CowCard' import { moneyString } from '../../../utils/moneyString' -import { - getPlayerName, - farmProductsSold, - integerString, - levelAchieved, -} from '../../../utils' +import { levelAchieved } from '../../../utils/levelAchieved' +import { getPlayerName, integerString } from '../../../utils' import './OnlinePeer.sass' @@ -28,10 +24,7 @@ const OnlinePeer = ({ subheader: (

Day: {integerString(dayCount)}

-

- Level:{' '} - {integerString(levelAchieved(farmProductsSold(itemsSold)))} -

+

Level: {integerString(levelAchieved({ itemsSold }))}

Money: {moneyString(money)}

), diff --git a/src/components/OnlinePeersView/OnlinePeersView.js b/src/components/OnlinePeersView/OnlinePeersView.js index 36afcc03a..c31c655d2 100644 --- a/src/components/OnlinePeersView/OnlinePeersView.js +++ b/src/components/OnlinePeersView/OnlinePeersView.js @@ -9,7 +9,8 @@ import { array, number, object, string } from 'prop-types' import BailOutErrorBoundary from '../BailOutErrorBoundary' -import { getPlayerName, farmProductsSold, levelAchieved } from '../../utils' +import { levelAchieved } from '../../utils/levelAchieved' +import { getPlayerName } from '../../utils' import FarmhandContext from '../Farmhand/Farmhand.context' import CowCard from '../CowCard' @@ -58,7 +59,7 @@ const OnlinePeersView = ({ {sortBy(populatedPeers, [ peerId => // Use negative value to reverse sort order - -levelAchieved(farmProductsSold(peers[peerId].itemsSold || 0)), + -levelAchieved({ itemsSold: peers[peerId].itemsSold || 0 }), ]).map(peerId => ( diff --git a/src/components/Recipe/Recipe.js b/src/components/Recipe/Recipe.js index b68f59c19..dda0bfd76 100644 --- a/src/components/Recipe/Recipe.js +++ b/src/components/Recipe/Recipe.js @@ -8,13 +8,13 @@ import CardActions from '@material-ui/core/CardActions' import Typography from '@material-ui/core/Typography' import { array, func, number, object } from 'prop-types' +import { totalIngredientsInRecipe } from '../../utils/totalIngredientsInRecipe' import { canMakeRecipe, doesInventorySpaceRemain, dollarString, maxYieldOfRecipe, integerString, - totalIngredientsInRecipe, } from '../../utils' import { itemsMap } from '../../data/maps' import { craftedItems } from '../../img' diff --git a/src/components/SettingsView/SettingsView.js b/src/components/SettingsView/SettingsView.js index 34af40d08..88a252430 100644 --- a/src/components/SettingsView/SettingsView.js +++ b/src/components/SettingsView/SettingsView.js @@ -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' @@ -21,6 +21,7 @@ import './SettingsView.sass' const SettingsView = ({ allowCustomPeerCowNames, + features, handleAllowCustomPeerCowNamesChange, handleClearPersistedDataClick, handleExportDataClick, @@ -29,8 +30,10 @@ const SettingsView = ({ handleShowNotificationsChange, handleUseAlternateEndDayButtonPositionChange, handleShowHomeScreenChange, + handleUseLegacyLevelSystemChange, showNotifications, useAlternateEndDayButtonPosition, + useLegacyLevelingSystem, showHomeScreen, }) => { const [isClearDataDialogOpen, setIsClearDataDialogOpen] = useState(false) @@ -99,6 +102,19 @@ const SettingsView = ({ } label="Display custom names for cows received from other players" /> + {features.EXPERIENCE ? ( + + } + label="Use legacy leveling system (experience is only gained by selling items)" + /> + ) : null} @@ -199,6 +215,7 @@ const SettingsView = ({ SettingsView.propTypes = { allowCustomPeerCowNames: bool.isRequired, + features: object.isRequired, handleAllowCustomPeerCowNamesChange: func.isRequired, handleClearPersistedDataClick: func.isRequired, handleExportDataClick: func.isRequired, @@ -210,6 +227,7 @@ SettingsView.propTypes = { showHomeScreen: bool.isRequired, showNotifications: bool.isRequired, useAlternateEndDayButtonPosition: bool.isRequired, + useLegacyLevelingSystem: bool, } export default function Consumer(props) { diff --git a/src/components/StatsView/StatsView.js b/src/components/StatsView/StatsView.js index b330bf346..49bd91b22 100644 --- a/src/components/StatsView/StatsView.js +++ b/src/components/StatsView/StatsView.js @@ -13,14 +13,14 @@ import sortBy from 'lodash.sortby' import { itemsMap } from '../../data/maps' import FarmhandContext from '../Farmhand/Farmhand.context' import { moneyString } from '../../utils/moneyString' +import { farmProductsSold } from '../../utils/farmProductsSold' +import { levelAchieved } from '../../utils/levelAchieved' import { farmProductSalesVolumeNeededForLevel, - farmProductsSold, get7DayAverage, getProfit, getProfitRecord, integerString, - levelAchieved, moneyTotal, } from '../../utils' import { @@ -51,7 +51,7 @@ const StatsView = ({ todaysRevenue, totalFarmProductsSold = farmProductsSold(itemsSold), - currentLevel = levelAchieved(totalFarmProductsSold), + currentLevel = levelAchieved({ itemsSold }), }) => (
diff --git a/src/components/UpgradePurchase/UpgradePurchase.js b/src/components/UpgradePurchase/UpgradePurchase.js index 0c2804350..b94587cef 100644 --- a/src/components/UpgradePurchase/UpgradePurchase.js +++ b/src/components/UpgradePurchase/UpgradePurchase.js @@ -8,11 +8,8 @@ import { array, func, number, object } from 'prop-types' import IngredientsList from '../IngredientsList' -import { - canMakeRecipe, - doesInventorySpaceRemain, - totalIngredientsInRecipe, -} from '../../utils' +import { totalIngredientsInRecipe } from '../../utils/totalIngredientsInRecipe' +import { canMakeRecipe, doesInventorySpaceRemain } from '../../utils' import { craftedItems } from '../../img' diff --git a/src/constants.js b/src/constants.js index 096db8f74..0c22b5379 100644 --- a/src/constants.js +++ b/src/constants.js @@ -143,6 +143,7 @@ export const PERSISTED_STATE_KEYS = [ 'cowsTraded', 'cropsHarvested', 'dayCount', + 'experience', 'farmName', 'field', 'historicalDailyLosses', @@ -182,6 +183,7 @@ export const PERSISTED_STATE_KEYS = [ 'todaysStartingInventory', 'toolLevels', 'useAlternateEndDayButtonPosition', + 'useLegacyLevelingSystem', 'valueAdjustments', 'version', ] diff --git a/src/game-logic/reducers/addExperience.js b/src/game-logic/reducers/addExperience.js new file mode 100644 index 000000000..69c16709a --- /dev/null +++ b/src/game-logic/reducers/addExperience.js @@ -0,0 +1,11 @@ +/** + * @param {farmhand.state} state + * @param {number} amount + * @returns {farmhand.state} + */ +export const addExperience = (state, amount) => { + return { + ...state, + experience: state.experience + amount, + } +} diff --git a/src/game-logic/reducers/addExperience.test.js b/src/game-logic/reducers/addExperience.test.js new file mode 100644 index 000000000..810bcd6a0 --- /dev/null +++ b/src/game-logic/reducers/addExperience.test.js @@ -0,0 +1,11 @@ +import { addExperience } from './addExperience' + +describe('addExperience', () => { + it('adds experience to current experience', () => { + const gameState = { experience: 0, itemsSold: {} } + + const newState = addExperience(gameState, 100) + + expect(newState.experience).toEqual(100) + }) +}) diff --git a/src/game-logic/reducers/generatePriceEvents.js b/src/game-logic/reducers/generatePriceEvents.js index de02d3a4a..fbe329a47 100644 --- a/src/game-logic/reducers/generatePriceEvents.js +++ b/src/game-logic/reducers/generatePriceEvents.js @@ -1,9 +1,8 @@ +import { levelAchieved } from '../../utils/levelAchieved' import { - farmProductsSold, filterItemIdsToSeeds, getPriceEventForCrop, getRandomUnlockedCrop, - levelAchieved, } from '../../utils' import { getLevelEntitlements } from '../../utils/getLevelEntitlements' import { PRICE_EVENT_CHANCE } from '../../constants' @@ -29,7 +28,7 @@ export const generatePriceEvents = state => { // less-than check. if (random() < PRICE_EVENT_CHANCE) { const { items: unlockedItems } = getLevelEntitlements( - levelAchieved(farmProductsSold(state.itemsSold)) + levelAchieved({ itemsSold: state.itemsSold }) ) const cropItem = getRandomUnlockedCrop( diff --git a/src/game-logic/reducers/processLevelUp.js b/src/game-logic/reducers/processLevelUp.js index 3bc37daef..b88d4ccc3 100644 --- a/src/game-logic/reducers/processLevelUp.js +++ b/src/game-logic/reducers/processLevelUp.js @@ -1,9 +1,8 @@ import { levels } from '../../data/levels' +import { levelAchieved } from '../../utils/levelAchieved' import { - farmProductsSold, getRandomLevelUpReward, getRandomLevelUpRewardQuantity, - levelAchieved, unlockTool, } from '../../utils' import { getLevelEntitlements } from '../../utils/getLevelEntitlements' @@ -20,7 +19,7 @@ import { showNotification } from './showNotification' */ export const processLevelUp = (state, oldLevel) => { const { itemsSold, selectedItemId } = state - const newLevel = levelAchieved(farmProductsSold(itemsSold)) + const newLevel = levelAchieved({ itemsSold }) // Loop backwards so that the notifications appear in descending order. for (let i = newLevel; i > oldLevel; i--) { @@ -48,7 +47,7 @@ export const processLevelUp = (state, oldLevel) => { selectedItemId === SPRINKLER_ITEM_ID ) { const { sprinklerRange } = getLevelEntitlements( - levelAchieved(farmProductsSold(itemsSold)) + levelAchieved({ itemsSold }) ) if (sprinklerRange > state.hoveredPlotRangeSize) { diff --git a/src/game-logic/reducers/processSprinklers.js b/src/game-logic/reducers/processSprinklers.js index 92ff18ba2..35a50efb5 100644 --- a/src/game-logic/reducers/processSprinklers.js +++ b/src/game-logic/reducers/processSprinklers.js @@ -1,10 +1,6 @@ import { itemType } from '../../enums' -import { - farmProductsSold, - getPlotContentType, - getRangeCoords, - levelAchieved, -} from '../../utils' +import { levelAchieved } from '../../utils/levelAchieved' +import { getPlotContentType, getRangeCoords } from '../../utils' import { getLevelEntitlements } from '../../utils/getLevelEntitlements' import { setWasWatered } from './helpers' @@ -19,9 +15,7 @@ export const processSprinklers = state => { const crops = new Map() let modifiedField = [...field] - const { sprinklerRange } = getLevelEntitlements( - levelAchieved(farmProductsSold(itemsSold)) - ) + const { sprinklerRange } = getLevelEntitlements(levelAchieved({ itemsSold })) field.forEach((row, plotY) => { row.forEach((plot, plotX) => { diff --git a/src/game-logic/reducers/sellItem.js b/src/game-logic/reducers/sellItem.js index 8feb6a42c..a293fa9f1 100644 --- a/src/game-logic/reducers/sellItem.js +++ b/src/game-logic/reducers/sellItem.js @@ -1,13 +1,12 @@ import { itemsMap } from '../../data/maps' +import { isItemAFarmProduct } from '../../utils/isItemAFarmProduct' +import { levelAchieved } from '../../utils/levelAchieved' import { castToMoney, - farmProductsSold, getAdjustedItemValue, getResaleValue, getSalePriceMultiplier, - isItemAFarmProduct, isItemSoldInShop, - levelAchieved, moneyTotal, } from '../../utils' import { LOAN_GARNISHMENT_RATE } from '../../constants' @@ -15,6 +14,7 @@ import { SOLD_ITEM_PEER_NOTIFICATION } from '../../templates' import { decrementItemFromInventory } from './decrementItemFromInventory' import { processLevelUp } from './processLevelUp' +import { addExperience } from './addExperience' import { addRevenue } from './addRevenue' import { updateLearnedRecipes } from './updateLearnedRecipes' import { adjustLoan } from './adjustLoan' @@ -39,7 +39,7 @@ export const sellItem = (state, { id }, howMany = 1) => { money: initialMoney, valueAdjustments, } = state - const oldLevel = levelAchieved(farmProductsSold(itemsSold)) + const oldLevel = levelAchieved({ itemsSold }) let { loanBalance } = state const adjustedItemValue = isItemSoldInShop(item) @@ -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 @@ -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 @@ -82,6 +85,8 @@ export const sellItem = (state, { id }, howMany = 1) => { state = addRevenue({ ...state, money: initialMoney }, saleValue) } + state = addExperience(state, experienceGained) + state = { ...state, itemsSold: newItemsSold, diff --git a/src/game-logic/reducers/sellItem.test.js b/src/game-logic/reducers/sellItem.test.js index 84c0830eb..2f52b89ca 100644 --- a/src/game-logic/reducers/sellItem.test.js +++ b/src/game-logic/reducers/sellItem.test.js @@ -128,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, @@ -144,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', () => { @@ -182,6 +189,7 @@ describe('sellItem', () => { beforeEach(() => { state = sellItem( { + experience: 0, inventory: [testItem({ id: 'sample-crop-1', quantity: 3 })], itemsSold: {}, loanBalance: 1.5, @@ -211,6 +219,10 @@ describe('sellItem', () => { { message: LOAN_PAYOFF``, severity: 'success' }, ]) }) + + test('experience is gained', () => { + expect(state.experience).toEqual(3) + }) }) }) }) diff --git a/src/game-logic/reducers/sellKeg.js b/src/game-logic/reducers/sellKeg.js index 7cfcc04dc..da4cd93c5 100644 --- a/src/game-logic/reducers/sellKeg.js +++ b/src/game-logic/reducers/sellKeg.js @@ -5,13 +5,8 @@ */ import { itemsMap } from '../../data/maps' -import { - castToMoney, - farmProductsSold, - getSalePriceMultiplier, - levelAchieved, - moneyTotal, -} from '../../utils' +import { levelAchieved } from '../../utils/levelAchieved' +import { castToMoney, getSalePriceMultiplier, moneyTotal } from '../../utils' import { LOAN_GARNISHMENT_RATE } from '../../constants' import { SOLD_FERMENTED_ITEM_PEER_NOTIFICATION } from '../../templates' import { getKegValue } from '../../utils/getKegValue' @@ -38,7 +33,7 @@ export const sellKeg = (state, keg) => { itemsSold, money: initialMoney, } = state - const oldLevel = levelAchieved(farmProductsSold(itemsSold)) + const oldLevel = levelAchieved({ itemsSold }) let { loanBalance } = state let saleValue = 0 diff --git a/src/handlers/ui-events.js b/src/handlers/ui-events.js index 279692718..347f4a984 100644 --- a/src/handlers/ui-events.js +++ b/src/handlers/ui-events.js @@ -531,4 +531,11 @@ export default { const newUrl = `${origin}${pathname}${newSearch}${hash}` window.history.replaceState({}, '', newUrl) }, + + /** + * @param {React.SyntheticEvent} e + */ + handleUseLegacyLevelSystemChange(e) { + this.setState({ useLegacyLevelingSystem: e.target.checked }) + }, } diff --git a/src/utils/farmProductsSold.js b/src/utils/farmProductsSold.js new file mode 100644 index 000000000..ad44d7c19 --- /dev/null +++ b/src/utils/farmProductsSold.js @@ -0,0 +1,17 @@ +import { itemsMap } from '../data/maps' + +import { memoize } from './memoize' +import { isItemAFarmProduct } from './isItemAFarmProduct' + +export const farmProductsSold = memoize( + /** + * @param {Record} itemsSold + * @returns {number} + */ + itemsSold => + Object.entries(itemsSold).reduce( + (sum, [itemId, numberSold]) => + sum + (isItemAFarmProduct(itemsMap[itemId]) ? numberSold : 0), + 0 + ) +) diff --git a/src/utils/index.js b/src/utils/index.js index 5b2a44370..4f159023b 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -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], @@ -289,24 +290,6 @@ export const getPlotContentType = ({ itemId }) => export const doesPlotContainCrop = plot => plot !== null && getPlotContentType(plot) === itemType.CROP -/** - * @param {farmhand.item} item - * @returns {boolean} - */ -export const isItemAGrownCrop = item => - Boolean(item.type === itemType.CROP && !item.growsInto) - -/** - * @param {farmhand.item} item - * @returns {boolean} - */ -export const isItemAFarmProduct = item => - Boolean( - isItemAGrownCrop(item) || - item.type === itemType.MILK || - item.type === itemType.CRAFTED_ITEM - ) - export const getLifeStageRange = memoize(( /** @type {farmhand.cropTimetable} */ cropTimetable ) => @@ -791,26 +774,6 @@ export const findCowById = memoize( (cowInventory, id) => cowInventory.find(cow => id === cow.id) ) -export const farmProductsSold = memoize( - /** - * @param {Record} itemsSold - * @returns {number} - */ - itemsSold => - Object.entries(itemsSold).reduce( - (sum, [itemId, numberSold]) => - sum + (isItemAFarmProduct(itemsMap[itemId]) ? numberSold : 0), - 0 - ) -) - -/** - * @param {number} farmProductsSold - * @returns {number} - */ -export const levelAchieved = farmProductsSold => - Math.floor(Math.sqrt(farmProductsSold) / 10) + 1 - /** * @param {number} targetLevel * @returns {number} @@ -986,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 } @@ -1200,5 +1167,3 @@ export const isOctober = () => new Date().getMonth() === 9 * @returns {boolean} */ export const isDecember = () => new Date().getMonth() === 11 - -export { default as totalIngredientsInRecipe } from './totalIngredientsInRecipe' diff --git a/src/utils/index.test.js b/src/utils/index.test.js index 6a75a6d2b..8342ac221 100644 --- a/src/utils/index.test.js +++ b/src/utils/index.test.js @@ -25,6 +25,10 @@ import { MALE_COW_WEIGHT_MULTIPLIER, } from '../constants' +import { levelAchieved } from './levelAchieved' +import { farmProductsSold } from './farmProductsSold' +import { isItemAFarmProduct } from './isItemAFarmProduct' + import { canMakeRecipe, castToMoney, @@ -32,7 +36,6 @@ import { chooseRandom, dollarString, farmProductSalesVolumeNeededForLevel, - farmProductsSold, generateCow, generateOffspringCow, get7DayAverage, @@ -53,12 +56,11 @@ import { getRangeCoords, getSalePriceMultiplier, integerString, - isItemAFarmProduct, - levelAchieved, maxYieldOfRecipe, moneyTotal, percentageString, randomChoice, + transformStateDataForImport, } from './index' jest.mock('../data/maps') @@ -768,12 +770,41 @@ describe('farmProductsSold', () => { }) describe('levelAchieved', () => { - test('calculates achieved level', () => { - expect(levelAchieved(0)).toEqual(1) - expect(levelAchieved(100)).toEqual(2) - expect(levelAchieved(150)).toEqual(2) - expect(levelAchieved(400)).toEqual(3) - expect(levelAchieved(980100)).toEqual(100) + const cases = [ + [1, 0], + [2, 100], + [2, 150], + [3, 400], + [100, 980100], + ] + + describe('with legacy system', () => { + test.each(cases)( + `returns level %p for %p items sold`, + (expectedLevel, numItemsSold) => { + const level = levelAchieved({ + itemsSold: { carrot: numItemsSold }, + useLegacyLevelingSystem: true, + }) + + expect(level).toEqual(expectedLevel) + } + ) + }) + + describe('with experience system', () => { + test.each(cases)( + `returns level %p for %p experience`, + (expectedLevel, experience) => { + const level = levelAchieved({ + experience, + features: { EXPERIENCE: true }, + useLegacyLevelingSystem: false, + }) + + expect(level).toEqual(expectedLevel) + } + ) }) }) @@ -1016,3 +1047,52 @@ describe('getCowImage', () => { expect(image).toEqual(animals.cow.rainbow) }) }) + +describe('transformStateDataForImport', () => { + 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, + }) + }) +}) diff --git a/src/utils/isItemAFarmProduct.js b/src/utils/isItemAFarmProduct.js new file mode 100644 index 000000000..108d8bd87 --- /dev/null +++ b/src/utils/isItemAFarmProduct.js @@ -0,0 +1,12 @@ +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) || FARM_PRODUCT_TYPES.includes(item.type)) diff --git a/src/utils/isItemAGrownCrop.js b/src/utils/isItemAGrownCrop.js new file mode 100644 index 000000000..990f8144c --- /dev/null +++ b/src/utils/isItemAGrownCrop.js @@ -0,0 +1,8 @@ +import { itemType } from '../enums' + +/** + * @param {farmhand.item} item + * @returns {boolean} + */ +export const isItemAGrownCrop = item => + Boolean(item.type === itemType.CROP && !item.growsInto) diff --git a/src/utils/levelAchieved.js b/src/utils/levelAchieved.js new file mode 100644 index 000000000..548d93fb0 --- /dev/null +++ b/src/utils/levelAchieved.js @@ -0,0 +1,23 @@ +import { farmProductsSold } from './farmProductsSold' + +/** + * @param {{ + * itemsSold: Record, + * experience?: number, + * features?: { EXPERIENCE?: boolean }, + * useLegacyLevelingSystem?: boolean, + * }} props + * @returns {number} + */ +export function levelAchieved({ + itemsSold, + experience = 0, + features = {}, + useLegacyLevelingSystem = true, +}) { + if (features.EXPERIENCE && !useLegacyLevelingSystem) { + return Math.floor(Math.sqrt(experience) / 10) + 1 + } + + return Math.floor(Math.sqrt(farmProductsSold(itemsSold)) / 10) + 1 +} diff --git a/src/utils/totalIngredientsInRecipe.js b/src/utils/totalIngredientsInRecipe.js index 068a1c8a3..dd8a7c35f 100644 --- a/src/utils/totalIngredientsInRecipe.js +++ b/src/utils/totalIngredientsInRecipe.js @@ -1,4 +1,4 @@ -export default function totalIngredientsInRecipe(recipe, amount = 1) { +export function totalIngredientsInRecipe(recipe, amount = 1) { return ( amount * Object.values(recipe.ingredients).reduce( diff --git a/src/utils/totalIngredientsInRecipe.test.js b/src/utils/totalIngredientsInRecipe.test.js index b4d1d7931..6d1050168 100644 --- a/src/utils/totalIngredientsInRecipe.test.js +++ b/src/utils/totalIngredientsInRecipe.test.js @@ -1,4 +1,4 @@ -import totalIngredientsInRecipe from './totalIngredientsInRecipe' +import { totalIngredientsInRecipe } from './totalIngredientsInRecipe' describe('totalIngredientsInRecipe', () => { test('it can total a single ingredient upgrade', () => { From 23cf9c6ec8e251e3fcf5ecc9e50605b81ed28ad5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:30:56 -0500 Subject: [PATCH 3/6] chore(deps-dev): bump word-wrap from 1.2.3 to 1.2.4 (#425) Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4. - [Release notes](https://github.com/jonschlinkert/word-wrap/releases) - [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4) --- updated-dependencies: - dependency-name: word-wrap dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 09ea170d0..b9ecdf740 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33001,9 +33001,10 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -55894,7 +55895,9 @@ } }, "word-wrap": { - "version": "1.2.3", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true }, "workbox-background-sync": { From ee29696fd50af8c0004767a2756182d6e7c8ec84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:32:16 -0500 Subject: [PATCH 4/6] chore(deps-dev): bump electron from 22.1.0 to 22.3.21 (#450) Bumps [electron](https://github.com/electron/electron) from 22.1.0 to 22.3.21. - [Release notes](https://github.com/electron/electron/releases) - [Changelog](https://github.com/electron/electron/blob/main/docs/breaking-changes.md) - [Commits](https://github.com/electron/electron/compare/v22.1.0...v22.3.21) --- updated-dependencies: - dependency-name: electron dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9ecdf740..e8101d7c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11954,9 +11954,9 @@ } }, "node_modules/electron": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-22.1.0.tgz", - "integrity": "sha512-wz5s4N6V7zyKm4YQmXJImFoxO1Doai32ShYm0FzOLPBMwLMdQBV+REY+j1opRx0KJ9xJEIdjYgcA8OSw6vx3pA==", + "version": "22.3.21", + "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.21.tgz", + "integrity": "sha512-9JzWgvehRrqA30M7RvWCwwbyq2EgPUSbCFaqyZGnG0B52m4ayB8H+uFNIKXyWuyFwAEPDpQW5cGwCzXir1HuLA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -41552,9 +41552,9 @@ } }, "electron": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-22.1.0.tgz", - "integrity": "sha512-wz5s4N6V7zyKm4YQmXJImFoxO1Doai32ShYm0FzOLPBMwLMdQBV+REY+j1opRx0KJ9xJEIdjYgcA8OSw6vx3pA==", + "version": "22.3.21", + "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.21.tgz", + "integrity": "sha512-9JzWgvehRrqA30M7RvWCwwbyq2EgPUSbCFaqyZGnG0B52m4ayB8H+uFNIKXyWuyFwAEPDpQW5cGwCzXir1HuLA==", "dev": true, "requires": { "@electron/get": "^2.0.0", From dd619eeadb05705f9b749742c6635490feec59cf Mon Sep 17 00:00:00 2001 From: Luke Stebner Date: Fri, 8 Sep 2023 09:29:27 -0700 Subject: [PATCH 5/6] feat: enable experience system (#449) * move portion of navigation to DayAndProgressContainer to make it easier to work with * update DayAndProgressContainer to be able to handle experience leveling system * add constants for EXPERIENCE_VALUES * add achievement for paying off loan * go all in with experience based leveling system - remove EXPERIENCE feature flag - remove farmProductSalesNeededForLevel util and update any references to use experienceNeededForLevel - simplify levelAchieved arguments to only reference experience and update all calls to use experience value - remove everything related to 'legacy leveling system' * add processLevelUp to addExperience * change arg from object to just experience * add experience when selling a keg * fix(online): support peers that haven't upgraded experience system * fix(online): show accurate peer level --------- Co-authored-by: Jeremy Kahn Co-authored-by: Jeremy Kahn --- .env.development.local | 1 - src/components/Farmhand/Farmhand.js | 21 +++--- src/components/Field/Field.js | 14 ++-- src/components/Field/Field.test.js | 20 ++--- .../Navigation/DayAndProgressContainer.js | 74 +++++++++++++++++++ src/components/Navigation/Navigation.js | 49 +----------- .../OnlinePeersView/OnlinePeer/OnlinePeer.js | 7 +- .../OnlinePeer/OnlinePeer.test.js | 2 +- .../OnlinePeersView/OnlinePeersView.js | 2 +- src/components/SettingsView/SettingsView.js | 20 +---- src/components/StatsView/StatsView.js | 10 +-- src/constants.js | 24 +++++- src/data/achievements.js | 16 +++- src/data/achievements.test.js | 21 ++++++ src/game-logic/reducers/addExperience.js | 15 +++- src/game-logic/reducers/addExperience.test.js | 25 ++++++- .../reducers/generatePriceEvents.js | 2 +- src/game-logic/reducers/index.js | 1 + src/game-logic/reducers/processLevelUp.js | 8 +- .../reducers/processLevelUp.test.js | 10 +-- src/game-logic/reducers/processSprinklers.js | 4 +- src/game-logic/reducers/sellItem.js | 7 +- src/game-logic/reducers/sellKeg.js | 11 +-- src/handlers/ui-events.js | 7 -- src/index.js | 2 +- src/utils/index.js | 2 +- src/utils/index.test.js | 50 ++++--------- src/utils/levelAchieved.js | 18 +---- 28 files changed, 249 insertions(+), 194 deletions(-) create mode 100644 src/components/Navigation/DayAndProgressContainer.js diff --git a/.env.development.local b/.env.development.local index 18006bc20..09062c3e0 100644 --- a/.env.development.local +++ b/.env.development.local @@ -1,3 +1,2 @@ REACT_APP_API_ROOT=http://localhost:3001/ REACT_APP_ENABLE_KEGS=true -REACT_APP_ENABLE_EXPERIENCE=true diff --git a/src/components/Farmhand/Farmhand.js b/src/components/Farmhand/Farmhand.js index c32cc48cb..267e99a37 100644 --- a/src/components/Farmhand/Farmhand.js +++ b/src/components/Farmhand/Farmhand.js @@ -207,14 +207,15 @@ const applyPriceEvents = (valueAdjustments, priceCrashes, priceSurges) => { * totals of crops harvested. Keys are crop type IDs, values are the number of * that crop harvested. * @property {number} dayCount + * @property {number} experience * @property {string} farmName - * @property {boolean} hasBooted * @property {(?farmhand.plotContent)[][]} field * @property {farmhand.fieldMode} fieldMode * @property {Function?} getCowAccept https://github.com/dmotz/trystero#receiver * @property {Function?} getCowReject https://github.com/dmotz/trystero#receiver * @property {Function?} getCowTradeRequest https://github.com/dmotz/trystero#receiver * @property {Function?} getPeerMetadata https://github.com/dmotz/trystero#receiver + * @property {boolean} hasBooted * @property {number?} heartbeatTimeoutId * @property {Array.} historicalDailyLosses * @property {Array.} historicalDailyRevenue @@ -379,9 +380,7 @@ export default class Farmhand extends FarmhandReducers { } get levelEntitlements() { - return getLevelEntitlements( - levelAchieved({ itemsSold: this.state.itemsSold }) - ) + return getLevelEntitlements(levelAchieved(this.state.experience)) } get shopInventory() { @@ -497,12 +496,19 @@ export default class Farmhand extends FarmhandReducers { [toolType.WATERING_CAN]: toolLevel.DEFAULT, }, useAlternateEndDayButtonPosition: false, - useLegacyLevelingSystem: true, valueAdjustments: {}, version: process.env.REACT_APP_VERSION ?? '', } } + async initializeNewGame() { + await this.incrementDay(true) + this.setState(() => ({ + historicalValueAdjustments: [], + })) + this.showNotification(LOAN_INCREASED`${STANDARD_LOAN_AMOUNT}`, 'info') + } + initInputHandlers() { const debouncedInputRate = 50 @@ -602,10 +608,7 @@ export default class Farmhand extends FarmhandReducers { }) }) } else { - // Initialize new game - await this.incrementDay(true) - this.setState(() => ({ historicalValueAdjustments: [] })) - this.showNotification(LOAN_INCREASED`${STANDARD_LOAN_AMOUNT}`, 'info') + await this.initializeNewGame() } this.syncToRoom().catch(errorCode => this.handleRoomSyncError(errorCode)) diff --git a/src/components/Field/Field.js b/src/components/Field/Field.js index 24f779d5e..8d8c1bc3a 100644 --- a/src/components/Field/Field.js +++ b/src/components/Field/Field.js @@ -52,10 +52,10 @@ if (tools.shovel) { } export const isInHoverRange = ({ + experience, fieldMode, hoveredPlotRangeSize, hoveredPlot: { x: hoveredPlotX, y: hoveredPlotY }, - itemsSold, x, y, }) => { @@ -70,7 +70,7 @@ export const isInHoverRange = ({ switch (fieldMode) { case SET_SPRINKLER: hoveredPlotRangeSizeToRender = getLevelEntitlements( - levelAchieved({ itemsSold }) + levelAchieved(experience) ).sprinklerRange break @@ -127,10 +127,10 @@ export const MemoPlot = memo( ) MemoPlot.propTypes = { + experience: number.isRequired, fieldMode: string.isRequired, hoveredPlot: object.isRequired, hoveredPlotRangeSize: number.isRequired, - itemsSold: object.isRequired, plotContent: object, setHoveredPlot: func.isRequired, x: number.isRequired, @@ -210,13 +210,13 @@ FieldContentWrapper.propTypes = { export const FieldContent = ({ columns, + experience, field, fieldMode, handleCombineEnabledChange, hoveredPlot, hoveredPlotRangeSize, isCombineEnabled, - itemsSold, purchasedCombine, rows, setHoveredPlot, @@ -235,10 +235,10 @@ export const FieldContent = ({ { Field.propTypes = { columns: number.isRequired, + experience: number.isRequired, field: array.isRequired, fieldMode: string.isRequired, handleCombineEnabledChange: func.isRequired, @@ -429,7 +430,6 @@ Field.propTypes = { inventory: array.isRequired, inventoryLimit: number.isRequired, isCombineEnabled: bool.isRequired, - itemsSold: object.isRequired, purchasedCombine: number.isRequired, purchasedField: number.isRequired, rows: number.isRequired, diff --git a/src/components/Field/Field.test.js b/src/components/Field/Field.test.js index fdfd1ce8f..0297fd436 100644 --- a/src/components/Field/Field.test.js +++ b/src/components/Field/Field.test.js @@ -22,10 +22,10 @@ beforeEach(() => { { { hoveredPlotRangeSize: 0, fieldMode: fieldMode.OBSERVE, isCombineEnabled: false, - itemsSold: {}, purchasedCombine: 0, rows: 0, setHoveredPlot: noop, @@ -162,9 +162,9 @@ describe('isInHoverRange', () => { test('indicates when plot is not in hover range', () => { expect( isInHoverRange({ + experience: 0, hoveredPlotRangeSize: 2, hoveredPlot: { x: 1, y: 1 }, - itemsSold: {}, x: 4, y: 4, }) @@ -174,9 +174,9 @@ describe('isInHoverRange', () => { test('indicates when plot is in hover range', () => { expect( isInHoverRange({ + experience: 0, hoveredPlotRangeSize: 2, hoveredPlot: { x: 1, y: 1 }, - itemsSold: {}, x: 0, y: 0, }) @@ -187,10 +187,10 @@ describe('isInHoverRange', () => { test('indicates when plot is not in hover range', () => { expect( isInHoverRange({ + experience: 0, hoveredPlotRangeSize: 2, hoveredPlot: { x: 1, y: 1 }, fieldMode: fieldMode.OBSERVE, - itemsSold: {}, x: 4, y: 4, }) @@ -200,10 +200,10 @@ describe('isInHoverRange', () => { test('indicates when plot is in hover range', () => { expect( isInHoverRange({ + experience: 0, hoveredPlotRangeSize: 2, hoveredPlot: { x: 1, y: 1 }, fieldMode: fieldMode.OBSERVE, - itemsSold: {}, x: 0, y: 0, }) @@ -215,10 +215,10 @@ describe('isInHoverRange', () => { test('indicates when plot is not in hover range', () => { expect( isInHoverRange({ + experience: 0, hoveredPlotRangeSize: 2, hoveredPlot: { x: 1, y: 1 }, fieldMode: fieldMode.SET_SPRINKLER, - itemsSold: {}, x: 4, y: 4, }) @@ -228,10 +228,10 @@ describe('isInHoverRange', () => { test('indicates when plot is in hover range', () => { expect( isInHoverRange({ + experience: 0, hoveredPlotRangeSize: 2, hoveredPlot: { x: 1, y: 1 }, fieldMode: fieldMode.SET_SPRINKLER, - itemsSold: {}, x: 0, y: 0, }) @@ -243,10 +243,10 @@ describe('isInHoverRange', () => { test('indicates that all plots are in hover range', () => { expect( isInHoverRange({ + experience: 0, hoveredPlotRangeSize: 2, hoveredPlot: { x: 1, y: 1 }, fieldMode: fieldMode.SET_SCARECROW, - itemsSold: {}, x: 2, y: 2, }) @@ -254,10 +254,10 @@ describe('isInHoverRange', () => { expect( isInHoverRange({ + experience: 0, hoveredPlotRangeSize: 2, hoveredPlot: { x: 1, y: 1 }, fieldMode: fieldMode.SET_SCARECROW, - itemsSold: {}, x: 100, y: 100, }) diff --git a/src/components/Navigation/DayAndProgressContainer.js b/src/components/Navigation/DayAndProgressContainer.js new file mode 100644 index 000000000..bc4b2c3f7 --- /dev/null +++ b/src/components/Navigation/DayAndProgressContainer.js @@ -0,0 +1,74 @@ +import React from 'react' +import { number, object } from 'prop-types' + +import Box from '@material-ui/core/Box' +import CircularProgress from '@material-ui/core/CircularProgress' +import Tooltip from '@material-ui/core/Tooltip' + +import FarmhandContext from '../Farmhand/Farmhand.context' + +import { levelAchieved } from '../../utils/levelAchieved' +import { + experienceNeededForLevel, + integerString, + scaleNumber, +} from '../../utils' + +export function DayAndProgressContainer({ dayCount, experience, itemsSold }) { + const currentLevel = levelAchieved(experience) + + const levelPercent = scaleNumber( + experience, + experienceNeededForLevel(currentLevel), + experienceNeededForLevel(currentLevel + 1), + 0, + 100 + ) + + const tooltipText = `${integerString( + experienceNeededForLevel(currentLevel + 1) - experience + )} more experience points needed to reach level ${integerString( + currentLevel + 1 + )}` + + return ( +

+ Day {integerString(dayCount)}, level: + + + + + {integerString(currentLevel)} + + + +

+ ) +} + +DayAndProgressContainer.propTypes = { + dayCount: number.isRequired, + experience: number.isRequired, + itemsSold: object.isRequired, +} + +export default function Consumer(props) { + return ( + + {({ gameState, handlers }) => ( + + )} + + ) +} diff --git a/src/components/Navigation/Navigation.js b/src/components/Navigation/Navigation.js index 41fadf4ee..f5c06cb8e 100644 --- a/src/components/Navigation/Navigation.js +++ b/src/components/Navigation/Navigation.js @@ -5,9 +5,7 @@ import AccountBalanceIcon from '@material-ui/icons/AccountBalance' import AssessmentIcon from '@material-ui/icons/Assessment' import BeenhereIcon from '@material-ui/icons/Beenhere.js' import BookIcon from '@material-ui/icons/Book' -import Box from '@material-ui/core/Box' import Button from '@material-ui/core/Button' -import CircularProgress from '@material-ui/core/CircularProgress' import Dialog from '@material-ui/core/Dialog' import DialogActions from '@material-ui/core/DialogActions' import DialogContent from '@material-ui/core/DialogContent' @@ -24,17 +22,13 @@ import Switch from '@material-ui/core/Switch' import TextField from '@material-ui/core/TextField' import Tooltip from '@material-ui/core/Tooltip' import Typography from '@material-ui/core/Typography' -import { array, bool, func, number, object, string } from 'prop-types' +import { array, bool, func, number, string } from 'prop-types' import FarmhandContext from '../Farmhand/Farmhand.context' -import { farmProductsSold } from '../../utils/farmProductsSold' -import { levelAchieved } from '../../utils/levelAchieved' import { doesInventorySpaceRemain, - farmProductSalesVolumeNeededForLevel, integerString, inventorySpaceConsumed, - scaleNumber, } from '../../utils' import { dialogView } from '../../enums' import { INFINITE_STORAGE_LIMIT, STAGE_TITLE_MAP } from '../../constants' @@ -49,6 +43,8 @@ import SettingsView from '../SettingsView' import StatsView from '../StatsView' import KeybindingsView from '../KeybindingsView' +import DayAndProgressContainer from './DayAndProgressContainer' + import './Navigation.sass' const FarmNameDisplay = ({ farmName, handleFarmNameUpdate }) => { @@ -205,7 +201,6 @@ export const Navigation = ({ activePlayers, blockInput, currentDialogView, - dayCount, farmName, handleActivePlayerButtonClick, handleClickDialogViewButton, @@ -217,22 +212,12 @@ export const Navigation = ({ handleViewChange, inventory, inventoryLimit, - itemsSold, isDialogViewOpen, isOnline, room, stageFocus, viewList, - totalFarmProductsSold = farmProductsSold(itemsSold), - currentLevel = levelAchieved({ itemsSold }), - levelPercent = scaleNumber( - totalFarmProductsSold, - farmProductSalesVolumeNeededForLevel(currentLevel), - farmProductSalesVolumeNeededForLevel(currentLevel + 1), - 0, - 100 - ), currentDialogViewLowerCase = currentDialogView.toLowerCase(), modalTitleId = `${currentDialogViewLowerCase}-modal-title`, modalContentId = `${currentDialogViewLowerCase}-modal-content`, @@ -241,31 +226,7 @@ export const Navigation = ({

Farmhand

v{process.env.REACT_APP_VERSION}

-

- Day {integerString(dayCount)}, level: - - - - - {integerString(currentLevel)} - - - -

+ { return (
  • @@ -24,7 +24,8 @@ const OnlinePeer = ({ subheader: (

    Day: {integerString(dayCount)}

    -

    Level: {integerString(levelAchieved({ itemsSold }))}

    + {/* TODO: Remove `?? 0` after 10/24 */} +

    Level: {integerString(levelAchieved(experience ?? 0))}

    Money: {moneyString(money)}

    ), @@ -46,8 +47,8 @@ OnlinePeer.propTypes = { peer: shape({ cowOfferedForTrade: object, dayCount: number.isRequired, + experience: number.isRequired, id: string.isRequired, - itemsSold: object.isRequired, money: number.isRequired, }).isRequired, } diff --git a/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.test.js b/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.test.js index 00299483e..978ed5558 100644 --- a/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.test.js +++ b/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.test.js @@ -12,7 +12,7 @@ beforeEach(() => { peer: { dayCount: 0, id: '', - itemsSold: {}, + experience: 1, money: 0, }, }} diff --git a/src/components/OnlinePeersView/OnlinePeersView.js b/src/components/OnlinePeersView/OnlinePeersView.js index c31c655d2..7469a1c3f 100644 --- a/src/components/OnlinePeersView/OnlinePeersView.js +++ b/src/components/OnlinePeersView/OnlinePeersView.js @@ -59,7 +59,7 @@ const OnlinePeersView = ({ {sortBy(populatedPeers, [ peerId => // Use negative value to reverse sort order - -levelAchieved({ itemsSold: peers[peerId].itemsSold || 0 }), + -levelAchieved(peers[peerId].experience || 0), ]).map(peerId => ( diff --git a/src/components/SettingsView/SettingsView.js b/src/components/SettingsView/SettingsView.js index 88a252430..34af40d08 100644 --- a/src/components/SettingsView/SettingsView.js +++ b/src/components/SettingsView/SettingsView.js @@ -1,5 +1,5 @@ import React, { useState } from 'react' -import { bool, func, object } from 'prop-types' +import { bool, func } from 'prop-types' import Button from '@material-ui/core/Button' import Dialog from '@material-ui/core/Dialog' import DialogActions from '@material-ui/core/DialogActions' @@ -21,7 +21,6 @@ import './SettingsView.sass' const SettingsView = ({ allowCustomPeerCowNames, - features, handleAllowCustomPeerCowNamesChange, handleClearPersistedDataClick, handleExportDataClick, @@ -30,10 +29,8 @@ const SettingsView = ({ handleShowNotificationsChange, handleUseAlternateEndDayButtonPositionChange, handleShowHomeScreenChange, - handleUseLegacyLevelSystemChange, showNotifications, useAlternateEndDayButtonPosition, - useLegacyLevelingSystem, showHomeScreen, }) => { const [isClearDataDialogOpen, setIsClearDataDialogOpen] = useState(false) @@ -102,19 +99,6 @@ const SettingsView = ({ } label="Display custom names for cows received from other players" /> - {features.EXPERIENCE ? ( - - } - label="Use legacy leveling system (experience is only gained by selling items)" - /> - ) : null} @@ -215,7 +199,6 @@ const SettingsView = ({ SettingsView.propTypes = { allowCustomPeerCowNames: bool.isRequired, - features: object.isRequired, handleAllowCustomPeerCowNamesChange: func.isRequired, handleClearPersistedDataClick: func.isRequired, handleExportDataClick: func.isRequired, @@ -227,7 +210,6 @@ SettingsView.propTypes = { showHomeScreen: bool.isRequired, showNotifications: bool.isRequired, useAlternateEndDayButtonPosition: bool.isRequired, - useLegacyLevelingSystem: bool, } export default function Consumer(props) { diff --git a/src/components/StatsView/StatsView.js b/src/components/StatsView/StatsView.js index 49bd91b22..1e5c5a1eb 100644 --- a/src/components/StatsView/StatsView.js +++ b/src/components/StatsView/StatsView.js @@ -16,7 +16,7 @@ import { moneyString } from '../../utils/moneyString' import { farmProductsSold } from '../../utils/farmProductsSold' import { levelAchieved } from '../../utils/levelAchieved' import { - farmProductSalesVolumeNeededForLevel, + experienceNeededForLevel, get7DayAverage, getProfit, getProfitRecord, @@ -37,6 +37,7 @@ const ElevatedPaper = props => ( const StatsView = ({ cowsTraded, + experience, farmName, historicalDailyLosses, historicalDailyRevenue, @@ -51,7 +52,7 @@ const StatsView = ({ todaysRevenue, totalFarmProductsSold = farmProductsSold(itemsSold), - currentLevel = levelAchieved({ itemsSold }), + currentLevel = levelAchieved(experience), }) => (
    @@ -94,12 +95,11 @@ const StatsView = ({ > - Sales Needed for Next Level + Experience Points Needed for Next Level {integerString( - farmProductSalesVolumeNeededForLevel(currentLevel + 1) - - totalFarmProductsSold + experienceNeededForLevel(currentLevel + 1) - experience )} diff --git a/src/constants.js b/src/constants.js index 0c22b5379..68609c143 100644 --- a/src/constants.js +++ b/src/constants.js @@ -183,7 +183,6 @@ export const PERSISTED_STATE_KEYS = [ 'todaysStartingInventory', 'toolLevels', 'useAlternateEndDayButtonPosition', - 'useLegacyLevelingSystem', 'valueAdjustments', 'version', ] @@ -192,8 +191,8 @@ export const PEER_METADATA_STATE_KEYS = [ 'cowsSold', 'cropsHarvested', 'dayCount', + 'experience', 'id', - 'itemsSold', 'money', 'pendingPeerMessages', 'version', @@ -257,3 +256,24 @@ export const WEEDS_SPAWN_CHANCE = 0.15 export const KEG_INTEREST_RATE = 0.02 export const KEG_SPOILAGE_RATE_MULTIPLIER = 0.001 + +// NOTE: not all of these are implemented yet, these are for all the currently +// planned experience rewards +export const EXPERIENCE_VALUES = { + COMPOSTER_ACQUIRED: 10, + CELLAR_ACQUIRED: 10, + CELLAR_EXPANDED: 5, + COW_BRED: 1, + COW_PEN_ACQUIRED: 10, + COW_PEN_EXPANDED: 5, + COW_TRADED: 1, + FIELD_EXPANDED: 5, + ITEM_FORGED: 3, + ITEM_SOLD: 1, + KEG_SOLD: 2, + LOAN_PAID_OFF: 25, + NEW_YEAR: 5, + RAINBOW_COW_BRED: 2, + RECIPE_CRAFTED: 2, + SMELTER_ACQUIRED: 10, +} diff --git a/src/data/achievements.js b/src/data/achievements.js index 1e4eb45a0..ac2a78c10 100644 --- a/src/data/achievements.js +++ b/src/data/achievements.js @@ -11,8 +11,13 @@ import { } from '../utils' import { memoize } from '../utils/memoize' import { findInField } from '../utils/findInField' +import { addExperience } from '../game-logic/reducers' import { cropLifeStage, standardCowColors } from '../enums' -import { COW_FEED_ITEM_ID, I_AM_RICH_BONUSES } from '../constants' +import { + COW_FEED_ITEM_ID, + EXPERIENCE_VALUES, + I_AM_RICH_BONUSES, +} from '../constants' import { itemsMap } from './maps' @@ -68,6 +73,15 @@ const achievements = [ reward: state => addMoney(state, reward), }))(), + ((reward = EXPERIENCE_VALUES.LOAN_PAID_OFF) => ({ + id: 'financial-freedom', + name: 'Financial Freedom', + description: 'Pay off your initial loan from the bank.', + rewardDescription: `${reward} experience points`, + condition: state => state.loanBalance === 0, + reward: state => addExperience(state, reward), + }))(), + ((goal = 10000) => ({ id: 'unlock-crop-price-guide', name: 'Prove Yourself as a Farmer', diff --git a/src/data/achievements.test.js b/src/data/achievements.test.js index d383602c8..a9064d744 100644 --- a/src/data/achievements.test.js +++ b/src/data/achievements.test.js @@ -118,3 +118,24 @@ describe('gold-digger', () => { expect(ingot).toEqual({ id: 'gold-ingot', quantity: 1 }) }) }) + +describe('financial-freedom', () => { + const achievement = achievementsMap['financial-freedom'] + let state + + beforeEach(() => { + state = { + loanBalance: 100, + } + }) + + test('is not achievemed when loan balance is greater than 0', () => { + expect(achievement.condition(state)).toEqual(false) + }) + + test('is achievemented when the loan balance is at 0', () => { + state.loanBalance = 0 + + expect(achievement.condition(state)).toEqual(true) + }) +}) diff --git a/src/game-logic/reducers/addExperience.js b/src/game-logic/reducers/addExperience.js index 69c16709a..4a2ae853b 100644 --- a/src/game-logic/reducers/addExperience.js +++ b/src/game-logic/reducers/addExperience.js @@ -1,11 +1,22 @@ +import { levelAchieved } from '../../utils/levelAchieved' + +import { processLevelUp } from './processLevelUp' + /** * @param {farmhand.state} state * @param {number} amount * @returns {farmhand.state} */ export const addExperience = (state, amount) => { - return { + const { experience } = state + const oldLevel = levelAchieved(experience) + + let newState = { ...state, - experience: state.experience + amount, + experience: experience + amount, } + + newState = processLevelUp(newState, oldLevel) + + return newState } diff --git a/src/game-logic/reducers/addExperience.test.js b/src/game-logic/reducers/addExperience.test.js index 810bcd6a0..a948cd222 100644 --- a/src/game-logic/reducers/addExperience.test.js +++ b/src/game-logic/reducers/addExperience.test.js @@ -1,11 +1,30 @@ +import { experienceNeededForLevel } from '../../utils' + import { addExperience } from './addExperience' describe('addExperience', () => { + let gameState + + beforeEach(() => { + gameState = { + experience: 0, + inventory: [], + showNotifications: true, + todaysNotifications: [], + } + }) + it('adds experience to current experience', () => { - const gameState = { experience: 0, itemsSold: {} } + const newState = addExperience(gameState, 10) + + expect(newState.experience).toEqual(10) + }) - const newState = addExperience(gameState, 100) + it('process a level up when enough experience is achieved', () => { + const newState = addExperience(gameState, experienceNeededForLevel(2)) - expect(newState.experience).toEqual(100) + expect(newState.todaysNotifications[0].message).toEqual( + expect.stringContaining('You reached **level 2!**') + ) }) }) diff --git a/src/game-logic/reducers/generatePriceEvents.js b/src/game-logic/reducers/generatePriceEvents.js index fbe329a47..b3b40f803 100644 --- a/src/game-logic/reducers/generatePriceEvents.js +++ b/src/game-logic/reducers/generatePriceEvents.js @@ -28,7 +28,7 @@ export const generatePriceEvents = state => { // less-than check. if (random() < PRICE_EVENT_CHANCE) { const { items: unlockedItems } = getLevelEntitlements( - levelAchieved({ itemsSold: state.itemsSold }) + levelAchieved(state.experience) ) const cropItem = getRandomUnlockedCrop( diff --git a/src/game-logic/reducers/index.js b/src/game-logic/reducers/index.js index 7053daec3..ae38907ad 100644 --- a/src/game-logic/reducers/index.js +++ b/src/game-logic/reducers/index.js @@ -4,6 +4,7 @@ */ export * from './addCowToInventory' +export * from './addExperience' export * from './addItemToInventory' export * from './addPeer' export * from './addRevenue' diff --git a/src/game-logic/reducers/processLevelUp.js b/src/game-logic/reducers/processLevelUp.js index b88d4ccc3..7793bc57b 100644 --- a/src/game-logic/reducers/processLevelUp.js +++ b/src/game-logic/reducers/processLevelUp.js @@ -18,8 +18,8 @@ import { showNotification } from './showNotification' * @returns {farmhand.state} */ export const processLevelUp = (state, oldLevel) => { - const { itemsSold, selectedItemId } = state - const newLevel = levelAchieved({ itemsSold }) + const { experience, selectedItemId } = state + const newLevel = levelAchieved(experience) // Loop backwards so that the notifications appear in descending order. for (let i = newLevel; i > oldLevel; i--) { @@ -46,9 +46,7 @@ export const processLevelUp = (state, oldLevel) => { levelObject.increasesSprinklerRange && selectedItemId === SPRINKLER_ITEM_ID ) { - const { sprinklerRange } = getLevelEntitlements( - levelAchieved({ itemsSold }) - ) + const { sprinklerRange } = getLevelEntitlements(levelAchieved(experience)) if (sprinklerRange > state.hoveredPlotRangeSize) { state = { diff --git a/src/game-logic/reducers/processLevelUp.test.js b/src/game-logic/reducers/processLevelUp.test.js index 012267e55..a61dd65d1 100644 --- a/src/game-logic/reducers/processLevelUp.test.js +++ b/src/game-logic/reducers/processLevelUp.test.js @@ -1,6 +1,6 @@ import { LEVEL_GAINED_NOTIFICATION } from '../../templates' import { toolLevel } from '../../enums' -import { farmProductSalesVolumeNeededForLevel } from '../../utils' +import { experienceNeededForLevel } from '../../utils' jest.mock('../../data/achievements') jest.mock('../../data/maps') @@ -20,10 +20,8 @@ describe('processLevelUp', () => { })) const { todaysNotifications } = jest.requireActual('./').processLevelUp( { + experience: experienceNeededForLevel(3), inventory: [], - itemsSold: { - 'sample-crop-1': farmProductSalesVolumeNeededForLevel(3), - }, todaysNotifications: [], }, 1 @@ -65,10 +63,8 @@ describe('processLevelUp', () => { const { hoveredPlotRangeSize } = jest.requireActual('./').processLevelUp( { + experience: experienceNeededForLevel(2), hoveredPlotRangeSize: 1, - itemsSold: { - 'sample-crop-1': farmProductSalesVolumeNeededForLevel(2), - }, selectedItemId: 'sprinkler', todaysNotifications: [], }, diff --git a/src/game-logic/reducers/processSprinklers.js b/src/game-logic/reducers/processSprinklers.js index 35a50efb5..db4522b47 100644 --- a/src/game-logic/reducers/processSprinklers.js +++ b/src/game-logic/reducers/processSprinklers.js @@ -11,11 +11,11 @@ import { modifyFieldPlotAt } from './modifyFieldPlotAt' * @returns {farmhand.state} */ export const processSprinklers = state => { - const { field, itemsSold } = state + const { field, experience } = state const crops = new Map() let modifiedField = [...field] - const { sprinklerRange } = getLevelEntitlements(levelAchieved({ itemsSold })) + const { sprinklerRange } = getLevelEntitlements(levelAchieved(experience)) field.forEach((row, plotY) => { row.forEach((plot, plotX) => { diff --git a/src/game-logic/reducers/sellItem.js b/src/game-logic/reducers/sellItem.js index a293fa9f1..6067f1c97 100644 --- a/src/game-logic/reducers/sellItem.js +++ b/src/game-logic/reducers/sellItem.js @@ -9,7 +9,7 @@ import { isItemSoldInShop, moneyTotal, } from '../../utils' -import { LOAN_GARNISHMENT_RATE } from '../../constants' +import { LOAN_GARNISHMENT_RATE, EXPERIENCE_VALUES } from '../../constants' import { SOLD_ITEM_PEER_NOTIFICATION } from '../../templates' import { decrementItemFromInventory } from './decrementItemFromInventory' @@ -35,11 +35,12 @@ export const sellItem = (state, { id }, howMany = 1) => { const item = itemsMap[id] const { completedAchievements, + experience, itemsSold, money: initialMoney, valueAdjustments, } = state - const oldLevel = levelAchieved({ itemsSold }) + const oldLevel = levelAchieved(experience) let { loanBalance } = state const adjustedItemValue = isItemSoldInShop(item) @@ -61,7 +62,7 @@ export const sellItem = (state, { id }, howMany = 1) => { if (isItemAFarmProduct(item)) { salePriceMultiplier = getSalePriceMultiplier(completedAchievements) - experienceGained += 1 + experienceGained += EXPERIENCE_VALUES.ITEM_SOLD } const garnishedProfit = diff --git a/src/game-logic/reducers/sellKeg.js b/src/game-logic/reducers/sellKeg.js index da4cd93c5..60a4450b3 100644 --- a/src/game-logic/reducers/sellKeg.js +++ b/src/game-logic/reducers/sellKeg.js @@ -5,17 +5,16 @@ */ import { itemsMap } from '../../data/maps' -import { levelAchieved } from '../../utils/levelAchieved' import { castToMoney, getSalePriceMultiplier, moneyTotal } from '../../utils' -import { LOAN_GARNISHMENT_RATE } from '../../constants' +import { EXPERIENCE_VALUES, LOAN_GARNISHMENT_RATE } from '../../constants' import { SOLD_FERMENTED_ITEM_PEER_NOTIFICATION } from '../../templates' import { getKegValue } from '../../utils/getKegValue' -import { processLevelUp } from './processLevelUp' +import { addExperience } from './addExperience' import { addRevenue } from './addRevenue' -import { updateLearnedRecipes } from './updateLearnedRecipes' import { adjustLoan } from './adjustLoan' import { removeKegFromCellar } from './removeKegFromCellar' +import { updateLearnedRecipes } from './updateLearnedRecipes' import { prependPendingPeerMessage } from './index' @@ -33,7 +32,6 @@ export const sellKeg = (state, keg) => { itemsSold, money: initialMoney, } = state - const oldLevel = levelAchieved({ itemsSold }) let { loanBalance } = state let saleValue = 0 @@ -74,8 +72,7 @@ export const sellKeg = (state, keg) => { // money needs to be passed in explicitly here because state.money gets // mutated above and addRevenue needs its initial value. state = addRevenue({ ...state, money: initialMoney }, saleValue) - - state = processLevelUp(state, oldLevel) + state = addExperience(state, EXPERIENCE_VALUES.KEG_SOLD) state = removeKegFromCellar(state, keg.id) // NOTE: This notification will need to be revisited to support Wine sales. diff --git a/src/handlers/ui-events.js b/src/handlers/ui-events.js index 347f4a984..279692718 100644 --- a/src/handlers/ui-events.js +++ b/src/handlers/ui-events.js @@ -531,11 +531,4 @@ export default { const newUrl = `${origin}${pathname}${newSearch}${hash}` window.history.replaceState({}, '', newUrl) }, - - /** - * @param {React.SyntheticEvent} e - */ - handleUseLegacyLevelSystemChange(e) { - this.setState({ useLegacyLevelingSystem: e.target.checked }) - }, } diff --git a/src/index.js b/src/index.js index ad2a41788..80a5461f9 100644 --- a/src/index.js +++ b/src/index.js @@ -206,7 +206,7 @@ /** * @typedef farmhand.peerMetadata - * @type {Pick & { cowOfferedForTrade?: farmhand.offeredCow }} + * @type {Pick & { cowOfferedForTrade?: farmhand.offeredCow }} */ /** diff --git a/src/utils/index.js b/src/utils/index.js index 4f159023b..5747ec3d4 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -778,7 +778,7 @@ export const findCowById = memoize( * @param {number} targetLevel * @returns {number} */ -export const farmProductSalesVolumeNeededForLevel = targetLevel => +export const experienceNeededForLevel = targetLevel => ((targetLevel - 1) * 10) ** 2 /** diff --git a/src/utils/index.test.js b/src/utils/index.test.js index 8342ac221..aabac0929 100644 --- a/src/utils/index.test.js +++ b/src/utils/index.test.js @@ -35,7 +35,7 @@ import { computeMarketPositions, chooseRandom, dollarString, - farmProductSalesVolumeNeededForLevel, + experienceNeededForLevel, generateCow, generateOffspringCow, get7DayAverage, @@ -778,42 +778,22 @@ describe('levelAchieved', () => { [100, 980100], ] - describe('with legacy system', () => { - test.each(cases)( - `returns level %p for %p items sold`, - (expectedLevel, numItemsSold) => { - const level = levelAchieved({ - itemsSold: { carrot: numItemsSold }, - useLegacyLevelingSystem: true, - }) - - expect(level).toEqual(expectedLevel) - } - ) - }) - - describe('with experience system', () => { - test.each(cases)( - `returns level %p for %p experience`, - (expectedLevel, experience) => { - const level = levelAchieved({ - experience, - features: { EXPERIENCE: true }, - useLegacyLevelingSystem: false, - }) - - expect(level).toEqual(expectedLevel) - } - ) - }) + test.each(cases)( + `returns level %p for %p experience`, + (expectedLevel, experience) => { + expect(levelAchieved(experience)).toEqual(expectedLevel) + } + ) }) -describe('farmProductSalesVolumeNeededForLevel', () => { - test('calculates farm sales volume that will meet level requirements', () => { - expect(farmProductSalesVolumeNeededForLevel(1)).toEqual(0) - expect(farmProductSalesVolumeNeededForLevel(2)).toEqual(100) - expect(farmProductSalesVolumeNeededForLevel(3)).toEqual(400) - expect(farmProductSalesVolumeNeededForLevel(100)).toEqual(980100) +describe('experienceNeededForLevel', () => { + test.each([ + [0, 1], + [100, 2], + [400, 3], + [980100, 100], + ])('it returns %s experience for level %s', (experienceNeeded, levelNum) => { + expect(experienceNeededForLevel(levelNum)).toEqual(experienceNeeded) }) }) diff --git a/src/utils/levelAchieved.js b/src/utils/levelAchieved.js index 548d93fb0..81fc1d10f 100644 --- a/src/utils/levelAchieved.js +++ b/src/utils/levelAchieved.js @@ -1,23 +1,9 @@ -import { farmProductsSold } from './farmProductsSold' - /** * @param {{ - * itemsSold: Record, * experience?: number, - * features?: { EXPERIENCE?: boolean }, - * useLegacyLevelingSystem?: boolean, * }} props * @returns {number} */ -export function levelAchieved({ - itemsSold, - experience = 0, - features = {}, - useLegacyLevelingSystem = true, -}) { - if (features.EXPERIENCE && !useLegacyLevelingSystem) { - return Math.floor(Math.sqrt(experience) / 10) + 1 - } - - return Math.floor(Math.sqrt(farmProductsSold(itemsSold)) / 10) + 1 +export function levelAchieved(experience = 0) { + return Math.floor(Math.sqrt(experience) / 10) + 1 } From 51ab78f5ddb3f575cc6bf1f12c5e927d0932ceed Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 8 Sep 2023 16:39:57 +0000 Subject: [PATCH 6/6] 1.18.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8101d7c3..0b4c88012 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@jeremyckahn/farmhand", - "version": "1.17.6", + "version": "1.18.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@jeremyckahn/farmhand", - "version": "1.17.6", + "version": "1.18.0", "license": "GPL-2.0-or-later", "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.27", diff --git a/package.json b/package.json index cd65dd4da..3945b804f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@jeremyckahn/farmhand", - "version": "1.17.6", + "version": "1.18.0", "publishConfig": { "access": "public" },