Merge branch 'pagefaultgames:main' into flingImplementation

This commit is contained in:
AyushBarik 2024-06-16 22:28:38 +05:30 committed by GitHub
commit cb3da4cc4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
62 changed files with 2140 additions and 528 deletions

384
.dependency-cruiser.cjs Normal file
View File

@ -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

1
.gitignore vendored
View File

@ -39,3 +39,4 @@ coverage
# Local Documentation
/typedoc
/dependency-graph.svg

13
dependency-graph.js Normal file
View File

@ -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);

717
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -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)

View File

@ -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");
}
}
}

View File

@ -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)

View File

@ -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<boolean> {
return new Promise<boolean>(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(),

View File

@ -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);
}

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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",

View File

@ -14,6 +14,8 @@ export const pokemonInfo: PokemonInfoTranslationEntries = {
"SPDEFshortened": "SpVert",
"SPD": "Initiative",
"SPDshortened": "Init",
"ACC": "Accuracy",
"EVA": "Evasiveness"
},
Type: {

View File

@ -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;

View File

@ -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",

View File

@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = {
"SPDEF": "Sp. Def",
"SPDEFshortened": "SpDef",
"SPD": "Speed",
"SPDshortened": "Spd"
"SPDshortened": "Spd",
"ACC": "Accuracy",
"EVA": "Evasiveness"
},
Type: {

View File

@ -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;

View File

@ -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",

View File

@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = {
"SPDEF": "Def. Esp.",
"SPDEFshortened": "DefEsp",
"SPD": "Velocidad",
"SPDshortened": "Veloc."
"SPDshortened": "Veloc.",
"ACC": "Accuracy",
"EVA": "Evasiveness"
},
Type: {

View File

@ -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;

View File

@ -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",

View File

@ -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: {

View File

@ -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;

View File

@ -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",

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = {
"SPDEF": "Dif. Sp.",
"SPDEFshortened": "DifSp",
"SPD": "Velocità",
"SPDshortened": "Vel"
"SPDshortened": "Vel",
"ACC": "Precisione",
"EVA": "Elusione"
},
Type: {

View File

@ -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;

View File

@ -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!",

View File

@ -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": "",
"gen2": "",
"gen3": "",
"gen4": "",
"gen5": "",
"gen6": "",
"gen7": "",
"gen8": "",
"gen9": "",
"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"
};

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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": "검은띠",

View File

@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = {
"SPDEF": "특수방어",
"SPDEFshortened": "특방",
"SPD": "스피드",
"SPDshortened": "스피드"
"SPDshortened": "스피드",
"ACC": "명중률",
"EVA": "회피율"
},
Type: {

View File

@ -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;

View File

@ -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
};

View File

@ -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",

View File

@ -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: {

View File

@ -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;

View File

@ -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": "黑带",

View File

@ -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;

View File

@ -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;

View File

@ -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: "黑帶",

View File

@ -13,7 +13,9 @@ export const pokemonInfo: PokemonInfoTranslationEntries = {
"SPDEF": "特殊防禦",
"SPDEFshortened": "特防",
"SPD": "速度",
"SPDshortened": "速度"
"SPDshortened": "速度",
"ACC": "Accuracy",
"EVA": "Evasiveness"
},
Type: {

View File

@ -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 => {

View File

@ -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<void> {
@ -109,8 +115,6 @@ export async function initI18n(): Promise<void> {
}
isInitialized = true;
initFonts();
/**
* i18next is a localization library for maintaining and using translation resources.
*
@ -172,6 +176,8 @@ export async function initI18n(): Promise<void> {
},
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;
};
}
}

View File

@ -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) {

View File

@ -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<void> {
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);
}
}

View File

@ -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]);
});
});
});
});

View File

@ -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: () => {},
}
});
});

View File

@ -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;
}

View File

@ -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);

View File

@ -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"
]
}

View File

@ -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,
},
}
})

30
vite.config.ts Normal file
View File

@ -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,
},
}));

View File

@ -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,
},
}
})

38
vitest.config.ts Normal file
View File

@ -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,
},
}))