diff --git a/.dependency-cruiser.cjs b/.dependency-cruiser.cjs new file mode 100644 index 00000000000..25f7b64ce85 --- /dev/null +++ b/.dependency-cruiser.cjs @@ -0,0 +1,384 @@ +/** @type {import('dependency-cruiser').IConfiguration} */ +module.exports = { + forbidden: [ + { + name: 'no-circular-at-runtime', + severity: 'warn', + comment: + 'This dependency is part of a circular relationship. You might want to revise ' + + 'your solution (i.e. use dependency inversion, make sure the modules have a single responsibility) ', + from: {}, + to: { + circular: true, + viaOnly: { + dependencyTypesNot: [ + 'type-only' + ] + } + } + }, + { + name: 'no-orphans', + comment: + "This is an orphan module - it's likely not used (anymore?). Either use it or " + + "remove it. If it's logical this module is an orphan (i.e. it's a config file), " + + "add an exception for it in your dependency-cruiser configuration. By default " + + "this rule does not scrutinize dot-files (e.g. .eslintrc.js), TypeScript declaration " + + "files (.d.ts), tsconfig.json and some of the babel and webpack configs.", + severity: 'warn', + from: { + orphan: true, + pathNot: [ + '(^|/)[.][^/]+[.](?:js|cjs|mjs|ts|cts|mts|json)$', // dot files + '[.]d[.]ts$', // TypeScript declaration files + '(^|/)tsconfig[.]json$', // TypeScript config + '(^|/)(?:babel|webpack)[.]config[.](?:js|cjs|mjs|ts|cts|mts|json)$' // other configs + ] + }, + to: {}, + }, + { + name: 'no-deprecated-core', + comment: + 'A module depends on a node core module that has been deprecated. Find an alternative - these are ' + + "bound to exist - node doesn't deprecate lightly.", + severity: 'warn', + from: {}, + to: { + dependencyTypes: [ + 'core' + ], + path: [ + '^v8/tools/codemap$', + '^v8/tools/consarray$', + '^v8/tools/csvparser$', + '^v8/tools/logreader$', + '^v8/tools/profile_view$', + '^v8/tools/profile$', + '^v8/tools/SourceMap$', + '^v8/tools/splaytree$', + '^v8/tools/tickprocessor-driver$', + '^v8/tools/tickprocessor$', + '^node-inspect/lib/_inspect$', + '^node-inspect/lib/internal/inspect_client$', + '^node-inspect/lib/internal/inspect_repl$', + '^async_hooks$', + '^punycode$', + '^domain$', + '^constants$', + '^sys$', + '^_linklist$', + '^_stream_wrap$' + ], + } + }, + { + name: 'not-to-deprecated', + comment: + 'This module uses a (version of an) npm module that has been deprecated. Either upgrade to a later ' + + 'version of that module, or find an alternative. Deprecated modules are a security risk.', + severity: 'warn', + from: {}, + to: { + dependencyTypes: [ + 'deprecated' + ] + } + }, + { + name: 'no-non-package-json', + severity: 'error', + comment: + "This module depends on an npm package that isn't in the 'dependencies' section of your package.json. " + + "That's problematic as the package either (1) won't be available on live (2 - worse) will be " + + "available on live with an non-guaranteed version. Fix it by adding the package to the dependencies " + + "in your package.json.", + from: {}, + to: { + dependencyTypes: [ + 'npm-no-pkg', + 'npm-unknown' + ] + } + }, + { + name: 'not-to-unresolvable', + comment: + "This module depends on a module that cannot be found ('resolved to disk'). If it's an npm " + + 'module: add it to your package.json. In all other cases you likely already know what to do.', + severity: 'error', + from: {}, + to: { + couldNotResolve: true + } + }, + { + name: 'no-duplicate-dep-types', + comment: + "Likely this module depends on an external ('npm') package that occurs more than once " + + "in your package.json i.e. bot as a devDependencies and in dependencies. This will cause " + + "maintenance problems later on.", + severity: 'warn', + from: {}, + to: { + moreThanOneDependencyType: true, + // as it's pretty common to have a type import be a type only import + // _and_ (e.g.) a devDependency - don't consider type-only dependency + // types for this rule + dependencyTypesNot: ["type-only"] + } + }, + + /* rules you might want to tweak for your specific situation: */ + + { + name: 'not-to-spec', + comment: + 'This module depends on a spec (test) file. The sole responsibility of a spec file is to test code. ' + + "If there's something in a spec that's of use to other modules, it doesn't have that single " + + 'responsibility anymore. Factor it out into (e.g.) a separate utility/ helper or a mock.', + severity: 'error', + from: {}, + to: { + path: '[.](?:spec|test)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$' + } + }, + { + name: 'not-to-dev-dep', + severity: 'error', + comment: + "This module depends on an npm package from the 'devDependencies' section of your " + + 'package.json. It looks like something that ships to production, though. To prevent problems ' + + "with npm packages that aren't there on production declare it (only!) in the 'dependencies'" + + 'section of your package.json. If this module is development only - add it to the ' + + 'from.pathNot re of the not-to-dev-dep rule in the dependency-cruiser configuration', + from: { + path: '^(src)', + pathNot: [ + '[.](?:spec|test|setup|script)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$', + 'src/test' + ] + }, + to: { + dependencyTypes: [ + 'npm-dev', + ], + // type only dependencies are not a problem as they don't end up in the + // production code or are ignored by the runtime. + dependencyTypesNot: [ + 'type-only' + ], + pathNot: [ + 'node_modules/@types/' + ] + } + }, + { + name: 'optional-deps-used', + severity: 'info', + comment: + "This module depends on an npm package that is declared as an optional dependency " + + "in your package.json. As this makes sense in limited situations only, it's flagged here. " + + "If you're using an optional dependency here by design - add an exception to your" + + "dependency-cruiser configuration.", + from: {}, + to: { + dependencyTypes: [ + 'npm-optional' + ] + } + }, + { + name: 'peer-deps-used', + comment: + "This module depends on an npm package that is declared as a peer dependency " + + "in your package.json. This makes sense if your package is e.g. a plugin, but in " + + "other cases - maybe not so much. If the use of a peer dependency is intentional " + + "add an exception to your dependency-cruiser configuration.", + severity: 'warn', + from: {}, + to: { + dependencyTypes: [ + 'npm-peer' + ] + } + } + ], + options: { + + /* Which modules not to follow further when encountered */ + doNotFollow: { + /* path: an array of regular expressions in strings to match against */ + path: ['node_modules'] + }, + + /* Which modules to exclude */ + // exclude : { + // /* path: an array of regular expressions in strings to match against */ + // path: '', + // }, + + /* Which modules to exclusively include (array of regular expressions in strings) + dependency-cruiser will skip everything not matching this pattern + */ + // includeOnly : [''], + + /* List of module systems to cruise. + When left out dependency-cruiser will fall back to the list of _all_ + module systems it knows of. It's the default because it's the safe option + It might come at a performance penalty, though. + moduleSystems: ['amd', 'cjs', 'es6', 'tsd'] + + As in practice only commonjs ('cjs') and ecmascript modules ('es6') + are widely used, you can limit the moduleSystems to those. + */ + + // moduleSystems: ['cjs', 'es6'], + + /* prefix for links in html and svg output (e.g. 'https://github.com/you/yourrepo/blob/main/' + to open it on your online repo or `vscode://file/${process.cwd()}/` to + open it in visual studio code), + */ + // prefix: `vscode://file/${process.cwd()}/`, + + /* false (the default): ignore dependencies that only exist before typescript-to-javascript compilation + true: also detect dependencies that only exist before typescript-to-javascript compilation + "specify": for each dependency identify whether it only exists before compilation or also after + */ + // tsPreCompilationDeps: false, + + /* list of extensions to scan that aren't javascript or compile-to-javascript. + Empty by default. Only put extensions in here that you want to take into + account that are _not_ parsable. + */ + // extraExtensionsToScan: [".json", ".jpg", ".png", ".svg", ".webp"], + + /* if true combines the package.jsons found from the module up to the base + folder the cruise is initiated from. Useful for how (some) mono-repos + manage dependencies & dependency definitions. + */ + // combinedDependencies: false, + + /* if true leave symlinks untouched, otherwise use the realpath */ + // preserveSymlinks: false, + + /* TypeScript project file ('tsconfig.json') to use for + (1) compilation and + (2) resolution (e.g. with the paths property) + + The (optional) fileName attribute specifies which file to take (relative to + dependency-cruiser's current working directory). When not provided + defaults to './tsconfig.json'. + */ + tsConfig: { + fileName: 'tsconfig.json' + }, + + /* Webpack configuration to use to get resolve options from. + + The (optional) fileName attribute specifies which file to take (relative + to dependency-cruiser's current working directory. When not provided defaults + to './webpack.conf.js'. + + The (optional) `env` and `arguments` attributes contain the parameters + to be passed if your webpack config is a function and takes them (see + webpack documentation for details) + */ + // webpackConfig: { + // fileName: 'webpack.config.js', + // env: {}, + // arguments: {} + // }, + + /* Babel config ('.babelrc', '.babelrc.json', '.babelrc.json5', ...) to use + for compilation + */ + // babelConfig: { + // fileName: '.babelrc', + // }, + + /* List of strings you have in use in addition to cjs/ es6 requires + & imports to declare module dependencies. Use this e.g. if you've + re-declared require, use a require-wrapper or use window.require as + a hack. + */ + // exoticRequireStrings: [], + + /* options to pass on to enhanced-resolve, the package dependency-cruiser + uses to resolve module references to disk. The values below should be + suitable for most situations + + If you use webpack: you can also set these in webpack.conf.js. The set + there will override the ones specified here. + */ + enhancedResolveOptions: { + /* What to consider as an 'exports' field in package.jsons */ + exportsFields: ["exports"], + /* List of conditions to check for in the exports field. + Only works when the 'exportsFields' array is non-empty. + */ + conditionNames: ["import", "require", "node", "default", "types"], + /* + The extensions, by default are the same as the ones dependency-cruiser + can access (run `npx depcruise --info` to see which ones that are in + _your_ environment). If that list is larger than you need you can pass + the extensions you actually use (e.g. [".js", ".jsx"]). This can speed + up module resolution, which is the most expensive step. + */ + // extensions: [".js", ".jsx", ".ts", ".tsx", ".d.ts"], + /* What to consider a 'main' field in package.json */ + mainFields: ["module", "main", "types", "typings"], + /* + A list of alias fields in package.jsons + See [this specification](https://github.com/defunctzombie/package-browser-field-spec) and + the webpack [resolve.alias](https://webpack.js.org/configuration/resolve/#resolvealiasfields) + documentation + + Defaults to an empty array (= don't use alias fields). + */ + // aliasFields: ["browser"], + }, + reporterOptions: { + dot: { + /* pattern of modules that can be consolidated in the detailed + graphical dependency graph. The default pattern in this configuration + collapses everything in node_modules to one folder deep so you see + the external modules, but their innards. + */ + collapsePattern: 'node_modules/(?:@[^/]+/[^/]+|[^/]+)', + + /* Options to tweak the appearance of your graph.See + https://github.com/sverweij/dependency-cruiser/blob/main/doc/options-reference.md#reporteroptions + for details and some examples. If you don't specify a theme + dependency-cruiser falls back to a built-in one. + */ + // theme: { + // graph: { + // /* splines: "ortho" gives straight lines, but is slow on big graphs + // splines: "true" gives bezier curves (fast, not as nice as ortho) + // */ + // splines: "true" + // }, + // } + }, + archi: { + /* pattern of modules that can be consolidated in the high level + graphical dependency graph. If you use the high level graphical + dependency graph reporter (`archi`) you probably want to tweak + this collapsePattern to your situation. + */ + collapsePattern: '^(?:packages|src|lib(s?)|app(s?)|bin|test(s?)|spec(s?))/[^/]+|node_modules/(?:@[^/]+/[^/]+|[^/]+)', + + /* Options to tweak the appearance of your graph. If you don't specify a + theme for 'archi' dependency-cruiser will use the one specified in the + dot section above and otherwise use the default one. + */ + // theme: { }, + }, + "text": { + "highlightFocused": true + }, + } + } +}; +// generated: dependency-cruiser@16.3.3 on 2024-06-13T23:26:36.169Z diff --git a/.gitignore b/.gitignore index 669f8df003f..0ae49fe9e1c 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ coverage # Local Documentation /typedoc +/dependency-graph.svg \ No newline at end of file diff --git a/dependency-graph.js b/dependency-graph.js new file mode 100644 index 00000000000..627aa3dcf13 --- /dev/null +++ b/dependency-graph.js @@ -0,0 +1,13 @@ +import { Graphviz } from "@hpcc-js/wasm/graphviz"; + +const graphviz = await Graphviz.load(); + +const inputFile = []; +for await (const chunk of process.stdin) { + inputFile.push(chunk); +} + +const file = Buffer.concat(inputFile).toString("utf-8"); + +const svg = graphviz.dot(file, "svg"); +process.stdout.write(svg); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7f71787cb4d..45ce400ca2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,11 @@ "name": "pokemon-rogue-battle", "version": "1.0.4", "dependencies": { + "@hpcc-js/wasm": "^2.16.2", "@material/material-color-utilities": "^0.2.7", + "@types/jsdom": "^21.1.7", "crypto-js": "^4.2.0", + "dependency-cruiser": "^16.3.3", "i18next": "^23.11.1", "i18next-browser-languagedetector": "^7.2.1", "i18next-korean-postposition-processor": "^1.0.0", @@ -815,6 +818,17 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@hpcc-js/wasm": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-2.16.2.tgz", + "integrity": "sha512-THiidUMYR8/cIfFT3MVcWuRE7bQKh295nrFBxGvUNc4Nq8e2uU1LtiplHs7AUkJ0GxgvZoR+8TQ1/E3Qb/uE2g==", + "dependencies": { + "yargs": "17.7.2" + }, + "bin": { + "dot-wasm": "bin/dot-wasm.js" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -1177,6 +1191,16 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/jsdom": { + "version": "21.1.7", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", + "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1187,11 +1211,15 @@ "version": "20.12.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.13.tgz", "integrity": "sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==", - "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.10.0.tgz", @@ -1603,7 +1631,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -1615,16 +1642,30 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-jsx-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/acorn-jsx-walk/-/acorn-jsx-walk-2.0.0.tgz", + "integrity": "sha512-uuo6iJj4D4ygkdzd6jPtcxs8vZgDX9YFIkqczGImoypX2fQ4dVImmu3UzA4ynixCIMTrEOWW+95M2HuBaCEOVA==" + }, + "node_modules/acorn-loose": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/acorn-loose/-/acorn-loose-8.4.0.tgz", + "integrity": "sha512-M0EUka6rb+QC4l9Z3T0nJEzNOO7JcoJlYMrBlyBCiFSXRyxjLKayd4TbQs2FDRWQU1h9FR7QVNHt+PEaoNL5rQ==", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/acorn-walk": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -1661,7 +1702,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2022,6 +2062,19 @@ "node": ">=4" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -2071,6 +2124,14 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2364,6 +2425,155 @@ "node": ">= 0.8" } }, + "node_modules/dependency-cruiser": { + "version": "16.3.3", + "resolved": "https://registry.npmjs.org/dependency-cruiser/-/dependency-cruiser-16.3.3.tgz", + "integrity": "sha512-+YHPbd6RqM1nLUUbRVkbYO6mVeeq+VEL+bBkR+KFkYVU20vs1D0TalZ9z/hDLxiYiYCSTctUaoWWaUrRc1I+mw==", + "dependencies": { + "acorn": "8.11.3", + "acorn-jsx": "5.3.2", + "acorn-jsx-walk": "2.0.0", + "acorn-loose": "8.4.0", + "acorn-walk": "8.3.2", + "ajv": "8.16.0", + "chalk": "5.3.0", + "commander": "12.1.0", + "enhanced-resolve": "5.17.0", + "figures": "6.1.0", + "ignore": "5.3.1", + "indent-string": "5.0.0", + "interpret": "^3.1.1", + "is-installed-globally": "1.0.0", + "json5": "2.2.3", + "lodash": "4.17.21", + "memoize": "10.0.0", + "picomatch": "4.0.2", + "prompts": "2.4.2", + "rechoir": "^0.8.0", + "safe-regex": "2.1.1", + "semver": "^7.6.2", + "semver-try-require": "7.0.0", + "teamcity-service-messages": "0.1.14", + "tsconfig-paths-webpack-plugin": "4.1.0", + "watskeburt": "4.0.2", + "wrap-ansi": "9.0.0" + }, + "bin": { + "depcruise": "bin/dependency-cruise.mjs", + "depcruise-baseline": "bin/depcruise-baseline.mjs", + "depcruise-fmt": "bin/depcruise-fmt.mjs", + "depcruise-wrap-stream-in-html": "bin/wrap-stream-in-html.mjs", + "dependency-cruise": "bin/dependency-cruise.mjs", + "dependency-cruiser": "bin/dependency-cruise.mjs" + }, + "engines": { + "node": "^18.17||>=20" + } + }, + "node_modules/dependency-cruiser/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/dependency-cruiser/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/dependency-cruiser/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/dependency-cruiser/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/dependency-cruiser/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==" + }, + "node_modules/dependency-cruiser/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/dependency-cruiser/node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dependency-cruiser/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/dependency-cruiser/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -2419,6 +2629,11 @@ "integrity": "sha512-LRMMrM9ITOvue0PoBrvNIraVmuDbJV5QC9ierz/z5VilMdPOVMjOtpICNld3PuXuTZ3CHH/UPxX9gHhAPwi+0Q==", "dev": true }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -2428,11 +2643,22 @@ "node": ">= 0.8" } }, + "node_modules/enhanced-resolve": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, "engines": { "node": ">=0.12" }, @@ -2612,7 +2838,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, "engines": { "node": ">=6" } @@ -3027,8 +3252,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-defer": { "version": "1.1.8", @@ -3085,6 +3309,20 @@ "reusify": "^1.0.4" } }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3261,6 +3499,25 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", @@ -3349,6 +3606,20 @@ "node": ">=10.13.0" } }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -3411,6 +3682,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -3647,7 +3923,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, "engines": { "node": ">= 4" } @@ -3677,6 +3952,17 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inflation": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.1.0.tgz", @@ -3703,6 +3989,14 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -3717,6 +4011,14 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -3777,7 +4079,6 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, "dependencies": { "hasown": "^2.0.0" }, @@ -3824,6 +4125,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", @@ -3851,6 +4160,32 @@ "node": ">=0.10.0" } }, + "node_modules/is-installed-globally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.0.tgz", + "integrity": "sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==", + "dependencies": { + "global-directory": "^4.0.1", + "is-path-inside": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally/node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -3990,6 +4325,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unicode-supported": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", + "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -4261,7 +4607,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -4304,6 +4649,14 @@ "json-buffer": "3.0.1" } }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, "node_modules/koa": { "version": "2.15.3", "resolved": "https://registry.npmjs.org/koa/-/koa-2.15.3.tgz", @@ -4562,6 +4915,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4648,6 +5006,20 @@ "node": ">= 0.6" } }, + "node_modules/memoize": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/memoize/-/memoize-10.0.0.tgz", + "integrity": "sha512-H6cBLgsi6vMWOcCpvVCdFFnl3kerEXbrYh9q+lY6VXvQSmM6CkmV08VOwT+WE2tzIEqRPFfAq3fm4v/UIW6mSA==", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/memoize?sponsor=1" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -4718,6 +5090,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4734,7 +5117,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5071,7 +5453,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, "dependencies": { "entities": "^4.4.0" }, @@ -5118,8 +5499,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { "version": "6.2.2", @@ -5207,7 +5587,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, "engines": { "node": ">=12" }, @@ -5314,6 +5693,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -5330,7 +5721,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -5434,11 +5824,30 @@ "integrity": "sha512-wRiUsea88TjKDc4FBEn+sLvIDesp6brMbGWnJGjew2waAc9evdhja/2LvePc898HJbHw0L+MTWy7NhpnELAvLQ==", "dev": true }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -5457,6 +5866,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -5467,7 +5892,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -5597,6 +6021,14 @@ } ] }, + "node_modules/safe-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", + "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", + "dependencies": { + "regexp-tree": "~0.1.1" + } + }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", @@ -5633,13 +6065,9 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -5647,24 +6075,17 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, + "node_modules/semver-try-require": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver-try-require/-/semver-try-require-7.0.0.tgz", + "integrity": "sha512-LI7GzDuAZmNKOY0/LY4nB3ifh6kYMvBimFTHVpA6wNEl3gw59QrLbTAnJb7vQzPd1qXPz+BtKJZaYORXWMerrA==", "dependencies": { - "yallist": "^4.0.0" + "semver": "^7.6.0" }, "engines": { - "node": ">=10" + "node": "^18.17||>=20" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -5771,6 +6192,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -5810,6 +6236,19 @@ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", @@ -5863,7 +6302,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5875,7 +6313,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, "engines": { "node": ">=4" } @@ -5938,7 +6375,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -5952,6 +6388,19 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/teamcity-service-messages": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/teamcity-service-messages/-/teamcity-service-messages-0.1.14.tgz", + "integrity": "sha512-29aQwaHqm8RMX74u2o/h1KbMLP89FjNiMxD9wbF2BbWOnbM+q+d1sCEC+MqCc4QW3NJykn77OMpTFw/xTHIc0w==" + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -6090,6 +6539,96 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz", + "integrity": "sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA==", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tsconfig-paths": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tsconfig-paths/node_modules/json5": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", @@ -6338,8 +6877,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/universalify": { "version": "0.2.0", @@ -6393,7 +6931,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -7649,6 +8186,17 @@ "node": ">=18" } }, + "node_modules/watskeburt": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/watskeburt/-/watskeburt-4.0.2.tgz", + "integrity": "sha512-w7X8AGrBZExP5/3e3c1X/CUY8Yod/aiAazQCvrg7n8Un6piD+NFFK926G15zRq4+wu0XAEWpSsZ4C+fEfVOCYw==", + "bin": { + "watskeburt": "dist/run-cli.js" + }, + "engines": { + "node": "^18||>=20" + } + }, "node_modules/webfontloader": { "version": "1.6.28", "resolved": "https://registry.npmjs.org/webfontloader/-/webfontloader-1.6.28.tgz", @@ -7764,6 +8312,52 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -7806,12 +8400,45 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, "node_modules/ylru": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.4.0.tgz", diff --git a/package.json b/package.json index 7ee9010acda..29a956f19c6 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "test:silent": "vitest run --silent", "eslint": "eslint --fix .", "eslint-ci": "eslint .", - "docs": "typedoc" + "docs": "typedoc", + "depcruise": "depcruise src", + "depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg" }, "devDependencies": { "@eslint/js": "^9.3.0", @@ -41,8 +43,11 @@ "vitest-canvas-mock": "^0.3.3" }, "dependencies": { + "@hpcc-js/wasm": "^2.16.2", "@material/material-color-utilities": "^0.2.7", + "@types/jsdom": "^21.1.7", "crypto-js": "^4.2.0", + "dependency-cruiser": "^16.3.3", "i18next": "^23.11.1", "i18next-browser-languagedetector": "^7.2.1", "i18next-korean-postposition-processor": "^1.0.0", diff --git a/src/data/ability.ts b/src/data/ability.ts index 4c27e6c6859..3280f81dd6d 100755 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -3413,6 +3413,9 @@ export class SuppressFieldAbilitiesAbAttr extends AbAttr { export class AlwaysHitAbAttr extends AbAttr { } +/** Attribute for abilities that allow moves that make contact to ignore protection (i.e. Unseen Fist) */ +export class IgnoreProtectOnContactAbAttr extends AbAttr { } + export class UncopiableAbilityAbAttr extends AbAttr { constructor() { super(false); @@ -4672,7 +4675,7 @@ export function initAbilities() { new Ability(Abilities.QUICK_DRAW, 8) .unimplemented(), new Ability(Abilities.UNSEEN_FIST, 8) - .unimplemented(), + .attr(IgnoreProtectOnContactAbAttr), new Ability(Abilities.CURIOUS_MEDICINE, 8) .attr(PostSummonClearAllyStatsAbAttr), new Ability(Abilities.TRANSISTOR, 8) diff --git a/src/data/api.ts b/src/data/api-generator.script.ts similarity index 100% rename from src/data/api.ts rename to src/data/api-generator.script.ts diff --git a/src/data/battle-stat.ts b/src/data/battle-stat.ts index 46e5a7dac8b..86764f9973a 100644 --- a/src/data/battle-stat.ts +++ b/src/data/battle-stat.ts @@ -1,3 +1,5 @@ +import i18next from "i18next"; + export enum BattleStat { ATK, DEF, @@ -12,19 +14,19 @@ export enum BattleStat { export function getBattleStatName(stat: BattleStat) { switch (stat) { case BattleStat.ATK: - return "Attack"; + return i18next.t("pokemonInfo:Stat.ATK"); case BattleStat.DEF: - return "Defense"; + return i18next.t("pokemonInfo:Stat.DEF"); case BattleStat.SPATK: - return "Sp. Atk"; + return i18next.t("pokemonInfo:Stat.SPATK"); case BattleStat.SPDEF: - return "Sp. Def"; + return i18next.t("pokemonInfo:Stat.SPDEF"); case BattleStat.SPD: - return "Speed"; + return i18next.t("pokemonInfo:Stat.SPD"); case BattleStat.ACC: - return "Accuracy"; + return i18next.t("pokemonInfo:Stat.ACC"); case BattleStat.EVA: - return "Evasiveness"; + return i18next.t("pokemonInfo:Stat.EVA"); default: return "???"; } @@ -34,30 +36,30 @@ export function getBattleStatLevelChangeDescription(levels: integer, up: boolean if (up) { switch (levels) { case 1: - return "rose"; + return i18next.t("battle:statRose"); case 2: - return "sharply rose"; + return i18next.t("battle:statSharplyRose"); case 3: case 4: case 5: case 6: - return "rose drastically"; + return i18next.t("battle:statRoseDrastically"); default: - return "won't go any higher"; + return i18next.t("battle:statWontGoAnyHigher"); } } else { switch (levels) { case 1: - return "fell"; + return i18next.t("battle:statFell"); case 2: - return "harshly fell"; + return i18next.t("battle:statHarshlyFell"); case 3: case 4: case 5: case 6: - return "severely fell"; + return i18next.t("battle:statSeverelyFell"); default: - return "won't go any lower"; + return i18next.t("battle:statWontGoAnyLower"); } } } diff --git a/src/data/biomes.ts b/src/data/biomes.ts index 4de3e3f3a21..782826d8695 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -1,12 +1,12 @@ import { Type } from "./type"; import * as Utils from "../utils"; -import beautify from "json-beautify"; import {pokemonEvolutions, SpeciesFormEvolution} from "./pokemon-evolutions"; import i18next from "i18next"; import { Biome } from "#enums/biome"; import { Species } from "#enums/species"; import { TimeOfDay } from "#enums/time-of-day"; import { TrainerType } from "#enums/trainer-type"; +// import beautify from "json-beautify"; export function getBiomeName(biome: Biome | -1) { if (biome === -1) { @@ -7808,57 +7808,56 @@ export function initBiomes() { // used in a commented code - // eslint-disable-next-line @typescript-eslint/no-unused-vars - function outputPools() { - const pokemonOutput = {}; - const trainerOutput = {}; + // function outputPools() { + // const pokemonOutput = {}; + // const trainerOutput = {}; - for (const b of Object.keys(biomePokemonPools)) { - const biome = Biome[b]; - pokemonOutput[biome] = {}; - trainerOutput[biome] = {}; + // for (const b of Object.keys(biomePokemonPools)) { + // const biome = Biome[b]; + // pokemonOutput[biome] = {}; + // trainerOutput[biome] = {}; - for (const t of Object.keys(biomePokemonPools[b])) { - const tier = BiomePoolTier[t]; + // for (const t of Object.keys(biomePokemonPools[b])) { + // const tier = BiomePoolTier[t]; - pokemonOutput[biome][tier] = {}; + // pokemonOutput[biome][tier] = {}; - for (const tod of Object.keys(biomePokemonPools[b][t])) { - const timeOfDay = TimeOfDay[tod]; + // for (const tod of Object.keys(biomePokemonPools[b][t])) { + // const timeOfDay = TimeOfDay[tod]; - pokemonOutput[biome][tier][timeOfDay] = []; + // pokemonOutput[biome][tier][timeOfDay] = []; - for (const f of biomePokemonPools[b][t][tod]) { - if (typeof f === "number") { - pokemonOutput[biome][tier][timeOfDay].push(Species[f]); - } else { - const tree = {}; + // for (const f of biomePokemonPools[b][t][tod]) { + // if (typeof f === "number") { + // pokemonOutput[biome][tier][timeOfDay].push(Species[f]); + // } else { + // const tree = {}; - for (const l of Object.keys(f)) { - tree[l] = f[l].map(s => Species[s]); - } + // for (const l of Object.keys(f)) { + // tree[l] = f[l].map(s => Species[s]); + // } - pokemonOutput[biome][tier][timeOfDay].push(tree); - } - } + // pokemonOutput[biome][tier][timeOfDay].push(tree); + // } + // } - } - } + // } + // } - for (const t of Object.keys(biomeTrainerPools[b])) { - const tier = BiomePoolTier[t]; + // for (const t of Object.keys(biomeTrainerPools[b])) { + // const tier = BiomePoolTier[t]; - trainerOutput[biome][tier] = []; + // trainerOutput[biome][tier] = []; - for (const f of biomeTrainerPools[b][t]) { - trainerOutput[biome][tier].push(TrainerType[f]); - } - } - } + // for (const f of biomeTrainerPools[b][t]) { + // trainerOutput[biome][tier].push(TrainerType[f]); + // } + // } + // } - console.log(beautify(pokemonOutput, null, 2, 180).replace(/( | (?:\{ "\d+": \[ )?| "(?:.*?)": \[ |(?:,|\[) (?:"\w+": \[ |(?:\{ )?"\d+": \[ )?)"(\w+)"(?= |,|\n)/g, "$1Species.$2").replace(/"(\d+)": /g, "$1: ").replace(/((?: )|(?:(?!\n) "(?:.*?)": \{) |\[(?: .*? )?\], )"(\w+)"/g, "$1[TimeOfDay.$2]").replace(/( )"(.*?)"/g, "$1[BiomePoolTier.$2]").replace(/( )"(.*?)"/g, "$1[Biome.$2]")); - console.log(beautify(trainerOutput, null, 2, 120).replace(/( | (?:\{ "\d+": \[ )?| "(?:.*?)": \[ |, (?:(?:\{ )?"\d+": \[ )?)"(.*?)"/g, "$1TrainerType.$2").replace(/"(\d+)": /g, "$1: ").replace(/( )"(.*?)"/g, "$1[BiomePoolTier.$2]").replace(/( )"(.*?)"/g, "$1[Biome.$2]")); - } + // console.log(beautify(pokemonOutput, null, 2, 180).replace(/( | (?:\{ "\d+": \[ )?| "(?:.*?)": \[ |(?:,|\[) (?:"\w+": \[ |(?:\{ )?"\d+": \[ )?)"(\w+)"(?= |,|\n)/g, "$1Species.$2").replace(/"(\d+)": /g, "$1: ").replace(/((?: )|(?:(?!\n) "(?:.*?)": \{) |\[(?: .*? )?\], )"(\w+)"/g, "$1[TimeOfDay.$2]").replace(/( )"(.*?)"/g, "$1[BiomePoolTier.$2]").replace(/( )"(.*?)"/g, "$1[Biome.$2]")); + // console.log(beautify(trainerOutput, null, 2, 120).replace(/( | (?:\{ "\d+": \[ )?| "(?:.*?)": \[ |, (?:(?:\{ )?"\d+": \[ )?)"(.*?)"/g, "$1TrainerType.$2").replace(/"(\d+)": /g, "$1: ").replace(/( )"(.*?)"/g, "$1[BiomePoolTier.$2]").replace(/( )"(.*?)"/g, "$1[Biome.$2]")); + // } /*for (let pokemon of allSpecies) { if (pokemon.speciesId >= Species.XERNEAS) diff --git a/src/data/move.ts b/src/data/move.ts index c57bf86fc47..0fd8e35747c 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -9,7 +9,7 @@ import { Type } from "./type"; import * as Utils from "../utils"; import { WeatherType } from "./weather"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; -import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr } from "./ability"; +import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr, IgnoreProtectOnContactAbAttr } from "./ability"; import { allAbilities } from "./ability"; import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier"; import { BattlerIndex } from "../battle"; @@ -560,6 +560,11 @@ export default class Move implements Localizable { return true; } } + case MoveFlags.IGNORE_PROTECT: + if (user.hasAbilityWithAttr(IgnoreProtectOnContactAbAttr) && + this.checkFlag(MoveFlags.MAKES_CONTACT, user, target)) { + return true; + } } return !!(this.flags & flag); @@ -812,7 +817,8 @@ export class MoveEffectAttr extends MoveAttr { */ canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { return !! (this.selfTarget ? user.hp && !user.getTag(BattlerTagType.FRENZY) : target.hp) - && (this.selfTarget || !target.getTag(BattlerTagType.PROTECTED) || move.hasFlag(MoveFlags.IGNORE_PROTECT)); + && (this.selfTarget || !target.getTag(BattlerTagType.PROTECTED) || + move.checkFlag(MoveFlags.IGNORE_PROTECT, user, target)); } /** Applies move effects so long as they are able based on {@linkcode canApply} */ @@ -1734,7 +1740,11 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr { return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(user.status?.effect, true, false, user) ? Math.floor(move.chance * -0.1) : 0; } } - +/** + * The following needs to be implemented for Thief + * "If the user faints due to the target's Ability (Rough Skin or Iron Barbs) or held Rocky Helmet, it cannot remove the target's held item." + * "If Knock Off causes a Pokémon with the Sticky Hold Ability to faint, it can now remove that Pokémon's held item." + */ export class StealHeldItemChanceAttr extends MoveEffectAttr { private chance: number; @@ -1784,37 +1794,65 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { } } +/** + * Removes a random held item (or berry) from target. + * Used for Incinerate and Knock Off. + * Not Implemented Cases: (Same applies for Thief) + * "If the user faints due to the target's Ability (Rough Skin or Iron Barbs) or held Rocky Helmet, it cannot remove the target's held item." + * "If Knock Off causes a Pokémon with the Sticky Hold Ability to faint, it can now remove that Pokémon's held item." + */ export class RemoveHeldItemAttr extends MoveEffectAttr { - private chance: number; - constructor(chance: number) { + /** Optional restriction for item pool to berries only i.e. Differentiating Incinerate and Knock Off */ + private berriesOnly: boolean; + + constructor(berriesOnly: boolean) { super(false, MoveEffectTrigger.HIT); - this.chance = chance; + this.berriesOnly = berriesOnly; } - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { - return new Promise(resolve => { - const rand = Phaser.Math.RND.realInRange(0, 1); - if (rand >= this.chance) { - return resolve(false); - } - const heldItems = this.getTargetHeldItems(target).filter(i => i.getTransferrable(false)); - if (heldItems.length) { - const poolType = target.isPlayer() ? ModifierPoolType.PLAYER : target.hasTrainer() ? ModifierPoolType.TRAINER : ModifierPoolType.WILD; - const highestItemTier = heldItems.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier, highestTier), 0); - const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier(poolType) === highestItemTier); - const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; - user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => { - if (success) { - user.scene.queueMessage(getPokemonMessage(user, ` knocked off\n${target.name}'s ${stolenItem.type.name}!`)); - } - resolve(success); - }); - return; - } + /** + * + * @param user {@linkcode Pokemon} that used the move + * @param target Target {@linkcode Pokemon} that the moves applies to + * @param move {@linkcode Move} that is used + * @param args N/A + * @returns {boolean} True if an item was removed + */ + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - resolve(false); - }); + if (!this.berriesOnly && target.isPlayer()) { // "Wild Pokemon cannot knock off Player Pokemon's held items" (See Bulbapedia) + return false; + } + + const cancelled = new Utils.BooleanHolder(false); + applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // Check for abilities that block item theft + + if (cancelled.value === true) { + return false; + } + + // Considers entire transferrable item pool by default (Knock Off). Otherwise berries only if specified (Incinerate). + let heldItems = this.getTargetHeldItems(target).filter(i => i.getTransferrable(false)); + if (this.berriesOnly) { + heldItems = heldItems.filter(m => m instanceof BerryModifier && m.pokemonId === target.id, target.isPlayer()); + } + + if (heldItems.length) { + const removedItem = heldItems[user.randSeedInt(heldItems.length)]; + + // Decrease item amount and update icon + !--removedItem.stackCount; + target.scene.updateModifiers(target.isPlayer()); + + if (this.berriesOnly) { + user.scene.queueMessage(getPokemonMessage(user, ` incinerated\n${target.name}'s ${removedItem.type.name}!`)); + } else { + user.scene.queueMessage(getPokemonMessage(user, ` knocked off\n${target.name}'s ${removedItem.type.name}!`)); + } + } + + return true; } getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] { @@ -3221,17 +3259,6 @@ export class PresentPowerAttr extends VariablePowerAttr { } } -export class KnockOffPowerAttr extends VariablePowerAttr { - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (target.getHeldItems().length > 0) { - (args[0] as Utils.NumberHolder).value *= 1.5; - return true; - } - - return false; - } -} - export class WaterShurikenPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (user.species.speciesId === Species.GRENINJA && user.hasAbility(Abilities.BATTLE_BOND) && user.formIndex === 2) { @@ -5419,6 +5446,32 @@ export class LastResortAttr extends MoveAttr { } } + +/** + * The move only works if the target has a transferable held item + * @extends MoveAttr + * @see {@linkcode getCondition} + */ +export class AttackedByItemAttr extends MoveAttr { + /** + * @returns the {@linkcode MoveConditionFunc} for this {@linkcode Move} + */ + getCondition(): MoveConditionFunc { + return (user: Pokemon, target: Pokemon, move: Move) => { + const heldItems = target.getHeldItems().filter(i => i.getTransferrable(true)); + if (heldItems.length === 0) { + return false; + } + + const itemName = heldItems[0]?.type?.name ?? "item"; + const attackedByItemString = ` is about to be attacked by its ${itemName}!`; + target.scene.queueMessage(getPokemonMessage(target, attackedByItemString)); + + return true; + }; + } +} + export class VariableTargetAttr extends MoveAttr { private targetChangeFunc: (user: Pokemon, target: Pokemon, move: Move) => number; @@ -6363,8 +6416,8 @@ export function initMoves() { .attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, true) .condition((user, target, move) => !target.status), new AttackMove(Moves.KNOCK_OFF, Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3) - .attr(KnockOffPowerAttr) - .partial(), + .attr(MovePowerMultiplierAttr, (user, target, move) => target.getHeldItems().filter(i => i.getTransferrable(false)).length > 0 ? 1.5 : 1) + .attr(RemoveHeldItemAttr, false), new AttackMove(Moves.ENDEAVOR, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 3) .attr(MatchHpAttr) .condition(failOnBossCondition), @@ -6994,7 +7047,7 @@ export function initMoves() { .attr(ForceSwitchOutAttr), new AttackMove(Moves.INCINERATE, Type.FIRE, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 5) .target(MoveTarget.ALL_NEAR_ENEMIES) - .partial(), + .attr(RemoveHeldItemAttr, true), new StatusMove(Moves.QUASH, Type.DARK, 100, 15, -1, 0, 5) .unimplemented(), new AttackMove(Moves.ACROBATICS, Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5) @@ -7893,8 +7946,8 @@ export function initMoves() { new AttackMove(Moves.LASH_OUT, Type.DARK, MoveCategory.PHYSICAL, 75, 100, 5, -1, 0, 8) .partial(), new AttackMove(Moves.POLTERGEIST, Type.GHOST, MoveCategory.PHYSICAL, 110, 90, 5, -1, 0, 8) - .makesContact(false) - .partial(), + .attr(AttackedByItemAttr) + .makesContact(false), new StatusMove(Moves.CORROSIVE_GAS, Type.POISON, 100, 40, -1, 0, 8) .target(MoveTarget.ALL_NEAR_OTHERS) .unimplemented(), diff --git a/src/data/temp-battle-stat.ts b/src/data/temp-battle-stat.ts index 35653bfd75a..2d461a1d647 100644 --- a/src/data/temp-battle-stat.ts +++ b/src/data/temp-battle-stat.ts @@ -1,4 +1,5 @@ import { BattleStat, getBattleStatName } from "./battle-stat"; +import i18next from "i18next"; export enum TempBattleStat { ATK, @@ -12,7 +13,7 @@ export enum TempBattleStat { export function getTempBattleStatName(tempBattleStat: TempBattleStat) { if (tempBattleStat === TempBattleStat.CRIT) { - return "critical-hit ratio"; + return i18next.t("modifierType:TempBattleStatBoosterStatName.CRIT"); } return getBattleStatName(tempBattleStat as integer as BattleStat); } diff --git a/src/egg-hatch-phase.ts b/src/egg-hatch-phase.ts index 3fce35e4f88..6e44b832181 100644 --- a/src/egg-hatch-phase.ts +++ b/src/egg-hatch-phase.ts @@ -262,6 +262,9 @@ export class EggHatchPhase extends Phase { if (!this.canSkip || this.skipped) { return false; } + if (this.eggCounterContainer.eggCountText?.data === undefined) { + return false; + } this.skipped = true; if (!this.hatched) { this.doHatch(); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index c42e8b1b75c..396f3f3e539 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1729,7 +1729,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } // Apply arena tags for conditional protection - if (!move.hasFlag(MoveFlags.IGNORE_PROTECT) && !move.isAllyTarget()) { + if (!move.checkFlag(MoveFlags.IGNORE_PROTECT, source, this) && !move.isAllyTarget()) { const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; this.scene.arena.applyTagsForSide(ArenaTagType.QUICK_GUARD, defendingSide, cancelled, this, move.priority); this.scene.arena.applyTagsForSide(ArenaTagType.WIDE_GUARD, defendingSide, cancelled, this, move.moveTarget); diff --git a/src/locales/de/battle.ts b/src/locales/de/battle.ts index 07687f8a535..86336b0e233 100644 --- a/src/locales/de/battle.ts +++ b/src/locales/de/battle.ts @@ -61,5 +61,13 @@ export const battle: SimpleTranslationEntries = { "useMove": "{{pokemonNameWithAffix}} setzt {{moveName}} ein!", "drainMessage": "{{pokemonName}} wurde Energie abgesaugt", "regainHealth": "KP von {{pokemonName}} wurden wieder aufgefrischt!", - "fainted": "{{pokemonNameWithAffix}} wurde besiegt!" + "fainted": "{{pokemonNameWithAffix}} wurde besiegt!", + "statRose": "rose", + "statSharplyRose": "sharply rose", + "statRoseDrastically": "rose drastically", + "statWontGoAnyHigher": "won't go any higher", + "statFell": "fell", + "statHarshlyFell": "harshly fell", + "statSeverelyFell": "severely fell", + "statWontGoAnyLower": "won't go any lower", } as const; diff --git a/src/locales/de/modifier-type.ts b/src/locales/de/modifier-type.ts index 175c426143b..8f0f7aded5c 100644 --- a/src/locales/de/modifier-type.ts +++ b/src/locales/de/modifier-type.ts @@ -249,6 +249,20 @@ export const modifierType: ModifierTypeTranslationEntries = { "x_accuracy": "X-Treffer", "dire_hit": "X-Volltreffer", }, + + TempBattleStatBoosterStatName: { + "ATK": "Angriff", + "DEF": "Verteidigung", + "SPATK": "Sp. Ang", + "SPDEF": "Sp. Vert", + "SPD": "Initiative", + "ACC": "Genauigkeit", + "CRIT": "Volltrefferquote", + "EVA": "Fluchtwert", + "DEFAULT": "???", + }, + + AttackTypeBoosterItem: { "silk_scarf": "Seidenschal", "black_belt": "Schwarzgurt", diff --git a/src/locales/de/pokemon-info.ts b/src/locales/de/pokemon-info.ts index 203ad9e6e1e..0d350a75c36 100644 --- a/src/locales/de/pokemon-info.ts +++ b/src/locales/de/pokemon-info.ts @@ -14,6 +14,8 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPDEFshortened": "SpVert", "SPD": "Initiative", "SPDshortened": "Init", + "ACC": "Accuracy", + "EVA": "Evasiveness" }, Type: { diff --git a/src/locales/en/battle.ts b/src/locales/en/battle.ts index 52b64b8b614..39393331a72 100644 --- a/src/locales/en/battle.ts +++ b/src/locales/en/battle.ts @@ -61,5 +61,13 @@ export const battle: SimpleTranslationEntries = { "useMove": "{{pokemonNameWithAffix}} used {{moveName}}!", "drainMessage": "{{pokemonName}} had its\nenergy drained!", "regainHealth": "{{pokemonName}} regained\nhealth!", - "fainted": "{{pokemonNameWithAffix}} fainted!" + "fainted": "{{pokemonNameWithAffix}} fainted!", + "statRose": "rose", + "statSharplyRose": "sharply rose", + "statRoseDrastically": "rose drastically", + "statWontGoAnyHigher": "won't go any higher", + "statFell": "fell", + "statHarshlyFell": "harshly fell", + "statSeverelyFell": "severely fell", + "statWontGoAnyLower": "won't go any lower", } as const; diff --git a/src/locales/en/modifier-type.ts b/src/locales/en/modifier-type.ts index 87d4a0ccf4f..3899e73dcac 100644 --- a/src/locales/en/modifier-type.ts +++ b/src/locales/en/modifier-type.ts @@ -248,6 +248,19 @@ export const modifierType: ModifierTypeTranslationEntries = { "x_accuracy": "X Accuracy", "dire_hit": "Dire Hit", }, + + TempBattleStatBoosterStatName: { + "ATK": "Attack", + "DEF": "Defense", + "SPATK": "Sp. Atk", + "SPDEF": "Sp. Def", + "SPD": "Speed", + "ACC": "Accuracy", + "CRIT": "Critical Hit Ratio", + "EVA": "Evasiveness", + "DEFAULT": "???", + }, + AttackTypeBoosterItem: { "silk_scarf": "Silk Scarf", "black_belt": "Black Belt", diff --git a/src/locales/en/pokemon-info.ts b/src/locales/en/pokemon-info.ts index b9a24d7e449..f34ad219e7f 100644 --- a/src/locales/en/pokemon-info.ts +++ b/src/locales/en/pokemon-info.ts @@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPDEF": "Sp. Def", "SPDEFshortened": "SpDef", "SPD": "Speed", - "SPDshortened": "Spd" + "SPDshortened": "Spd", + "ACC": "Accuracy", + "EVA": "Evasiveness" }, Type: { diff --git a/src/locales/es/battle.ts b/src/locales/es/battle.ts index 2b5f725caf2..875421617de 100644 --- a/src/locales/es/battle.ts +++ b/src/locales/es/battle.ts @@ -61,5 +61,13 @@ export const battle: SimpleTranslationEntries = { "useMove": "¡{{pokemonNameWithAffix}} usó {{moveName}}!", "drainMessage": "¡{{pokemonName}} tuvo su\nenergía absorbida!", "regainHealth": "¡{{pokemonName}} recuperó\nPS!", - "fainted": "¡{{pokemonNameWithAffix}} se debilitó!" + "fainted": "¡{{pokemonNameWithAffix}} se debilitó!", + "statRose": "rose", + "statSharplyRose": "sharply rose", + "statRoseDrastically": "rose drastically", + "statWontGoAnyHigher": "won't go any higher", + "statFell": "fell", + "statHarshlyFell": "harshly fell", + "statSeverelyFell": "severely fell", + "statWontGoAnyLower": "won't go any lower", } as const; diff --git a/src/locales/es/modifier-type.ts b/src/locales/es/modifier-type.ts index 3c1925eaa67..5689f039f5c 100644 --- a/src/locales/es/modifier-type.ts +++ b/src/locales/es/modifier-type.ts @@ -248,6 +248,18 @@ export const modifierType: ModifierTypeTranslationEntries = { "x_accuracy": "Precisión X", "dire_hit": "Crítico X", }, + + TempBattleStatBoosterStatName: { + "ATK": "Attack", + "DEF": "Defense", + "SPATK": "Sp. Atk", + "SPDEF": "Sp. Def", + "SPD": "Speed", + "ACC": "Accuracy", + "CRIT": "Critical Hit Ratio", + "EVA": "Evasiveness", + "DEFAULT": "???", + }, AttackTypeBoosterItem: { "silk_scarf": "Pañuelo Seda", "black_belt": "Cinturón Negro", diff --git a/src/locales/es/pokemon-info.ts b/src/locales/es/pokemon-info.ts index 4861ac1f82f..d3a39c83b44 100644 --- a/src/locales/es/pokemon-info.ts +++ b/src/locales/es/pokemon-info.ts @@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPDEF": "Def. Esp.", "SPDEFshortened": "DefEsp", "SPD": "Velocidad", - "SPDshortened": "Veloc." + "SPDshortened": "Veloc.", + "ACC": "Accuracy", + "EVA": "Evasiveness" }, Type: { diff --git a/src/locales/fr/battle.ts b/src/locales/fr/battle.ts index 1f3ec637a40..3bb051830ee 100644 --- a/src/locales/fr/battle.ts +++ b/src/locales/fr/battle.ts @@ -61,5 +61,13 @@ export const battle: SimpleTranslationEntries = { "useMove": "{{pokemonNameWithAffix}} utilise\n{{moveName}} !", "drainMessage": "L’énergie de {{pokemonName}}\nest drainée !", "regainHealth": "{{pokemonName}} récupère\ndes PV !", - "fainted": "{{pokemonNameWithAffix}}\nest K.O. !" + "fainted": "{{pokemonNameWithAffix}}\nest K.O. !", + "statRose": "rose", + "statSharplyRose": "sharply rose", + "statRoseDrastically": "rose drastically", + "statWontGoAnyHigher": "won't go any higher", + "statFell": "fell", + "statHarshlyFell": "harshly fell", + "statSeverelyFell": "severely fell", + "statWontGoAnyLower": "won't go any lower", } as const; diff --git a/src/locales/fr/modifier-type.ts b/src/locales/fr/modifier-type.ts index 766629b88d8..9ef99f49330 100644 --- a/src/locales/fr/modifier-type.ts +++ b/src/locales/fr/modifier-type.ts @@ -248,6 +248,19 @@ export const modifierType: ModifierTypeTranslationEntries = { "x_accuracy": "Précision +", "dire_hit": "Muscle +", }, + + TempBattleStatBoosterStatName: { + "ATK": "Attaque", + "DEF": "Défense", + "SPATK": "Atq. Spé.", + "SPDEF": "Déf. Spé.", + "SPD": "Vitesse", + "ACC": "Précision", + "CRIT": "Taux de critique", + "EVA": "Esquive", + "DEFAULT": "???", + }, + AttackTypeBoosterItem: { "silk_scarf": "Mouchoir Soie", "black_belt": "Ceinture Noire", diff --git a/src/locales/fr/pokemon-info.ts b/src/locales/fr/pokemon-info.ts index 9341e5d77ca..373106d732b 100644 --- a/src/locales/fr/pokemon-info.ts +++ b/src/locales/fr/pokemon-info.ts @@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPDEF": "Déf. Spé.", "SPDEFshortened": "DéfSp", "SPD": "Vitesse", - "SPDshortened": "Vit" + "SPDshortened": "Vit", + "ACC": "Accuracy", + "EVA": "Evasiveness" }, Type: { diff --git a/src/locales/it/battle.ts b/src/locales/it/battle.ts index 35082a4d7f0..8fb9cf56c70 100644 --- a/src/locales/it/battle.ts +++ b/src/locales/it/battle.ts @@ -61,5 +61,13 @@ export const battle: SimpleTranslationEntries = { "useMove": "{{pokemonNameWithAffix}} usa {{moveName}}!", "drainMessage": "Viene prelevata energia\n da{{pokemonName}}!", "regainHealth": "{{pokemonName}} ha rigenerato\npunti salute!", - "fainted": "{{pokemonNameWithAffix}} non è più in\ngrado di combattere!" + "fainted": "{{pokemonNameWithAffix}} non è più in\ngrado di combattere!", + "statRose": "rose", + "statSharplyRose": "sharply rose", + "statRoseDrastically": "rose drastically", + "statWontGoAnyHigher": "won't go any higher", + "statFell": "fell", + "statHarshlyFell": "harshly fell", + "statSeverelyFell": "severely fell", + "statWontGoAnyLower": "won't go any lower", } as const; diff --git a/src/locales/it/modifier-type.ts b/src/locales/it/modifier-type.ts index b16604200f8..44006a3f76a 100644 --- a/src/locales/it/modifier-type.ts +++ b/src/locales/it/modifier-type.ts @@ -248,6 +248,19 @@ export const modifierType: ModifierTypeTranslationEntries = { "x_accuracy": "Precisione X", "dire_hit": "Supercolpo", }, + + TempBattleStatBoosterStatName: { + "ATK": "Attack", + "DEF": "Defense", + "SPATK": "Sp. Atk", + "SPDEF": "Sp. Def", + "SPD": "Speed", + "ACC": "Accuracy", + "CRIT": "Critical Hit Ratio", + "EVA": "Evasiveness", + "DEFAULT": "???", + }, + AttackTypeBoosterItem: { "silk_scarf": "Sciarpa seta", "black_belt": "Cinturanera", diff --git a/src/locales/it/party-ui-handler.ts b/src/locales/it/party-ui-handler.ts index 9d3c7baa9ae..486e711b96f 100644 --- a/src/locales/it/party-ui-handler.ts +++ b/src/locales/it/party-ui-handler.ts @@ -1,10 +1,10 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const partyUiHandler: SimpleTranslationEntries = { - "SEND_OUT": "Send Out", - "SUMMARY": "Summary", - "CANCEL": "Cancel", - "RELEASE": "Release", - "APPLY": "Apply", - "TEACH": "Teach" + "SEND_OUT": "Manda in campo", + "SUMMARY": "Sommario", + "CANCEL": "Annulla", + "RELEASE": "Rilascia", + "APPLY": "Applica", + "TEACH": "Insegna" } as const; diff --git a/src/locales/it/pokeball.ts b/src/locales/it/pokeball.ts index a07e4c2ca7d..ad43c652478 100644 --- a/src/locales/it/pokeball.ts +++ b/src/locales/it/pokeball.ts @@ -6,5 +6,5 @@ export const pokeball: SimpleTranslationEntries = { "ultraBall": "Ultra Ball", "rogueBall": "Rogue Ball", "masterBall": "Master Ball", - "luxuryBall": "Chich Ball", + "luxuryBall": "Chic Ball", } as const; diff --git a/src/locales/it/pokemon-info-container.ts b/src/locales/it/pokemon-info-container.ts index 068c9ebb431..b1bd585363d 100644 --- a/src/locales/it/pokemon-info-container.ts +++ b/src/locales/it/pokemon-info-container.ts @@ -1,11 +1,11 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const pokemonInfoContainer: SimpleTranslationEntries = { - "moveset": "Moveset", - "gender": "Gender:", - "ability": "Ability:", - "nature": "Nature:", - "epic": "Epic", - "rare": "Rare", - "common": "Common" + "moveset": "Set di mosse", + "gender": "Genere:", + "ability": "Abilità:", + "nature": "Natura:", + "epic": "Epico", + "rare": "Raro", + "common": "Comune" } as const; diff --git a/src/locales/it/pokemon-info.ts b/src/locales/it/pokemon-info.ts index 6da12e30720..f5f21f645c3 100644 --- a/src/locales/it/pokemon-info.ts +++ b/src/locales/it/pokemon-info.ts @@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPDEF": "Dif. Sp.", "SPDEFshortened": "DifSp", "SPD": "Velocità", - "SPDshortened": "Vel" + "SPDshortened": "Vel", + "ACC": "Precisione", + "EVA": "Elusione" }, Type: { diff --git a/src/locales/it/save-slot-select-ui-handler.ts b/src/locales/it/save-slot-select-ui-handler.ts index 16e36e471a5..a7485c842f2 100644 --- a/src/locales/it/save-slot-select-ui-handler.ts +++ b/src/locales/it/save-slot-select-ui-handler.ts @@ -1,9 +1,9 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const saveSlotSelectUiHandler: SimpleTranslationEntries = { - "overwriteData": "Overwrite the data in the selected slot?", - "loading": "Loading...", - "wave": "Wave", + "overwriteData": "Sovrascrivere i dati nello slot selezionato?", + "loading": "Caricamento...", + "wave": "Onda", "lv": "Lv", "empty": "Vuoto", } as const; diff --git a/src/locales/it/splash-messages.ts b/src/locales/it/splash-messages.ts index 5fc1f7ed7b9..6ad80f64e89 100644 --- a/src/locales/it/splash-messages.ts +++ b/src/locales/it/splash-messages.ts @@ -5,10 +5,10 @@ export const splashMessages: SimpleTranslationEntries = { "joinTheDiscord": "Entra nel Discord!", "infiniteLevels": "Livelli Infiniti!", "everythingStacks": "Tutto si impila!", - "optionalSaveScumming": "Salvataggio Facoltativo!", + "optionalSaveScumming": "Salvataggi Facoltativi!", "biomes": "35 Biomi!", "openSource": "Open Source!", - "playWithSpeed": "Gioca con il 5x di Velocità!", + "playWithSpeed": "Gioca con la velocità aumentata di 5 volte!", "liveBugTesting": "Test dei Bug in Tempo Reale!", "heavyInfluence": "Influenzato da RoR2!", "pokemonRiskAndPokemonRain": "Pokémon Risk e Pokémon Rain!", diff --git a/src/locales/it/starter-select-ui-handler.ts b/src/locales/it/starter-select-ui-handler.ts index 16061766f30..48a0badaefc 100644 --- a/src/locales/it/starter-select-ui-handler.ts +++ b/src/locales/it/starter-select-ui-handler.ts @@ -7,38 +7,38 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; */ export const starterSelectUiHandler: SimpleTranslationEntries = { "confirmStartTeam":"Vuoi iniziare con questi Pokémon?", - "gen1": "I", - "gen2": "II", - "gen3": "III", - "gen4": "IV", - "gen5": "V", - "gen6": "VI", - "gen7": "VII", - "gen8": "VIII", - "gen9": "IX", + "gen1": "1ª", + "gen2": "2ª", + "gen3": "3ª", + "gen4": "4ª", + "gen5": "5ª", + "gen6": "6ª", + "gen7": "7ª", + "gen8": "8ª", + "gen9": "9ª", "growthRate": "Vel. Crescita:", "ability": "Abilità:", "passive": "Passiva:", "nature": "Natura:", - "eggMoves": "Mosse delle uova", + "eggMoves": "Mosse da uova", "start": "Inizia", - "addToParty": "Aggiungi al Gruppo", + "addToParty": "Aggiungi al gruppo", "toggleIVs": "Vedi/Nascondi IV", - "manageMoves": "Gestisci Mosse", - "useCandies": "Usa Caramelle", + "manageMoves": "Gestisci mosse", + "useCandies": "Usa caramelle", "selectMoveSwapOut": "Seleziona una mossa da scambiare.", "selectMoveSwapWith": "Seleziona una mossa da scambiare con", - "unlockPassive": "Sblocca Passiva", - "reduceCost": "Riduci Costo", + "unlockPassive": "Sblocca passiva", + "reduceCost": "Riduci costo", "cycleShiny": ": Shiny", "cycleForm": ": Forma", - "cycleGender": ": Sesso", + "cycleGender": ": Genere", "cycleAbility": ": Abilità", "cycleNature": ": Natura", "cycleVariant": ": Variante", - "enablePassive": "Attiva Passiva", - "disablePassive": "Disattiva Passiva", + "enablePassive": "Attiva passiva", + "disablePassive": "Disattiva passiva", "locked": "Bloccato", "disabled": "Disabilitato", - "uncaught": "Non Catturato" + "uncaught": "Non catturato" }; diff --git a/src/locales/it/trainers.ts b/src/locales/it/trainers.ts index 9c0a644c1c6..dffac3bb9f4 100644 --- a/src/locales/it/trainers.ts +++ b/src/locales/it/trainers.ts @@ -6,258 +6,258 @@ export const titles: SimpleTranslationEntries = { "elite_four_female": "Superquattro", "gym_leader": "Capopalestra", "gym_leader_female": "Capopalestra", - "gym_leader_double": "Gym Leader Duo", + "gym_leader_double": "Duo Capopalestra", "champion": "Campione", - "champion_female": "Champion", - "champion_double": "Champion Duo", + "champion_female": "Campionessa", + "champion_double": "Duo Campioni", "rival": "Rivale", "professor": "Professore", - "frontier_brain": "Asso Lotta", + "frontier_brain": "Asso lotta", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; // Titles of trainers like "Youngster" or "Lass" export const trainerClasses: SimpleTranslationEntries = { - "ace_trainer": "Ace Trainer", - "ace_trainer_female": "Ace Trainer", - "ace_duo": "Ace Duo", - "artist": "Artist", - "artist_female": "Artist", - "backers": "Backers", - "backpacker": "Backpacker", - "backpacker_female": "Backpacker", - "backpackers": "Backpackers", - "baker": "Baker", - "battle_girl": "Battle Girl", - "beauty": "Beauty", - "beginners": "Beginners", - "biker": "Biker", - "black_belt": "Black Belt", - "breeder": "Breeder", - "breeder_female": "Breeder", - "breeders": "Breeders", - "clerk": "Clerk", - "clerk_female": "Clerk", - "colleagues": "Colleagues", - "crush_kin": "Crush Kin", - "cyclist": "Cyclist", - "cyclist_female": "Cyclist", - "cyclists": "Cyclists", - "dancer": "Dancer", - "dancer_female": "Dancer", - "depot_agent": "Depot Agent", - "doctor": "Doctor", - "doctor_female": "Doctor", - "firebreather": "Firebreather", - "fisherman": "Fisherman", - "fisherman_female": "Fisherman", - "gentleman": "Gentleman", - "guitarist": "Guitarist", - "guitarist_female": "Guitarist", - "harlequin": "Harlequin", - "hiker": "Hiker", - "hooligans": "Hooligans", - "hoopster": "Hoopster", - "infielder": "Infielder", - "janitor": "Janitor", + "ace_trainer": "Fantallenatore", + "ace_trainer_female": "Fantallenatrice", + "ace_duo": "Fantallenatori", + "artist": "Artista", + "artist_female": "Artista", + "backers": "Fan", + "backpacker": "Giramondo", + "backpacker_female": "Giramondo", + "backpackers": "Giramondo", + "baker": "Panettiera", + "battle_girl": "Combat Girl", + "beauty": "Bellezza", + "beginners": "Novellini", + "biker": "Centauro", + "black_belt": "Cinturanera", + "breeder": "Allevapokémon", + "breeder_female": "Allevapokémon", + "breeders": "Allevapokémon", + "clerk": "Affarista", + "clerk_female": "Donna in carriera", + "colleagues": "Soci in affari", + "crush_kin": "Duo Lotta", + "cyclist": "Ciclista", + "cyclist_female": "Ciclista", + "cyclists": "Ciclisti", + "dancer": "Ballerino", + "dancer_female": "Ballerina", + "depot_agent": "Ferroviario", + "doctor": "Medico", + "doctor_female": "Medica", + "firebreather": "Mangiafuoco", + "fisherman": "Pescatore", + "fisherman_female": "Pescatrice", + "gentleman": "Gentiluomo", + "guitarist": "Chitarrista", + "guitarist_female": "Chitarrista", + "harlequin": "Buffone", + "hiker": "Montanaro", + "hooligans": "Teppisti", + "hoopster": "Cestista", + "infielder": "Battitore", + "janitor": "Netturbino", "lady": "Lady", - "lass": "Lass", - "linebacker": "Linebacker", - "maid": "Maid", + "lass": "Pupa", + "linebacker": "Quarterback", + "maid": "Domestica", "madame": "Madame", - "medical_team": "Medical Team", - "musician": "Musician", - "hex_maniac": "Hex Maniac", - "nurse": "Nurse", - "nursery_aide": "Nursery Aide", - "officer": "Officer", - "parasol_lady": "Parasol Lady", - "pilot": "Pilot", - "pokéfan": "Poké Fan", - "pokéfan_female": "Poké Fan", - "pokéfan_family": "Poké Fan Family", - "preschooler": "Preschooler", - "preschooler_female": "Preschooler", - "preschoolers": "Preschoolers", - "psychic": "Psychic", - "psychic_female": "Psychic", - "psychics": "Psychics", + "medical_team": "Équipe medica", + "musician": "Musicista", + "hex_maniac": "Streghetta", + "nurse": "Infermiera", + "nursery_aide": "Maestrina", + "officer": "Guardia", + "parasol_lady": "Ombrellina", + "pilot": "Pilota", + "pokéfan": "PokéFan", + "pokéfan_female": "PokéFan", + "pokéfan_family": "Famiglia PokéFan", + "preschooler": "Bimbo", + "preschooler_female": "Bimba", + "preschoolers": "Bimbi", + "psychic": "Sensitivo", + "psychic_female": "Sensitiva", + "psychics": "Sensitivi", "pokémon_ranger": "Pokémon Ranger", "pokémon_ranger_female": "Pokémon Ranger", - "pokémon_rangers": "Pokémon Ranger", + "pokémon_rangers": "Duo Ranger", "ranger": "Ranger", - "restaurant_staff": "Restaurant Staff", - "rich": "Rich", - "rich_female": "Rich", - "rich_boy": "Rich Boy", - "rich_couple": "Rich Couple", - "rich_kid": "Rich Kid", - "rich_kid_female": "Rich Kid", - "rich_kids": "Rich Kids", - "roughneck": "Roughneck", - "sailor": "Sailor", - "scientist": "Scientist", - "scientist_female": "Scientist", - "scientists": "Scientists", - "smasher": "Smasher", - "snow_worker": "Snow Worker", - "snow_worker_female": "Snow Worker", - "striker": "Striker", - "school_kid": "School Kid", - "school_kid_female": "School Kid", - "school_kids": "School Kids", - "swimmer": "Swimmer", - "swimmer_female": "Swimmer", - "swimmers": "Swimmers", - "twins": "Twins", - "veteran": "Veteran", - "veteran_female": "Veteran", - "veteran_duo": "Veteran Duo", - "waiter": "Waiter", - "waitress": "Waitress", - "worker": "Worker", - "worker_female": "Worker", - "workers": "Workers", - "youngster": "Youngster" + "restaurant_staff": "Personale del ristorante", + "rich": "Ricco", + "rich_female": "Ricca", + "rich_boy": "Elegantone", + "rich_couple": "Ricchi", + "rich_kid": "Bimbo ricco", + "rich_kid_female": "Bimba ricca", + "rich_kids": "Bimbi ricchi", + "roughneck": "Zuccapelata", + "sailor": "Marinaio", + "scientist": "Scienziato", + "scientist_female": "Scienziata", + "scientists": "Scienziati", + "smasher": "Tennista", + "snow_worker": "Lavoratore", + "snow_worker_female": "Lavoratrice", + "striker": "Calciatore", + "school_kid": "Alunno", + "school_kid_female": "Alunna", + "school_kids": "Alunni", + "swimmer": "Nuotatore", + "swimmer_female": "Nuotatrice", + "swimmers": "Nuotatori", + "twins": "Gemelli", + "veteran": "Veterano", + "veteran_female": "Veterana", + "veteran_duo": "Veterani", + "waiter": "Cameriere", + "waitress": "Cameriera", + "worker": "Operaio", + "worker_female": "Lavoratrice", + "workers": "Lavoratori", + "youngster": "Bullo" } as const; // Names of special trainers like gym leaders, elite four, and the champion export const trainerNames: SimpleTranslationEntries = { "brock": "Brock", "misty": "Misty", - "lt_surge": "Lt Surge", + "lt_surge": "Lt. Surge", "erika": "Erika", - "janine": "Janine", + "janine": "Nina", "sabrina": "Sabrina", "blaine": "Blaine", "giovanni": "Giovanni", - "falkner": "Falkner", - "bugsy": "Bugsy", - "whitney": "Whitney", - "morty": "Morty", - "chuck": "Chuck", + "falkner": "Valerio", + "bugsy": "Raffaello", + "whitney": "Chiara", + "morty": "Angelo", + "chuck": "Furio", "jasmine": "Jasmine", - "pryce": "Pryce", - "clair": "Clair", - "roxanne": "Roxanne", - "brawly": "Brawly", - "wattson": "Wattson", - "flannery": "Flannery", + "pryce": "Alfredo", + "clair": "Sandra", + "roxanne": "Petra", + "brawly": "Rudi", + "wattson": "Walter", + "flannery": "Fiammetta", "norman": "Norman", - "winona": "Winona", - "tate": "Tate", - "liza": "Liza", - "juan": "Juan", - "roark": "Roark", + "winona": "Alice", + "tate": "Tell", + "liza": "Pat", + "juan": "Rodolfo", + "roark": "Pedro", "gardenia": "Gardenia", - "maylene": "Maylene", - "crasher_wake": "Crasher Wake", - "fantina": "Fantina", - "byron": "Byron", - "candice": "Candice", - "volkner": "Volkner", - "cilan": "Cilan", - "chili": "Chili", - "cress": "Cress", - "cheren": "Cheren", - "lenora": "Lenora", - "roxie": "Roxie", - "burgh": "Burgh", - "elesa": "Elesa", - "clay": "Clay", - "skyla": "Skyla", - "brycen": "Brycen", - "drayden": "Drayden", - "marlon": "Marlon", - "viola": "Viola", - "grant": "Grant", - "korrina": "Korrina", - "ramos": "Ramos", - "clemont": "Clemont", - "valerie": "Valerie", - "olympia": "Olympia", - "wulfric": "Wulfric", - "milo": "Milo", - "nessa": "Nessa", + "maylene": "Marzia", + "crasher_wake": "Omar", + "fantina": "Fannie", + "byron": "Ferruccio", + "candice": "Bianca", + "volkner": "Corrado", + "cilan": "Spighetto", + "chili": "Chicco", + "cress": "Maisello", + "cheren": "Komor", + "lenora": "Aloé", + "roxie": "Velia", + "burgh": "Artemisio", + "elesa": "Camelia", + "clay": "Rafan", + "skyla": "Anemone", + "brycen": "Silvestro", + "drayden": "Aristide", + "marlon": "Ciprian", + "viola": "Violetta", + "grant": "Lino", + "korrina": "Ornella", + "ramos": "Amur", + "clemont": "Lem", + "valerie": "Valérie", + "olympia": "Astra", + "wulfric": "Edel", + "milo": "Yarrow", + "nessa": "Azzurra", "kabu": "Kabu", - "bea": "Bea", - "allister": "Allister", - "opal": "Opal", - "bede": "Bede", - "gordie": "Gordie", - "melony": "Melony", - "piers": "Piers", - "marnie": "Marnie", + "bea": "Fabia", + "allister": "Onion", + "opal": "Poppy", + "bede": "Beet", + "gordie": "Milo", + "melony": "Melania", + "piers": "Ginepro", + "marnie": "Mary", "raihan": "Raihan", - "katy": "Katy", + "katy": "Aceria", "brassius": "Brassius", - "iono": "Iono", - "kofu": "Kofu", - "larry": "Larry", + "iono": "Kissara", + "kofu": "Algaro", + "larry": "Ubaldo", "ryme": "Ryme", - "tulip": "Tulip", + "tulip": "Tulipa", "grusha": "Grusha", "lorelei": "Lorelei", "bruno": "Bruno", "agatha": "Agatha", "lance": "Lance", - "will": "Will", + "will": "Pino", "koga": "Koga", "karen": "Karen", - "sidney": "Sidney", - "phoebe": "Phoebe", - "glacia": "Glacia", + "sidney": "Fosco", + "phoebe": "Ester", + "glacia": "Frida", "drake": "Drake", "aaron": "Aaron", - "bertha": "Bertha", - "flint": "Flint", - "lucian": "Lucian", - "shauntal": "Shauntal", - "marshal": "Marshal", - "grimsley": "Grimsley", - "caitlin": "Caitlin", + "bertha": "Terrie", + "flint": "Vulcano", + "lucian": "Luciano", + "shauntal": "Antemia", + "marshal": "Marzio", + "grimsley": "Mirton", + "caitlin": "Catlina", "malva": "Malva", - "siebold": "Siebold", - "wikstrom": "Wikstrom", - "drasna": "Drasna", + "siebold": "Narciso", + "wikstrom": "Timeos", + "drasna": "Lila", "hala": "Hala", - "molayne": "Molayne", - "olivia": "Olivia", - "acerola": "Acerola", + "molayne": "Tapso", + "olivia": "Olive", + "acerola": "Mapli", "kahili": "Kahili", "rika": "Rika", "poppy": "Poppy", - "hassel": "Hassel", - "crispin": "Crispin", - "amarys": "Amarys", - "lacey": "Lacey", - "drayton": "Drayton", - "blue": "Blue", - "red": "Red", - "steven": "Steven", - "wallace": "Wallace", - "cynthia": "Cynthia", - "alder": "Alder", + "hassel": "Oranzio", + "crispin": "Piros", + "amarys": "Erin", + "lacey": "Rupi", + "drayton": "Aris", + "blue": "Blu", + "red": "Rosso", + "steven": "Rocco", + "wallace": "Adriano", + "cynthia": "Camilla", + "alder": "Nardo", "iris": "Iris", "diantha": "Diantha", "hau": "Hau", - "geeta": "Geeta", - "nemona": "Nemona", - "kieran": "Kieran", - "leon": "Leon", + "geeta": "Alisma", + "nemona": "Nemi", + "kieran": "Riben", + "leon": "Dandel", "rival": "Finn", "rival_female": "Ivy", // Double Names - "blue_red_double": "Blue & Red", - "red_blue_double": "Red & Blue", - "tate_liza_double": "Tate & Liza", - "liza_tate_double": "Liza & Tate", - "steven_wallace_double": "Steven & Wallace", - "wallace_steven_double": "Wallace & Steven", - "alder_iris_double": "Alder & Iris", - "iris_alder_double": "Iris & Alder", - "marnie_piers_double": "Marnie & Piers", - "piers_marnie_double": "Piers & Marnie", + "blue_red_double": "Blu & Rosso", + "red_blue_double": "Rosso & Blu", + "tate_liza_double": "Tell & Pat", + "liza_tate_double": "Pat & Tell", + "steven_wallace_double": "Rocco & Adriano", + "wallace_steven_double": "Adriano & Rocco", + "alder_iris_double": "Nardo & Iris", + "iris_alder_double": "Iris & Nardo", + "marnie_piers_double": "Mary & Ginepro", + "piers_marnie_double": "Ginepro & Mary", } as const; diff --git a/src/locales/it/voucher.ts b/src/locales/it/voucher.ts index f2bcb8d723c..66478283ff9 100644 --- a/src/locales/it/voucher.ts +++ b/src/locales/it/voucher.ts @@ -2,10 +2,10 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const voucher: SimpleTranslationEntries = { "vouchers": "Vouchers", - "eggVoucher": "Egg Voucher", - "eggVoucherPlus": "Egg Voucher Plus", - "eggVoucherPremium": "Egg Voucher Premium", - "eggVoucherGold": "Egg Voucher Gold", - "locked": "Locked", - "defeatTrainer": "Defeat {{trainerName}}" -} as const; + "eggVoucher": "Voucher uovo", + "eggVoucherPlus": "Voucher uovo plus", + "eggVoucherPremium": "Voucher uovo premium", + "eggVoucherGold": "Voucher uovo dorato", + "locked": "Bloccato", + "defeatTrainer": "Sconfiggi {{trainerName}}" +} as const; diff --git a/src/locales/ko/battle.ts b/src/locales/ko/battle.ts index cd81dce400f..d9774bf1c06 100644 --- a/src/locales/ko/battle.ts +++ b/src/locales/ko/battle.ts @@ -62,4 +62,12 @@ export const battle: SimpleTranslationEntries = { "drainMessage": "{{pokemonName}}[[로]]부터\n체력을 흡수했다!", "regainHealth": "{{pokemonName}}[[는]]\n기력을 회복했다!", "fainted": "{{pokemonNameWithAffix}}[[는]] 쓰러졌다!", + "statRose": "상승했다", + "statSharplyRose": "약간 상승했다", + "statRoseDrastically": "대폭 상승했다", + "statWontGoAnyHigher": "더 이상 상승할 수 없다", + "statFell": "떨어졌다", + "statHarshlyFell": "약간 떨어졌다", + "statSeverelyFell": "대폭 떨어졌다", + "statWontGoAnyLower": "더 이상 떨어질 수 없다", } as const; diff --git a/src/locales/ko/modifier-type.ts b/src/locales/ko/modifier-type.ts index d181ca55a25..29b4cd08f32 100644 --- a/src/locales/ko/modifier-type.ts +++ b/src/locales/ko/modifier-type.ts @@ -248,6 +248,19 @@ export const modifierType: ModifierTypeTranslationEntries = { "x_accuracy": "잘-맞히기", "dire_hit": "크리티컬커터", }, + + TempBattleStatBoosterStatName: { + "ATK": "Attack", + "DEF": "Defense", + "SPATK": "Sp. Atk", + "SPDEF": "Sp. Def", + "SPD": "Speed", + "ACC": "Accuracy", + "CRIT": "Critical Hit Ratio", + "EVA": "Evasiveness", + "DEFAULT": "???", + }, + AttackTypeBoosterItem: { "silk_scarf": "실크스카프", "black_belt": "검은띠", diff --git a/src/locales/ko/pokemon-info.ts b/src/locales/ko/pokemon-info.ts index aadc3611692..29041d5b20e 100644 --- a/src/locales/ko/pokemon-info.ts +++ b/src/locales/ko/pokemon-info.ts @@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPDEF": "특수방어", "SPDEFshortened": "특방", "SPD": "스피드", - "SPDshortened": "스피드" + "SPDshortened": "스피드", + "ACC": "명중률", + "EVA": "회피율" }, Type: { diff --git a/src/locales/pt_BR/battle.ts b/src/locales/pt_BR/battle.ts index 3fc8eb1a5d6..72d97f9f1cf 100644 --- a/src/locales/pt_BR/battle.ts +++ b/src/locales/pt_BR/battle.ts @@ -62,4 +62,12 @@ export const battle: SimpleTranslationEntries = { "drainMessage": "{{pokemonName}} teve sua\nenergia drenada!", "regainHealth": "{{pokemonName}} recuperou\npontos de saúde!", "fainted": "{{pokemonNameWithAffix}} desmaiou!", + "statRose": "aumentou", + "statSharplyRose": "aumentou bruscamente", + "statRoseDrastically": "aumentou drasticamente", + "statWontGoAnyHigher": "não vai mais aumentar", + "statFell": "diminuiu", + "statHarshlyFell": "diminuiu duramente", + "statSeverelyFell": "diminuiu severamente", + "statWontGoAnyLower": "não vai mais diminuir", } as const; diff --git a/src/locales/pt_BR/config.ts b/src/locales/pt_BR/config.ts index 7fa3c483926..fd35076a8f1 100644 --- a/src/locales/pt_BR/config.ts +++ b/src/locales/pt_BR/config.ts @@ -27,7 +27,6 @@ import { menuUiHandler } from "./menu-ui-handler"; import { modifierType } from "./modifier-type"; import { move } from "./move"; import { nature } from "./nature"; -import { partyUiHandler } from "./party-ui-handler"; import { pokeball } from "./pokeball"; import { pokemon } from "./pokemon"; import { pokemonInfo } from "./pokemon-info"; @@ -39,6 +38,7 @@ import { titles, trainerClasses, trainerNames } from "./trainers"; import { tutorial } from "./tutorial"; import { voucher } from "./voucher"; import { weather } from "./weather"; +import { partyUiHandler } from "./party-ui-handler"; export const ptBrConfig = { ability: ability, @@ -82,5 +82,5 @@ export const ptBrConfig = { trainerNames: trainerNames, tutorial: tutorial, voucher: voucher, - weather: weather, + weather: weather }; diff --git a/src/locales/pt_BR/modifier-type.ts b/src/locales/pt_BR/modifier-type.ts index b0df31d5f65..a0033434a3d 100644 --- a/src/locales/pt_BR/modifier-type.ts +++ b/src/locales/pt_BR/modifier-type.ts @@ -248,6 +248,19 @@ export const modifierType: ModifierTypeTranslationEntries = { "x_accuracy": "Precisão X", "dire_hit": "Direto", }, + + TempBattleStatBoosterStatName: { + "ATK": "Ataque", + "DEF": "Defesa", + "SPATK": "Ataque Esp.", + "SPDEF": "Defesa Esp.", + "SPD": "Velocidade", + "ACC": "Precisão", + "CRIT": "Chance de Acerto Crítico", + "EVA": "Evasão", + "DEFAULT": "???", + }, + AttackTypeBoosterItem: { "silk_scarf": "Lenço de Seda", "black_belt": "Faixa Preta", diff --git a/src/locales/pt_BR/pokemon-info.ts b/src/locales/pt_BR/pokemon-info.ts index 70b0664f30b..8b37e6e1f74 100644 --- a/src/locales/pt_BR/pokemon-info.ts +++ b/src/locales/pt_BR/pokemon-info.ts @@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPDEF": "Def. Esp.", "SPDEFshortened": "DefEsp", "SPD": "Veloc.", - "SPDshortened": "Veloc." + "SPDshortened": "Veloc.", + "ACC": "Precisão", + "EVA": "Evasão", }, Type: { diff --git a/src/locales/zh_CN/battle.ts b/src/locales/zh_CN/battle.ts index 3b7451f5cde..6d911b7b502 100644 --- a/src/locales/zh_CN/battle.ts +++ b/src/locales/zh_CN/battle.ts @@ -61,5 +61,13 @@ export const battle: SimpleTranslationEntries = { "useMove": "{{pokemonNameWithAffix}} used {{moveName}}!", "drainMessage": "{{pokemonName}} had its\nenergy drained!", "regainHealth": "{{pokemonName}} regained\nhealth!", - "fainted": "{{pokemonNameWithAffix}} fainted!" + "fainted": "{{pokemonNameWithAffix}} fainted!", + "statRose": "rose", + "statSharplyRose": "sharply rose", + "statRoseDrastically": "rose drastically", + "statWontGoAnyHigher": "won't go any higher", + "statFell": "fell", + "statHarshlyFell": "harshly fell", + "statSeverelyFell": "severely fell", + "statWontGoAnyLower": "won't go any lower", } as const; diff --git a/src/locales/zh_CN/modifier-type.ts b/src/locales/zh_CN/modifier-type.ts index 92617e39741..c94c8e4b04f 100644 --- a/src/locales/zh_CN/modifier-type.ts +++ b/src/locales/zh_CN/modifier-type.ts @@ -248,6 +248,19 @@ export const modifierType: ModifierTypeTranslationEntries = { "x_accuracy": "命中强化", "dire_hit": "要害攻击", }, + + TempBattleStatBoosterStatName: { + "ATK": "Attack", + "DEF": "Defense", + "SPATK": "Sp. Atk", + "SPDEF": "Sp. Def", + "SPD": "Speed", + "ACC": "Accuracy", + "CRIT": "Critical Hit Ratio", + "EVA": "Evasiveness", + "DEFAULT": "???", + }, + AttackTypeBoosterItem: { "silk_scarf": "丝绸围巾", "black_belt": "黑带", diff --git a/src/locales/zh_CN/pokemon-info.ts b/src/locales/zh_CN/pokemon-info.ts index 4c12acc3e67..7c72acb1b2a 100644 --- a/src/locales/zh_CN/pokemon-info.ts +++ b/src/locales/zh_CN/pokemon-info.ts @@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPDEF": "特防", "SPDEFshortened": "特防", "SPD": "速度", - "SPDshortened": "速度" + "SPDshortened": "速度", + "ACC": "Accuracy", + "EVA": "Evasiveness" }, Type: { @@ -38,4 +40,4 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "FAIRY": "妖精", "STELLAR": "星晶", }, -} as const; +} as const; diff --git a/src/locales/zh_TW/battle.ts b/src/locales/zh_TW/battle.ts index 086f0cf9266..224a9f2bf0f 100644 --- a/src/locales/zh_TW/battle.ts +++ b/src/locales/zh_TW/battle.ts @@ -58,5 +58,13 @@ export const battle: SimpleTranslationEntries = { "useMove": "{{pokemonNameWithAffix}} used {{moveName}}!", "drainMessage": "{{pokemonName}} had its\nenergy drained!", "regainHealth": "{{pokemonName}} regained\nhealth!", - "fainted": "{{pokemonNameWithAffix}} fainted!" + "fainted": "{{pokemonNameWithAffix}} fainted!", + "statRose": "rose", + "statSharplyRose": "sharply rose", + "statRoseDrastically": "rose drastically", + "statWontGoAnyHigher": "won't go any higher", + "statFell": "fell", + "statHarshlyFell": "harshly fell", + "statSeverelyFell": "severely fell", + "statWontGoAnyLower": "won't go any lower", } as const; diff --git a/src/locales/zh_TW/modifier-type.ts b/src/locales/zh_TW/modifier-type.ts index 2577db69d65..f44c6efef84 100644 --- a/src/locales/zh_TW/modifier-type.ts +++ b/src/locales/zh_TW/modifier-type.ts @@ -306,6 +306,19 @@ export const modifierType: ModifierTypeTranslationEntries = { x_accuracy: "命中強化", dire_hit: "要害攻擊", }, + + TempBattleStatBoosterStatName: { + "ATK": "Attack", + "DEF": "Defense", + "SPATK": "Sp. Atk", + "SPDEF": "Sp. Def", + "SPD": "Speed", + "ACC": "Accuracy", + "CRIT": "Critical Hit Ratio", + "EVA": "Evasiveness", + "DEFAULT": "???", + }, + AttackTypeBoosterItem: { silk_scarf: "絲綢圍巾", black_belt: "黑帶", diff --git a/src/locales/zh_TW/pokemon-info.ts b/src/locales/zh_TW/pokemon-info.ts index 5c00add8081..b1466033f1a 100644 --- a/src/locales/zh_TW/pokemon-info.ts +++ b/src/locales/zh_TW/pokemon-info.ts @@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPDEF": "特殊防禦", "SPDEFshortened": "特防", "SPD": "速度", - "SPDshortened": "速度" + "SPDshortened": "速度", + "ACC": "Accuracy", + "EVA": "Evasiveness" }, Type: { diff --git a/src/phases.ts b/src/phases.ts index 011b0e07f54..ad5819edf30 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -35,7 +35,7 @@ import { TrainerSlot, trainerConfigs } from "./data/trainer-config"; import { EggHatchPhase } from "./egg-hatch-phase"; import { Egg } from "./data/egg"; import { vouchers } from "./system/voucher"; -import { loggedInUser, updateUserInfo } from "./account"; +import { clientSessionId, loggedInUser, updateUserInfo } from "./account"; import { SessionSaveData } from "./system/game-data"; import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims"; import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms"; @@ -2889,7 +2889,7 @@ export class MoveEffectPhase extends PokemonPhase { continue; } - const isProtected = !move.hasFlag(MoveFlags.IGNORE_PROTECT) && target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType)); + const isProtected = !this.move.getMove().checkFlag(MoveFlags.IGNORE_PROTECT, user, target) && target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType)); const firstHit = moveHistoryEntry.result !== MoveResult.SUCCESS; @@ -4198,8 +4198,7 @@ export class GameOverPhase extends BattlePhase { If Offline, execute offlineNewClear(), a localStorage implementation of newClear daily run checks */ if (this.victory) { if (!Utils.isLocal) { - Utils.apiFetch(`savedata/newclear?slot=${this.scene.sessionSlotId}`, true) - .then(response => response.json()) + Utils.apiFetch(`savedata/session/newclear?slot=${this.scene.sessionSlotId}&clientSessionId=${clientSessionId}`, true) .then(response => response.json()) .then(newClear => doGameOver(newClear)); } else { this.scene.gameData.offlineNewClear(this.scene).then(result => { diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index a9a610693a1..9bd288cd676 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -44,6 +44,7 @@ export interface ModifierTypeTranslationEntries { ModifierType: { [key: string]: ModifierTypeTranslationEntry }, AttackTypeBoosterItem: SimpleTranslationEntries, TempBattleStatBoosterItem: SimpleTranslationEntries, + TempBattleStatBoosterStatName: SimpleTranslationEntries, BaseStatBoosterItem: SimpleTranslationEntries, EvolutionItem: SimpleTranslationEntries, FormChangeItem: SimpleTranslationEntries, @@ -96,10 +97,15 @@ const fonts = [ ), ]; -function initFonts() { - fonts.forEach((fontFace: FontFace) => { - fontFace.load().then(f => document.fonts.add(f)).catch(e => console.error(e)); - }); +async function initFonts() { + const results = await Promise.allSettled(fonts.map(font => font.load())); + for (const result of results) { + if (result.status === "fulfilled") { + document.fonts?.add(result.value); + } else { + console.error(result.reason); + } + } } export async function initI18n(): Promise { @@ -109,8 +115,6 @@ export async function initI18n(): Promise { } isInitialized = true; - initFonts(); - /** * i18next is a localization library for maintaining and using translation resources. * @@ -172,6 +176,8 @@ export async function initI18n(): Promise { }, postProcess: ["korean-postposition"], }); + + await initFonts(); } // Module declared to make referencing keys in the localization files type-safe. @@ -222,6 +228,7 @@ declare module "i18next" { tutorial: SimpleTranslationEntries; voucher: SimpleTranslationEntries; weather: SimpleTranslationEntries; + battleStat: SimpleTranslationEntries; }; } } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 119842cb621..9fb253df092 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -313,7 +313,7 @@ export class GameData { localStorage.setItem(`data_${loggedInUser.username}`, encrypt(systemData, bypassLogin)); if (!bypassLogin) { - Utils.apiPost(`savedata/update?datatype=${GameDataType.SYSTEM}&clientSessionId=${clientSessionId}`, systemData, undefined, true) + Utils.apiPost(`savedata/system/update?clientSessionId=${clientSessionId}`, systemData, undefined, true) .then(response => response.text()) .then(error => { this.scene.ui.savingIcon.hide(); @@ -347,7 +347,7 @@ export class GameData { } if (!bypassLogin) { - Utils.apiFetch(`savedata/system?clientSessionId=${clientSessionId}`, true) + Utils.apiFetch(`savedata/system/get?clientSessionId=${clientSessionId}`, true) .then(response => response.text()) .then(response => { if (!response.length || response[0] !== "{") { @@ -545,7 +545,7 @@ export class GameData { return true; } - const response = await Utils.apiPost("savedata/system/verify", JSON.stringify({ clientSessionId: clientSessionId }), undefined, true) + const response = await Utils.apiFetch(`savedata/system/verify?clientSessionId=${clientSessionId}`, true) .then(response => response.json()); if (!response.valid) { @@ -815,7 +815,7 @@ export class GameData { }; if (!bypassLogin && !localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser.username}`)) { - Utils.apiFetch(`savedata/session?slot=${slotId}&clientSessionId=${clientSessionId}`, true) + Utils.apiFetch(`savedata/session/get?slot=${slotId}&clientSessionId=${clientSessionId}`, true) .then(response => response.text()) .then(async response => { if (!response.length || response[0] !== "{") { @@ -963,7 +963,7 @@ export class GameData { if (success !== null && !success) { return resolve(false); } - Utils.apiFetch(`savedata/delete?datatype=${GameDataType.SESSION}&slot=${slotId}&clientSessionId=${clientSessionId}`, true).then(response => { + Utils.apiFetch(`savedata/session/delete?slot=${slotId}&clientSessionId=${clientSessionId}`, true).then(response => { if (response.ok) { loggedInUser.lastSessionSlot = -1; localStorage.removeItem(`sessionData${this.scene.sessionSlotId ? this.scene.sessionSlotId : ""}_${loggedInUser.username}`); @@ -1027,7 +1027,7 @@ export class GameData { return resolve([false, false]); } const sessionData = this.getSessionSaveData(scene); - Utils.apiPost(`savedata/clear?slot=${slotId}&trainerId=${this.trainerId}&secretId=${this.secretId}&clientSessionId=${clientSessionId}`, JSON.stringify(sessionData), undefined, true).then(response => { + Utils.apiPost(`savedata/session/clear?slot=${slotId}&trainerId=${this.trainerId}&secretId=${this.secretId}&clientSessionId=${clientSessionId}`, JSON.stringify(sessionData), undefined, true).then(response => { if (response.ok) { loggedInUser.lastSessionSlot = -1; localStorage.removeItem(`sessionData${this.scene.sessionSlotId ? this.scene.sessionSlotId : ""}_${loggedInUser.username}`); @@ -1184,7 +1184,7 @@ export class GameData { link.remove(); }; if (!bypassLogin && dataType < GameDataType.SETTINGS) { - Utils.apiFetch(`savedata/${dataType === GameDataType.SYSTEM ? "system" : "session"}?clientSessionId=${clientSessionId}${dataType === GameDataType.SESSION ? `&slot=${slotId}` : ""}`, true) + Utils.apiFetch(`savedata/${dataType === GameDataType.SYSTEM ? "system" : "session"}/get?clientSessionId=${clientSessionId}${dataType === GameDataType.SESSION ? `&slot=${slotId}` : ""}`, true) .then(response => response.text()) .then(response => { if (!response.length || response[0] !== "{") { @@ -1264,7 +1264,13 @@ export class GameData { if (!success) { return displayError(`Could not contact the server. Your ${dataName} data could not be imported.`); } - Utils.apiPost(`savedata/update?datatype=${dataType}${dataType === GameDataType.SESSION ? `&slot=${slotId}` : ""}&trainerId=${this.trainerId}&secretId=${this.secretId}&clientSessionId=${clientSessionId}`, dataStr, undefined, true) + let url: string; + if (dataType === GameDataType.SESSION) { + url = `savedata/session/update?slot=${slotId}&trainerId=${this.trainerId}&secretId=${this.secretId}&clientSessionId=${clientSessionId}`; + } else { + url = `savedata/system/update?trainerId=${this.trainerId}&secretId=${this.secretId}&clientSessionId=${clientSessionId}`; + } + Utils.apiPost(url, dataStr, undefined, true) .then(response => response.text()) .then(error => { if (error) { diff --git a/src/test/abilities/unseen_fist.test.ts b/src/test/abilities/unseen_fist.test.ts new file mode 100644 index 00000000000..a799e203f03 --- /dev/null +++ b/src/test/abilities/unseen_fist.test.ts @@ -0,0 +1,91 @@ +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; +import GameManager from "../utils/gameManager"; +import * as Overrides from "#app/overrides"; +import { Species } from "#enums/species"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { getMovePosition } from "../utils/gameManagerUtils"; +import { TurnEndPhase } from "#app/phases.js"; + +const TIMEOUT = 20 * 1000; + +describe("Abilities - Unseen Fist", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(Overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.URSHIFU); + vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX); + vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]); + vi.spyOn(Overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100); + }); + + test( + "ability causes a contact move to ignore Protect", + () => testUnseenFistHitResult(game, Moves.QUICK_ATTACK, Moves.PROTECT, true), + TIMEOUT + ); + + test( + "ability does not cause a non-contact move to ignore Protect", + () => testUnseenFistHitResult(game, Moves.ABSORB, Moves.PROTECT, false), + TIMEOUT + ); + + test( + "ability does not apply if the source has Long Reach", + () => { + vi.spyOn(Overrides, "PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.LONG_REACH); + testUnseenFistHitResult(game, Moves.QUICK_ATTACK, Moves.PROTECT, false); + }, TIMEOUT + ); + + test( + "ability causes a contact move to ignore Wide Guard", + () => testUnseenFistHitResult(game, Moves.BREAKING_SWIPE, Moves.WIDE_GUARD, true), + TIMEOUT + ); + + test( + "ability does not cause a non-contact move to ignore Wide Guard", + () => testUnseenFistHitResult(game, Moves.BULLDOZE, Moves.WIDE_GUARD, false), + TIMEOUT + ); +}); + +async function testUnseenFistHitResult(game: GameManager, attackMove: Moves, protectMove: Moves, shouldSucceed: boolean = true): Promise { + vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([attackMove]); + vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([protectMove, protectMove, protectMove, protectMove]); + + await game.startBattle(); + + const leadPokemon = game.scene.getPlayerPokemon(); + expect(leadPokemon).not.toBe(undefined); + + const enemyPokemon = game.scene.getEnemyPokemon(); + expect(enemyPokemon).not.toBe(undefined); + + const enemyStartingHp = enemyPokemon.hp; + + game.doAttack(getMovePosition(game.scene, 0, attackMove)); + await game.phaseInterceptor.to(TurnEndPhase); + + if (shouldSucceed) { + expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp); + } else { + expect(enemyPokemon.hp).toBe(enemyStartingHp); + } +} diff --git a/src/test/lokalisation/battle-stat.test.ts b/src/test/lokalisation/battle-stat.test.ts new file mode 100644 index 00000000000..99269c6ec4c --- /dev/null +++ b/src/test/lokalisation/battle-stat.test.ts @@ -0,0 +1,205 @@ +import {beforeAll, describe, expect, it} from "vitest"; +import { getBattleStatName, getBattleStatLevelChangeDescription } from "#app/data/battle-stat.js"; +import { BattleStat } from "#app/data/battle-stat.js"; +import { pokemonInfo as enPokemonInfo } from "#app/locales/en/pokemon-info.js"; +import { battle as enBattleStat } from "#app/locales/en/battle.js"; +import { pokemonInfo as dePokemonInfo } from "#app/locales/de/pokemon-info.js"; +import { battle as deBattleStat } from "#app/locales/de/battle.js"; +import { pokemonInfo as esPokemonInfo } from "#app/locales/es/pokemon-info.js"; +import { battle as esBattleStat } from "#app/locales/es/battle.js"; +import { pokemonInfo as frPokemonInfo } from "#app/locales/fr/pokemon-info.js"; +import { battle as frBattleStat } from "#app/locales/fr/battle.js"; +import { pokemonInfo as itPokemonInfo } from "#app/locales/it/pokemon-info.js"; +import { battle as itBattleStat } from "#app/locales/it/battle.js"; +import { pokemonInfo as koPokemonInfo } from "#app/locales/ko/pokemon-info.js"; +import { battle as koBattleStat } from "#app/locales/ko/battle.js"; +import { pokemonInfo as ptBrPokemonInfo } from "#app/locales/pt_BR/pokemon-info.js"; +import { battle as ptBrBattleStat } from "#app/locales/pt_BR/battle.js"; +import { pokemonInfo as zhCnPokemonInfo } from "#app/locales/zh_CN/pokemon-info.js"; +import { battle as zhCnBattleStat } from "#app/locales/zh_CN/battle.js"; +import { pokemonInfo as zhTwPokemonInfo } from "#app/locales/zh_TW/pokemon-info.js"; +import { battle as zhTwBattleStat } from "#app/locales/zh_TW/battle.js"; + +import i18next, {initI18n} from "#app/plugins/i18n"; + +interface BattleStatTestUnit { + stat: BattleStat, + key: string +} + +interface BattleStatLevelTestUnit { + levels: integer, + up: boolean, + key: string +} + +function testBattleStatName(stat: BattleStat, expectMessage: string) { + const message = getBattleStatName(stat); + console.log(`message ${message}, expected ${expectMessage}`); + expect(message).toBe(expectMessage); +} + +function testBattleStatLevelChangeDescription(levels: integer, up: boolean, expectMessage: string) { + const message = getBattleStatLevelChangeDescription(levels, up); + console.log(`message ${message}, expected ${expectMessage}`); + expect(message).toBe(expectMessage); +} + +describe("Test for BattleStat Localization", () => { + const battleStatUnits: BattleStatTestUnit[] = []; + const battleStatLevelUnits: BattleStatLevelTestUnit[] = []; + + beforeAll(() => { + initI18n(); + + battleStatUnits.push({ stat: BattleStat.ATK, key: "Stat.ATK" }); + battleStatUnits.push({ stat: BattleStat.DEF, key: "Stat.DEF" }); + battleStatUnits.push({ stat: BattleStat.SPATK, key: "Stat.SPATK" }); + battleStatUnits.push({ stat: BattleStat.SPDEF, key: "Stat.SPDEF" }); + battleStatUnits.push({ stat: BattleStat.SPD, key: "Stat.SPD" }); + battleStatUnits.push({ stat: BattleStat.ACC, key: "Stat.ACC" }); + battleStatUnits.push({ stat: BattleStat.EVA, key: "Stat.EVA" }); + + battleStatLevelUnits.push({ levels: 1, up: true, key: "statRose" }); + battleStatLevelUnits.push({ levels: 2, up: true, key: "statSharplyRose" }); + battleStatLevelUnits.push({ levels: 3, up: true, key: "statRoseDrastically" }); + battleStatLevelUnits.push({ levels: 4, up: true, key: "statRoseDrastically" }); + battleStatLevelUnits.push({ levels: 5, up: true, key: "statRoseDrastically" }); + battleStatLevelUnits.push({ levels: 6, up: true, key: "statRoseDrastically" }); + battleStatLevelUnits.push({ levels: 7, up: true, key: "statWontGoAnyHigher" }); + battleStatLevelUnits.push({ levels: 1, up: false, key: "statFell" }); + battleStatLevelUnits.push({ levels: 2, up: false, key: "statHarshlyFell" }); + battleStatLevelUnits.push({ levels: 3, up: false, key: "statSeverelyFell" }); + battleStatLevelUnits.push({ levels: 4, up: false, key: "statSeverelyFell" }); + battleStatLevelUnits.push({ levels: 5, up: false, key: "statSeverelyFell" }); + battleStatLevelUnits.push({ levels: 6, up: false, key: "statSeverelyFell" }); + battleStatLevelUnits.push({ levels: 7, up: false, key: "statWontGoAnyLower" }); + }); + + it("Test getBattleStatName() in English", async () => { + i18next.changeLanguage("en"); + battleStatUnits.forEach(unit => { + testBattleStatName(unit.stat, enPokemonInfo[unit.key.split(".")[0]][unit.key.split(".")[1]]); + }); + }); + + it("Test getBattleStatLevelChangeDescription() in English", async () => { + i18next.changeLanguage("en"); + battleStatLevelUnits.forEach(unit => { + testBattleStatLevelChangeDescription(unit.levels, unit.up, enBattleStat[unit.key]); + }); + }); + + it("Test getBattleStatName() in Español", async () => { + i18next.changeLanguage("es"); + battleStatUnits.forEach(unit => { + testBattleStatName(unit.stat, esPokemonInfo[unit.key.split(".")[0]][unit.key.split(".")[1]]); + }); + }); + + it("Test getBattleStatLevelChangeDescription() in Español", async () => { + i18next.changeLanguage("es"); + battleStatLevelUnits.forEach(unit => { + testBattleStatLevelChangeDescription(unit.levels, unit.up, esBattleStat[unit.key]); + }); + }); + + it("Test getBattleStatName() in Italiano", async () => { + i18next.changeLanguage("it"); + battleStatUnits.forEach(unit => { + testBattleStatName(unit.stat, itPokemonInfo[unit.key.split(".")[0]][unit.key.split(".")[1]]); + }); + }); + + it("Test getBattleStatLevelChangeDescription() in Italiano", async () => { + i18next.changeLanguage("it"); + battleStatLevelUnits.forEach(unit => { + testBattleStatLevelChangeDescription(unit.levels, unit.up, itBattleStat[unit.key]); + }); + }); + + it("Test getBattleStatName() in Français", async () => { + i18next.changeLanguage("fr"); + battleStatUnits.forEach(unit => { + testBattleStatName(unit.stat, frPokemonInfo[unit.key.split(".")[0]][unit.key.split(".")[1]]); + }); + }); + + it("Test getBattleStatLevelChangeDescription() in Français", async () => { + i18next.changeLanguage("fr"); + battleStatLevelUnits.forEach(unit => { + testBattleStatLevelChangeDescription(unit.levels, unit.up, frBattleStat[unit.key]); + }); + }); + + it("Test getBattleStatName() in Deutsch", async () => { + i18next.changeLanguage("de"); + battleStatUnits.forEach(unit => { + testBattleStatName(unit.stat, dePokemonInfo[unit.key.split(".")[0]][unit.key.split(".")[1]]); + }); + }); + + it("Test getBattleStatLevelChangeDescription() in Deutsch", async () => { + i18next.changeLanguage("de"); + battleStatLevelUnits.forEach(unit => { + testBattleStatLevelChangeDescription(unit.levels, unit.up, deBattleStat[unit.key]); + }); + }); + + it("Test getBattleStatName() in Português (BR)", async () => { + i18next.changeLanguage("pt-BR"); + battleStatUnits.forEach(unit => { + testBattleStatName(unit.stat, ptBrPokemonInfo[unit.key.split(".")[0]][unit.key.split(".")[1]]); + }); + }); + + it("Test getBattleStatLevelChangeDescription() in Português (BR)", async () => { + i18next.changeLanguage("pt-BR"); + battleStatLevelUnits.forEach(unit => { + testBattleStatLevelChangeDescription(unit.levels, unit.up, ptBrBattleStat[unit.key]); + }); + }); + + it("Test getBattleStatName() in 简体中文", async () => { + i18next.changeLanguage("zh-CN"); + battleStatUnits.forEach(unit => { + testBattleStatName(unit.stat, zhCnPokemonInfo[unit.key.split(".")[0]][unit.key.split(".")[1]]); + }); + }); + + it("Test getBattleStatLevelChangeDescription() in 简体中文", async () => { + i18next.changeLanguage("zh-CN"); + battleStatLevelUnits.forEach(unit => { + testBattleStatLevelChangeDescription(unit.levels, unit.up, zhCnBattleStat[unit.key]); + }); + }); + + it("Test getBattleStatName() in 繁體中文", async () => { + i18next.changeLanguage("zh-TW"); + battleStatUnits.forEach(unit => { + testBattleStatName(unit.stat, zhTwPokemonInfo[unit.key.split(".")[0]][unit.key.split(".")[1]]); + }); + }); + + it("Test getBattleStatLevelChangeDescription() in 繁體中文", async () => { + i18next.changeLanguage("zh-TW"); + battleStatLevelUnits.forEach(unit => { + testBattleStatLevelChangeDescription(unit.levels, unit.up, zhTwBattleStat[unit.key]); + }); + }); + + it("Test getBattleStatName() in 한국어", async () => { + await i18next.changeLanguage("ko"); + battleStatUnits.forEach(unit => { + testBattleStatName(unit.stat, koPokemonInfo[unit.key.split(".")[0]][unit.key.split(".")[1]]); + }); + }); + + it("Test getBattleStatLevelChangeDescription() in 한국어", async () => { + i18next.changeLanguage("ko", () => { + battleStatLevelUnits.forEach(unit => { + testBattleStatLevelChangeDescription(unit.levels, unit.up, koBattleStat[unit.key]); + }); + }); + }); +}); diff --git a/src/test/vitest.setup.ts b/src/test/vitest.setup.ts index 29af5b034b2..2caa82289d9 100644 --- a/src/test/vitest.setup.ts +++ b/src/test/vitest.setup.ts @@ -1,16 +1,19 @@ -import "vitest-canvas-mock"; import "#app/test/fontFace.setup"; -import {initStatsKeys} from "#app/ui/game-stats-ui-handler"; -import {initPokemonPrevolutions} from "#app/data/pokemon-evolutions"; -import {initBiomes} from "#app/data/biomes"; -import {initEggMoves} from "#app/data/egg-moves"; -import {initPokemonForms} from "#app/data/pokemon-forms"; -import {initSpecies} from "#app/data/pokemon-species"; -import {initMoves} from "#app/data/move"; -import {initAbilities} from "#app/data/ability"; -import {initAchievements} from "#app/system/achv.js"; +import "vitest-canvas-mock"; + +import { initLoggedInUser } from "#app/account"; +import { initAbilities } from "#app/data/ability"; +import { initBiomes } from "#app/data/biomes"; +import { initEggMoves } from "#app/data/egg-moves"; +import { initMoves } from "#app/data/move"; +import { initPokemonPrevolutions } from "#app/data/pokemon-evolutions"; +import { initPokemonForms } from "#app/data/pokemon-forms"; +import { initSpecies } from "#app/data/pokemon-species"; +import { initAchievements } from "#app/system/achv.js"; import { initVouchers } from "#app/system/voucher.js"; -import {initLoggedInUser} from "#app/account"; +import { initStatsKeys } from "#app/ui/game-stats-ui-handler"; + +import { beforeAll } from "vitest"; initVouchers(); initAchievements(); @@ -25,3 +28,12 @@ initAbilities(); initLoggedInUser(); global.testFailed = false; + +beforeAll(() => { + Object.defineProperty(document, "fonts", { + writable: true, + value: { + add: () => {}, + } + }); +}); diff --git a/src/ui/egg-counter-container.ts b/src/ui/egg-counter-container.ts index 1c5779ef777..a688b8b7efc 100644 --- a/src/ui/egg-counter-container.ts +++ b/src/ui/egg-counter-container.ts @@ -17,7 +17,7 @@ export default class EggCounterContainer extends Phaser.GameObjects.Container { private battleScene: BattleScene; private eggCount: integer; private eggCountWindow: Phaser.GameObjects.NineSlice; - private eggCountText: Phaser.GameObjects.Text; + public eggCountText: Phaser.GameObjects.Text; /** * @param {BattleScene} scene - The scene to which this container belongs. @@ -49,6 +49,7 @@ export default class EggCounterContainer extends Phaser.GameObjects.Container { eggSprite.setScale(0.32); this.eggCountText = addTextObject(this.battleScene, 28, 13, `${this.eggCount}`, TextStyle.MESSAGE, { fontSize: "66px" }); + this.eggCountText.setName("text-egg-count"); this.add(eggSprite); this.add(this.eggCountText); @@ -69,7 +70,7 @@ export default class EggCounterContainer extends Phaser.GameObjects.Container { */ private onEggCountChanged(event: Event): void { const eggCountChangedEvent = event as EggCountChangedEvent; - if (!eggCountChangedEvent) { + if (!eggCountChangedEvent || !this.eggCountText?.data) { return; } diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 2c114ec3e8d..0aa71de7e90 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -787,6 +787,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.starterSelectContainer.setVisible(true); + this.setCursor(0); this.setGenMode(false); this.setCursor(0); this.setGenMode(true); diff --git a/tsconfig.json b/tsconfig.json index 2df676d8433..353abd27d4f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,8 +20,14 @@ "noEmit": true }, "typedocOptions": { - "entryPoints": ["src/"], + "entryPoints": ["src/"], "entryPointStrategy": "expand", - "out": "typedoc", - } + "out": "typedoc", + }, + "exclude": [ + "node_modules", + "dist", + "vite.config.ts", + "vitest.config.ts" + ] } \ No newline at end of file diff --git a/vite.config.js b/vite.config.js deleted file mode 100644 index d0fff2e428b..00000000000 --- a/vite.config.js +++ /dev/null @@ -1,34 +0,0 @@ -import { resolve } from 'path'; -import { defineConfig } from 'vite'; -import tsconfigPaths from 'vite-tsconfig-paths'; -// import fs from 'vite-plugin-fs'; - -export default defineConfig(({ mode }) => { - return { - plugins: [tsconfigPaths()], - server: { host: '0.0.0.0', port: 8000 }, - clearScreen: false, - build: { - minify: 'esbuild', - sourcemap: false, - }, - rollupOptions: { - onwarn(warning, warn) { - // Suppress "Module level directives cause errors when bundled" warnings - if (warning.code === "MODULE_LEVEL_DIRECTIVE") { - return; - } - warn(warning); - }, - }, - resolve: { - alias: { - "#enums": resolve('./src/enums') - } - }, - esbuild: { - pure: mode === 'production' ? [ 'console.log' ] : [], - keepNames: true, - }, - } -}) diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 00000000000..f0830f5b9be --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,30 @@ +import { defineConfig } from 'vite'; +import tsconfigPaths from 'vite-tsconfig-paths'; + +export const defaultConfig = { + plugins: [tsconfigPaths() as any], + server: { host: '0.0.0.0', port: 8000 }, + clearScreen: false, + build: { + minify: 'esbuild' as const, + sourcemap: false, + }, + rollupOptions: { + onwarn(warning, warn) { + // Suppress "Module level directives cause errors when bundled" warnings + if (warning.code === "MODULE_LEVEL_DIRECTIVE") { + return; + } + warn(warning); + }, + } +}; + + +export default defineConfig(({mode}) => ({ + ...defaultConfig, + esbuild: { + pure: mode === 'production' ? [ 'console.log' ] : [], + keepNames: true, + }, +})); diff --git a/vitest.config.js b/vitest.config.js deleted file mode 100644 index d68ce4d52fe..00000000000 --- a/vitest.config.js +++ /dev/null @@ -1,48 +0,0 @@ -import { defineConfig } from 'vite'; -import path from 'path'; -// import fs from 'vite-plugin-fs'; - -export default defineConfig(({ mode }) => { - return { - test: { - setupFiles: ['./src/test/vitest.setup.ts'], - environment: 'jsdom', - deps: { - optimizer: { - web: { - include: ['vitest-canvas-mock'], - } - } - }, - threads: false, - trace: true, - restoreMocks: true, - environmentOptions: { - jsdom: { - resources: 'usable', - }, - }, - coverage: { - provider: 'istanbul', - reportsDirectory: 'coverage', - reporters: ['text-summary', 'html'], - }, - }, - plugins: [/*fs()*/], - server: { host: '0.0.0.0', port: 8000 }, - clearScreen: false, - build: { - minify: 'esbuild', - sourcemap: true - }, - resolve: { - alias: { - "#enums": path.resolve('./src/enums') - } - }, - esbuild: { - pure: mode === 'production' ? [ 'console.log' ] : [], - keepNames: true, - }, - } -}) diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000000..7f16059a8ad --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,38 @@ +import { defineConfig } from 'vitest/config'; +import { defaultConfig } from './vite.config'; + +export default defineConfig(({mode}) => ({ + ...defaultConfig, + test: { + setupFiles: ['./src/test/vitest.setup.ts'], + server: { + deps: { + inline: ['vitest-canvas-mock'], + optimizer: { + web: { + include: ['vitest-canvas-mock'], + } + } + } + }, + environment: 'jsdom' as const, + environmentOptions: { + jsdom: { + resources: 'usable', + }, + }, + threads: false, + trace: true, + restoreMocks: true, + watch: false, + coverage: { + provider: 'istanbul' as const, + reportsDirectory: 'coverage' as const, + reporters: ['text-summary', 'html'], + }, + }, + esbuild: { + pure: mode === 'production' ? [ 'console.log' ] : [], + keepNames: true, + }, +}))