diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 032e1fee69c..a25a2f807f3 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -65,7 +65,7 @@ Do the reviewers need to do something special in order to test your changes? - [ ] The PR is self-contained and cannot be split into smaller PRs? - [ ] Have I provided a clear explanation of the changes? - [ ] Have I tested the changes manually? -- [ ] Are all unit tests still passing? (`npm run test`) +- [ ] Are all unit tests still passing? (`npm run test:silent`) - [ ] Have I created new automated tests (`npm run create-test`) or updated existing tests related to the PR's changes? - [ ] Have I provided screenshots/videos of the changes (if applicable)? - [ ] Have I made sure that any UI change works for both UI themes (default and legacy)? diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 00000000000..35a31f6b4d1 --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,73 @@ +name: Create Release Branch +on: + workflow_dispatch: + inputs: + versionName: + description: "Name of version (i.e. 1.9.0)" + type: string + required: true + confirmVersion: + type: string + required: true + description: "Confirm version name" + +# explicitly specify the necessary scopes +permissions: + pull-requests: write + actions: write + contents: write + +jobs: + create-release: + if: github.repository == 'pagefaultgames/pokerogue' && (vars.BETA_DEPLOY_BRANCH == '' || ! startsWith(vars.BETA_DEPLOY_BRANCH, 'release')) + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed for github cli commands + runs-on: ubuntu-latest + steps: + - name: Validate provided version + # Ensure version matches confirmation and conforms to expected pattern. + run: | + if [[ "${{ github.event.inputs.versionName }}" != "${{ github.event.inputs.confirmVersion }}" ]]; then + echo "Version name does not match confirmation. Exiting." + exit 1 + fi + if [[ ! "${{ github.event.inputs.versionName }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Version name must follow the format X.Y.Z where X, Y, and Z are all numbers. Exiting..." + exit 1 + fi + shell: bash + - name: Check out code + uses: actions/checkout@v4 + with: + submodules: "recursive" + # Always base off of beta branch, regardless of the branch the workflow was triggered from. + ref: beta + - name: Create release branch + run: git checkout -b release + # In order to be able to open a PR into beta, we need the branch to have at least one change. + - name: Overwrite RELEASE file + run: | + git config --local user.name "github-actions[bot]" + git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" + echo "Release v${{ github.event.inputs.versionName }}" > RELEASE + git add RELEASE + git commit -m "Stage release v${{ github.event.inputs.versionName }}" + - name: Push new branch + run: git push origin release + # The repository variable is used by the deploy-beta workflow to determine whether to deploy from beta or release. + - name: Set repository variable + run: GITHUB_TOKEN="${{ secrets.RW_VARS_PAT }}" gh variable set BETA_DEPLOY_BRANCH --body "release" + - name: Create pull request to main + run: | + gh pr create --base main \ + --head release \ + --title "Release v${{ github.event.inputs.versionName }} to main" \ + --body "This PR is for the release of v${{ github.event.inputs.versionName }}, and was created automatically by the GitHub Actions workflow invoked by ${{ github.actor }}" \ + --draft + - name: Create pull request to beta + run: | + gh pr create --base beta \ + --head release \ + --title "Release v${{ github.event.inputs.versionName }} to beta" \ + --body "This PR is for the release of v${{ github.event.inputs.versionName }}, and was created automatically by the GitHub Actions workflow invoked by ${{ github.actor }}" \ + --draft diff --git a/.github/workflows/deploy-beta.yml b/.github/workflows/deploy-beta.yml index d8d8126193d..90b3008c8e9 100644 --- a/.github/workflows/deploy-beta.yml +++ b/.github/workflows/deploy-beta.yml @@ -4,18 +4,23 @@ on: push: branches: - beta + - release + workflow_run: + types: completed + workflows: ["Post Release Deleted"] jobs: deploy: - if: github.repository == 'pagefaultgames/pokerogue' + if: github.repository == 'pagefaultgames/pokerogue' && github.ref_name == ${{ vars.BETA_DEPLOY_BRANCH || 'beta' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: - submodules: 'recursive' + submodules: "recursive" + ref: ${{ vars.BETA_DEPLOY_BRANCH || 'beta'}} - uses: actions/setup-node@v4 with: - node-version: "20" + node-version-file: ".nvmrc" - name: Install dependencies run: npm ci - name: Build @@ -30,5 +35,5 @@ jobs: chmod 600 ~/.ssh/* ssh-keyscan -H ${{ secrets.BETA_SSH_HOST }} >> ~/.ssh/known_hosts - name: Deploy build on server - run: | - rsync --del --no-times --checksum -vrm dist/* ${{ secrets.BETA_SSH_USER }}@${{ secrets.BETA_SSH_HOST }}:${{ secrets.BETA_DESTINATION_DIR }} \ No newline at end of file + run: | + rsync --del --no-times --checksum -vrm dist/* ${{ secrets.BETA_SSH_USER }}@${{ secrets.BETA_SSH_HOST }}:${{ secrets.BETA_DESTINATION_DIR }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e40b18eb69b..00190e477d5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,7 +18,7 @@ jobs: submodules: 'recursive' - uses: actions/setup-node@v4 with: - node-version: "20" + node-version-file: '.nvmrc' - name: Install dependencies run: npm ci - name: Build diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 58067ac81ac..ce7c17e2db9 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository for Typedoc - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: 'recursive' path: pokerogue_docs @@ -34,14 +34,14 @@ jobs: sudo apt update sudo apt install -y git openssh-client - - name: Setup Node 20.13.1 - uses: actions/setup-node@v1 + - name: Setup Node 22.14.1 + uses: actions/setup-node@v4 with: - node-version: 20 + node-version-file: "pokerogue_docs/.nvmrc" - name: Checkout repository for Github Pages if: github.event_name == 'push' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: pokerogue_gh ref: gh-pages diff --git a/.github/workflows/post-release-deleted.yml b/.github/workflows/post-release-deleted.yml new file mode 100644 index 00000000000..65447e7826b --- /dev/null +++ b/.github/workflows/post-release-deleted.yml @@ -0,0 +1,12 @@ +name: Post Release Deleted +on: + delete: + +jobs: + # Set the BETA_DEPLOY_BRANCH variable to beta when a release branch is deleted + update-release-var: + if: github.repository == 'pagefaultgames/pokerogue' && github.event.ref_type == 'branch' && github.event.ref == 'release' + runs-on: ubuntu-latest + steps: + - name: Set BETA_DEPLOY_BRANCH to beta + run: GITHUB_TOKEN="${{ secrets.RW_VARS_PAT }}" gh variable set BETA_DEPLOY_BRANCH --body "beta" --repo "pagefaultgames/pokerogue" \ No newline at end of file diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 7e33a77a73a..d9592662998 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -29,6 +29,7 @@ jobs: uses: actions/setup-node@v4 # Use the setup-node action version 4 with: node-version-file: '.nvmrc' + cache: 'npm' - name: Install Node.js dependencies # Step to install Node.js dependencies run: npm ci # Use 'npm ci' to install dependencies diff --git a/.github/workflows/test-shard-template.yml b/.github/workflows/test-shard-template.yml index 9fc41d1b965..cee452f3a59 100644 --- a/.github/workflows/test-shard-template.yml +++ b/.github/workflows/test-shard-template.yml @@ -19,13 +19,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out Git repository - uses: actions/checkout@v4 + uses: actions/checkout@v4.2.2 with: submodules: 'recursive' - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version-file: '.nvmrc' + cache: 'npm' - name: Install Node.js dependencies run: npm ci - name: Run tests diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 167a108e58c..d9db8401f8e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,18 +5,60 @@ on: # but only for the main branch push: branches: - - main # Trigger on push events to the main branch + - main # Trigger on push events to the main branch - beta # Trigger on push events to the beta branch + - release # Trigger on push events to the release branch + # go upvote https://github.com/actions/runner/issues/1182 and yell at microsoft until they fix this or ditch yml for workflows + paths: + # src and test files + - "src/**" + - "test/**" + - "public/**" + # Workflows that can impact tests + - ".github/workflows/test*.yml" + # top-level files + - "package*.json" + - ".nvrmc" # Updates to node version can break tests + - "vite.*.ts" # vite.config.ts, vite.vitest.config.ts, vitest.workspace.ts + - "tsconfig*.json" # tsconfig.json tweaking can impact compilation + - "global.d.ts" + - ".env.*" + # Blanket negations for files that cannot impact tests + - "!**/*.py" # No .py files + - "!**/*.sh" # No .sh files + - "!**/*.md" # No .md files + - "!**/.git*" # .gitkeep and family + pull_request: branches: - - main # Trigger on pull request events targeting the main branch + - main # Trigger on pull request events targeting the main branch - beta # Trigger on pull request events targeting the beta branch + - release # Trigger on pull request events targeting the release branch + paths: # go upvote https://github.com/actions/runner/issues/1182 and yell at microsoft because until then we have to duplicate this + # src and test files + - "src/**" + - "test/**" + - "public/**" + # Workflows that can impact tests + - ".github/workflows/test*.yml" + # top-level files + - "package*.json" + - ".nvrmc" # Updates to node version can break tests + - "vite*" # vite.config.ts, vite.vitest.config.ts, vitest.workspace.ts + - "tsconfig*.json" # tsconfig.json tweaking can impact compilation + - "global.d.ts" + - ".env.*" + # Blanket negations for files that cannot impact tests + - "!**/*.py" # No .py files + - "!**/*.sh" # No .sh files + - "!**/*.md" # No .md files + - "!**/.git*" # .gitkeep and family merge_group: types: [checks_requested] jobs: run-tests: - name: Run Tests + name: Run Tests strategy: matrix: shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] @@ -24,4 +66,4 @@ jobs: with: project: main shard: ${{ matrix.shard }} - totalShards: 10 \ No newline at end of file + totalShards: 10 diff --git a/.gitignore b/.gitignore index 9d96ed04a15..00df0002e01 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,8 @@ dist-ssr *.local # Editor directories and files -.vscode/* +.vscode +*.code-workspace .idea .DS_Store *.suo diff --git a/.nvmrc b/.nvmrc index 9bcccb9439d..517f38666b4 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20.13.1 +v22.14.0 diff --git a/README.md b/README.md index 5bb3ecfd26f..56392808b3c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ If you have the motivation and experience with Typescript/Javascript (or are wil #### Prerequisites -- node: 20.13.1 +- node: 22.14.0 - npm: [how to install](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) #### Running Locally diff --git a/biome.jsonc b/biome.jsonc index c5e1d713d86..3385614635c 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -31,13 +31,16 @@ "src/overrides.ts", // TODO: these files are too big and complex, ignore them until their respective refactors "src/data/moves/move.ts", - "src/data/ability.ts", + "src/data/abilities/ability.ts", "src/field/pokemon.ts", // this file is just too big: "src/data/balance/tms.ts" ] }, + + // While it'd be nice to enable consistent sorting, enabling this causes issues due to circular import resolution order + // TODO: Remove if we ever get down to 0 circular imports "organizeImports": { "enabled": false }, "linter": { "ignore": [ @@ -55,31 +58,35 @@ }, "style": { "noVar": "error", - "useEnumInitializers": "off", + "useEnumInitializers": "off", // large enums like Moves/Species would make this cumbersome "useBlockStatements": "error", "useConst": "error", "useImportType": "error", - "noNonNullAssertion": "off", // TODO: Turn this on ASAP and fix all non-null assertions + "noNonNullAssertion": "off", // TODO: Turn this on ASAP and fix all non-null assertions in non-test files "noParameterAssign": "off", - "useExponentiationOperator": "off", + "useExponentiationOperator": "off", // Too typo-prone and easy to mixup with standard multiplication (* vs **) "useDefaultParameterLast": "off", // TODO: Fix spots in the codebase where this flag would be triggered, and then enable "useSingleVarDeclarator": "off", "useNodejsImportProtocol": "off", - "useTemplate": "off" // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation + "useTemplate": "off", // string concatenation is faster: https://stackoverflow.com/questions/29055518/are-es6-template-literals-faster-than-string-concatenation + "noNamespaceImport": "error" }, "suspicious": { "noDoubleEquals": "error", + // While this would be a nice rule to enable, the current structure of the codebase makes this infeasible + // due to being used for move/ability `args` params and save data-related code. + // This can likely be enabled for all non-utils files once these are eventually reworked, but until then we leave it off. "noExplicitAny": "off", "noAssignInExpressions": "off", "noPrototypeBuiltins": "off", - "noFallthroughSwitchClause": "off", - "noImplicitAnyLet": "info", // TODO: Refactor and make this an error - "noRedeclare": "off", // TODO: Refactor and make this an error + "noFallthroughSwitchClause": "error", // Prevents accidental automatic fallthroughs in switch cases (use disable comment if needed) + "noImplicitAnyLet": "warn", // TODO: Refactor and make this an error + "noRedeclare": "info", // TODO: Refactor and make this an error "noGlobalIsNan": "off", "noAsyncPromiseExecutor": "warn" // TODO: Refactor and make this an error }, "complexity": { - "noExcessiveCognitiveComplexity": "warn", + "noExcessiveCognitiveComplexity": "warn", // TODO: Refactor and make this an error "useLiteralKeys": "off", "noForEach": "off", // Foreach vs for of is not that simple. "noUselessSwitchCase": "off", // Explicit > Implicit @@ -98,7 +105,10 @@ "linter": { "rules": { "performance": { - "noDelete": "off" + "noDelete": "off" // TODO: evaluate if this is necessary for the test(s) to function + }, + "style": { + "noNamespaceImport": "off" // this is required for `vi.spyOn` to work in some tests } } } diff --git a/docs/comments.md b/docs/comments.md index 9610052adf2..ba6c9929625 100644 --- a/docs/comments.md +++ b/docs/comments.md @@ -1,64 +1,107 @@ -## How do I comment my code? +# Commenting code -### While we're not enforcing a strict standard, there are some things to keep in mind: +People spend more time reading code than writing it (sometimes substantially more so). As such, comments and documentation are **vital** for any large codebase like this. + +## General Guidelines +While we're not enforcing a strict standard, here are some things to keep in mind: - Make comments meaningful - - Comments should be explaining why a line or block of code exists and what the reason behind it is - - Comments should not be repeating chunks of code or explaining what 'true' and 'false' means in typescript + - Comments should **NOT** repeat _what_ code _does_[^1] or explain concepts obvious to someone with a basic understanding of the language at hand. Instead, focus on explaining _why_ a line or block of code exists. + - Anyone with basic reading comprehension and a good IDE can figure out what code does; gaining a _post hoc_ understanding of the _reasons_ behind its existence takes a lot more digging, effort and bloodshed. +- Keep comments readable + - A comment's verbosity should roughly scale with the complexity of its subject matter. Some people naturally write shorter or longer comments as a personal style, but summarizing a 300 line function with "does a thing" is about as good as writing nothing. Conversely, writing a paragraph-level response where a basic one-liner would suffice is no less undesirable. + - Long comments should ideally be broken into multiple lines at around the 100-120 character mark. This isn't _mandatory_, but avoids unnecessary scrolling in terminals and IDEs. - Make sure comments exist on Functions, Classes, Methods, and Properties - - This may be the most important things to comment. When someone goes to use a function/class/method/etc., having a comment reduces the need to flip back and forth between files to figure out how something works. Peek Definition is great until you're three nested functions deep. - - The best example of this is JSDoc-style comments as seen below: - - When formatted this way, the comment gets shown by intellisense in VS Code or similar IDEs just by hovering over the text! - - Functions also show each the comment for parameter as you type them, making keeping track of what each one does in lengthy functions much more clear -```js -/** - * Changes the type-based weather modifier if this move's power would be reduced by it - * @param user {@linkcode Pokemon} using this move - * @param target {@linkcode Pokemon} target of this move - * @param move {@linkcode Move} being used - * @param args [0] {@linkcode Utils.NumberHolder} for arenaAttackTypeMultiplier - * @returns true if the function succeeds - */ -apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { -} + - These may be the most important things to comment. When someone goes to use a function/class/method/etc., having a comment reduces the need to flip back and forth between files to figure out what XYZ does. Peek Definition is great until you're three nested levels deep. -/** Set to true when experimental animated sprites from Gen6+ are used */ -public experimentalSprites: boolean = false; +[^1]: With exceptions for extremely long, convoluted or unintuitive methods (though an over-dependency on said comments is likely a symptom of poorly structured code). +# TSDoc +The codebase makes extensive use of [TSDoc](https://tsdoc.org), which is a TypeScript-specific version of [JSDoc](https://jsdoc.app/about-getting-started) +that uses similar syntax and attaches to functions, classes, etc. + +When formatted correctly, these comments are shown within VS Code or similar IDEs just by hovering over the function or object. +- Functions also show the comment for each parameter as you type them, making keeping track of arguments inside lengthy functions much more clear. + +They can also be used to generate a commentated overview of the codebase. There is a GitHub action that automatically updates [this docs site](https://pagefaultgames.github.io/pokerogue/main/index.html) +and you can generate it locally as well via `npm run docs` which will generate into the `typedoc/` directory. + +## Syntax +For an example of how TSDoc comments work, here are some TSDoc comments taken from `src/data/moves/move.ts`: +```ts /** - * Cures the user's party of non-volatile status conditions, ie. Heal Bell, Aromatherapy - * @extends MoveAttr - * @see {@linkcode apply} + * Attribute to put in a {@link https://bulbapedia.bulbagarden.net/wiki/Substitute_(doll) | Substitute Doll} for the user. */ -export class DontHealThePartyPlsAttr extends MoveAttr { +export class AddSubstituteAttr extends MoveEffectAttr { + /** The ratio of the user's max HP that is required to apply this effect */ + private hpCost: number; + /** Whether the damage taken should be rounded up (Shed Tail rounds up) */ + private roundUp: boolean; + + constructor(hpCost: number, roundUp: boolean) { + // code removed + } + + /** + * Removes 1/4 of the user's maximum HP (rounded down) to create a substitute for the user + * @param user - The {@linkcode Pokemon} that used the move. + * @param target - n/a + * @param move - The {@linkcode Move} with this attribute. + * @param args - n/a + * @returns `true` if the attribute successfully applies, `false` otherwise + */ + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + // code removed + } + + getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { + // code removed + } + + getCondition(): MoveConditionFunc { + // code removed + } + + /** + * Get the substitute-specific failure message if one should be displayed. + * @param user - The pokemon using the move. + * @returns The substitute-specific failure message if the conditions apply, otherwise `undefined` + */ + getFailedText(user: Pokemon, _target: Pokemon, _move: Move): string | undefined { + // code removed + } } ``` -You'll notice this contains an `{@linkcode Object}` tag for each parameter. This provides an easy type denomination and hyperlink to that type using VS Code's Intellisense. `@linkcode` is used instead of `@link` so that the text appears in monospace which is more obviously a `type` rather than a random hyperlink. -If you're interested in going more in depth, you can find a reference guide for how comments like these work [here](https://jsdoc.app) +Looking at the example given, you'll notice this contains an `{@linkcode XYZ}` tag in some of the parameters. This provides a clickable hyperlink to that type or object in most modern IDEs. (`@linkcode` is used here instead of `@link` so that the text appears in monospace which is more obviously a `type` rather than a random hyperlink.) \ +Also note the dashes (` - `) between the parameter names and descriptions - these are **mandatory** under the TSDoc spec[^2]. + +If you're interested in going more in depth, you can find a reference guide for how comments like these work [on the TSDoc website](https://tsdoc.org). +The [playground page](https://tsdoc.org/play/) there can also be used for live testing of examples. + +[^2]: Incidentally, this is also the only place dashes are explicitly _required_. ### What not to do: - Don't leave comments for code you don't understand - - Incorrect information is worse than no information. If you aren't sure how something works, don't make something up to explain it. Ask for help instead. + - Incorrect information is worse than no information. If you aren't sure how something works, don't make something up to explain it - ask for help and/or mark it as TODO. - Don't over-comment - - Not everything needs an explanation. Try to summarize blocks of code instead of singular lines where possible. Single line comments should call out specific oddities. + - Not everything needs a comment. Try to summarize blocks of code instead of singular lines where possible, always preferring giving a reason over stating a fact. Single line comments should call out specific oddities or features. ## How do Abilities and Moves differ from other classes? While other classes should be fully documented, Abilities and Moves heavily incoperate inheritance (i.e. the `extends` keyword). Because of this, much of the functionality in these classes is duplicated or only slightly changed between classes. ### With this in mind, there's a few more things to keep in mind for these: - Do not document any parameters if the function mirrors the one they extend. - - Keep this in mind for functions that are not the `apply` function as they are usually sparce and mostly reused -- The class itself must be documented - - This must include the `@extends BaseClass` and `@see {@linkcode apply}` tags + - Keep this in mind for functions that are not the `apply` function as they are usually sparse and mostly reused - Class member variables must be documented - You can use a single line documentation comment for these `/** i.e. a comment like this */` - `args` parameters must be documented if used - - This should look something like this when there are multiple: + - This should look something vaguely like this when there are multiple: ```ts /** ... - * @param args [0] {@linkcode Utils.NumberHolder} of arenaAttackTypeMultiplier - * [1] {@linkcode Utils.BooleanHolder} of cancelled - * [2] {@linkcode Utils.BooleanHolder} of rWeDoneYet + * @param args - + * `[0]` The {@linkcode Move} being used + * `[1]` A {@linkcode BooleanHolder} used to track XYZ + * `[2]` {@linkcode BooleanHolder} `paramC` - paramC description here ... */ -``` \ No newline at end of file +``` diff --git a/docs/enemy-ai.md b/docs/enemy-ai.md index 8edf5a3f10e..d73b0af980e 100644 --- a/docs/enemy-ai.md +++ b/docs/enemy-ai.md @@ -37,12 +37,12 @@ The `EnemyCommandPhase` follows this process to determine whether or not an enem 1. If the Pokémon has a move already queued (e.g. they are recharging after using Hyper Beam), or they are trapped (e.g. by Bind or Arena Trap), skip to resolving a `FIGHT` command (see next section). 2. For each Pokémon in the enemy's party, [compute their matchup scores](#calculating-matchup-scores) against the active player Pokémon. If there are two active player Pokémon in the battle, add their matchup scores together. 3. Take the party member with the highest matchup score and apply a multiplier to the score that reduces the score based on how frequently the enemy trainer has switched Pokémon in the current battle. - - The multiplier scales off of a counter that increments when the enemy trainer chooses to switch a Pokémon and decrements when they choose to use a move. + - The multiplier scales off of a counter that increments when the enemy trainer chooses to switch a Pokémon and decrements when they choose to use a move. 4. Compare the result of Step 3 with the active enemy Pokémon's matchup score. If the party member's matchup score is at least three times that of the active Pokémon, switch to that party member. - - "Boss" trainers only require the party member's matchup score to be at least two times that of the active Pokémon, so they are more likely to switch than other trainers. The full list of boss trainers in the game is as follows: - - All gym leaders, Elite 4 members, and Champions - - All Evil Team leaders - - The last three Rival Fights (on waves 95, 145, and 195) + - "Boss" trainers only require the party member's matchup score to be at least two times that of the active Pokémon, so they are more likely to switch than other trainers. The full list of boss trainers in the game is as follows: + - All gym leaders, Elite 4 members, and Champions + - All Evil Team leaders + - The last three Rival Fights (on waves 95, 145, and 195) 5. If the enemy decided to switch, send a switch `turnCommand` and end this `EnemyCommandPhase`; otherwise, move on to resolving a `FIGHT` enemy command. ## Step 2: Selecting a Move @@ -54,28 +54,35 @@ At this point, the enemy (a wild or trainer Pokémon) has decided against switch In `getNextMove()`, the enemy Pokémon chooses a move to use in the following steps: 1. If the Pokémon has a move in its Move Queue (e.g. the second turn of a charging move), and the queued move is still usable, use that move against the given target. 2. Filter out any moves it can't use within its moveset. The remaining moves make up the enemy's **move pool** for the turn. - 1. A move can be unusable if it has no PP left or it has been disabled by another move or effect - 2. If the enemy's move pool is empty, use Struggle. + 1. A move can be unusable if it has no PP left or it has been disabled by another move or effect. + 2. If the enemy's move pool is empty, use Struggle. 3. Calculate the **move score** of each move in the enemy's move pool. - 1. A move's move score is equivalent to the move's maximum **target score** among all of the move's possible targets on the field ([more on this later](#calculating-move-and-target-scores)). - 2. A move's move score is set to -20 if at least one of these conditions are met: - - The move is unimplemented (or, more precisely, the move's name ends with " (N)"). - - Conditions for the move to succeed are not met (unless the move is Sucker Punch, Upper Hand, or Thunderclap, as those moves' conditions can't be resolved before the turn starts). - - The move's target scores are 0 or `NaN` for each target. In this case, the game assumes the target score calculation for that move is unimplemented. + 1. A move's move score is equivalent to the move's maximum **target score** among all of the move's possible targets on the field ([more on this later](#calculating-move-and-target-scores)). + 2. A move's move score is set to -20 if at least one of these conditions are met: + - The move is unimplemented (or, more precisely, the move's name ends with "(N)"). + - Conditions for the move to succeed are not met (unless the move is Sucker Punch, Upper Hand or Thunderclap, as those moves' conditions can't be resolved until after the turn starts). + - The move's target scores are 0 or `NaN` for each target. In this case, the game assumes the target score calculation for that move is unimplemented. 4. Sort the move pool in descending order of move scores. 5. From here, the enemy's move selection varies based on its `aiType`. If the enemy is a Boss Pokémon or has a Trainer, it uses the `SMART` AI type; otherwise, it uses the `SMART_RANDOM` AI type. - 1. Let $m_i$ be the *i*-th move in the sorted move pool $M$: - - If `aiType === SMART_RANDOM`, the enemy has a 5/8 chance of selecting $m_0$ and a 3/8 chance of advancing to the next best move $m_1$, where it then repeats this roll. This process stops when a move is selected or the last move in the move pool is reached. - - If `aiType === SMART`, a similar loop is used to decide between selecting the move $m_i$ and advancing to the next iteration with the move $m_{i+1}$. However, instead of using a flat probability, the following conditions need to be met to advance from selecting $m_i$ to $m_{i+1}$: - - $\text{sign}(s_i) = \text{sign}(s_{i+1})$, where $s_i$ is the move score of $m_i$. - - $\text{randInt}(0, 100) < \text{round}(\frac{s_{i+1}}{s_i}\times 50)$. In other words: if the scores of $m_i$ and $m_{i+1}$ have the same sign, the chance to advance to the next iteration with $m_{i+1}$ is proportional to how close the scores are to each other. The probability to advance to the next iteration is at most 50 percent (when $s_i$ and $s_{i+1}$ are equal). + 1. Let $m_i$ be the *i*-th move in the sorted move pool $M$: + - If `aiType === SMART_RANDOM`, the enemy has a 5/8 chance of selecting $m_0$ and a 3/8 chance of advancing to the next best move $m_1$, where it then repeats this roll. This process stops when a move is selected or the last move in the move pool is reached. + - If `aiType === SMART`, a similar loop is used to decide between selecting the move $m_i$ and advancing to the next iteration with the move $m_{i+1}$. However, instead of using a flat probability, the following conditions need to be met to advance from selecting $m_i$ to $m_{i+1}$: + - $\text{sign}(s_i) = \text{sign}(s_{i+1})$, where $s_i$ is the move score of $m_i$. + - $\text{randInt}(0, 100) < \text{round}(\frac{s_{i+1}}{s_i}\times 50)$. In other words: if the scores of $m_i$ and $m_{i+1}$ have the same sign, the chance to advance to the next iteration with $m_{i+1}$ is proportional to how close the scores are to each other. The probability to advance to the next iteration is at most 50 percent (when $s_i$ and $s_{i+1}$ are equal). 6. The enemy will use the move selected in Step 5 against the target(s) with the highest [**target selection score (TSS)**](#choosing-targets-with-getnexttargets) ### Calculating Move and Target Scores -As part of the move selection process, the enemy Pokémon must compute a **target score (TS)** for each legal target for each move in its move pool. The base target score for all moves is a combination of the move's **user benefit score (UBS)** and **target benefit score (TBS)**. +As part of the move selection process, the enemy Pokémon must compute a **target score (TS)** for each legal target for each move in its move pool. The base target score is a combination of the move's **user benefit score (UBS)** and **target benefit score (TBS)**, representing how much the move helps or hinders the user and/or its target(s). -![equation](https://latex.codecogs.com/png.image?%5Cinline%20%5Cdpi%7B100%7D%5Cbg%7Bwhite%7D%5Ctext%7BTS%7D=%5Ctext%7BUBS%7D+%5Ctext%7BTBS%7D%5Ctimes%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D-1&%5Ctext%7Bif%20target%20is%20an%20opponent%7D%5C%5C1&%5Ctext%7Botherwise%7D%5C%5C%5Cend%7Bmatrix%7D%5Cright.) +$$ +\text{TS} = \text{UBS} + \left( \text{TBS} \times +\begin{cases} +-1 & \text{if target is an opponent} \\ +1 & \text{otherwise} +\end{cases} +\right) +$$ A move's UBS and TBS are computed with the respective functions in the `Move` class: @@ -96,19 +103,38 @@ In addition to the base score from `Move.getTargetBenefitScore()`, attack moves - The move's category (Physical/Special), and whether the user has a higher Attack or Special Attack stat. More specifically, the following steps are taken to compute the move's `attackScore`: -1. Compute a multiplier based on the move's type effectiveness: +1. Compute a multiplier based on the move's type effectiveness: - ![typeMultEqn](https://latex.codecogs.com/png.image?%5Cdpi%7B110%7D%5Cbg%7Bwhite%7D%5Ctext%7BtypeMult%7D=%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D2&&%5Ctext%7Bif%20move%20is%20super%20effective(or%20better)%7D%5C%5C-2&&%5Ctext%7Botherwise%7D%5C%5C%5Cend%7Bmatrix%7D%5Cright.) + $$ + \text{typeMult} = + \begin{cases} + 2 & \text{if move is super effective (or better)} \\ + -2 & \text{otherwise} + \end{cases} + $$ 2. Compute a multiplier based on the move's category and the user's offensive stats: - 1. Compute the user's offensive stat ratio: - - ![statRatioEqn](https://latex.codecogs.com/png.image?%5Cinline%20%5Cdpi%7B100%7D%5Cbg%7Bwhite%7D%5Ctext%7BstatRatio%7D=%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%5Cfrac%7B%5Ctext%7BuserSpAtk%7D%7D%7B%5Ctext%7BuserAtk%7D%7D&%5Ctext%7Bif%20move%20is%20physical%7D%5C%5C%5Cfrac%7B%5Ctext%7BuserAtk%7D%7D%7B%5Ctext%7BuserSpAtk%7D%7D&%5Ctext%7Botherwise%7D%5C%5C%5Cend%7Bmatrix%7D%5Cright.) - 2. Compute the stat-based multiplier: + 1. Compute the user's offensive stat ratio: - ![statMultEqn](https://latex.codecogs.com/png.image?%5Cinline%20%5Cdpi%7B100%7D%5Cbg%7Bwhite%7D%5Ctext%7BstatMult%7D=%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D2&%5Ctext%7Bif%20statRatio%7D%5Cle%200.75%5C%5C1.5&%5Ctext%7Bif%5C;%7D0.75%5Cle%5Ctext%7BstatRatio%7D%5Cle%200.875%5C%5C1&%5Ctext%7Botherwise%7D%5C%5C%5Cend%7Bmatrix%7D%5Cright.) + $$ + \text{statRatio} = + \begin{cases} + \frac{\text{userSpAtk}}{\text{userAtk}} & \text{if move is physical} \\ + \frac{\text{userAtk}}{\text{userSpAtk}} & \text{otherwise} + \end{cases} + $$ + 2. Compute the stat-based multiplier: + + $$ + \text{statMult} = + \begin{cases} + 2 & \text{if statRatio} \leq 0.75 \\ + 1.5 & \text{if } 0.75 \leq \text{statRatio} \leq 0.875 \\ + 1 & \text{otherwise} + \end{cases} + $$ 3. Calculate the move's `attackScore`: - $\text{attackScore} = (\text{typeMult}\times \text{statMult})+\lfloor \frac{\text{power}}{5} \rfloor$ + $\text{attackScore} = (\text{typeMult}\times \text{statMult})+\lfloor \frac{\text{power}}{5} \rfloor$ The maximum total multiplier in `attackScore` ($\text{typeMult}\times \text{statMult}$) is 4, which occurs for attacks that are super effective against the target and are categorically aligned with the user's offensive stats (e.g. the move is physical, and the user has much higher Attack than Sp. Atk). The minimum total multiplier of -4 occurs (somewhat confusingly) for attacks that are not super effective but are categorically aligned with the user's offensive stats. @@ -125,18 +151,31 @@ The final step to calculate an attack move's target score (TS) is to multiply th The enemy's target selection for single-target moves works in a very similar way to its move selection. Each potential target is given a **target selection score (TSS)** which is based on the move's [target benefit score](#calculating-move-and-target-scores) for that target: -![TSSEqn](https://latex.codecogs.com/png.image?%5Cinline%20%5Cdpi%7B100%7D%5Cbg%7Bwhite%7D%5Ctext%7BTSS%7D=%5Ctext%7BTBS%7D%5Ctimes%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D-1&%5Ctext%7Bif%20target%20is%20an%20opponent%7D%5C%5C1&%5Ctext%7Botherwise%7D%5C%5C%5Cend%7Bmatrix%7D%5Cright.) +$$ +\text{TSS} = \text{TBS} \times +\begin{cases} +-1 & \text{if target is an opponent} \\ +1 & \text{otherwise} +\end{cases} +$$ Once the TSS is calculated for each target, the target is selected as follows: 1. Sort the targets (indexes) in decreasing order of their target selection scores (or weights). Let $t_i$ be the index of the *i*-th target in the sorted list, and let $w_i$ be that target's corresponding TSS. 2. Normalize the weights. Let $w_n$ be the lowest-weighted target in the sorted list, then: - - ![normWeightEqn](https://latex.codecogs.com/png.image?%5Cinline%20%5Cdpi%7B100%7D%5Cbg%7Bwhite%7DW_i=%5Cleft%5C%7B%5Cbegin%7Bmatrix%7Dw_i+%7Cw_n%7C&%5Ctext%7Bif%5C;%7Dw_n%5C;%5Ctext%7Bis%20negative%7D%5C%5Cw_i&%5Ctext%7Botherwise%7D%5C%5C%5Cend%7Bmatrix%7D%5Cright.) + + $$ + W_i = + \begin{cases} + w_i + |w_n| & \text{if } w_n \text{ is negative} \\ + w_i & \text{otherwise} + \end{cases} + $$ + 3. Remove all weights from the list such that $W_i < \frac{W_0}{2}$ 4. Generate a random integer $R=\text{rand}(0, W_{\text{total}})$ where $W_{\text{total}}$ is the sum of all the remaining weights after Step 3. 5. For each target $(t_i, W_i)$, - 1. if $R \le \sum_{j=0}^{i} W_i$, or if $t_i$ is the last target in the list, **return** $t_i$ - 2. otherwise, advance to the next target $t_{i+1}$ and repeat this check. + 1. if $R \le \sum_{j=0}^{i} W_i$, or if $t_i$ is the last target in the list, **return** $t_i$ + 2. otherwise, advance to the next target $t_{i+1}$ and repeat this check. Once the target is selected, the enemy has successfully determined its next action for the turn, and its corresponding `EnemyCommandPhase` ends. From here, the `TurnStartPhase` processes the enemy's commands alongside the player's commands and begins to resolve the turn. @@ -145,15 +184,15 @@ Once the target is selected, the enemy has successfully determined its next acti Suppose you enter a single battle against an enemy trainer with the following Pokémon in their party: 1. An [Excadrill](https://bulbapedia.bulbagarden.net/wiki/Excadrill_(Pok%C3%A9mon)) with the Ability Sand Force and the following moveset - 1. Earthquake - 2. Iron Head - 3. Crush Claw - 4. Swords Dance + 1. Earthquake + 2. Iron Head + 3. Crush Claw + 4. Swords Dance 2. A [Heatmor](https://bulbapedia.bulbagarden.net/wiki/Heatmor_(Pok%C3%A9mon)) with the Ability Flash Fire and the following moveset - 1. Fire Lash - 2. Inferno - 3. Hone Claws - 4. Shadow Claw + 1. Fire Lash + 2. Inferno + 3. Hone Claws + 4. Shadow Claw The enemy trainer leads with their Heatmor, and you lead with a [Dachsbun](https://bulbapedia.bulbagarden.net/wiki/Dachsbun_(Pok%C3%A9mon)) with the Ability Well-Baked Body. We'll cover the enemy's behavior over the next two turns. @@ -172,13 +211,13 @@ Based on the enemy party's matchup scores, whether or not the trainer switches o Now that the enemy Pokémon with the best matchup score is on the field (assuming it survives Dachsbun's attack on the last turn), the enemy will now decide to have Excadrill use one of its moves. Assuming all of its moves are usable, we'll go through the target score calculations for each move: - **Earthquake**: In a single battle, this move is just a 100-power Ground-type physical attack with no additional effects. With no additional benefit score from attributes, the move's base target score against the player's Dachsbun is just the `attackScore` from `AttackMove.getTargetBenefitScore()`. In this case, Earthquake's `attackScore` is given by - + $\text{attackScore}=(\text{typeMult}\times \text{statMult}) + \lfloor \frac{\text{power}}{5} \rfloor = -2\times 2 + 20 = 16$ Here, `typeMult` is -2 because the move is not super effective, and `statMult` is 2 because Excadrill's Attack is significantly higher than its Sp. Atk. Accounting for STAB thanks to Excadrill's typing, the final target score for this move is **24** - **Iron Head**: This move is an 80-power Steel-type physical attack with an additional chance to cause the target to flinch. With these properties, Iron Head has a user benefit score of 0 and a target benefit score given by - + $\text{TBS}=\text{getTargetBenefitScore(FlinchAttr)}-\text{attackScore}$ Under its current implementation, the target benefit score of `FlinchAttr` is -5. Calculating the move's `attackScore`, we get: @@ -198,7 +237,7 @@ Now that the enemy Pokémon with the best matchup score is on the field (assumin where `levels` is the number of stat stages added by the attribute (in this case, +2). The final score for this move is **6** (Note: because this move is self-targeted, we don't flip the sign of TBS when computing the target score). - **Crush Claw**: This move is a 75-power Normal-type physical attack with a 50 percent chance to lower the target's Defense by one stage. The additional effect is implemented by the same `StatStageChangeAttr` as Swords Dance, so we can use the same formulas from before to compute the total TBS and base target score. - + $\text{TBS}=\text{getTargetBenefitScore(StatStageChangeAttr)}-\text{attackScore}$ $\text{TBS}=(-4 + 2)-(-2\times 2 + \lfloor \frac{75}{5} \rfloor)=-2-11=-13$ diff --git a/docs/linting.md b/docs/linting.md index 39b30b7a1c0..d3b4e47675f 100644 --- a/docs/linting.md +++ b/docs/linting.md @@ -1,40 +1,65 @@ -# ESLint -## Key Features +# Linting & Formatting -1. **Automation**: - - A pre-commit hook has been added to automatically run ESLint on the added or modified files, ensuring code quality before commits. +> "Any fool can write code that a computer can understand. Good programmers write code that humans can understand." +> +> — Martin Fowler -2. **Manual Usage**: - - If you prefer not to use the pre-commit hook, you can manually run ESLint to automatically fix issues using the command: - ```sh - npx eslint --fix . or npm run eslint - ``` - - Running this command will lint all files in the repository. +Writing clean, readable code is important, and linters and formatters are an integral part of ensuring code quality and readability. +It is for this reason we are using [Biome](https://biomejs.dev), an opinionated linter/formatter (akin to Prettier) with a heavy focus on speed and performance. -3. **GitHub Action**: - - A GitHub Action has been added to automatically run ESLint on every push and pull request, ensuring code quality in the CI/CD pipeline. +### Installation +You probably installed Biome already without noticing it - it's included inside `package.json` and should've been downloaded when you ran `npm install` after cloning the repo (assuming you followed proper instructions, that is). If you haven't done that yet, go do it. -## Summary of ESLint Rules +# Using Biome -1. **General Rules**: - - **Equality**: Use `===` and `!==` instead of `==` and `!=` (`eqeqeq`). - - **Indentation**: Enforce 2-space indentation (`indent`). - - **Quotes**: Use doublequotes for strings (`quotes`). - - **Variable Declarations**: - - Disallow `var`; use `let` or `const` (`no-var`). - - Prefer `const` for variables that are never reassigned (`prefer-const`). - - **Unused Variables**: Allow unused function parameters but enforce error for other unused variables (`@typescript-eslint/no-unused-vars`). - - **End of Line**: Ensure at least one newline at the end of files (`eol-last`). - - **Curly Braces**: Enforce the use of curly braces for all control statements (`curly`). - - **Brace Style**: Use one true brace style (`1tbs`) for TypeScript-specific syntax (`@typescript-eslint/brace-style`). +For the most part, Biome attempts to stay "out of your hair", letting you write code while enforcing a consistent formatting standard and only notifying for errors it can't automatically fix.\ +On the other hand, if Biome complains about a piece of code, **there's probably a good reason why**. Disable comments should be used sparingly or when readabilty demands it - your first instinct should be to fix the code in question, not disable the rule. -2. **TypeScript-Specific Rules**: - - **Semicolons**: - - Enforce semicolons for TypeScript-specific syntax (`@typescript-eslint/semi`). - - Disallow unnecessary semicolons (`@typescript-eslint/no-extra-semi`). +## Editor Integration +Biome has integration with many popular code editors. See [these](https://biomejs.dev/guides/editors/first-party-extensions/) [pages](https://biomejs.dev/guides/editors/third-party-extensions/) for information about enabling Biome in your editor of choice. -## Benefits +## Automated Runs +Generally speaking, most users shouldn't need to run Biome directly; in addition to editor integration, [pre-commit hook](../lefthook.yml) will periodically run Biome before each commit. +You will **not** be able to push code with `error`-level linting problems - fix them beforehand. -- **Consistency**: Ensures consistent coding style across the project. -- **Code Quality**: Helps catch potential errors and improve overall code quality. -- **Readability**: Makes the codebase easier to read and maintain. \ No newline at end of file +We also have a [Github Action](../.github/workflows/quality.yml) to verify code quality each time a PR is updated, preventing bad code from inadvertently making its way upstream. + +### Why am I getting errors for code I didn't write? + +To save time and minimize friction with existing code, both the pre-commit hook and workflow run will only check files **directly changed** by a given PR or commit. +As a result, changes to files not updated since Biome's introduction can cause any _prior_ linting errors in them to resurface and get flagged. +This should occur less and less often as time passes and more files are updated to the new standard. + +## Running Biome via CLI +If you want Biome to check your files manually, you can run it from the command line like so: + +```sh +npx biome check --[flags] +``` + +A full list of flags and options can be found on [their website](https://biomejs.dev/reference/cli/), but here's a few useful ones to keep in mind: + +- `--write` will cause Biome to write all "safe" fixes and formatting changes directly to your files (rather than just complaining and doing nothing). +- `--changed` and `--staged` will only perform checks on all changed or staged files respectively. Biome sources this info from the relevant version control system (in this case Git). +- `diagnostic-level=XXX` will only show diagnostics with at least the given severity level (`info/warn/error`). Useful to only focus on errors causing a failed workflow run or similar. + +## Linting Rules + +We primarily use Biome's [recommended ruleset](https://biomejs.dev/linter/rules/) for linting JS/TS, with some customizations to better suit our project's needs[^1]. + +Some things to consider: + +- We have disabled rules that prioritize style over performance, such as `useTemplate`. +- Some rules are currently disabled or marked as warnings (`warn`) to allow for gradual refactoring without blocking development. **Do not write new code that triggers these warnings.** +- The linter is configured to ignore specific files and folders (such as excessively large files or ones in need of refactoring) to improve performance and focus on actionable areas. + +Any questions about linting rules should be brought up in the `#dev-corner` channel in the discord. + +[^1]: A complete list of rules can be found in the `biome.jsonc` file in the project root. + +## What about ESLint? + + +Our project migrated away from ESLint around March 2025 due to it simply not scaling well enough with the codebase's ever-growing size. The [existing eslint rules](../eslint.config.js) are considered _deprecated_, only kept due to Biome lacking the corresponding rules in its current ruleset. + +No additional ESLint rules should be added under any circumstances - even the few currently in circulation take longer to run than the entire Biome formatting/linting suite combined. \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js index a97e3902411..aebcab7feae 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,9 +1,10 @@ -import tseslint from "@typescript-eslint/eslint-plugin"; +/** @ts-check */ +import tseslint from "typescript-eslint"; import stylisticTs from "@stylistic/eslint-plugin-ts"; import parser from "@typescript-eslint/parser"; import importX from "eslint-plugin-import-x"; -export default [ +export default tseslint.config( { name: "eslint-config", files: ["src/**/*.{ts,tsx,js,jsx}", "test/**/*.{ts,tsx,js,jsx}"], @@ -14,12 +15,11 @@ export default [ plugins: { "import-x": importX, "@stylistic/ts": stylisticTs, - "@typescript-eslint": tseslint, + "@typescript-eslint": tseslint.plugin, }, rules: { - "prefer-const": "error", // Enforces the use of `const` for variables that are never reassigned "no-undef": "off", // Disables the rule that disallows the use of undeclared variables (TypeScript handles this) - "no-extra-semi": ["error"], // Disallows unnecessary semicolons for TypeScript-specific syntax + "no-extra-semi": "error", // Disallows unnecessary semicolons for TypeScript-specific syntax "import-x/extensions": ["error", "never", { json: "always" }], // Enforces no extension for imports unless json }, }, @@ -33,11 +33,11 @@ export default [ }, }, plugins: { - "@typescript-eslint": tseslint, + "@typescript-eslint": tseslint.plugin, }, rules: { "@typescript-eslint/no-floating-promises": "error", // Require Promise-like statements to be handled appropriately. - https://typescript-eslint.io/rules/no-floating-promises/ "@typescript-eslint/no-misused-promises": "error", // Disallow Promises in places not designed to handle them. - https://typescript-eslint.io/rules/no-misused-promises/ }, }, -]; +); diff --git a/lefthook.yml b/lefthook.yml index ddf875f15de..ff0ac00f9e5 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -2,13 +2,12 @@ pre-commit: parallel: true commands: biome-lint: - glob: "*.{js,jsx,ts,tsx}" - run: npx @biomejs/biome check --write --reporter=summary {staged_files} --no-errors-on-unmatched + run: npx biome check --write --reporter=summary --staged --no-errors-on-unmatched stage_fixed: true skip: - merge - rebase - + post-merge: commands: update-submodules: diff --git a/package-lock.json b/package-lock.json index 33e9dd08104..da00292e7b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "pokemon-rogue-battle", - "version": "1.8.4", + "version": "1.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.8.4", + "version": "1.9.0", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", + "compare-versions": "^6.1.1", "crypto-js": "^4.2.0", "i18next": "^24.2.2", "i18next-browser-languagedetector": "^8.0.4", @@ -17,8 +18,8 @@ "i18next-korean-postposition-processor": "^1.0.0", "json-stable-stringify": "^1.2.0", "jszip": "^3.10.1", - "phaser": "^3.70.0", - "phaser3-rex-plugins": "^1.80.14" + "phaser": "^3.88.2", + "phaser3-rex-plugins": "^1.80.15" }, "devDependencies": { "@biomejs/biome": "1.9.4", @@ -26,7 +27,7 @@ "@hpcc-js/wasm": "^2.22.4", "@stylistic/eslint-plugin-ts": "^4.1.0", "@types/jsdom": "^21.1.7", - "@types/node": "^20.12.13", + "@types/node": "^22.13.14", "@typescript-eslint/eslint-plugin": "^8.28.0", "@typescript-eslint/parser": "^8.28.0", "@vitest/coverage-istanbul": "^3.0.9", @@ -38,16 +39,17 @@ "lefthook": "^1.11.5", "msw": "^2.7.3", "phaser3spectorjs": "^0.0.8", + "rollup": "^4.40.1", "typedoc": "^0.28.1", "typescript": "^5.8.2", "typescript-eslint": "^8.28.0", - "vite": "^6.2.0", + "vite": "^6.3.4", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.9", "vitest-canvas-mock": "^0.3.3" }, "engines": { - "node": ">=20.0.0" + "node": ">=22.0.0" } }, "node_modules/@ampproject/remapping": { @@ -2160,9 +2162,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.38.0.tgz", - "integrity": "sha512-ldomqc4/jDZu/xpYU+aRxo3V4mGCV9HeTgUBANI3oIQMOL+SsxB+S2lxMpkFp5UamSS3XuTMQVbsS24R4J4Qjg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.1.tgz", + "integrity": "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==", "cpu": [ "arm" ], @@ -2174,9 +2176,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.38.0.tgz", - "integrity": "sha512-VUsgcy4GhhT7rokwzYQP+aV9XnSLkkhlEJ0St8pbasuWO/vwphhZQxYEKUP3ayeCYLhk6gEtacRpYP/cj3GjyQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.1.tgz", + "integrity": "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==", "cpu": [ "arm64" ], @@ -2188,9 +2190,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.38.0.tgz", - "integrity": "sha512-buA17AYXlW9Rn091sWMq1xGUvWQFOH4N1rqUxGJtEQzhChxWjldGCCup7r/wUnaI6Au8sKXpoh0xg58a7cgcpg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.1.tgz", + "integrity": "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==", "cpu": [ "arm64" ], @@ -2202,9 +2204,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.38.0.tgz", - "integrity": "sha512-Mgcmc78AjunP1SKXl624vVBOF2bzwNWFPMP4fpOu05vS0amnLcX8gHIge7q/lDAHy3T2HeR0TqrriZDQS2Woeg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.1.tgz", + "integrity": "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==", "cpu": [ "x64" ], @@ -2216,9 +2218,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.38.0.tgz", - "integrity": "sha512-zzJACgjLbQTsscxWqvrEQAEh28hqhebpRz5q/uUd1T7VTwUNZ4VIXQt5hE7ncs0GrF+s7d3S4on4TiXUY8KoQA==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.1.tgz", + "integrity": "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==", "cpu": [ "arm64" ], @@ -2230,9 +2232,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.38.0.tgz", - "integrity": "sha512-hCY/KAeYMCyDpEE4pTETam0XZS4/5GXzlLgpi5f0IaPExw9kuB+PDTOTLuPtM10TlRG0U9OSmXJ+Wq9J39LvAg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.1.tgz", + "integrity": "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==", "cpu": [ "x64" ], @@ -2244,9 +2246,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.38.0.tgz", - "integrity": "sha512-mimPH43mHl4JdOTD7bUMFhBdrg6f9HzMTOEnzRmXbOZqjijCw8LA5z8uL6LCjxSa67H2xiLFvvO67PT05PRKGg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.1.tgz", + "integrity": "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==", "cpu": [ "arm" ], @@ -2258,9 +2260,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.38.0.tgz", - "integrity": "sha512-tPiJtiOoNuIH8XGG8sWoMMkAMm98PUwlriOFCCbZGc9WCax+GLeVRhmaxjJtz6WxrPKACgrwoZ5ia/uapq3ZVg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.1.tgz", + "integrity": "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==", "cpu": [ "arm" ], @@ -2272,9 +2274,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.38.0.tgz", - "integrity": "sha512-wZco59rIVuB0tjQS0CSHTTUcEde+pXQWugZVxWaQFdQQ1VYub/sTrNdY76D1MKdN2NB48JDuGABP6o6fqos8mA==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.1.tgz", + "integrity": "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==", "cpu": [ "arm64" ], @@ -2286,9 +2288,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.38.0.tgz", - "integrity": "sha512-fQgqwKmW0REM4LomQ+87PP8w8xvU9LZfeLBKybeli+0yHT7VKILINzFEuggvnV9M3x1Ed4gUBmGUzCo/ikmFbQ==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.1.tgz", + "integrity": "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==", "cpu": [ "arm64" ], @@ -2300,9 +2302,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.38.0.tgz", - "integrity": "sha512-hz5oqQLXTB3SbXpfkKHKXLdIp02/w3M+ajp8p4yWOWwQRtHWiEOCKtc9U+YXahrwdk+3qHdFMDWR5k+4dIlddg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.1.tgz", + "integrity": "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==", "cpu": [ "loong64" ], @@ -2314,9 +2316,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.38.0.tgz", - "integrity": "sha512-NXqygK/dTSibQ+0pzxsL3r4Xl8oPqVoWbZV9niqOnIHV/J92fe65pOir0xjkUZDRSPyFRvu+4YOpJF9BZHQImw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.1.tgz", + "integrity": "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==", "cpu": [ "ppc64" ], @@ -2328,9 +2330,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.38.0.tgz", - "integrity": "sha512-GEAIabR1uFyvf/jW/5jfu8gjM06/4kZ1W+j1nWTSSB3w6moZEBm7iBtzwQ3a1Pxos2F7Gz+58aVEnZHU295QTg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.1.tgz", + "integrity": "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==", "cpu": [ "riscv64" ], @@ -2342,9 +2344,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.38.0.tgz", - "integrity": "sha512-9EYTX+Gus2EGPbfs+fh7l95wVADtSQyYw4DfSBcYdUEAmP2lqSZY0Y17yX/3m5VKGGJ4UmIH5LHLkMJft3bYoA==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.1.tgz", + "integrity": "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==", "cpu": [ "riscv64" ], @@ -2356,9 +2358,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.38.0.tgz", - "integrity": "sha512-Mpp6+Z5VhB9VDk7RwZXoG2qMdERm3Jw07RNlXHE0bOnEeX+l7Fy4bg+NxfyN15ruuY3/7Vrbpm75J9QHFqj5+Q==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.1.tgz", + "integrity": "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==", "cpu": [ "s390x" ], @@ -2370,9 +2372,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.38.0.tgz", - "integrity": "sha512-vPvNgFlZRAgO7rwncMeE0+8c4Hmc+qixnp00/Uv3ht2x7KYrJ6ERVd3/R0nUtlE6/hu7/HiiNHJ/rP6knRFt1w==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", + "integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==", "cpu": [ "x64" ], @@ -2384,9 +2386,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.38.0.tgz", - "integrity": "sha512-q5Zv+goWvQUGCaL7fU8NuTw8aydIL/C9abAVGCzRReuj5h30TPx4LumBtAidrVOtXnlB+RZkBtExMsfqkMfb8g==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz", + "integrity": "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==", "cpu": [ "x64" ], @@ -2398,9 +2400,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.38.0.tgz", - "integrity": "sha512-u/Jbm1BU89Vftqyqbmxdq14nBaQjQX1HhmsdBWqSdGClNaKwhjsg5TpW+5Ibs1mb8Es9wJiMdl86BcmtUVXNZg==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.1.tgz", + "integrity": "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==", "cpu": [ "arm64" ], @@ -2412,9 +2414,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.38.0.tgz", - "integrity": "sha512-mqu4PzTrlpNHHbu5qleGvXJoGgHpChBlrBx/mEhTPpnAL1ZAYFlvHD7rLK839LLKQzqEQMFJfGrrOHItN4ZQqA==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.1.tgz", + "integrity": "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==", "cpu": [ "ia32" ], @@ -2426,9 +2428,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.38.0.tgz", - "integrity": "sha512-jjqy3uWlecfB98Psxb5cD6Fny9Fupv9LrDSPTQZUROqjvZmcCqNu4UMl7qqhlUUGpwiAkotj6GYu4SZdcr/nLw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.1.tgz", + "integrity": "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==", "cpu": [ "x64" ], @@ -2581,12 +2583,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", - "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "version": "22.13.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz", + "integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.20.0" } }, "node_modules/@types/statuses": { @@ -3605,6 +3608,12 @@ "node": ">=18" } }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4419,6 +4428,21 @@ "reusify": "^1.0.4" } }, + "node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -6219,18 +6243,18 @@ } }, "node_modules/phaser": { - "version": "3.80.1", - "resolved": "https://registry.npmjs.org/phaser/-/phaser-3.80.1.tgz", - "integrity": "sha512-VQGAWoDOkEpAWYkI+PUADv5Ql+SM0xpLuAMBJHz9tBcOLqjJ2wd8bUhxJgOqclQlLTg97NmMd9MhS75w16x1Cw==", + "version": "3.88.2", + "resolved": "https://registry.npmjs.org/phaser/-/phaser-3.88.2.tgz", + "integrity": "sha512-UBgd2sAFuRJbF2xKaQ5jpMWB8oETncChLnymLGHcrnT53vaqiGrQWbUKUDBawKLm24sghjKo4Bf+/xfv8espZQ==", "license": "MIT", "dependencies": { "eventemitter3": "^5.0.1" } }, "node_modules/phaser3-rex-plugins": { - "version": "1.80.14", - "resolved": "https://registry.npmjs.org/phaser3-rex-plugins/-/phaser3-rex-plugins-1.80.14.tgz", - "integrity": "sha512-eHi3VgryO9umNu6D1yQU5IS6tH4TyC2Y6RgJ495nNp37X2fdYnmYpBfgFg+YaumvtaoOvCkUVyi/YqWNPf2X2A==", + "version": "1.80.15", + "resolved": "https://registry.npmjs.org/phaser3-rex-plugins/-/phaser3-rex-plugins-1.80.15.tgz", + "integrity": "sha512-Ur973N1W5st6XEYBcJko8eTcEbdDHMM+m7VqvT3j/EJeJwYyJ3bVb33JJDsFgefk3A2iAz2itP/UY7CzxJOJVA==", "license": "MIT", "dependencies": { "dagre": "^0.8.5", @@ -6551,9 +6575,9 @@ } }, "node_modules/rollup": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.38.0.tgz", - "integrity": "sha512-5SsIRtJy9bf1ErAOiFMFzl64Ex9X5V7bnJ+WlFMb+zmP459OSWCEG7b0ERZ+PEU7xPt4OG3RHbrp1LJlXxYTrw==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.1.tgz", + "integrity": "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==", "dev": true, "license": "MIT", "dependencies": { @@ -6567,26 +6591,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.38.0", - "@rollup/rollup-android-arm64": "4.38.0", - "@rollup/rollup-darwin-arm64": "4.38.0", - "@rollup/rollup-darwin-x64": "4.38.0", - "@rollup/rollup-freebsd-arm64": "4.38.0", - "@rollup/rollup-freebsd-x64": "4.38.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.38.0", - "@rollup/rollup-linux-arm-musleabihf": "4.38.0", - "@rollup/rollup-linux-arm64-gnu": "4.38.0", - "@rollup/rollup-linux-arm64-musl": "4.38.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.38.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.38.0", - "@rollup/rollup-linux-riscv64-gnu": "4.38.0", - "@rollup/rollup-linux-riscv64-musl": "4.38.0", - "@rollup/rollup-linux-s390x-gnu": "4.38.0", - "@rollup/rollup-linux-x64-gnu": "4.38.0", - "@rollup/rollup-linux-x64-musl": "4.38.0", - "@rollup/rollup-win32-arm64-msvc": "4.38.0", - "@rollup/rollup-win32-ia32-msvc": "4.38.0", - "@rollup/rollup-win32-x64-msvc": "4.38.0", + "@rollup/rollup-android-arm-eabi": "4.40.1", + "@rollup/rollup-android-arm64": "4.40.1", + "@rollup/rollup-darwin-arm64": "4.40.1", + "@rollup/rollup-darwin-x64": "4.40.1", + "@rollup/rollup-freebsd-arm64": "4.40.1", + "@rollup/rollup-freebsd-x64": "4.40.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.1", + "@rollup/rollup-linux-arm-musleabihf": "4.40.1", + "@rollup/rollup-linux-arm64-gnu": "4.40.1", + "@rollup/rollup-linux-arm64-musl": "4.40.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-musl": "4.40.1", + "@rollup/rollup-linux-s390x-gnu": "4.40.1", + "@rollup/rollup-linux-x64-gnu": "4.40.1", + "@rollup/rollup-linux-x64-musl": "4.40.1", + "@rollup/rollup-win32-arm64-msvc": "4.40.1", + "@rollup/rollup-win32-ia32-msvc": "4.40.1", + "@rollup/rollup-win32-x64-msvc": "4.40.1", "fsevents": "~2.3.2" } }, @@ -7035,6 +7059,23 @@ "dev": true, "license": "MIT" }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/tinypool": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", @@ -7305,9 +7346,9 @@ "dev": true }, "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==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true, "license": "MIT" }, @@ -7405,15 +7446,18 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vite": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.4.tgz", - "integrity": "sha512-veHMSew8CcRzhL5o8ONjy8gkfmFJAd5Ac16oxBUjlwgX3Gq2Wqr+qNC3TjPIpy7TPV/KporLga5GT9HqdrCizw==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", + "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", "postcss": "^8.5.3", - "rollup": "^4.30.1" + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" diff --git a/package.json b/package.json index 6b1c73db158..8504db8d0d8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.8.4", + "version": "1.9.0", "type": "module", "scripts": { "start": "vite", @@ -9,7 +9,7 @@ "build": "vite build", "build:beta": "vite build --mode beta", "preview": "vite preview", - "test": "vitest run", + "test": "vitest run --no-isolate", "test:cov": "vitest run --coverage --no-isolate", "test:watch": "vitest watch --coverage --no-isolate", "test:silent": "vitest run --silent --no-isolate", @@ -33,7 +33,7 @@ "@hpcc-js/wasm": "^2.22.4", "@stylistic/eslint-plugin-ts": "^4.1.0", "@types/jsdom": "^21.1.7", - "@types/node": "^20.12.13", + "@types/node": "^22.13.14", "@typescript-eslint/eslint-plugin": "^8.28.0", "@typescript-eslint/parser": "^8.28.0", "@vitest/coverage-istanbul": "^3.0.9", @@ -48,13 +48,14 @@ "typedoc": "^0.28.1", "typescript": "^5.8.2", "typescript-eslint": "^8.28.0", - "vite": "^6.2.0", + "vite": "^6.3.4", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.9", "vitest-canvas-mock": "^0.3.3" }, "dependencies": { "@material/material-color-utilities": "^0.2.7", + "compare-versions": "^6.1.1", "crypto-js": "^4.2.0", "i18next": "^24.2.2", "i18next-browser-languagedetector": "^8.0.4", @@ -62,10 +63,10 @@ "i18next-korean-postposition-processor": "^1.0.0", "json-stable-stringify": "^1.2.0", "jszip": "^3.10.1", - "phaser": "^3.70.0", - "phaser3-rex-plugins": "^1.80.14" + "phaser": "^3.88.2", + "phaser3-rex-plugins": "^1.80.15" }, "engines": { - "node": ">=20.0.0" + "node": ">=22.0.0" } } diff --git a/public/exp-sprites.json b/public/exp-sprites.json index d6c8534e008..2595b5a7983 100644 --- a/public/exp-sprites.json +++ b/public/exp-sprites.json @@ -613,12 +613,6 @@ "780", "781", "781", - "782", - "782", - "783", - "783", - "784", - "784", "785", "785", "786", @@ -1733,12 +1727,6 @@ "780b", "781b", "781b", - "782b", - "782b", - "783b", - "783b", - "784b", - "784b", "785b", "785b", "786b", @@ -2853,12 +2841,6 @@ "780sb", "781sb", "781sb", - "782sb", - "782sb", - "783sb", - "783sb", - "784sb", - "784sb", "785sb", "785sb", "786sb", @@ -3978,12 +3960,6 @@ "780s", "781s", "781s", - "782s", - "782s", - "783s", - "783s", - "784s", - "784s", "785s", "785s", "786s", diff --git a/public/images/events/spr25event-de.png b/public/images/events/spr25event-de.png new file mode 100644 index 00000000000..1ccd9557460 Binary files /dev/null and b/public/images/events/spr25event-de.png differ diff --git a/public/images/events/spr25event-en.png b/public/images/events/spr25event-en.png new file mode 100644 index 00000000000..0e73f9247e3 Binary files /dev/null and b/public/images/events/spr25event-en.png differ diff --git a/public/images/events/spr25event-es-ES.png b/public/images/events/spr25event-es-ES.png new file mode 100644 index 00000000000..137f1c6e743 Binary files /dev/null and b/public/images/events/spr25event-es-ES.png differ diff --git a/public/images/events/spr25event-es-MX.png b/public/images/events/spr25event-es-MX.png new file mode 100644 index 00000000000..137f1c6e743 Binary files /dev/null and b/public/images/events/spr25event-es-MX.png differ diff --git a/public/images/events/spr25event-fr.png b/public/images/events/spr25event-fr.png new file mode 100644 index 00000000000..e7089eee4a1 Binary files /dev/null and b/public/images/events/spr25event-fr.png differ diff --git a/public/images/events/spr25event-it.png b/public/images/events/spr25event-it.png new file mode 100644 index 00000000000..2664b4367cc Binary files /dev/null and b/public/images/events/spr25event-it.png differ diff --git a/public/images/events/spr25event-ja.png b/public/images/events/spr25event-ja.png new file mode 100644 index 00000000000..90b02af8050 Binary files /dev/null and b/public/images/events/spr25event-ja.png differ diff --git a/public/images/events/spr25event-ko.png b/public/images/events/spr25event-ko.png new file mode 100644 index 00000000000..a8fe279617a Binary files /dev/null and b/public/images/events/spr25event-ko.png differ diff --git a/public/images/events/spr25event-pt-BR.png b/public/images/events/spr25event-pt-BR.png new file mode 100644 index 00000000000..ae195fecc97 Binary files /dev/null and b/public/images/events/spr25event-pt-BR.png differ diff --git a/public/images/inputs/keyboard.json b/public/images/inputs/keyboard.json index c9b3c79fbfb..1e8e415b72f 100644 --- a/public/images/inputs/keyboard.json +++ b/public/images/inputs/keyboard.json @@ -516,8 +516,36 @@ "trimmed": true, "spriteSourceSize": { "x": 0, "y": 0, "w": 28, "h": 11 }, "sourceSize": { "w": 28, "h": 11 } + }, + "BACK_SLASH.png": { + "frame": { "x": 147, "y": 66, "w": 12, "h": 11 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 }, + "sourceSize": { "w": 12, "h": 11 } + }, + "FORWARD_SLASH.png": { + "frame": { "x": 144, "y": 55, "w": 12, "h": 11 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 }, + "sourceSize": { "w": 12, "h": 11 } + }, + "COMMA.png": { + "frame": { "x": 144, "y": 44, "w": 12, "h": 11 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 }, + "sourceSize": { "w": 12, "h": 11 } + }, + "PERIOD.png": { + "frame": { "x": 143, "y": 22, "w": 11, "h": 11 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 11, "h": 11 }, + "sourceSize": { "w": 11, "h": 11 } } - }, + }, "meta": { "app": "https://www.aseprite.org/", "version": "1.3.7-dev", diff --git a/public/images/inputs/keyboard.png b/public/images/inputs/keyboard.png index e4d849be0fb..0c33e579006 100644 Binary files a/public/images/inputs/keyboard.png and b/public/images/inputs/keyboard.png differ diff --git a/public/images/items.json b/public/images/items.json index 5848b02dd6a..4312f2a58c4 100644 --- a/public/images/items.json +++ b/public/images/items.json @@ -4,139 +4,13 @@ "image": "items.png", "format": "RGBA8888", "size": { - "w": 435, - "h": 435 + "w": 432, + "h": 432 }, "scale": 1, "frames": [ { - "filename": "relic_gold", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 11, - "w": 15, - "h": 11 - }, - "frame": { - "x": 0, - "y": 0, - "w": 15, - "h": 11 - } - }, - { - "filename": "ability_capsule", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 9, - "w": 24, - "h": 14 - }, - "frame": { - "x": 15, - "y": 0, - "w": 24, - "h": 14 - } - }, - { - "filename": "candy_overlay", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 12, - "w": 16, - "h": 15 - }, - "frame": { - "x": 39, - "y": 0, - "w": 16, - "h": 15 - } - }, - { - "filename": "eviolite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 15, - "h": 15 - }, - "frame": { - "x": 55, - "y": 0, - "w": 15, - "h": 15 - } - }, - { - "filename": "prism_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 8, - "w": 15, - "h": 15 - }, - "frame": { - "x": 70, - "y": 0, - "w": 15, - "h": 15 - } - }, - { - "filename": "silver_powder", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 11, - "w": 24, - "h": 15 - }, - "frame": { - "x": 85, - "y": 0, - "w": 24, - "h": 15 - } - }, - { - "filename": "ultranecrozium_z", + "filename": "galarica_cuff", "rotated": false, "trimmed": true, "sourceSize": { @@ -145,7848 +19,15 @@ }, "spriteSourceSize": { "x": 1, - "y": 9, - "w": 30, - "h": 15 - }, - "frame": { - "x": 109, - "y": 0, - "w": 30, - "h": 15 - } - }, - { - "filename": "abomasite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 139, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "absolite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 155, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "aerodactylite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 171, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "aggronite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 187, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "alakazite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 203, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "altarianite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 219, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "ampharosite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 235, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "audinite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 251, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "banettite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 267, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "beedrillite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 283, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "blastoisinite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 299, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "blazikenite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 315, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "cameruptite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 331, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "charizardite_x", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 347, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "charizardite_y", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 363, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "diancite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 379, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "galladite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 395, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "garchompite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 411, - "y": 0, - "w": 16, - "h": 16 - } - }, - { - "filename": "revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 10, - "y": 8, - "w": 12, - "h": 17 - }, - "frame": { - "x": 0, - "y": 11, - "w": 12, - "h": 17 - } - }, - { - "filename": "gardevoirite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 12, - "y": 14, - "w": 16, - "h": 16 - } - }, - { - "filename": "gengarite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 28, - "y": 15, - "w": 16, - "h": 16 - } - }, - { - "filename": "glalitite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 44, - "y": 15, - "w": 16, - "h": 16 - } - }, - { - "filename": "gyaradosite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 60, - "y": 15, - "w": 16, - "h": 16 - } - }, - { - "filename": "heracronite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 76, - "y": 15, - "w": 16, - "h": 16 - } - }, - { - "filename": "houndoominite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 92, - "y": 15, - "w": 16, - "h": 16 - } - }, - { - "filename": "kangaskhanite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 108, - "y": 15, - "w": 16, - "h": 16 - } - }, - { - "filename": "latiasite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 124, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "latiosite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 140, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "lopunnite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 156, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "lucarionite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 172, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "manectite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 188, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "mawilite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 204, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "medichamite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 220, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "mega_bracelet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 16 - }, - "frame": { - "x": 236, - "y": 16, - "w": 20, - "h": 16 - } - }, - { - "filename": "metagrossite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 256, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "mewtwonite_x", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 272, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "mewtwonite_y", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 288, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "nugget", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 304, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "pidgeotite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 320, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "pinsirite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 336, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "rayquazite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 352, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "relic_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 9, - "w": 17, - "h": 16 - }, - "frame": { - "x": 368, - "y": 16, - "w": 17, - "h": 16 - } - }, - { - "filename": "sablenite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 385, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "salamencite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 401, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "sceptilite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 417, - "y": 16, - "w": 16, - "h": 16 - } - }, - { - "filename": "scizorite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 0, - "y": 30, - "w": 16, - "h": 16 - } - }, - { - "filename": "sharpedonite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 16, - "y": 31, - "w": 16, - "h": 16 - } - }, - { - "filename": "slowbronite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 32, - "y": 31, - "w": 16, - "h": 16 - } - }, - { - "filename": "soul_dew", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 48, - "y": 31, - "w": 16, - "h": 16 - } - }, - { - "filename": "steelixite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 64, - "y": 31, - "w": 16, - "h": 16 - } - }, - { - "filename": "strawberry_sweet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 7, - "w": 16, - "h": 16 - }, - "frame": { - "x": 80, - "y": 31, - "w": 16, - "h": 16 - } - }, - { - "filename": "swampertite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 96, - "y": 31, - "w": 16, - "h": 16 - } - }, - { - "filename": "tyranitarite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 112, - "y": 32, - "w": 16, - "h": 16 - } - }, - { - "filename": "venusaurite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 128, - "y": 32, - "w": 16, - "h": 16 - } - }, - { - "filename": "black_glasses", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 144, - "y": 32, - "w": 23, - "h": 17 - } - }, - { - "filename": "burn_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 167, - "y": 32, - "w": 23, - "h": 17 - } - }, - { - "filename": "chill_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 190, - "y": 32, - "w": 23, - "h": 17 - } - }, - { - "filename": "douse_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 213, - "y": 32, - "w": 23, - "h": 17 - } - }, - { - "filename": "everstone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 17 - }, - "frame": { - "x": 236, - "y": 32, - "w": 20, - "h": 17 - } - }, - { - "filename": "shock_drive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 256, - "y": 32, - "w": 23, - "h": 17 - } - }, - { - "filename": "wise_glasses", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 23, - "h": 17 - }, - "frame": { - "x": 279, - "y": 32, - "w": 23, - "h": 17 - } - }, - { - "filename": "baton", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 302, - "y": 32, - "w": 18, - "h": 18 - } - }, - { - "filename": "candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 11, - "w": 18, - "h": 18 - }, - "frame": { - "x": 320, - "y": 32, - "w": 18, - "h": 18 - } - }, - { - "filename": "choice_specs", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 24, - "h": 18 - }, - "frame": { - "x": 338, - "y": 32, - "w": 24, - "h": 18 - } - }, - { - "filename": "dark_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 362, - "y": 32, - "w": 18, - "h": 18 - } - }, - { - "filename": "dragon_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 8, - "w": 24, - "h": 18 - }, - "frame": { - "x": 380, - "y": 32, - "w": 24, - "h": 18 - } - }, - { - "filename": "flame_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 404, - "y": 32, - "w": 18, - "h": 18 - } - }, - { - "filename": "mystery_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 18 - }, - "frame": { - "x": 0, - "y": 46, - "w": 16, - "h": 18 - } - }, - { - "filename": "light_ball", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 16, - "y": 47, - "w": 18, - "h": 18 - } - }, - { - "filename": "light_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 34, - "y": 47, - "w": 18, - "h": 18 - } - }, - { - "filename": "masterpiece_teacup", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 21, - "h": 18 - }, - "frame": { - "x": 52, - "y": 47, - "w": 21, - "h": 18 - } - }, - { - "filename": "old_gateau", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 21, - "h": 18 - }, - "frame": { - "x": 73, - "y": 47, - "w": 21, - "h": 18 - } - }, - { - "filename": "toxic_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 18 - }, - "frame": { - "x": 94, - "y": 47, - "w": 18, - "h": 18 - } - }, - { - "filename": "relic_crown", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 18 - }, - "frame": { - "x": 112, - "y": 48, - "w": 23, - "h": 18 - } - }, - { - "filename": "sharp_meteorite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 21, - "h": 18 - }, - "frame": { - "x": 135, - "y": 49, - "w": 21, - "h": 18 - } - }, - { - "filename": "unremarkable_teacup", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 21, - "h": 18 - }, - "frame": { - "x": 156, - "y": 49, - "w": 21, - "h": 18 - } - }, - { - "filename": "wl_ability_urge", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 177, - "y": 49, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_antidote", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 197, - "y": 49, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_awakening", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 217, - "y": 49, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_burn_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 237, - "y": 49, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_custom_spliced", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 257, - "y": 49, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_custom_thief", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 277, - "y": 49, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 297, - "y": 50, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 317, - "y": 50, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_full_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 337, - "y": 50, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_full_restore", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 357, - "y": 50, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_guard_spec", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 377, - "y": 50, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_hyper_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 397, - "y": 50, - "w": 20, - "h": 18 - } - }, - { - "filename": "oval_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 19 - }, - "frame": { - "x": 417, - "y": 50, - "w": 18, - "h": 19 - } - }, - { - "filename": "wl_ice_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 0, - "y": 65, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_item_drop", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 20, - "y": 65, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_item_urge", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 40, - "y": 65, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 60, - "y": 65, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 80, - "y": 65, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 100, - "y": 66, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 120, - "y": 67, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_paralyze_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 140, - "y": 67, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 160, - "y": 67, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_reset_urge", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 180, - "y": 67, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 200, - "y": 67, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_super_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 220, - "y": 67, - "w": 20, - "h": 18 - } - }, - { - "filename": "big_mushroom", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 19 - }, - "frame": { - "x": 240, - "y": 67, - "w": 19, - "h": 19 - } - }, - { - "filename": "black_sludge", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 19 - }, - "frame": { - "x": 259, - "y": 67, - "w": 22, - "h": 19 - } - }, - { - "filename": "blunder_policy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 19 - }, - "frame": { - "x": 281, - "y": 68, - "w": 22, - "h": 19 - } - }, - { - "filename": "coupon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 303, - "y": 68, - "w": 23, - "h": 19 - } - }, - { - "filename": "dubious_disc", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 19 - }, - "frame": { - "x": 326, - "y": 68, - "w": 22, - "h": 19 - } - }, - { - "filename": "golden_mystic_ticket", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 348, - "y": 68, - "w": 23, - "h": 19 - } - }, - { - "filename": "lum_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 371, - "y": 68, - "w": 20, - "h": 19 - } - }, - { - "filename": "metal_alloy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 21, - "h": 19 - }, - "frame": { - "x": 391, - "y": 68, - "w": 21, - "h": 19 - } - }, - { - "filename": "miracle_seed", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 19, - "h": 19 - }, - "frame": { - "x": 412, - "y": 69, - "w": 19, - "h": 19 - } - }, - { - "filename": "mystic_ticket", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 0, - "y": 83, - "w": 23, - "h": 19 - } - }, - { - "filename": "pair_of_tickets", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 23, - "h": 19 - }, - "frame": { - "x": 23, - "y": 83, - "w": 23, - "h": 19 - } - }, - { - "filename": "power_herb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 46, - "y": 83, - "w": 20, - "h": 19 - } - }, - { - "filename": "razor_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 66, - "y": 83, - "w": 20, - "h": 19 - } - }, - { - "filename": "upgrade", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 19 - }, - "frame": { - "x": 86, - "y": 84, - "w": 22, - "h": 19 - } - }, - { - "filename": "white_herb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 7, - "w": 20, - "h": 19 - }, - "frame": { - "x": 108, - "y": 85, - "w": 20, - "h": 19 - } - }, - { - "filename": "apicot_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 128, - "y": 85, - "w": 19, - "h": 20 - } - }, - { - "filename": "big_nugget", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 147, - "y": 85, - "w": 20, - "h": 20 - } - }, - { - "filename": "binding_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 23, - "h": 20 - }, - "frame": { - "x": 167, - "y": 85, - "w": 23, - "h": 20 - } - }, - { - "filename": "blue_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 190, - "y": 85, - "w": 20, - "h": 20 - } - }, - { - "filename": "candy_jar", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 210, - "y": 85, - "w": 19, - "h": 20 - } - }, - { - "filename": "chipped_pot", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 6, - "w": 26, - "h": 20 - }, - "frame": { - "x": 229, - "y": 86, - "w": 26, - "h": 20 - } - }, - { - "filename": "cracked_pot", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 6, - "w": 26, - "h": 20 - }, - "frame": { - "x": 255, - "y": 86, - "w": 26, - "h": 20 - } - }, - { - "filename": "deep_sea_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 281, - "y": 87, - "w": 22, - "h": 20 - } - }, - { - "filename": "fairy_feather", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 20 - }, - "frame": { - "x": 303, - "y": 87, - "w": 22, - "h": 20 - } - }, - { - "filename": "gb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 325, - "y": 87, - "w": 20, - "h": 20 - } - }, - { - "filename": "golden_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 17, - "h": 20 - }, - "frame": { - "x": 345, - "y": 87, - "w": 17, - "h": 20 - } - }, - { - "filename": "hard_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 362, - "y": 87, - "w": 19, - "h": 20 - } - }, - { - "filename": "icy_reins_of_unity", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 381, - "y": 87, - "w": 24, - "h": 20 - } - }, - { - "filename": "legend_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 6, - "w": 25, - "h": 20 - }, - "frame": { - "x": 405, - "y": 88, - "w": 25, - "h": 20 - } - }, - { - "filename": "lucky_egg", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 17, - "h": 20 - }, - "frame": { - "x": 0, - "y": 102, - "w": 17, - "h": 20 - } - }, - { - "filename": "magnet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 17, - "y": 102, - "w": 20, - "h": 20 - } - }, - { - "filename": "malicious_armor", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 37, - "y": 102, - "w": 22, - "h": 20 - } - }, - { - "filename": "mb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 59, - "y": 102, - "w": 20, - "h": 20 - } - }, - { - "filename": "metal_powder", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 79, - "y": 103, - "w": 24, - "h": 20 - } - }, - { - "filename": "pb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 103, - "y": 104, - "w": 20, - "h": 20 - } - }, - { - "filename": "pb_gold", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 123, - "y": 105, - "w": 20, - "h": 20 - } - }, - { - "filename": "pb_silver", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 143, - "y": 105, - "w": 20, - "h": 20 - } - }, - { - "filename": "quick_powder", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 163, - "y": 105, - "w": 24, - "h": 20 - } - }, - { - "filename": "razor_fang", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 18, - "h": 20 - }, - "frame": { - "x": 187, - "y": 105, - "w": 18, - "h": 20 - } - }, - { - "filename": "rb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 205, - "y": 105, - "w": 20, - "h": 20 - } - }, - { - "filename": "reviver_seed", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 8, - "w": 23, - "h": 20 - }, - "frame": { - "x": 225, - "y": 106, - "w": 23, - "h": 20 - } - }, - { - "filename": "rusted_shield", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 24, - "h": 20 - }, - "frame": { - "x": 248, - "y": 106, - "w": 24, - "h": 20 - } - }, - { - "filename": "sacred_ash", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 272, - "y": 107, - "w": 24, - "h": 20 - } - }, - { - "filename": "shadow_reins_of_unity", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 296, - "y": 107, - "w": 24, - "h": 20 - } - }, - { - "filename": "shell_bell", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 23, - "h": 20 - }, - "frame": { - "x": 320, - "y": 107, - "w": 23, - "h": 20 - } - }, - { - "filename": "smooth_meteorite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 343, - "y": 107, - "w": 20, - "h": 20 - } - }, - { - "filename": "soft_sand", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 7, - "w": 24, - "h": 20 - }, - "frame": { - "x": 363, - "y": 107, - "w": 24, - "h": 20 - } - }, - { - "filename": "strange_ball", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 387, - "y": 108, - "w": 20, - "h": 20 - } - }, - { - "filename": "tera_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 407, - "y": 108, - "w": 22, - "h": 20 - } - }, - { - "filename": "ub", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 0, - "y": 122, - "w": 20, - "h": 20 - } - }, - { - "filename": "adamant_crystal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 20, - "y": 122, - "w": 23, - "h": 21 - } - }, - { - "filename": "amulet_coin", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 43, - "y": 122, - "w": 23, - "h": 21 - } - }, - { - "filename": "auspicious_armor", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 66, - "y": 123, - "w": 23, - "h": 21 - } - }, - { - "filename": "berry_juice", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 21 - }, - "frame": { - "x": 89, - "y": 124, - "w": 22, - "h": 21 - } - }, - { - "filename": "dawn_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 21 - }, - "frame": { - "x": 111, - "y": 125, - "w": 20, - "h": 21 - } - }, - { - "filename": "deep_sea_tooth", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 131, - "y": 125, - "w": 22, - "h": 21 - } - }, - { - "filename": "dusk_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 153, - "y": 125, - "w": 21, - "h": 21 - } - }, - { - "filename": "flying_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 20, - "h": 21 - }, - "frame": { - "x": 174, - "y": 125, - "w": 20, - "h": 21 - } - }, - { - "filename": "golden_net", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 21 - }, - "frame": { - "x": 194, - "y": 125, - "w": 24, - "h": 21 - } - }, - { - "filename": "liechi_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 218, - "y": 126, - "w": 22, - "h": 21 - } - }, - { - "filename": "mint_atk", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 240, - "y": 126, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_def", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 268, - "y": 127, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_neutral", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 296, - "y": 127, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_spatk", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 324, - "y": 127, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_spd", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 352, - "y": 127, - "w": 28, - "h": 21 - } - }, - { - "filename": "mint_spdef", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 28, - "h": 21 - }, - "frame": { - "x": 380, - "y": 128, - "w": 28, - "h": 21 - } - }, - { - "filename": "moon_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 408, - "y": 128, - "w": 23, - "h": 21 - } - }, - { - "filename": "quick_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 21 - }, - "frame": { - "x": 0, - "y": 142, - "w": 19, - "h": 21 - } - }, - { - "filename": "n_lunarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 19, - "y": 143, - "w": 23, - "h": 21 - } - }, - { - "filename": "n_solarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 42, - "y": 143, - "w": 23, - "h": 21 - } - }, - { - "filename": "poison_barb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 65, - "y": 144, - "w": 21, - "h": 21 - } - }, - { - "filename": "shiny_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 86, - "y": 145, - "w": 21, - "h": 21 - } - }, - { - "filename": "spell_tag", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 6, - "w": 19, - "h": 21 - }, - "frame": { - "x": 107, - "y": 146, - "w": 19, - "h": 21 - } - }, - { - "filename": "sweet_apple", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 126, - "y": 146, - "w": 22, - "h": 21 - } - }, - { - "filename": "syrupy_apple", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 148, - "y": 146, - "w": 22, - "h": 21 - } - }, - { - "filename": "tart_apple", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 21 - }, - "frame": { - "x": 170, - "y": 146, - "w": 22, - "h": 21 - } - }, - { - "filename": "wellspring_mask", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 21 - }, - "frame": { - "x": 192, - "y": 146, - "w": 23, - "h": 21 - } - }, - { - "filename": "zoom_lens", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 215, - "y": 147, - "w": 21, - "h": 21 - } - }, - { - "filename": "berry_pot", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 18, - "h": 22 - }, - "frame": { - "x": 236, - "y": 147, - "w": 18, - "h": 22 - } - }, - { - "filename": "bug_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 254, - "y": 148, - "w": 22, - "h": 22 - } - }, - { - "filename": "charcoal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 276, - "y": 148, - "w": 22, - "h": 22 - } - }, - { - "filename": "dark_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 298, - "y": 148, - "w": 22, - "h": 22 - } - }, - { - "filename": "dire_hit", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 320, - "y": 148, - "w": 22, - "h": 22 - } - }, - { - "filename": "dna_splicers", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 342, - "y": 148, - "w": 22, - "h": 22 - } - }, - { - "filename": "leftovers", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 15, - "h": 22 - }, - "frame": { - "x": 364, - "y": 148, - "w": 15, - "h": 22 - } - }, - { - "filename": "dragon_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 379, - "y": 149, - "w": 22, - "h": 22 - } - }, - { - "filename": "electirizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 401, - "y": 149, - "w": 22, - "h": 22 - } - }, - { - "filename": "lock_capsule", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 19, - "h": 22 - }, - "frame": { - "x": 0, - "y": 163, - "w": 19, - "h": 22 - } - }, - { - "filename": "electric_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 19, - "y": 164, - "w": 22, - "h": 22 - } - }, - { - "filename": "enigma_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 41, - "y": 164, - "w": 22, - "h": 22 - } - }, - { - "filename": "fairy_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 63, - "y": 165, - "w": 22, - "h": 22 - } - }, - { - "filename": "fighting_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 85, - "y": 166, - "w": 22, - "h": 22 - } - }, - { - "filename": "exp_balance", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 107, - "y": 167, - "w": 24, - "h": 22 - } - }, - { - "filename": "exp_share", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 131, - "y": 167, - "w": 24, - "h": 22 - } - }, - { - "filename": "fire_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 155, - "y": 167, - "w": 22, - "h": 22 - } - }, - { - "filename": "flying_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 177, - "y": 167, - "w": 22, - "h": 22 - } - }, - { - "filename": "full_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 4, - "w": 15, - "h": 23 - }, - "frame": { - "x": 199, - "y": 167, - "w": 15, - "h": 23 - } - }, - { - "filename": "ganlon_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 214, - "y": 168, - "w": 22, - "h": 22 - } - }, - { - "filename": "metronome", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 17, - "h": 22 - }, - "frame": { - "x": 236, - "y": 169, - "w": 17, - "h": 22 - } - }, - { - "filename": "ghost_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 253, - "y": 170, - "w": 22, - "h": 22 - } - }, - { - "filename": "grass_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 275, - "y": 170, - "w": 22, - "h": 22 - } - }, - { - "filename": "ground_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 297, - "y": 170, - "w": 22, - "h": 22 - } - }, - { - "filename": "guard_spec", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 319, - "y": 170, - "w": 22, - "h": 22 - } - }, - { - "filename": "hard_meteorite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 5, - "w": 20, - "h": 22 - }, - "frame": { - "x": 341, - "y": 170, - "w": 20, - "h": 22 - } - }, - { - "filename": "soothe_bell", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 22 - }, - "frame": { - "x": 361, - "y": 170, - "w": 17, - "h": 22 - } - }, - { - "filename": "healing_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 23, - "h": 22 - }, - "frame": { - "x": 378, - "y": 171, - "w": 23, - "h": 22 - } - }, - { - "filename": "ice_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 401, - "y": 171, - "w": 22, - "h": 22 - } - }, - { - "filename": "metal_coat", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 19, - "h": 22 - }, - "frame": { - "x": 0, - "y": 185, - "w": 19, - "h": 22 - } - }, - { - "filename": "ice_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 19, - "y": 186, - "w": 22, - "h": 22 - } - }, - { - "filename": "magmarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 41, - "y": 186, - "w": 22, - "h": 22 - } - }, - { - "filename": "mini_black_hole", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 63, - "y": 187, - "w": 22, - "h": 22 - } - }, - { - "filename": "moon_flute", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 85, - "y": 188, - "w": 22, - "h": 22 - } - }, - { - "filename": "map", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 5, - "w": 27, - "h": 22 - }, - "frame": { - "x": 107, - "y": 189, - "w": 27, - "h": 22 - } - }, - { - "filename": "normal_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 134, - "y": 189, - "w": 22, - "h": 22 - } - }, - { - "filename": "peat_block", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 156, - "y": 189, - "w": 24, - "h": 22 - } - }, - { - "filename": "hyper_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 180, - "y": 189, - "w": 17, - "h": 23 - } - }, - { - "filename": "poison_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 197, - "y": 190, - "w": 22, - "h": 22 - } - }, - { - "filename": "potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 219, - "y": 190, - "w": 17, - "h": 23 - } - }, - { - "filename": "protector", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 236, - "y": 192, - "w": 22, - "h": 22 - } - }, - { - "filename": "psychic_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 258, - "y": 192, - "w": 22, - "h": 22 - } - }, - { - "filename": "rock_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 280, - "y": 192, - "w": 22, - "h": 22 - } - }, - { - "filename": "rusted_sword", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 22 - }, - "frame": { - "x": 302, - "y": 192, - "w": 23, - "h": 22 - } - }, - { - "filename": "scroll_of_darkness", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 325, - "y": 192, - "w": 22, - "h": 22 - } - }, - { - "filename": "scroll_of_waters", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 347, - "y": 192, - "w": 22, - "h": 22 - } - }, - { - "filename": "shed_shell", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 369, - "y": 193, - "w": 22, - "h": 22 - } - }, - { - "filename": "sitrus_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 20, - "h": 22 - }, - "frame": { - "x": 391, - "y": 193, - "w": 20, - "h": 22 - } - }, - { - "filename": "starf_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 411, - "y": 193, - "w": 22, - "h": 22 - } - }, - { - "filename": "sachet", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 18, - "h": 23 - }, - "frame": { - "x": 0, - "y": 207, - "w": 18, - "h": 23 - } - }, - { - "filename": "steel_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 18, - "y": 208, - "w": 22, - "h": 22 - } - }, - { - "filename": "sun_flute", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 40, - "y": 208, - "w": 22, - "h": 22 - } - }, - { - "filename": "thick_club", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 62, - "y": 209, - "w": 22, - "h": 22 - } - }, - { - "filename": "thunder_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 84, - "y": 210, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_bug", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 106, - "y": 211, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_dark", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 128, - "y": 211, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_dragon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 150, - "y": 211, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_electric", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 172, - "y": 212, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_fairy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 194, - "y": 212, - "w": 22, - "h": 22 - } - }, - { - "filename": "mystic_water", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 20, - "h": 23 - }, - "frame": { - "x": 216, - "y": 213, - "w": 20, - "h": 23 - } - }, - { - "filename": "tm_fighting", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 236, - "y": 214, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_fire", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 258, - "y": 214, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_flying", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 280, - "y": 214, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_ghost", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 302, - "y": 214, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_grass", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 324, - "y": 214, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_ground", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 346, - "y": 214, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_ice", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 368, - "y": 215, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_normal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 390, - "y": 215, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_poison", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 412, - "y": 215, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_psychic", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 0, - "y": 230, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_rock", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 22, - "y": 230, - "w": 22, - "h": 22 - } - }, - { - "filename": "super_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 44, - "y": 230, - "w": 17, - "h": 23 - } - }, - { - "filename": "tm_steel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 61, - "y": 231, - "w": 22, - "h": 22 - } - }, - { - "filename": "tm_water", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 83, - "y": 232, - "w": 22, - "h": 22 - } - }, - { - "filename": "water_memory", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 105, - "y": 233, - "w": 22, - "h": 22 - } - }, - { - "filename": "water_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 127, - "y": 233, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_accuracy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 149, - "y": 233, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_attack", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 171, - "y": 234, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_defense", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 193, - "y": 234, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_sp_atk", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 215, - "y": 236, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_sp_def", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 237, - "y": 236, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_speed", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 259, - "y": 236, - "w": 22, - "h": 22 - } - }, - { - "filename": "berry_pouch", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 281, - "y": 236, - "w": 23, - "h": 23 - } - }, - { - "filename": "black_belt", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 304, - "y": 236, - "w": 22, - "h": 23 - } - }, - { - "filename": "bug_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 326, - "y": 236, - "w": 22, - "h": 23 - } - }, - { - "filename": "calcium", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 348, - "y": 236, - "w": 16, - "h": 24 - } - }, - { - "filename": "clefairy_doll", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 364, - "y": 237, - "w": 24, - "h": 23 - } - }, - { - "filename": "coin_case", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 388, - "y": 237, - "w": 24, - "h": 23 - } - }, - { - "filename": "dark_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 412, - "y": 237, - "w": 22, - "h": 23 - } - }, - { - "filename": "dragon_fang", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, - "h": 23 - }, - "frame": { - "x": 0, - "y": 252, - "w": 21, - "h": 23 - } - }, - { - "filename": "dragon_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 21, - "y": 252, - "w": 22, - "h": 23 - } - }, - { - "filename": "dynamax_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 23, - "h": 23 - }, - "frame": { - "x": 43, - "y": 253, - "w": 23, - "h": 23 - } - }, - { - "filename": "carbos", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 66, - "y": 253, - "w": 16, - "h": 24 - } - }, - { - "filename": "electric_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 82, - "y": 254, - "w": 22, - "h": 23 - } - }, - { - "filename": "expert_belt", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 23 - }, - "frame": { - "x": 104, - "y": 255, - "w": 24, - "h": 23 - } - }, - { - "filename": "fairy_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 128, - "y": 255, - "w": 22, - "h": 23 - } - }, - { - "filename": "lansat_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 21, - "h": 23 - }, - "frame": { - "x": 150, - "y": 255, - "w": 21, - "h": 23 - } - }, - { - "filename": "fighting_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 171, - "y": 256, - "w": 22, - "h": 23 - } - }, - { - "filename": "fire_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 23 - }, - "frame": { - "x": 193, - "y": 256, - "w": 22, - "h": 23 - } - }, - { - "filename": "fire_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 215, - "y": 258, - "w": 22, - "h": 23 - } - }, - { - "filename": "focus_sash", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 237, - "y": 258, - "w": 22, - "h": 23 - } - }, - { - "filename": "ghost_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 259, - "y": 258, - "w": 22, - "h": 23 - } - }, - { - "filename": "grass_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 281, - "y": 259, - "w": 22, - "h": 23 - } - }, - { - "filename": "griseous_core", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 303, - "y": 259, - "w": 23, - "h": 23 - } - }, - { - "filename": "ground_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 326, - "y": 259, - "w": 22, - "h": 23 - } - }, - { - "filename": "hearthflame_mask", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 23 - }, - "frame": { - "x": 348, - "y": 260, - "w": 24, - "h": 23 - } - }, - { - "filename": "ice_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 372, - "y": 260, - "w": 22, - "h": 23 - } - }, - { - "filename": "leaf_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, - "h": 23 - }, - "frame": { - "x": 394, - "y": 260, - "w": 21, - "h": 23 - } - }, - { - "filename": "elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 415, - "y": 260, - "w": 18, - "h": 24 - } - }, - { - "filename": "leek", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 0, - "y": 275, - "w": 23, - "h": 23 - } - }, - { - "filename": "ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 23, - "y": 275, - "w": 18, - "h": 24 - } - }, - { - "filename": "leppa_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 41, - "y": 276, - "w": 24, - "h": 23 - } - }, - { - "filename": "macho_brace", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 65, - "y": 277, - "w": 23, - "h": 23 - } - }, - { - "filename": "hp_up", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 88, - "y": 277, - "w": 16, - "h": 24 - } - }, - { - "filename": "never_melt_ice", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 23 - }, - "frame": { - "x": 104, - "y": 278, - "w": 22, - "h": 23 - } - }, - { - "filename": "normal_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 126, - "y": 278, - "w": 22, - "h": 23 - } - }, - { - "filename": "petaya_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 23 - }, - "frame": { - "x": 148, - "y": 278, - "w": 22, - "h": 23 - } - }, - { - "filename": "poison_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 170, - "y": 279, - "w": 22, - "h": 23 - } - }, - { - "filename": "psychic_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 192, - "y": 279, - "w": 22, - "h": 23 - } - }, - { - "filename": "rare_candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 214, - "y": 281, - "w": 23, - "h": 23 - } - }, - { - "filename": "rarer_candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 237, - "y": 281, - "w": 23, - "h": 23 - } - }, - { - "filename": "sharp_beak", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 21, - "h": 23 - }, - "frame": { - "x": 260, - "y": 281, - "w": 21, - "h": 23 - } - }, - { - "filename": "reaper_cloth", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 23 - }, - "frame": { - "x": 281, - "y": 282, - "w": 22, - "h": 23 - } - }, - { - "filename": "rock_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 303, - "y": 282, - "w": 22, - "h": 23 - } - }, - { - "filename": "steel_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 325, - "y": 282, - "w": 22, - "h": 23 - } - }, - { - "filename": "scope_lens", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 347, - "y": 283, - "w": 24, - "h": 23 - } - }, - { - "filename": "stellar_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 371, - "y": 283, - "w": 22, - "h": 23 - } - }, - { - "filename": "water_tera_shard", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 393, - "y": 283, - "w": 22, - "h": 23 - } - }, - { - "filename": "full_restore", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 415, - "y": 284, - "w": 18, - "h": 24 - } - }, - { - "filename": "whipped_dream", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 21, - "h": 23 - }, - "frame": { - "x": 0, - "y": 298, - "w": 21, - "h": 23 - } - }, - { - "filename": "twisted_spoon", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 23 - }, - "frame": { - "x": 21, - "y": 299, - "w": 24, - "h": 23 - } - }, - { - "filename": "iron", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 45, - "y": 299, - "w": 16, - "h": 24 - } - }, - { - "filename": "wide_lens", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 23 - }, - "frame": { - "x": 61, - "y": 300, - "w": 22, - "h": 23 - } - }, - { - "filename": "big_root", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 83, - "y": 301, - "w": 23, - "h": 24 - } - }, - { - "filename": "blank_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 106, - "y": 301, - "w": 24, - "h": 24 - } - }, - { - "filename": "catching_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 21, - "h": 24 - }, - "frame": { - "x": 130, - "y": 301, - "w": 21, - "h": 24 - } - }, - { - "filename": "lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 151, - "y": 301, - "w": 17, - "h": 24 - } - }, - { - "filename": "choice_scarf", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 168, - "y": 302, - "w": 24, - "h": 24 - } - }, - { - "filename": "max_elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 192, - "y": 302, - "w": 18, - "h": 24 - } - }, - { - "filename": "draco_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 210, - "y": 304, - "w": 24, - "h": 24 - } - }, - { - "filename": "dread_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 234, - "y": 304, - "w": 24, - "h": 24 - } - }, - { - "filename": "kings_rock", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 258, - "y": 304, - "w": 23, - "h": 24 - } - }, - { - "filename": "earth_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 281, - "y": 305, - "w": 24, - "h": 24 - } - }, - { - "filename": "fist_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 305, - "y": 305, - "w": 24, - "h": 24 - } - }, - { - "filename": "max_ether", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 329, - "y": 305, - "w": 18, - "h": 24 - } - }, - { - "filename": "flame_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 347, - "y": 306, - "w": 24, - "h": 24 - } - }, - { - "filename": "focus_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 371, - "y": 306, - "w": 24, - "h": 24 - } - }, - { - "filename": "max_lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 395, - "y": 306, - "w": 17, - "h": 24 - } - }, - { - "filename": "max_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 412, - "y": 308, - "w": 18, - "h": 24 - } - }, - { - "filename": "max_repel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 0, - "y": 321, - "w": 16, - "h": 24 - } - }, - { - "filename": "golden_punch", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 16, - "y": 322, - "w": 24, - "h": 24 - } - }, - { - "filename": "gracidea", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 40, - "y": 323, - "w": 24, - "h": 24 - } - }, - { - "filename": "pp_max", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 64, - "y": 323, - "w": 16, - "h": 24 - } - }, - { - "filename": "grip_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 80, - "y": 325, - "w": 24, - "h": 24 - } - }, - { - "filename": "icicle_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 104, - "y": 325, - "w": 24, - "h": 24 - } - }, - { - "filename": "insect_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 128, - "y": 325, - "w": 24, - "h": 24 - } - }, - { - "filename": "pp_up", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 152, - "y": 325, - "w": 16, - "h": 24 - } - }, - { - "filename": "iron_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 168, - "y": 326, - "w": 24, - "h": 24 - } - }, - { - "filename": "protein", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 192, - "y": 326, - "w": 16, - "h": 24 - } - }, - { - "filename": "lucky_punch", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 208, - "y": 328, - "w": 24, - "h": 24 - } - }, - { - "filename": "lucky_punch_great", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 232, - "y": 328, - "w": 24, - "h": 24 - } - }, - { - "filename": "lucky_punch_master", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 256, - "y": 328, - "w": 24, - "h": 24 - } - }, - { - "filename": "lucky_punch_ultra", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 280, - "y": 329, - "w": 24, - "h": 24 - } - }, - { - "filename": "lustrous_globe", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 304, - "y": 329, - "w": 24, - "h": 24 - } - }, - { - "filename": "repel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 328, - "y": 329, - "w": 16, - "h": 24 - } - }, - { - "filename": "max_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 24 - }, - "frame": { - "x": 344, - "y": 330, - "w": 22, - "h": 24 - } - }, - { - "filename": "meadow_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 366, - "y": 330, - "w": 24, - "h": 24 - } - }, - { - "filename": "oval_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 21, - "h": 24 - }, - "frame": { - "x": 390, - "y": 330, - "w": 21, - "h": 24 - } - }, - { - "filename": "mind_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 411, - "y": 332, - "w": 24, - "h": 24 - } - }, - { - "filename": "super_repel", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 0, - "y": 345, - "w": 16, - "h": 24 - } - }, - { - "filename": "muscle_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 16, - "y": 346, - "w": 24, - "h": 24 - } - }, - { - "filename": "pixie_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 40, - "y": 347, - "w": 24, - "h": 24 - } - }, - { - "filename": "unknown", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 64, - "y": 347, - "w": 16, - "h": 24 - } - }, - { - "filename": "red_orb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 20, - "h": 24 - }, - "frame": { - "x": 80, - "y": 349, - "w": 20, - "h": 24 - } - }, - { - "filename": "reveal_glass", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 100, - "y": 349, - "w": 23, - "h": 24 - } - }, - { - "filename": "salac_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 123, - "y": 349, - "w": 24, - "h": 24 - } - }, - { - "filename": "shiny_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 4, - "w": 21, - "h": 24 - }, - "frame": { - "x": 147, - "y": 349, - "w": 21, - "h": 24 - } - }, - { - "filename": "scanner", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 168, - "y": 350, - "w": 24, - "h": 24 - } - }, - { - "filename": "zinc", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 192, - "y": 350, - "w": 16, - "h": 24 - } - }, - { - "filename": "silk_scarf", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 208, - "y": 352, - "w": 24, - "h": 24 - } - }, - { - "filename": "sky_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 232, - "y": 352, - "w": 24, - "h": 24 - } - }, - { - "filename": "splash_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 256, - "y": 352, - "w": 24, - "h": 24 - } - }, - { - "filename": "spooky_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 280, - "y": 353, - "w": 24, - "h": 24 - } - }, - { - "filename": "stone_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 304, - "y": 353, - "w": 24, - "h": 24 - } - }, - { - "filename": "sun_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 328, - "y": 354, - "w": 24, - "h": 24 - } - }, - { - "filename": "super_lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 352, - "y": 354, - "w": 17, - "h": 24 - } - }, - { - "filename": "toxic_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 369, - "y": 354, - "w": 24, - "h": 24 - } - }, - { - "filename": "zap_plate", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 393, - "y": 356, - "w": 24, - "h": 24 - } - }, - { - "filename": "prison_bottle", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, "y": 1, - "w": 17, + "w": 29, "h": 30 }, - "frame": { - "x": 417, - "y": 356, - "w": 17, - "h": 30 - } - }, - { - "filename": "black_augurite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 3, - "w": 22, - "h": 25 - }, "frame": { "x": 0, - "y": 370, - "w": 22, - "h": 25 - } - }, - { - "filename": "ability_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 23, - "h": 26 - }, - "frame": { - "x": 22, - "y": 371, - "w": 23, - "h": 26 - } - }, - { - "filename": "cornerstone_mask", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 3, - "w": 24, - "h": 26 - }, - "frame": { - "x": 45, - "y": 371, - "w": 24, - "h": 26 - } - }, - { - "filename": "linking_cord", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 27, - "h": 26 - }, - "frame": { - "x": 69, - "y": 373, - "w": 27, - "h": 26 - } - }, - { - "filename": "mystical_rock", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 28, - "h": 26 - }, - "frame": { - "x": 96, - "y": 373, - "w": 28, - "h": 26 + "y": 0, + "w": 29, + "h": 30 } }, { @@ -8004,54 +45,12 @@ "h": 27 }, "frame": { - "x": 124, - "y": 373, + "x": 29, + "y": 0, "w": 32, "h": 27 } }, - { - "filename": "leaders_crest", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 29, - "h": 27 - }, - "frame": { - "x": 156, - "y": 374, - "w": 29, - "h": 27 - } - }, - { - "filename": "ribbon_gen1", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 22, - "h": 28 - }, - "frame": { - "x": 185, - "y": 374, - "w": 22, - "h": 28 - } - }, { "filename": "max_mushrooms", "rotated": false, @@ -8067,33 +66,12 @@ "h": 28 }, "frame": { - "x": 207, - "y": 376, + "x": 0, + "y": 30, "w": 29, "h": 28 } }, - { - "filename": "ribbon_gen2", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 28, - "h": 28 - }, - "frame": { - "x": 236, - "y": 376, - "w": 28, - "h": 28 - } - }, { "filename": "ribbon_gen4", "rotated": false, @@ -8109,14 +87,14 @@ "h": 28 }, "frame": { - "x": 264, - "y": 377, + "x": 29, + "y": 27, "w": 30, "h": 28 } }, { - "filename": "ribbon_gen5", + "filename": "leaders_crest", "rotated": false, "trimmed": true, "sourceSize": { @@ -8124,184 +102,37 @@ "h": 32 }, "spriteSourceSize": { - "x": 5, + "x": 2, + "y": 3, + "w": 29, + "h": 27 + }, + "frame": { + "x": 61, + "y": 0, + "w": 29, + "h": 27 + } + }, + { + "filename": "ribbon_gen2", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, "y": 2, - "w": 22, + "w": 28, "h": 28 }, - "frame": { - "x": 294, - "y": 377, - "w": 22, - "h": 28 - } - }, - { - "filename": "ribbon_gen6", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 22, - "h": 28 - }, - "frame": { - "x": 316, - "y": 378, - "w": 22, - "h": 28 - } - }, - { - "filename": "ribbon_gen8", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 22, - "h": 28 - }, - "frame": { - "x": 338, - "y": 378, - "w": 22, - "h": 28 - } - }, - { - "filename": "ribbon_gen3", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 22, - "h": 29 - }, - "frame": { - "x": 360, - "y": 378, - "w": 22, - "h": 29 - } - }, - { - "filename": "ribbon_gen7", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 22, - "h": 29 - }, - "frame": { - "x": 382, - "y": 380, - "w": 22, - "h": 29 - } - }, - { - "filename": "ribbon_gen9", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 22, - "h": 29 - }, - "frame": { - "x": 404, - "y": 386, - "w": 22, - "h": 29 - } - }, - { - "filename": "inverse", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 22, - "h": 30 - }, "frame": { "x": 0, - "y": 395, - "w": 22, - "h": 30 - } - }, - { - "filename": "galarica_cuff", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 29, - "h": 30 - }, - "frame": { - "x": 22, - "y": 397, - "w": 29, - "h": 30 - } - }, - { - "filename": "exp_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 17, - "h": 31 - }, - "frame": { - "x": 51, - "y": 397, - "w": 17, - "h": 31 + "y": 58, + "w": 28, + "h": 28 } }, { @@ -8319,54 +150,12 @@ "h": 31 }, "frame": { - "x": 68, - "y": 399, + "x": 0, + "y": 86, "w": 22, "h": 31 } }, - { - "filename": "golden_exp_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 17, - "h": 31 - }, - "frame": { - "x": 90, - "y": 399, - "w": 17, - "h": 31 - } - }, - { - "filename": "super_exp_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 17, - "h": 31 - }, - "frame": { - "x": 107, - "y": 399, - "w": 17, - "h": 31 - } - }, { "filename": "great_ribbon", "rotated": false, @@ -8382,12 +171,33 @@ "h": 31 }, "frame": { - "x": 124, - "y": 400, + "x": 0, + "y": 117, "w": 22, "h": 31 } }, + { + "filename": "linking_cord", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 3, + "w": 27, + "h": 26 + }, + "frame": { + "x": 59, + "y": 27, + "w": 27, + "h": 26 + } + }, { "filename": "master_ribbon", "rotated": false, @@ -8403,8 +213,8 @@ "h": 31 }, "frame": { - "x": 146, - "y": 401, + "x": 0, + "y": 148, "w": 22, "h": 31 } @@ -8424,8 +234,8 @@ "h": 31 }, "frame": { - "x": 168, - "y": 402, + "x": 0, + "y": 179, "w": 22, "h": 31 } @@ -8445,11 +255,8201 @@ "h": 31 }, "frame": { - "x": 190, - "y": 404, + "x": 0, + "y": 210, "w": 22, "h": 31 } + }, + { + "filename": "inverse", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 30 + }, + "frame": { + "x": 0, + "y": 241, + "w": 22, + "h": 30 + } + }, + { + "filename": "ribbon_gen3", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 29 + }, + "frame": { + "x": 0, + "y": 271, + "w": 22, + "h": 29 + } + }, + { + "filename": "ribbon_gen7", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 29 + }, + "frame": { + "x": 0, + "y": 300, + "w": 22, + "h": 29 + } + }, + { + "filename": "ribbon_gen9", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 1, + "w": 22, + "h": 29 + }, + "frame": { + "x": 0, + "y": 329, + "w": 22, + "h": 29 + } + }, + { + "filename": "cornerstone_mask", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 3, + "w": 24, + "h": 26 + }, + "frame": { + "x": 90, + "y": 0, + "w": 24, + "h": 26 + } + }, + { + "filename": "ribbon_gen1", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 2, + "w": 22, + "h": 28 + }, + "frame": { + "x": 0, + "y": 358, + "w": 22, + "h": 28 + } + }, + { + "filename": "ribbon_gen5", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 2, + "w": 22, + "h": 28 + }, + "frame": { + "x": 0, + "y": 386, + "w": 22, + "h": 28 + } + }, + { + "filename": "choice_specs", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 24, + "h": 18 + }, + "frame": { + "x": 0, + "y": 414, + "w": 24, + "h": 18 + } + }, + { + "filename": "ability_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 3, + "w": 23, + "h": 26 + }, + "frame": { + "x": 114, + "y": 0, + "w": 23, + "h": 26 + } + }, + { + "filename": "map", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 5, + "w": 27, + "h": 22 + }, + "frame": { + "x": 137, + "y": 0, + "w": 27, + "h": 22 + } + }, + { + "filename": "mint_atk", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 164, + "y": 0, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_def", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 192, + "y": 0, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_neutral", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 220, + "y": 0, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_spatk", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 248, + "y": 0, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_spd", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 276, + "y": 0, + "w": 28, + "h": 21 + } + }, + { + "filename": "mint_spdef", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 2, + "y": 5, + "w": 28, + "h": 21 + }, + "frame": { + "x": 304, + "y": 0, + "w": 28, + "h": 21 + } + }, + { + "filename": "chipped_pot", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 6, + "w": 26, + "h": 20 + }, + "frame": { + "x": 332, + "y": 0, + "w": 26, + "h": 20 + } + }, + { + "filename": "cracked_pot", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 6, + "w": 26, + "h": 20 + }, + "frame": { + "x": 358, + "y": 0, + "w": 26, + "h": 20 + } + }, + { + "filename": "legend_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 6, + "w": 25, + "h": 20 + }, + "frame": { + "x": 384, + "y": 0, + "w": 25, + "h": 20 + } + }, + { + "filename": "big_root", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 23, + "h": 24 + }, + "frame": { + "x": 409, + "y": 0, + "w": 23, + "h": 24 + } + }, + { + "filename": "exp_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 1, + "w": 17, + "h": 31 + }, + "frame": { + "x": 22, + "y": 86, + "w": 17, + "h": 31 + } + }, + { + "filename": "golden_exp_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 1, + "w": 17, + "h": 31 + }, + "frame": { + "x": 22, + "y": 117, + "w": 17, + "h": 31 + } + }, + { + "filename": "super_exp_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 1, + "w": 17, + "h": 31 + }, + "frame": { + "x": 22, + "y": 148, + "w": 17, + "h": 31 + } + }, + { + "filename": "prison_bottle", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 1, + "w": 17, + "h": 30 + }, + "frame": { + "x": 22, + "y": 179, + "w": 17, + "h": 30 + } + }, + { + "filename": "ribbon_gen6", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 2, + "w": 22, + "h": 28 + }, + "frame": { + "x": 22, + "y": 209, + "w": 22, + "h": 28 + } + }, + { + "filename": "ribbon_gen8", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 2, + "w": 22, + "h": 28 + }, + "frame": { + "x": 22, + "y": 237, + "w": 22, + "h": 28 + } + }, + { + "filename": "black_augurite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 3, + "w": 22, + "h": 25 + }, + "frame": { + "x": 22, + "y": 265, + "w": 22, + "h": 25 + } + }, + { + "filename": "blank_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 22, + "y": 290, + "w": 24, + "h": 24 + } + }, + { + "filename": "choice_scarf", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 22, + "y": 314, + "w": 24, + "h": 24 + } + }, + { + "filename": "draco_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 22, + "y": 338, + "w": 24, + "h": 24 + } + }, + { + "filename": "dread_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 22, + "y": 362, + "w": 24, + "h": 24 + } + }, + { + "filename": "earth_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 22, + "y": 386, + "w": 24, + "h": 24 + } + }, + { + "filename": "exp_balance", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 24, + "y": 410, + "w": 24, + "h": 22 + } + }, + { + "filename": "ultranecrozium_z", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 1, + "y": 9, + "w": 30, + "h": 15 + }, + "frame": { + "x": 29, + "y": 55, + "w": 30, + "h": 15 + } + }, + { + "filename": "mega_bracelet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 16 + }, + "frame": { + "x": 28, + "y": 70, + "w": 20, + "h": 16 + } + }, + { + "filename": "mystical_rock", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 25, + "h": 23 + }, + "frame": { + "x": 59, + "y": 53, + "w": 25, + "h": 23 + } + }, + { + "filename": "calcium", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 39, + "y": 86, + "w": 16, + "h": 24 + } + }, + { + "filename": "carbos", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 39, + "y": 110, + "w": 16, + "h": 24 + } + }, + { + "filename": "catching_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 21, + "h": 24 + }, + "frame": { + "x": 39, + "y": 134, + "w": 21, + "h": 24 + } + }, + { + "filename": "fist_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 39, + "y": 158, + "w": 24, + "h": 24 + } + }, + { + "filename": "flame_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 39, + "y": 182, + "w": 24, + "h": 24 + } + }, + { + "filename": "focus_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 44, + "y": 206, + "w": 24, + "h": 24 + } + }, + { + "filename": "golden_punch", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 44, + "y": 230, + "w": 24, + "h": 24 + } + }, + { + "filename": "gracidea", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 44, + "y": 254, + "w": 24, + "h": 24 + } + }, + { + "filename": "grip_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 55, + "y": 76, + "w": 24, + "h": 24 + } + }, + { + "filename": "icicle_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 55, + "y": 100, + "w": 24, + "h": 24 + } + }, + { + "filename": "insect_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 46, + "y": 278, + "w": 24, + "h": 24 + } + }, + { + "filename": "iron_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 46, + "y": 302, + "w": 24, + "h": 24 + } + }, + { + "filename": "lucky_punch", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 46, + "y": 326, + "w": 24, + "h": 24 + } + }, + { + "filename": "lucky_punch_great", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 46, + "y": 350, + "w": 24, + "h": 24 + } + }, + { + "filename": "lucky_punch_master", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 46, + "y": 374, + "w": 24, + "h": 24 + } + }, + { + "filename": "kings_rock", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 23, + "h": 24 + }, + "frame": { + "x": 48, + "y": 398, + "w": 23, + "h": 24 + } + }, + { + "filename": "lucky_punch_ultra", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 60, + "y": 124, + "w": 24, + "h": 24 + } + }, + { + "filename": "lustrous_globe", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 63, + "y": 148, + "w": 24, + "h": 24 + } + }, + { + "filename": "meadow_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 63, + "y": 172, + "w": 24, + "h": 24 + } + }, + { + "filename": "max_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 24 + }, + "frame": { + "x": 68, + "y": 196, + "w": 22, + "h": 24 + } + }, + { + "filename": "mind_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 68, + "y": 220, + "w": 24, + "h": 24 + } + }, + { + "filename": "muscle_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 68, + "y": 244, + "w": 24, + "h": 24 + } + }, + { + "filename": "pixie_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 70, + "y": 268, + "w": 24, + "h": 24 + } + }, + { + "filename": "salac_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 70, + "y": 292, + "w": 24, + "h": 24 + } + }, + { + "filename": "scanner", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 70, + "y": 316, + "w": 24, + "h": 24 + } + }, + { + "filename": "silk_scarf", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 70, + "y": 340, + "w": 24, + "h": 24 + } + }, + { + "filename": "sky_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 70, + "y": 364, + "w": 24, + "h": 24 + } + }, + { + "filename": "reveal_glass", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 23, + "h": 24 + }, + "frame": { + "x": 71, + "y": 388, + "w": 23, + "h": 24 + } + }, + { + "filename": "icy_reins_of_unity", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 71, + "y": 412, + "w": 24, + "h": 20 + } + }, + { + "filename": "elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 79, + "y": 76, + "w": 18, + "h": 24 + } + }, + { + "filename": "ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 79, + "y": 100, + "w": 18, + "h": 24 + } + }, + { + "filename": "full_restore", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 84, + "y": 124, + "w": 18, + "h": 24 + } + }, + { + "filename": "hp_up", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 87, + "y": 148, + "w": 16, + "h": 24 + } + }, + { + "filename": "iron", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 87, + "y": 172, + "w": 16, + "h": 24 + } + }, + { + "filename": "lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 90, + "y": 196, + "w": 17, + "h": 24 + } + }, + { + "filename": "max_elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 92, + "y": 220, + "w": 18, + "h": 24 + } + }, + { + "filename": "max_ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 92, + "y": 244, + "w": 18, + "h": 24 + } + }, + { + "filename": "max_lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 94, + "y": 268, + "w": 17, + "h": 24 + } + }, + { + "filename": "max_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 94, + "y": 292, + "w": 18, + "h": 24 + } + }, + { + "filename": "oval_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 21, + "h": 24 + }, + "frame": { + "x": 94, + "y": 316, + "w": 21, + "h": 24 + } + }, + { + "filename": "shiny_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 21, + "h": 24 + }, + "frame": { + "x": 94, + "y": 340, + "w": 21, + "h": 24 + } + }, + { + "filename": "splash_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 94, + "y": 364, + "w": 24, + "h": 24 + } + }, + { + "filename": "spooky_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 94, + "y": 388, + "w": 24, + "h": 24 + } + }, + { + "filename": "metal_powder", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 24, + "h": 20 + }, + "frame": { + "x": 95, + "y": 412, + "w": 24, + "h": 20 + } + }, + { + "filename": "berry_pouch", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 84, + "y": 53, + "w": 23, + "h": 23 + } + }, + { + "filename": "max_repel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 97, + "y": 76, + "w": 16, + "h": 24 + } + }, + { + "filename": "pp_max", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 97, + "y": 100, + "w": 16, + "h": 24 + } + }, + { + "filename": "pp_up", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 102, + "y": 124, + "w": 16, + "h": 24 + } + }, + { + "filename": "protein", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 103, + "y": 148, + "w": 16, + "h": 24 + } + }, + { + "filename": "red_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 20, + "h": 24 + }, + "frame": { + "x": 103, + "y": 172, + "w": 20, + "h": 24 + } + }, + { + "filename": "repel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 107, + "y": 196, + "w": 16, + "h": 24 + } + }, + { + "filename": "stone_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 110, + "y": 220, + "w": 24, + "h": 24 + } + }, + { + "filename": "sun_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 110, + "y": 244, + "w": 24, + "h": 24 + } + }, + { + "filename": "toxic_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 111, + "y": 268, + "w": 24, + "h": 24 + } + }, + { + "filename": "zap_plate", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 112, + "y": 292, + "w": 24, + "h": 24 + } + }, + { + "filename": "black_belt", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 115, + "y": 316, + "w": 22, + "h": 23 + } + }, + { + "filename": "bug_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 115, + "y": 339, + "w": 22, + "h": 23 + } + }, + { + "filename": "clefairy_doll", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 118, + "y": 362, + "w": 24, + "h": 23 + } + }, + { + "filename": "coin_case", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 118, + "y": 385, + "w": 24, + "h": 23 + } + }, + { + "filename": "super_lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 119, + "y": 408, + "w": 17, + "h": 24 + } + }, + { + "filename": "super_repel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 136, + "y": 408, + "w": 16, + "h": 24 + } + }, + { + "filename": "ability_capsule", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 9, + "w": 24, + "h": 14 + }, + "frame": { + "x": 137, + "y": 22, + "w": 24, + "h": 14 + } + }, + { + "filename": "black_glasses", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 86, + "y": 36, + "w": 23, + "h": 17 + } + }, + { + "filename": "expert_belt", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 23 + }, + "frame": { + "x": 109, + "y": 26, + "w": 24, + "h": 23 + } + }, + { + "filename": "dragon_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 24, + "h": 18 + }, + "frame": { + "x": 133, + "y": 36, + "w": 24, + "h": 18 + } + }, + { + "filename": "exp_share", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 109, + "y": 49, + "w": 24, + "h": 22 + } + }, + { + "filename": "golden_net", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 21 + }, + "frame": { + "x": 133, + "y": 54, + "w": 24, + "h": 21 + } + }, + { + "filename": "mystic_water", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 20, + "h": 23 + }, + "frame": { + "x": 113, + "y": 71, + "w": 20, + "h": 23 + } + }, + { + "filename": "dark_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 113, + "y": 94, + "w": 22, + "h": 23 + } + }, + { + "filename": "coupon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 133, + "y": 75, + "w": 23, + "h": 19 + } + }, + { + "filename": "dragon_fang", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 21, + "h": 23 + }, + "frame": { + "x": 135, + "y": 94, + "w": 21, + "h": 23 + } + }, + { + "filename": "hearthflame_mask", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 23 + }, + "frame": { + "x": 118, + "y": 117, + "w": 24, + "h": 23 + } + }, + { + "filename": "dynamax_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 23, + "h": 23 + }, + "frame": { + "x": 119, + "y": 140, + "w": 23, + "h": 23 + } + }, + { + "filename": "unknown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 142, + "y": 117, + "w": 16, + "h": 24 + } + }, + { + "filename": "berry_pot", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 18, + "h": 22 + }, + "frame": { + "x": 142, + "y": 141, + "w": 18, + "h": 22 + } + }, + { + "filename": "leppa_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 123, + "y": 163, + "w": 24, + "h": 23 + } + }, + { + "filename": "scope_lens", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 123, + "y": 186, + "w": 24, + "h": 23 + } + }, + { + "filename": "relic_gold", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 11, + "w": 15, + "h": 11 + }, + "frame": { + "x": 123, + "y": 209, + "w": 15, + "h": 11 + } + }, + { + "filename": "zinc", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 147, + "y": 163, + "w": 16, + "h": 24 + } + }, + { + "filename": "bug_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 147, + "y": 187, + "w": 22, + "h": 22 + } + }, + { + "filename": "peat_block", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 138, + "y": 209, + "w": 24, + "h": 22 + } + }, + { + "filename": "twisted_spoon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 134, + "y": 231, + "w": 24, + "h": 23 + } + }, + { + "filename": "griseous_core", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 135, + "y": 254, + "w": 23, + "h": 23 + } + }, + { + "filename": "silver_powder", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 11, + "w": 24, + "h": 15 + }, + "frame": { + "x": 135, + "y": 277, + "w": 24, + "h": 15 + } + }, + { + "filename": "leek", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 136, + "y": 292, + "w": 23, + "h": 23 + } + }, + { + "filename": "dragon_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 137, + "y": 315, + "w": 22, + "h": 23 + } + }, + { + "filename": "electric_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 137, + "y": 338, + "w": 22, + "h": 23 + } + }, + { + "filename": "fairy_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 142, + "y": 361, + "w": 22, + "h": 23 + } + }, + { + "filename": "fighting_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 142, + "y": 384, + "w": 22, + "h": 23 + } + }, + { + "filename": "fire_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 152, + "y": 407, + "w": 22, + "h": 23 + } + }, + { + "filename": "charcoal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 162, + "y": 209, + "w": 22, + "h": 22 + } + }, + { + "filename": "macho_brace", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 158, + "y": 231, + "w": 23, + "h": 23 + } + }, + { + "filename": "rare_candy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 158, + "y": 254, + "w": 23, + "h": 23 + } + }, + { + "filename": "fire_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 159, + "y": 277, + "w": 22, + "h": 23 + } + }, + { + "filename": "focus_sash", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 159, + "y": 300, + "w": 22, + "h": 23 + } + }, + { + "filename": "ghost_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 159, + "y": 323, + "w": 22, + "h": 23 + } + }, + { + "filename": "candy_overlay", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 12, + "w": 16, + "h": 15 + }, + "frame": { + "x": 159, + "y": 346, + "w": 16, + "h": 15 + } + }, + { + "filename": "full_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 4, + "w": 15, + "h": 23 + }, + "frame": { + "x": 164, + "y": 361, + "w": 15, + "h": 23 + } + }, + { + "filename": "grass_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 164, + "y": 384, + "w": 22, + "h": 23 + } + }, + { + "filename": "ground_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 174, + "y": 407, + "w": 22, + "h": 23 + } + }, + { + "filename": "hyper_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 157, + "y": 36, + "w": 17, + "h": 23 + } + }, + { + "filename": "adamant_crystal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 157, + "y": 59, + "w": 23, + "h": 21 + } + }, + { + "filename": "rarer_candy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 23 + }, + "frame": { + "x": 156, + "y": 80, + "w": 23, + "h": 23 + } + }, + { + "filename": "healing_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 23, + "h": 22 + }, + "frame": { + "x": 174, + "y": 21, + "w": 23, + "h": 22 + } + }, + { + "filename": "rusted_sword", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 22 + }, + "frame": { + "x": 197, + "y": 21, + "w": 23, + "h": 22 + } + }, + { + "filename": "amulet_coin", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 220, + "y": 21, + "w": 23, + "h": 21 + } + }, + { + "filename": "auspicious_armor", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 243, + "y": 21, + "w": 23, + "h": 21 + } + }, + { + "filename": "moon_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 266, + "y": 21, + "w": 23, + "h": 21 + } + }, + { + "filename": "n_lunarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 289, + "y": 21, + "w": 23, + "h": 21 + } + }, + { + "filename": "berry_juice", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 21 + }, + "frame": { + "x": 312, + "y": 21, + "w": 22, + "h": 21 + } + }, + { + "filename": "dark_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 334, + "y": 20, + "w": 22, + "h": 22 + } + }, + { + "filename": "dire_hit", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 356, + "y": 20, + "w": 22, + "h": 22 + } + }, + { + "filename": "dna_splicers", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 378, + "y": 20, + "w": 22, + "h": 22 + } + }, + { + "filename": "relic_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 9, + "w": 17, + "h": 16 + }, + "frame": { + "x": 174, + "y": 43, + "w": 17, + "h": 16 + } + }, + { + "filename": "quick_powder", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 24, + "h": 20 + }, + "frame": { + "x": 191, + "y": 43, + "w": 24, + "h": 20 + } + }, + { + "filename": "rusted_shield", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 24, + "h": 20 + }, + "frame": { + "x": 400, + "y": 24, + "w": 24, + "h": 20 + } + }, + { + "filename": "ice_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 158, + "y": 103, + "w": 22, + "h": 23 + } + }, + { + "filename": "eviolite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 15, + "h": 15 + }, + "frame": { + "x": 158, + "y": 126, + "w": 15, + "h": 15 + } + }, + { + "filename": "dragon_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 160, + "y": 141, + "w": 22, + "h": 22 + } + }, + { + "filename": "lansat_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 21, + "h": 23 + }, + "frame": { + "x": 163, + "y": 163, + "w": 21, + "h": 23 + } + }, + { + "filename": "leaf_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 21, + "h": 23 + }, + "frame": { + "x": 169, + "y": 186, + "w": 21, + "h": 23 + } + }, + { + "filename": "prism_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 8, + "w": 15, + "h": 15 + }, + "frame": { + "x": 173, + "y": 126, + "w": 15, + "h": 15 + } + }, + { + "filename": "electirizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 182, + "y": 141, + "w": 22, + "h": 22 + } + }, + { + "filename": "never_melt_ice", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 184, + "y": 163, + "w": 22, + "h": 23 + } + }, + { + "filename": "normal_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 190, + "y": 186, + "w": 22, + "h": 23 + } + }, + { + "filename": "electric_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 184, + "y": 209, + "w": 22, + "h": 22 + } + }, + { + "filename": "petaya_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 181, + "y": 231, + "w": 22, + "h": 23 + } + }, + { + "filename": "poison_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 181, + "y": 254, + "w": 22, + "h": 23 + } + }, + { + "filename": "psychic_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 181, + "y": 277, + "w": 22, + "h": 23 + } + }, + { + "filename": "reaper_cloth", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 23 + }, + "frame": { + "x": 181, + "y": 300, + "w": 22, + "h": 23 + } + }, + { + "filename": "rock_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 181, + "y": 323, + "w": 22, + "h": 23 + } + }, + { + "filename": "sacred_ash", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 180, + "y": 63, + "w": 24, + "h": 20 + } + }, + { + "filename": "shadow_reins_of_unity", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 179, + "y": 83, + "w": 24, + "h": 20 + } + }, + { + "filename": "steel_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 180, + "y": 103, + "w": 22, + "h": 23 + } + }, + { + "filename": "apicot_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 20 + }, + "frame": { + "x": 204, + "y": 63, + "w": 19, + "h": 20 + } + }, + { + "filename": "big_nugget", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 203, + "y": 83, + "w": 20, + "h": 20 + } + }, + { + "filename": "sharp_beak", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 21, + "h": 23 + }, + "frame": { + "x": 202, + "y": 103, + "w": 21, + "h": 23 + } + }, + { + "filename": "binding_band", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 23, + "h": 20 + }, + "frame": { + "x": 215, + "y": 43, + "w": 23, + "h": 20 + } + }, + { + "filename": "n_solarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 238, + "y": 42, + "w": 23, + "h": 21 + } + }, + { + "filename": "stellar_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 223, + "y": 63, + "w": 22, + "h": 23 + } + }, + { + "filename": "water_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 223, + "y": 86, + "w": 22, + "h": 23 + } + }, + { + "filename": "soft_sand", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 24, + "h": 20 + }, + "frame": { + "x": 261, + "y": 42, + "w": 24, + "h": 20 + } + }, + { + "filename": "reviver_seed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 8, + "w": 23, + "h": 20 + }, + "frame": { + "x": 285, + "y": 42, + "w": 23, + "h": 20 + } + }, + { + "filename": "shell_bell", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 23, + "h": 20 + }, + "frame": { + "x": 308, + "y": 42, + "w": 23, + "h": 20 + } + }, + { + "filename": "wellspring_mask", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 23, + "h": 21 + }, + "frame": { + "x": 331, + "y": 42, + "w": 23, + "h": 21 + } + }, + { + "filename": "deep_sea_tooth", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 354, + "y": 42, + "w": 22, + "h": 21 + } + }, + { + "filename": "enigma_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 376, + "y": 42, + "w": 22, + "h": 22 + } + }, + { + "filename": "deep_sea_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 398, + "y": 44, + "w": 22, + "h": 20 + } + }, + { + "filename": "black_sludge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 223, + "y": 109, + "w": 22, + "h": 19 + } + }, + { + "filename": "potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 245, + "y": 63, + "w": 17, + "h": 23 + } + }, + { + "filename": "wide_lens", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 23 + }, + "frame": { + "x": 262, + "y": 62, + "w": 22, + "h": 23 + } + }, + { + "filename": "fairy_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 284, + "y": 62, + "w": 22, + "h": 22 + } + }, + { + "filename": "fighting_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 306, + "y": 62, + "w": 22, + "h": 22 + } + }, + { + "filename": "fire_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 328, + "y": 63, + "w": 22, + "h": 22 + } + }, + { + "filename": "flying_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 350, + "y": 63, + "w": 22, + "h": 22 + } + }, + { + "filename": "sachet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 4, + "w": 18, + "h": 23 + }, + "frame": { + "x": 245, + "y": 86, + "w": 18, + "h": 23 + } + }, + { + "filename": "whipped_dream", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 21, + "h": 23 + }, + "frame": { + "x": 263, + "y": 85, + "w": 21, + "h": 23 + } + }, + { + "filename": "ganlon_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 284, + "y": 84, + "w": 22, + "h": 22 + } + }, + { + "filename": "ghost_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 306, + "y": 84, + "w": 22, + "h": 22 + } + }, + { + "filename": "grass_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 328, + "y": 85, + "w": 22, + "h": 22 + } + }, + { + "filename": "ground_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 350, + "y": 85, + "w": 22, + "h": 22 + } + }, + { + "filename": "guard_spec", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 372, + "y": 64, + "w": 22, + "h": 22 + } + }, + { + "filename": "ice_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 394, + "y": 64, + "w": 22, + "h": 22 + } + }, + { + "filename": "ice_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 372, + "y": 86, + "w": 22, + "h": 22 + } + }, + { + "filename": "magmarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 394, + "y": 86, + "w": 22, + "h": 22 + } + }, + { + "filename": "mystery_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 18 + }, + "frame": { + "x": 416, + "y": 64, + "w": 16, + "h": 18 + } + }, + { + "filename": "abomasite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 416, + "y": 82, + "w": 16, + "h": 16 + } + }, + { + "filename": "absolite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 416, + "y": 98, + "w": 16, + "h": 16 + } + }, + { + "filename": "revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 10, + "y": 8, + "w": 12, + "h": 17 + }, + "frame": { + "x": 420, + "y": 44, + "w": 12, + "h": 17 + } + }, + { + "filename": "big_mushroom", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 19 + }, + "frame": { + "x": 245, + "y": 109, + "w": 19, + "h": 19 + } + }, + { + "filename": "blue_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 264, + "y": 108, + "w": 20, + "h": 20 + } + }, + { + "filename": "mini_black_hole", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 284, + "y": 106, + "w": 22, + "h": 22 + } + }, + { + "filename": "moon_flute", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 306, + "y": 106, + "w": 22, + "h": 22 + } + }, + { + "filename": "liechi_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 328, + "y": 107, + "w": 22, + "h": 21 + } + }, + { + "filename": "normal_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 350, + "y": 107, + "w": 22, + "h": 22 + } + }, + { + "filename": "poison_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 372, + "y": 108, + "w": 22, + "h": 22 + } + }, + { + "filename": "protector", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 394, + "y": 108, + "w": 22, + "h": 22 + } + }, + { + "filename": "aerodactylite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 416, + "y": 114, + "w": 16, + "h": 16 + } + }, + { + "filename": "psychic_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 179, + "y": 346, + "w": 22, + "h": 22 + } + }, + { + "filename": "aggronite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 179, + "y": 368, + "w": 16, + "h": 16 + } + }, + { + "filename": "super_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 186, + "y": 384, + "w": 17, + "h": 23 + } + }, + { + "filename": "alakazite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 195, + "y": 368, + "w": 16, + "h": 16 + } + }, + { + "filename": "hard_meteorite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 20, + "h": 22 + }, + "frame": { + "x": 201, + "y": 346, + "w": 20, + "h": 22 + } + }, + { + "filename": "leftovers", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 15, + "h": 22 + }, + "frame": { + "x": 203, + "y": 384, + "w": 15, + "h": 22 + } + }, + { + "filename": "altarianite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 211, + "y": 368, + "w": 16, + "h": 16 + } + }, + { + "filename": "lock_capsule", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 19, + "h": 22 + }, + "frame": { + "x": 218, + "y": 384, + "w": 19, + "h": 22 + } + }, + { + "filename": "metal_coat", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 19, + "h": 22 + }, + "frame": { + "x": 196, + "y": 407, + "w": 19, + "h": 22 + } + }, + { + "filename": "rock_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 215, + "y": 406, + "w": 22, + "h": 22 + } + }, + { + "filename": "metronome", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 17, + "h": 22 + }, + "frame": { + "x": 206, + "y": 209, + "w": 17, + "h": 22 + } + }, + { + "filename": "scroll_of_darkness", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 203, + "y": 231, + "w": 22, + "h": 22 + } + }, + { + "filename": "scroll_of_waters", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 203, + "y": 253, + "w": 22, + "h": 22 + } + }, + { + "filename": "shed_shell", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 203, + "y": 275, + "w": 22, + "h": 22 + } + }, + { + "filename": "starf_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 203, + "y": 297, + "w": 22, + "h": 22 + } + }, + { + "filename": "steel_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 203, + "y": 319, + "w": 22, + "h": 22 + } + }, + { + "filename": "quick_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 21 + }, + "frame": { + "x": 204, + "y": 126, + "w": 19, + "h": 21 + } + }, + { + "filename": "golden_mystic_ticket", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 223, + "y": 128, + "w": 23, + "h": 19 + } + }, + { + "filename": "mystic_ticket", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 246, + "y": 128, + "w": 23, + "h": 19 + } + }, + { + "filename": "pair_of_tickets", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 269, + "y": 128, + "w": 23, + "h": 19 + } + }, + { + "filename": "blunder_policy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 19 + }, + "frame": { + "x": 292, + "y": 128, + "w": 22, + "h": 19 + } + }, + { + "filename": "dubious_disc", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 314, + "y": 128, + "w": 22, + "h": 19 + } + }, + { + "filename": "ampharosite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 204, + "y": 147, + "w": 16, + "h": 16 + } + }, + { + "filename": "burn_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 220, + "y": 147, + "w": 23, + "h": 17 + } + }, + { + "filename": "chill_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 243, + "y": 147, + "w": 23, + "h": 17 + } + }, + { + "filename": "douse_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 266, + "y": 147, + "w": 23, + "h": 17 + } + }, + { + "filename": "relic_crown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 18 + }, + "frame": { + "x": 289, + "y": 147, + "w": 23, + "h": 18 + } + }, + { + "filename": "fairy_feather", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 20 + }, + "frame": { + "x": 312, + "y": 147, + "w": 22, + "h": 20 + } + }, + { + "filename": "sun_flute", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 206, + "y": 164, + "w": 22, + "h": 22 + } + }, + { + "filename": "thick_club", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 228, + "y": 164, + "w": 22, + "h": 22 + } + }, + { + "filename": "thunder_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 212, + "y": 186, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_bug", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 250, + "y": 164, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_dark", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 234, + "y": 186, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_dragon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 223, + "y": 208, + "w": 22, + "h": 22 + } + }, + { + "filename": "sitrus_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 20, + "h": 22 + }, + "frame": { + "x": 225, + "y": 230, + "w": 20, + "h": 22 + } + }, + { + "filename": "tm_electric", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 225, + "y": 252, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_fairy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 225, + "y": 274, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_fighting", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 225, + "y": 296, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_fire", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 225, + "y": 318, + "w": 22, + "h": 22 + } + }, + { + "filename": "soothe_bell", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 22 + }, + "frame": { + "x": 272, + "y": 164, + "w": 17, + "h": 22 + } + }, + { + "filename": "tm_flying", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 256, + "y": 186, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_ghost", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 245, + "y": 208, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_grass", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 245, + "y": 230, + "w": 22, + "h": 22 + } + }, + { + "filename": "sweet_apple", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 289, + "y": 165, + "w": 22, + "h": 21 + } + }, + { + "filename": "tm_ground", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 278, + "y": 186, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_ice", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 267, + "y": 208, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_normal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 267, + "y": 230, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_poison", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 247, + "y": 252, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_psychic", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 247, + "y": 274, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_rock", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 247, + "y": 296, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_steel", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 247, + "y": 318, + "w": 22, + "h": 22 + } + }, + { + "filename": "tm_water", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 269, + "y": 252, + "w": 22, + "h": 22 + } + }, + { + "filename": "water_memory", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 269, + "y": 274, + "w": 22, + "h": 22 + } + }, + { + "filename": "water_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 269, + "y": 296, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_accuracy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 269, + "y": 318, + "w": 22, + "h": 22 + } + }, + { + "filename": "malicious_armor", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 311, + "y": 167, + "w": 22, + "h": 20 + } + }, + { + "filename": "x_attack", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 289, + "y": 208, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_defense", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 289, + "y": 230, + "w": 22, + "h": 22 + } + }, + { + "filename": "syrupy_apple", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 300, + "y": 187, + "w": 22, + "h": 21 + } + }, + { + "filename": "x_sp_atk", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 291, + "y": 252, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_sp_def", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 291, + "y": 274, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_speed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 291, + "y": 296, + "w": 22, + "h": 22 + } + }, + { + "filename": "tart_apple", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 21 + }, + "frame": { + "x": 291, + "y": 318, + "w": 22, + "h": 21 + } + }, + { + "filename": "dawn_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 21 + }, + "frame": { + "x": 322, + "y": 187, + "w": 20, + "h": 21 + } + }, + { + "filename": "dusk_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 311, + "y": 208, + "w": 21, + "h": 21 + } + }, + { + "filename": "poison_barb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 311, + "y": 229, + "w": 21, + "h": 21 + } + }, + { + "filename": "flying_tera_shard", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 5, + "w": 20, + "h": 21 + }, + "frame": { + "x": 313, + "y": 250, + "w": 20, + "h": 21 + } + }, + { + "filename": "shiny_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 313, + "y": 271, + "w": 21, + "h": 21 + } + }, + { + "filename": "zoom_lens", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 313, + "y": 292, + "w": 21, + "h": 21 + } + }, + { + "filename": "tera_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 313, + "y": 313, + "w": 22, + "h": 20 + } + }, + { + "filename": "spell_tag", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 19, + "h": 21 + }, + "frame": { + "x": 332, + "y": 208, + "w": 19, + "h": 21 + } + }, + { + "filename": "candy_jar", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 20 + }, + "frame": { + "x": 332, + "y": 229, + "w": 19, + "h": 20 + } + }, + { + "filename": "gb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 333, + "y": 249, + "w": 20, + "h": 20 + } + }, + { + "filename": "hard_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, + "h": 20 + }, + "frame": { + "x": 334, + "y": 269, + "w": 19, + "h": 20 + } + }, + { + "filename": "magnet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 334, + "y": 289, + "w": 20, + "h": 20 + } + }, + { + "filename": "mb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 335, + "y": 309, + "w": 20, + "h": 20 + } + }, + { + "filename": "golden_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 17, + "h": 20 + }, + "frame": { + "x": 333, + "y": 167, + "w": 17, + "h": 20 + } + }, + { + "filename": "lucky_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 17, + "h": 20 + }, + "frame": { + "x": 334, + "y": 147, + "w": 17, + "h": 20 + } + }, + { + "filename": "masterpiece_teacup", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 21, + "h": 18 + }, + "frame": { + "x": 336, + "y": 129, + "w": 21, + "h": 18 + } + }, + { + "filename": "pb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 342, + "y": 187, + "w": 20, + "h": 20 + } + }, + { + "filename": "pb_gold", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 350, + "y": 167, + "w": 20, + "h": 20 + } + }, + { + "filename": "pb_silver", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 351, + "y": 147, + "w": 20, + "h": 20 + } + }, + { + "filename": "shock_drive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 357, + "y": 130, + "w": 23, + "h": 17 + } + }, + { + "filename": "wise_glasses", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 8, + "w": 23, + "h": 17 + }, + "frame": { + "x": 380, + "y": 130, + "w": 23, + "h": 17 + } + }, + { + "filename": "upgrade", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 371, + "y": 147, + "w": 22, + "h": 19 + } + }, + { + "filename": "metal_alloy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 21, + "h": 19 + }, + "frame": { + "x": 403, + "y": 130, + "w": 21, + "h": 19 + } + }, + { + "filename": "razor_fang", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 18, + "h": 20 + }, + "frame": { + "x": 351, + "y": 207, + "w": 18, + "h": 20 + } + }, + { + "filename": "rb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 351, + "y": 227, + "w": 20, + "h": 20 + } + }, + { + "filename": "smooth_meteorite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 353, + "y": 247, + "w": 20, + "h": 20 + } + }, + { + "filename": "strange_ball", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 353, + "y": 267, + "w": 20, + "h": 20 + } + }, + { + "filename": "ub", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 354, + "y": 287, + "w": 20, + "h": 20 + } + }, + { + "filename": "lum_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 355, + "y": 307, + "w": 20, + "h": 19 + } + }, + { + "filename": "old_gateau", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 21, + "h": 18 + }, + "frame": { + "x": 393, + "y": 149, + "w": 21, + "h": 18 + } + }, + { + "filename": "oval_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 19 + }, + "frame": { + "x": 414, + "y": 149, + "w": 18, + "h": 19 + } + }, + { + "filename": "miracle_seed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 19, + "h": 19 + }, + "frame": { + "x": 362, + "y": 187, + "w": 19, + "h": 19 + } + }, + { + "filename": "power_herb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 369, + "y": 206, + "w": 20, + "h": 19 + } + }, + { + "filename": "razor_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 371, + "y": 225, + "w": 20, + "h": 19 + } + }, + { + "filename": "white_herb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 7, + "w": 20, + "h": 19 + }, + "frame": { + "x": 373, + "y": 244, + "w": 20, + "h": 19 + } + }, + { + "filename": "sharp_meteorite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 21, + "h": 18 + }, + "frame": { + "x": 373, + "y": 263, + "w": 21, + "h": 18 + } + }, + { + "filename": "unremarkable_teacup", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 21, + "h": 18 + }, + "frame": { + "x": 374, + "y": 281, + "w": 21, + "h": 18 + } + }, + { + "filename": "wl_ability_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 375, + "y": 299, + "w": 20, + "h": 18 + } + }, + { + "filename": "everstone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 17 + }, + "frame": { + "x": 375, + "y": 317, + "w": 20, + "h": 17 + } + }, + { + "filename": "wl_antidote", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 355, + "y": 326, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_awakening", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 335, + "y": 329, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_burn_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 375, + "y": 334, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_custom_spliced", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 355, + "y": 344, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_custom_thief", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 375, + "y": 352, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 313, + "y": 333, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 333, + "y": 347, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_full_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 371, + "y": 166, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_full_restore", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 391, + "y": 167, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_guard_spec", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 411, + "y": 168, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_hyper_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 381, + "y": 185, + "w": 20, + "h": 18 + } + }, + { + "filename": "baton", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 389, + "y": 203, + "w": 18, + "h": 18 + } + }, + { + "filename": "candy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 11, + "w": 18, + "h": 18 + }, + "frame": { + "x": 391, + "y": 221, + "w": 18, + "h": 18 + } + }, + { + "filename": "dark_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 393, + "y": 239, + "w": 18, + "h": 18 + } + }, + { + "filename": "flame_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 394, + "y": 257, + "w": 18, + "h": 18 + } + }, + { + "filename": "wl_ice_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 412, + "y": 186, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_item_drop", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 412, + "y": 204, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_item_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 412, + "y": 222, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_max_elixir", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 412, + "y": 240, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_max_ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 412, + "y": 258, + "w": 20, + "h": 18 + } + }, + { + "filename": "audinite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 395, + "y": 275, + "w": 16, + "h": 16 + } + }, + { + "filename": "light_ball", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 395, + "y": 291, + "w": 18, + "h": 18 + } + }, + { + "filename": "light_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 395, + "y": 309, + "w": 18, + "h": 18 + } + }, + { + "filename": "toxic_orb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 18 + }, + "frame": { + "x": 395, + "y": 327, + "w": 18, + "h": 18 + } + }, + { + "filename": "wl_max_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 395, + "y": 345, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_max_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 395, + "y": 363, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_paralyze_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 225, + "y": 340, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 245, + "y": 340, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_reset_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 265, + "y": 340, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 227, + "y": 358, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_super_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 247, + "y": 358, + "w": 20, + "h": 18 + } + }, + { + "filename": "banettite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 267, + "y": 358, + "w": 16, + "h": 16 + } + }, + { + "filename": "beedrillite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 237, + "y": 376, + "w": 16, + "h": 16 + } + }, + { + "filename": "blastoisinite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 237, + "y": 392, + "w": 16, + "h": 16 + } + }, + { + "filename": "blazikenite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 237, + "y": 408, + "w": 16, + "h": 16 + } + }, + { + "filename": "cameruptite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 253, + "y": 376, + "w": 16, + "h": 16 + } + }, + { + "filename": "charizardite_x", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 253, + "y": 392, + "w": 16, + "h": 16 + } + }, + { + "filename": "charizardite_y", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 253, + "y": 408, + "w": 16, + "h": 16 + } + }, + { + "filename": "diancite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 269, + "y": 374, + "w": 16, + "h": 16 + } + }, + { + "filename": "galladite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 269, + "y": 390, + "w": 16, + "h": 16 + } + }, + { + "filename": "garchompite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 269, + "y": 406, + "w": 16, + "h": 16 + } + }, + { + "filename": "gardevoirite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 285, + "y": 340, + "w": 16, + "h": 16 + } + }, + { + "filename": "gengarite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 283, + "y": 358, + "w": 16, + "h": 16 + } + }, + { + "filename": "glalitite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 285, + "y": 374, + "w": 16, + "h": 16 + } + }, + { + "filename": "gyaradosite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 285, + "y": 390, + "w": 16, + "h": 16 + } + }, + { + "filename": "heracronite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 285, + "y": 406, + "w": 16, + "h": 16 + } + }, + { + "filename": "houndoominite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 353, + "y": 362, + "w": 16, + "h": 16 + } + }, + { + "filename": "kangaskhanite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 369, + "y": 370, + "w": 16, + "h": 16 + } + }, + { + "filename": "latiasite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 413, + "y": 276, + "w": 16, + "h": 16 + } + }, + { + "filename": "latiosite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 413, + "y": 292, + "w": 16, + "h": 16 + } + }, + { + "filename": "lopunnite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 413, + "y": 308, + "w": 16, + "h": 16 + } + }, + { + "filename": "lucarionite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 413, + "y": 324, + "w": 16, + "h": 16 + } + }, + { + "filename": "manectite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 415, + "y": 340, + "w": 16, + "h": 16 + } + }, + { + "filename": "mawilite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 415, + "y": 356, + "w": 16, + "h": 16 + } + }, + { + "filename": "medichamite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 415, + "y": 372, + "w": 16, + "h": 16 + } + }, + { + "filename": "metagrossite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 299, + "y": 356, + "w": 16, + "h": 16 + } + }, + { + "filename": "mewtwonite_x", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 301, + "y": 372, + "w": 16, + "h": 16 + } + }, + { + "filename": "mewtwonite_y", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 301, + "y": 388, + "w": 16, + "h": 16 + } + }, + { + "filename": "nugget", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 301, + "y": 404, + "w": 16, + "h": 16 + } + }, + { + "filename": "pidgeotite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 317, + "y": 351, + "w": 16, + "h": 16 + } + }, + { + "filename": "pinsirite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 317, + "y": 367, + "w": 16, + "h": 16 + } + }, + { + "filename": "rayquazite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 333, + "y": 365, + "w": 16, + "h": 16 + } + }, + { + "filename": "sablenite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 317, + "y": 383, + "w": 16, + "h": 16 + } + }, + { + "filename": "salamencite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 333, + "y": 381, + "w": 16, + "h": 16 + } + }, + { + "filename": "sceptilite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 317, + "y": 399, + "w": 16, + "h": 16 + } + }, + { + "filename": "scizorite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 333, + "y": 397, + "w": 16, + "h": 16 + } + }, + { + "filename": "sharpedonite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 349, + "y": 378, + "w": 16, + "h": 16 + } + }, + { + "filename": "slowbronite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 349, + "y": 394, + "w": 16, + "h": 16 + } + }, + { + "filename": "soul_dew", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 365, + "y": 386, + "w": 16, + "h": 16 + } + }, + { + "filename": "steelixite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 365, + "y": 402, + "w": 16, + "h": 16 + } + }, + { + "filename": "strawberry_sweet", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 7, + "w": 16, + "h": 16 + }, + "frame": { + "x": 349, + "y": 410, + "w": 16, + "h": 16 + } + }, + { + "filename": "swampertite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 333, + "y": 413, + "w": 16, + "h": 16 + } + }, + { + "filename": "tyranitarite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 317, + "y": 415, + "w": 16, + "h": 16 + } + }, + { + "filename": "venusaurite", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 381, + "y": 386, + "w": 16, + "h": 16 + } } ] } @@ -8457,6 +8457,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:7b927dc715c6335dfca9e369b61374b2:fb24603dd37bbe0cbdf1d74fcbcbd223:110e074689c9edd2c54833ce2e4d9270$" + "smartupdate": "$TexturePacker:SmartUpdate:c228145ca625236e53edc95aac265d56:86524cdf0e3043482141d77259bc4d47:110e074689c9edd2c54833ce2e4d9270$" } } diff --git a/public/images/items.png b/public/images/items.png index 4433ce43a40..eb9878a5bfc 100644 Binary files a/public/images/items.png and b/public/images/items.png differ diff --git a/public/images/items/mystical_rock.png b/public/images/items/mystical_rock.png index f87fe2a9dcb..81a397e4c2d 100644 Binary files a/public/images/items/mystical_rock.png and b/public/images/items/mystical_rock.png differ diff --git a/public/images/pokemon/1011.png b/public/images/pokemon/1011.png index 39ed4c0d519..035ea0aca44 100644 Binary files a/public/images/pokemon/1011.png and b/public/images/pokemon/1011.png differ diff --git a/public/images/pokemon/1019.png b/public/images/pokemon/1019.png index 9c11ccecb89..f29e2df2fcf 100644 Binary files a/public/images/pokemon/1019.png and b/public/images/pokemon/1019.png differ diff --git a/public/images/pokemon/143-gigantamax.png b/public/images/pokemon/143-gigantamax.png index aa775df6164..3adc2c148cd 100644 Binary files a/public/images/pokemon/143-gigantamax.png and b/public/images/pokemon/143-gigantamax.png differ diff --git a/public/images/pokemon/143.png b/public/images/pokemon/143.png index 8050627a9a1..a09d0533fce 100644 Binary files a/public/images/pokemon/143.png and b/public/images/pokemon/143.png differ diff --git a/public/images/pokemon/189.png b/public/images/pokemon/189.png index fb7f53ced67..632366956bb 100644 Binary files a/public/images/pokemon/189.png and b/public/images/pokemon/189.png differ diff --git a/public/images/pokemon/2038.png b/public/images/pokemon/2038.png index 71cedc8af13..7e8fd0ea1b2 100644 Binary files a/public/images/pokemon/2038.png and b/public/images/pokemon/2038.png differ diff --git a/public/images/pokemon/207.png b/public/images/pokemon/207.png index ec2f862a139..115c41b0673 100644 Binary files a/public/images/pokemon/207.png and b/public/images/pokemon/207.png differ diff --git a/public/images/pokemon/313.png b/public/images/pokemon/313.png index 0a6336ec37b..fb0dd07c924 100644 Binary files a/public/images/pokemon/313.png and b/public/images/pokemon/313.png differ diff --git a/public/images/pokemon/314.png b/public/images/pokemon/314.png index 575b962093a..7252a7fb840 100644 Binary files a/public/images/pokemon/314.png and b/public/images/pokemon/314.png differ diff --git a/public/images/pokemon/332.png b/public/images/pokemon/332.png index f320ab4c331..a9979480673 100644 Binary files a/public/images/pokemon/332.png and b/public/images/pokemon/332.png differ diff --git a/public/images/pokemon/34.png b/public/images/pokemon/34.png index 3eec3a66805..e697a987354 100644 Binary files a/public/images/pokemon/34.png and b/public/images/pokemon/34.png differ diff --git a/public/images/pokemon/396.png b/public/images/pokemon/396.png index 5f42fc90461..34033368ac6 100644 Binary files a/public/images/pokemon/396.png and b/public/images/pokemon/396.png differ diff --git a/public/images/pokemon/397.png b/public/images/pokemon/397.png index 0197ee7182e..e9d14db7eab 100644 Binary files a/public/images/pokemon/397.png and b/public/images/pokemon/397.png differ diff --git a/public/images/pokemon/398.png b/public/images/pokemon/398.png index 55f8c7c09a3..d1adb74b7ca 100644 Binary files a/public/images/pokemon/398.png and b/public/images/pokemon/398.png differ diff --git a/public/images/pokemon/404.png b/public/images/pokemon/404.png index 50038f7a17c..c3c77be70db 100644 Binary files a/public/images/pokemon/404.png and b/public/images/pokemon/404.png differ diff --git a/public/images/pokemon/417.png b/public/images/pokemon/417.png index 6d7100f66fe..02cffd1c73f 100644 Binary files a/public/images/pokemon/417.png and b/public/images/pokemon/417.png differ diff --git a/public/images/pokemon/420.png b/public/images/pokemon/420.png index 4b76cdfcd21..8cf4dfd0bfc 100644 Binary files a/public/images/pokemon/420.png and b/public/images/pokemon/420.png differ diff --git a/public/images/pokemon/421-overcast.png b/public/images/pokemon/421-overcast.png index fb91ea937f1..82b66fd07f9 100644 Binary files a/public/images/pokemon/421-overcast.png and b/public/images/pokemon/421-overcast.png differ diff --git a/public/images/pokemon/421-sunshine.png b/public/images/pokemon/421-sunshine.png index 3ab91a47ca6..9da091ae12a 100644 Binary files a/public/images/pokemon/421-sunshine.png and b/public/images/pokemon/421-sunshine.png differ diff --git a/public/images/pokemon/446.png b/public/images/pokemon/446.png index 40795f6cd17..523d790a89c 100644 Binary files a/public/images/pokemon/446.png and b/public/images/pokemon/446.png differ diff --git a/public/images/pokemon/472.png b/public/images/pokemon/472.png index cc13377bd53..eefd055ffc3 100644 Binary files a/public/images/pokemon/472.png and b/public/images/pokemon/472.png differ diff --git a/public/images/pokemon/498.png b/public/images/pokemon/498.png index d45f8988cc0..f019a1f38b3 100644 Binary files a/public/images/pokemon/498.png and b/public/images/pokemon/498.png differ diff --git a/public/images/pokemon/499.png b/public/images/pokemon/499.png index c8232f9bb34..8f2f76ca6bb 100644 Binary files a/public/images/pokemon/499.png and b/public/images/pokemon/499.png differ diff --git a/public/images/pokemon/500.png b/public/images/pokemon/500.png index 9d388d33640..ae842c38bcd 100644 Binary files a/public/images/pokemon/500.png and b/public/images/pokemon/500.png differ diff --git a/public/images/pokemon/511.png b/public/images/pokemon/511.png index ebf4b069b23..77ba327fd12 100644 Binary files a/public/images/pokemon/511.png and b/public/images/pokemon/511.png differ diff --git a/public/images/pokemon/512.png b/public/images/pokemon/512.png index 94ae881fdb2..58870d253cb 100644 Binary files a/public/images/pokemon/512.png and b/public/images/pokemon/512.png differ diff --git a/public/images/pokemon/513.png b/public/images/pokemon/513.png index f8d6e6017de..99f2fccc23e 100644 Binary files a/public/images/pokemon/513.png and b/public/images/pokemon/513.png differ diff --git a/public/images/pokemon/514.png b/public/images/pokemon/514.png index 87a2ece7f6d..57216c76e08 100644 Binary files a/public/images/pokemon/514.png and b/public/images/pokemon/514.png differ diff --git a/public/images/pokemon/515.png b/public/images/pokemon/515.png index 3dc40ff122d..e6187568544 100644 Binary files a/public/images/pokemon/515.png and b/public/images/pokemon/515.png differ diff --git a/public/images/pokemon/516.png b/public/images/pokemon/516.png index c13615fa119..cd4d5d64392 100644 Binary files a/public/images/pokemon/516.png and b/public/images/pokemon/516.png differ diff --git a/public/images/pokemon/522.png b/public/images/pokemon/522.png index 3e545afc925..64ca1253304 100644 Binary files a/public/images/pokemon/522.png and b/public/images/pokemon/522.png differ diff --git a/public/images/pokemon/523.png b/public/images/pokemon/523.png index 49674e2ee8b..3c491927a02 100644 Binary files a/public/images/pokemon/523.png and b/public/images/pokemon/523.png differ diff --git a/public/images/pokemon/535.png b/public/images/pokemon/535.png index afa9cfb10ee..b8a82d204c5 100644 Binary files a/public/images/pokemon/535.png and b/public/images/pokemon/535.png differ diff --git a/public/images/pokemon/536.png b/public/images/pokemon/536.png index bbc6d6b548c..90202df0339 100644 Binary files a/public/images/pokemon/536.png and b/public/images/pokemon/536.png differ diff --git a/public/images/pokemon/537.png b/public/images/pokemon/537.png index 9b70ea2eafe..906b546cf42 100644 Binary files a/public/images/pokemon/537.png and b/public/images/pokemon/537.png differ diff --git a/public/images/pokemon/554.png b/public/images/pokemon/554.png index d2483d4cec7..b0c4bb10335 100644 Binary files a/public/images/pokemon/554.png and b/public/images/pokemon/554.png differ diff --git a/public/images/pokemon/555-zen.png b/public/images/pokemon/555-zen.png index e94c779abce..48cbf58a17a 100644 Binary files a/public/images/pokemon/555-zen.png and b/public/images/pokemon/555-zen.png differ diff --git a/public/images/pokemon/555.png b/public/images/pokemon/555.png index 0843ef0026b..0ec02846a6a 100644 Binary files a/public/images/pokemon/555.png and b/public/images/pokemon/555.png differ diff --git a/public/images/pokemon/566.png b/public/images/pokemon/566.png index 67b5f09c056..e54a8680298 100644 Binary files a/public/images/pokemon/566.png and b/public/images/pokemon/566.png differ diff --git a/public/images/pokemon/572.png b/public/images/pokemon/572.png index ba9446aa9d2..32f01341e2f 100644 Binary files a/public/images/pokemon/572.png and b/public/images/pokemon/572.png differ diff --git a/public/images/pokemon/573.png b/public/images/pokemon/573.png index b827c23d78e..a33172fe8d3 100644 Binary files a/public/images/pokemon/573.png and b/public/images/pokemon/573.png differ diff --git a/public/images/pokemon/626.png b/public/images/pokemon/626.png index 281119efdc2..542cefe41bb 100644 Binary files a/public/images/pokemon/626.png and b/public/images/pokemon/626.png differ diff --git a/public/images/pokemon/643.png b/public/images/pokemon/643.png index b7c21248166..30d993791ab 100644 Binary files a/public/images/pokemon/643.png and b/public/images/pokemon/643.png differ diff --git a/public/images/pokemon/644.png b/public/images/pokemon/644.png index 4ccbb7700d5..14fce7e0bab 100644 Binary files a/public/images/pokemon/644.png and b/public/images/pokemon/644.png differ diff --git a/public/images/pokemon/646-black.png b/public/images/pokemon/646-black.png index 4c45fcf2a03..f5ad11ddcac 100644 Binary files a/public/images/pokemon/646-black.png and b/public/images/pokemon/646-black.png differ diff --git a/public/images/pokemon/646-white.png b/public/images/pokemon/646-white.png index 0de658c5a39..9907f8e278c 100644 Binary files a/public/images/pokemon/646-white.png and b/public/images/pokemon/646-white.png differ diff --git a/public/images/pokemon/746-school.png b/public/images/pokemon/746-school.png index e9d8bdbd944..c592b71a66a 100644 Binary files a/public/images/pokemon/746-school.png and b/public/images/pokemon/746-school.png differ diff --git a/public/images/pokemon/746.png b/public/images/pokemon/746.png index 22f4ec2fd6f..3de01770ee6 100644 Binary files a/public/images/pokemon/746.png and b/public/images/pokemon/746.png differ diff --git a/public/images/pokemon/782.json b/public/images/pokemon/782.json index 9b8f8e93d39..2a08877c58b 100644 --- a/public/images/pokemon/782.json +++ b/public/images/pokemon/782.json @@ -1,41 +1,1010 @@ -{ - "textures": [ - { - "image": "782.png", - "format": "RGBA8888", - "size": { - "w": 50, - "h": 50 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 46, - "h": 50 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 46, - "h": 50 - }, - "frame": { - "x": 0, - "y": 0, - "w": 46, - "h": 50 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:350889f3e7d7ba0c8471435ab283acd5:fde1ef9d118b98abfede0d4980b8ef8d:d07862436676aa228a148ee1f1d82a8f$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0002.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0003.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0004.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0005.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0006.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0007.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0008.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0009.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0010.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0011.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0012.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0013.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0014.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0015.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0016.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0017.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0018.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0019.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0020.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0021.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0022.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0023.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0024.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0025.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0026.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0027.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0028.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0029.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0030.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0031.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0032.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0033.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0034.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0035.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0036.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0037.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0038.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0039.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0040.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0041.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0042.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0043.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0044.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0045.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0046.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0047.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0048.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0049.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0050.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0051.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0052.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0053.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0054.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0055.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0056.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0057.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0058.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0059.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0060.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0061.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0062.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0063.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0064.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0065.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0066.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0067.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0068.png", + "frame": { "x": 98, "y": 109, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0069.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0070.png", + "frame": { "x": 49, "y": 161, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0071.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0072.png", + "frame": { "x": 146, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0073.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0074.png", + "frame": { "x": 97, "y": 162, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0075.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0076.png", + "frame": { "x": 194, "y": 162, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0077.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0078.png", + "frame": { "x": 1, "y": 109, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0079.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0080.png", + "frame": { "x": 1, "y": 160, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0081.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0082.png", + "frame": { "x": 50, "y": 109, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0083.png", + "frame": { "x": 148, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0084.png", + "frame": { "x": 197, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0085.png", + "frame": { "x": 1, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0086.png", + "frame": { "x": 50, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0087.png", + "frame": { "x": 193, "y": 108, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0088.png", + "frame": { "x": 193, "y": 108, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0089.png", + "frame": { "x": 148, "y": 54, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0090.png", + "frame": { "x": 196, "y": 54, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0091.png", + "frame": { "x": 1, "y": 55, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0092.png", + "frame": { "x": 49, "y": 55, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0093.png", + "frame": { "x": 99, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0094.png", + "frame": { "x": 99, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0095.png", + "frame": { "x": 193, "y": 108, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0096.png", + "frame": { "x": 193, "y": 108, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0097.png", + "frame": { "x": 97, "y": 55, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0098.png", + "frame": { "x": 97, "y": 55, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0099.png", + "frame": { "x": 49, "y": 55, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0100.png", + "frame": { "x": 49, "y": 55, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0101.png", + "frame": { "x": 99, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0102.png", + "frame": { "x": 99, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0103.png", + "frame": { "x": 99, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0104.png", + "frame": { "x": 193, "y": 108, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0105.png", + "frame": { "x": 193, "y": 108, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0106.png", + "frame": { "x": 97, "y": 55, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0107.png", + "frame": { "x": 97, "y": 55, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0108.png", + "frame": { "x": 1, "y": 55, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0109.png", + "frame": { "x": 145, "y": 108, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0110.png", + "frame": { "x": 197, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0111.png", + "frame": { "x": 148, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "782.png", + "format": "I8", + "size": { "w": 245, "h": 211 }, + "scale": "1" + } } diff --git a/public/images/pokemon/782.png b/public/images/pokemon/782.png index ad461fe00ae..093d0189535 100644 Binary files a/public/images/pokemon/782.png and b/public/images/pokemon/782.png differ diff --git a/public/images/pokemon/783.json b/public/images/pokemon/783.json index ff018d3f04a..df0c084fa38 100644 --- a/public/images/pokemon/783.json +++ b/public/images/pokemon/783.json @@ -1,41 +1,965 @@ -{ - "textures": [ - { - "image": "783.png", - "format": "RGBA8888", - "size": { - "w": 69, - "h": 69 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 61, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 61, - "h": 69 - }, - "frame": { - "x": 0, - "y": 0, - "w": 61, - "h": 69 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:a352518568888797dbb97bf40e2075df:76c85cf57217dd8c084dd2b2591b9bef:aab166e28c744865a0296041224dd01b$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 66, "y": 214, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0002.png", + "frame": { "x": 336, "y": 146, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0003.png", + "frame": { "x": 1, "y": 73, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0004.png", + "frame": { "x": 424, "y": 73, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0005.png", + "frame": { "x": 284, "y": 70, "w": 64, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 0, "w": 64, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0006.png", + "frame": { "x": 350, "y": 74, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0007.png", + "frame": { "x": 490, "y": 141, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0008.png", + "frame": { "x": 415, "y": 145, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0009.png", + "frame": { "x": 318, "y": 217, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0010.png", + "frame": { "x": 442, "y": 353, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0011.png", + "frame": { "x": 59, "y": 425, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0012.png", + "frame": { "x": 1, "y": 425, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0013.png", + "frame": { "x": 117, "y": 426, "w": 56, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 56, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0014.png", + "frame": { "x": 486, "y": 424, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0015.png", + "frame": { "x": 298, "y": 358, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0016.png", + "frame": { "x": 63, "y": 285, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0017.png", + "frame": { "x": 66, "y": 214, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0018.png", + "frame": { "x": 336, "y": 146, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0019.png", + "frame": { "x": 1, "y": 73, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0020.png", + "frame": { "x": 424, "y": 73, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0021.png", + "frame": { "x": 284, "y": 70, "w": 64, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 0, "w": 64, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0022.png", + "frame": { "x": 350, "y": 74, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0023.png", + "frame": { "x": 490, "y": 141, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0024.png", + "frame": { "x": 415, "y": 145, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0025.png", + "frame": { "x": 318, "y": 217, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0026.png", + "frame": { "x": 442, "y": 353, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0027.png", + "frame": { "x": 59, "y": 425, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0028.png", + "frame": { "x": 1, "y": 425, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0029.png", + "frame": { "x": 117, "y": 426, "w": 56, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 56, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0030.png", + "frame": { "x": 486, "y": 424, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0031.png", + "frame": { "x": 298, "y": 358, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0032.png", + "frame": { "x": 63, "y": 285, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0033.png", + "frame": { "x": 66, "y": 214, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0034.png", + "frame": { "x": 336, "y": 146, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0035.png", + "frame": { "x": 1, "y": 73, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0036.png", + "frame": { "x": 424, "y": 73, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0037.png", + "frame": { "x": 284, "y": 70, "w": 64, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 0, "w": 64, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0038.png", + "frame": { "x": 350, "y": 74, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0039.png", + "frame": { "x": 490, "y": 141, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0040.png", + "frame": { "x": 415, "y": 145, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0041.png", + "frame": { "x": 318, "y": 217, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0042.png", + "frame": { "x": 442, "y": 353, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0043.png", + "frame": { "x": 59, "y": 425, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0044.png", + "frame": { "x": 1, "y": 425, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0045.png", + "frame": { "x": 117, "y": 426, "w": 56, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 56, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0046.png", + "frame": { "x": 486, "y": 424, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0047.png", + "frame": { "x": 298, "y": 358, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0048.png", + "frame": { "x": 63, "y": 285, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0049.png", + "frame": { "x": 66, "y": 214, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0050.png", + "frame": { "x": 336, "y": 146, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0051.png", + "frame": { "x": 1, "y": 73, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0052.png", + "frame": { "x": 424, "y": 73, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0053.png", + "frame": { "x": 284, "y": 70, "w": 64, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 0, "w": 64, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0054.png", + "frame": { "x": 350, "y": 74, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0055.png", + "frame": { "x": 490, "y": 141, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0056.png", + "frame": { "x": 415, "y": 145, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0057.png", + "frame": { "x": 318, "y": 217, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0058.png", + "frame": { "x": 442, "y": 353, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0059.png", + "frame": { "x": 59, "y": 425, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0060.png", + "frame": { "x": 1, "y": 425, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0061.png", + "frame": { "x": 117, "y": 426, "w": 56, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 56, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0062.png", + "frame": { "x": 486, "y": 424, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0063.png", + "frame": { "x": 298, "y": 358, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0064.png", + "frame": { "x": 63, "y": 285, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0065.png", + "frame": { "x": 255, "y": 214, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0066.png", + "frame": { "x": 462, "y": 283, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0067.png", + "frame": { "x": 309, "y": 288, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0068.png", + "frame": { "x": 370, "y": 356, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0069.png", + "frame": { "x": 380, "y": 287, "w": 60, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 60, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0070.png", + "frame": { "x": 1, "y": 215, "w": 63, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 63, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0071.png", + "frame": { "x": 492, "y": 1, "w": 68, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 3, "w": 68, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0072.png", + "frame": { "x": 284, "y": 1, "w": 70, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 70, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0073.png", + "frame": { "x": 72, "y": 1, "w": 71, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 71, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0074.png", + "frame": { "x": 214, "y": 1, "w": 68, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 68, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0075.png", + "frame": { "x": 214, "y": 72, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0076.png", + "frame": { "x": 66, "y": 214, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0077.png", + "frame": { "x": 67, "y": 142, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0078.png", + "frame": { "x": 424, "y": 1, "w": 66, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 66, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0079.png", + "frame": { "x": 1, "y": 1, "w": 69, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 69, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0080.png", + "frame": { "x": 145, "y": 1, "w": 67, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 0, "w": 67, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0081.png", + "frame": { "x": 356, "y": 1, "w": 66, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 0, "w": 66, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0082.png", + "frame": { "x": 121, "y": 355, "w": 57, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 57, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0083.png", + "frame": { "x": 239, "y": 426, "w": 54, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 54, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0084.png", + "frame": { "x": 357, "y": 425, "w": 55, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 55, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0085.png", + "frame": { "x": 429, "y": 423, "w": 55, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 55, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0086.png", + "frame": { "x": 180, "y": 356, "w": 57, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 57, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0087.png", + "frame": { "x": 66, "y": 214, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0088.png", + "frame": { "x": 271, "y": 143, "w": 63, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 63, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0089.png", + "frame": { "x": 72, "y": 71, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0090.png", + "frame": { "x": 187, "y": 285, "w": 59, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 59, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0091.png", + "frame": { "x": 192, "y": 214, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0092.png", + "frame": { "x": 206, "y": 143, "w": 63, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 63, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0093.png", + "frame": { "x": 492, "y": 70, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0094.png", + "frame": { "x": 503, "y": 353, "w": 58, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 58, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0095.png", + "frame": { "x": 129, "y": 214, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0096.png", + "frame": { "x": 132, "y": 144, "w": 63, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 63, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0097.png", + "frame": { "x": 139, "y": 74, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0098.png", + "frame": { "x": 61, "y": 355, "w": 58, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 58, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0099.png", + "frame": { "x": 125, "y": 285, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0100.png", + "frame": { "x": 479, "y": 213, "w": 62, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 62, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0101.png", + "frame": { "x": 1, "y": 145, "w": 63, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 63, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0102.png", + "frame": { "x": 239, "y": 356, "w": 57, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 3, "w": 57, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0103.png", + "frame": { "x": 1, "y": 354, "w": 58, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 58, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0104.png", + "frame": { "x": 248, "y": 285, "w": 59, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 59, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0105.png", + "frame": { "x": 1, "y": 283, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0106.png", + "frame": { "x": 400, "y": 216, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "783.png", + "format": "I8", + "size": { "w": 562, "h": 494 }, + "scale": "1" + } } diff --git a/public/images/pokemon/783.png b/public/images/pokemon/783.png index 3ec37265afe..9396392b588 100644 Binary files a/public/images/pokemon/783.png and b/public/images/pokemon/783.png differ diff --git a/public/images/pokemon/784.json b/public/images/pokemon/784.json index 93433997311..7899177cfc7 100644 --- a/public/images/pokemon/784.json +++ b/public/images/pokemon/784.json @@ -1,41 +1,812 @@ -{ - "textures": [ - { - "image": "784.png", - "format": "RGBA8888", - "size": { - "w": 81, - "h": 81 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 79, - "h": 81 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 79, - "h": 81 - }, - "frame": { - "x": 0, - "y": 0, - "w": 79, - "h": 81 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:dcfcb88e42dad35e57b259d31fbc6143:26fe93636d2b2e8c3da41c05f0648a08:c2f7ca3ab1075b8c824730653d891244$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 260, "y": 244, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0002.png", + "frame": { "x": 381, "y": 166, "w": 84, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 84, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0003.png", + "frame": { "x": 291, "y": 161, "w": 88, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 4, "w": 88, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0004.png", + "frame": { "x": 106, "y": 80, "w": 94, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 94, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0005.png", + "frame": { "x": 422, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0006.png", + "frame": { "x": 1, "y": 1, "w": 103, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 103, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0007.png", + "frame": { "x": 106, "y": 1, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0008.png", + "frame": { "x": 212, "y": 1, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0009.png", + "frame": { "x": 316, "y": 79, "w": 96, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 5, "w": 96, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0010.png", + "frame": { "x": 414, "y": 82, "w": 89, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 89, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0011.png", + "frame": { "x": 505, "y": 165, "w": 82, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 82, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0012.png", + "frame": { "x": 325, "y": 333, "w": 77, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 77, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0013.png", + "frame": { "x": 237, "y": 410, "w": 76, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 6, "w": 76, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0014.png", + "frame": { "x": 483, "y": 333, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 5, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0015.png", + "frame": { "x": 585, "y": 332, "w": 78, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 78, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0016.png", + "frame": { "x": 165, "y": 252, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0017.png", + "frame": { "x": 260, "y": 244, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0018.png", + "frame": { "x": 381, "y": 166, "w": 84, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 84, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0019.png", + "frame": { "x": 291, "y": 161, "w": 88, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 4, "w": 88, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0020.png", + "frame": { "x": 106, "y": 80, "w": 94, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 94, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0021.png", + "frame": { "x": 422, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0022.png", + "frame": { "x": 1, "y": 1, "w": 103, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 103, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0023.png", + "frame": { "x": 106, "y": 1, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0024.png", + "frame": { "x": 212, "y": 1, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0025.png", + "frame": { "x": 316, "y": 79, "w": 96, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 5, "w": 96, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0026.png", + "frame": { "x": 414, "y": 82, "w": 89, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 89, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0027.png", + "frame": { "x": 505, "y": 165, "w": 82, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 82, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0028.png", + "frame": { "x": 325, "y": 333, "w": 77, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 77, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0029.png", + "frame": { "x": 237, "y": 410, "w": 76, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 6, "w": 76, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0030.png", + "frame": { "x": 483, "y": 333, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 5, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0031.png", + "frame": { "x": 585, "y": 332, "w": 78, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 78, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0032.png", + "frame": { "x": 165, "y": 252, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0033.png", + "frame": { "x": 260, "y": 244, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0034.png", + "frame": { "x": 381, "y": 166, "w": 84, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 84, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0035.png", + "frame": { "x": 291, "y": 161, "w": 88, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 4, "w": 88, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0036.png", + "frame": { "x": 106, "y": 80, "w": 94, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 94, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0037.png", + "frame": { "x": 422, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0038.png", + "frame": { "x": 1, "y": 1, "w": 103, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 103, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0039.png", + "frame": { "x": 106, "y": 1, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0040.png", + "frame": { "x": 212, "y": 1, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0041.png", + "frame": { "x": 316, "y": 79, "w": 96, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 5, "w": 96, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0042.png", + "frame": { "x": 414, "y": 82, "w": 89, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 89, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0043.png", + "frame": { "x": 505, "y": 165, "w": 82, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 82, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0044.png", + "frame": { "x": 325, "y": 333, "w": 77, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 77, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0045.png", + "frame": { "x": 237, "y": 410, "w": 76, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 6, "w": 76, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0046.png", + "frame": { "x": 483, "y": 333, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 5, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0047.png", + "frame": { "x": 585, "y": 332, "w": 78, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 78, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0048.png", + "frame": { "x": 165, "y": 252, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0049.png", + "frame": { "x": 260, "y": 244, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0050.png", + "frame": { "x": 381, "y": 166, "w": 84, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 84, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0051.png", + "frame": { "x": 291, "y": 161, "w": 88, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 4, "w": 88, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0052.png", + "frame": { "x": 106, "y": 80, "w": 94, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 94, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0053.png", + "frame": { "x": 422, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0054.png", + "frame": { "x": 1, "y": 1, "w": 103, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 103, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0055.png", + "frame": { "x": 106, "y": 1, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0056.png", + "frame": { "x": 212, "y": 1, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0057.png", + "frame": { "x": 316, "y": 79, "w": 96, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 5, "w": 96, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0058.png", + "frame": { "x": 414, "y": 82, "w": 89, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 89, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0059.png", + "frame": { "x": 505, "y": 165, "w": 82, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 82, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0060.png", + "frame": { "x": 325, "y": 333, "w": 77, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 77, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0061.png", + "frame": { "x": 237, "y": 410, "w": 76, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 6, "w": 76, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0062.png", + "frame": { "x": 483, "y": 333, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 5, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0063.png", + "frame": { "x": 585, "y": 332, "w": 78, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 78, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0064.png", + "frame": { "x": 165, "y": 252, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0065.png", + "frame": { "x": 83, "y": 246, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0066.png", + "frame": { "x": 589, "y": 166, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0067.png", + "frame": { "x": 1, "y": 162, "w": 89, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 89, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0068.png", + "frame": { "x": 1, "y": 81, "w": 95, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 6, "w": 95, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0069.png", + "frame": { "x": 624, "y": 1, "w": 100, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 7, "w": 100, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0070.png", + "frame": { "x": 316, "y": 1, "w": 104, "h": 76 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 9, "w": 104, "h": 76 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0071.png", + "frame": { "x": 523, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0072.png", + "frame": { "x": 505, "y": 82, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 14, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0073.png", + "frame": { "x": 624, "y": 81, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0074.png", + "frame": { "x": 202, "y": 81, "w": 87, "h": 85 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 0, "w": 87, "h": 85 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0075.png", + "frame": { "x": 92, "y": 162, "w": 84, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 84, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0076.png", + "frame": { "x": 159, "y": 335, "w": 76, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 5, "w": 76, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0077.png", + "frame": { "x": 562, "y": 414, "w": 75, "h": 74 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 14, "w": 75, "h": 74 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0078.png", + "frame": { "x": 1, "y": 412, "w": 75, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 7, "w": 75, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0079.png", + "frame": { "x": 78, "y": 413, "w": 76, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 9, "w": 76, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0080.png", + "frame": { "x": 404, "y": 333, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0081.png", + "frame": { "x": 245, "y": 327, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 5, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0082.png", + "frame": { "x": 178, "y": 168, "w": 80, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 80, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0083.png", + "frame": { "x": 1, "y": 244, "w": 80, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 80, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0084.png", + "frame": { "x": 342, "y": 249, "w": 79, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 3, "w": 79, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0085.png", + "frame": { "x": 1, "y": 328, "w": 77, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 3, "w": 77, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0086.png", + "frame": { "x": 80, "y": 329, "w": 77, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 3, "w": 77, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0087.png", + "frame": { "x": 423, "y": 249, "w": 79, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 3, "w": 79, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0088.png", + "frame": { "x": 589, "y": 249, "w": 79, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 79, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0089.png", + "frame": { "x": 504, "y": 250, "w": 79, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 79, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "784.png", + "format": "I8", + "size": { "w": 725, "h": 493 }, + "scale": "1" + } } diff --git a/public/images/pokemon/784.png b/public/images/pokemon/784.png index 7bca9f0794a..6d37807b8a0 100644 Binary files a/public/images/pokemon/784.png and b/public/images/pokemon/784.png differ diff --git a/public/images/pokemon/840.png b/public/images/pokemon/840.png index f0d1f83bd93..1a263e3ee19 100644 Binary files a/public/images/pokemon/840.png and b/public/images/pokemon/840.png differ diff --git a/public/images/pokemon/841-gigantamax.png b/public/images/pokemon/841-gigantamax.png index 69c53677722..07121b9c12f 100644 Binary files a/public/images/pokemon/841-gigantamax.png and b/public/images/pokemon/841-gigantamax.png differ diff --git a/public/images/pokemon/841.png b/public/images/pokemon/841.png index 5e665960df4..e7329f2eb97 100644 Binary files a/public/images/pokemon/841.png and b/public/images/pokemon/841.png differ diff --git a/public/images/pokemon/842-gigantamax.png b/public/images/pokemon/842-gigantamax.png index 69c53677722..aee95b7b881 100644 Binary files a/public/images/pokemon/842-gigantamax.png and b/public/images/pokemon/842-gigantamax.png differ diff --git a/public/images/pokemon/842.png b/public/images/pokemon/842.png index 468ca88562e..4e3fec8ef1b 100644 Binary files a/public/images/pokemon/842.png and b/public/images/pokemon/842.png differ diff --git a/public/images/pokemon/871.png b/public/images/pokemon/871.png index bdcedb9d90a..af53b0275e6 100644 Binary files a/public/images/pokemon/871.png and b/public/images/pokemon/871.png differ diff --git a/public/images/pokemon/back/1011.png b/public/images/pokemon/back/1011.png index 3e23fc1ebe3..ab3cc75482d 100644 Binary files a/public/images/pokemon/back/1011.png and b/public/images/pokemon/back/1011.png differ diff --git a/public/images/pokemon/back/1019.png b/public/images/pokemon/back/1019.png index ece50558c8c..d80a0930192 100644 Binary files a/public/images/pokemon/back/1019.png and b/public/images/pokemon/back/1019.png differ diff --git a/public/images/pokemon/back/143-gigantamax.png b/public/images/pokemon/back/143-gigantamax.png index 3ebb6f16483..cd251a515e6 100644 Binary files a/public/images/pokemon/back/143-gigantamax.png and b/public/images/pokemon/back/143-gigantamax.png differ diff --git a/public/images/pokemon/back/2038.png b/public/images/pokemon/back/2038.png index 68a9cfb2d6e..957b2d31714 100644 Binary files a/public/images/pokemon/back/2038.png and b/public/images/pokemon/back/2038.png differ diff --git a/public/images/pokemon/back/332.png b/public/images/pokemon/back/332.png index a6940fbaba6..a432b1af4b2 100644 Binary files a/public/images/pokemon/back/332.png and b/public/images/pokemon/back/332.png differ diff --git a/public/images/pokemon/back/34.png b/public/images/pokemon/back/34.png index 40827a68879..bb0ad630d1a 100644 Binary files a/public/images/pokemon/back/34.png and b/public/images/pokemon/back/34.png differ diff --git a/public/images/pokemon/back/396.png b/public/images/pokemon/back/396.png index 141103a25ad..843c9dca1e4 100644 Binary files a/public/images/pokemon/back/396.png and b/public/images/pokemon/back/396.png differ diff --git a/public/images/pokemon/back/397.png b/public/images/pokemon/back/397.png index 96a5d4f161a..236fc18ea44 100644 Binary files a/public/images/pokemon/back/397.png and b/public/images/pokemon/back/397.png differ diff --git a/public/images/pokemon/back/398.png b/public/images/pokemon/back/398.png index 57fbb92e12f..63ed37bfd15 100644 Binary files a/public/images/pokemon/back/398.png and b/public/images/pokemon/back/398.png differ diff --git a/public/images/pokemon/back/403.png b/public/images/pokemon/back/403.png index c8f49d37d96..303c4b57cbd 100644 Binary files a/public/images/pokemon/back/403.png and b/public/images/pokemon/back/403.png differ diff --git a/public/images/pokemon/back/404.png b/public/images/pokemon/back/404.png index eb1a04e4d1b..6592f80c58d 100644 Binary files a/public/images/pokemon/back/404.png and b/public/images/pokemon/back/404.png differ diff --git a/public/images/pokemon/back/405.png b/public/images/pokemon/back/405.png index b6c6f12a0fb..0afe5b3036d 100644 Binary files a/public/images/pokemon/back/405.png and b/public/images/pokemon/back/405.png differ diff --git a/public/images/pokemon/back/498.png b/public/images/pokemon/back/498.png index 8ea4900e8f3..c14fb4561e7 100644 Binary files a/public/images/pokemon/back/498.png and b/public/images/pokemon/back/498.png differ diff --git a/public/images/pokemon/back/500.png b/public/images/pokemon/back/500.png index de1b556bede..082f0460ff2 100644 Binary files a/public/images/pokemon/back/500.png and b/public/images/pokemon/back/500.png differ diff --git a/public/images/pokemon/back/522.png b/public/images/pokemon/back/522.png index 54c706d1455..ff5bbafb915 100644 Binary files a/public/images/pokemon/back/522.png and b/public/images/pokemon/back/522.png differ diff --git a/public/images/pokemon/back/523.png b/public/images/pokemon/back/523.png index 6f25fd9cc74..023afbd1008 100644 Binary files a/public/images/pokemon/back/523.png and b/public/images/pokemon/back/523.png differ diff --git a/public/images/pokemon/back/535.png b/public/images/pokemon/back/535.png index ac477600b72..2556d646aa6 100644 Binary files a/public/images/pokemon/back/535.png and b/public/images/pokemon/back/535.png differ diff --git a/public/images/pokemon/back/536.png b/public/images/pokemon/back/536.png index 32e48b10c85..393006e83b9 100644 Binary files a/public/images/pokemon/back/536.png and b/public/images/pokemon/back/536.png differ diff --git a/public/images/pokemon/back/554.png b/public/images/pokemon/back/554.png index 4ed9c06f0ee..f6423a5e66e 100644 Binary files a/public/images/pokemon/back/554.png and b/public/images/pokemon/back/554.png differ diff --git a/public/images/pokemon/back/555-zen.png b/public/images/pokemon/back/555-zen.png index 48ef6beb7c4..8fe0e672a3a 100644 Binary files a/public/images/pokemon/back/555-zen.png and b/public/images/pokemon/back/555-zen.png differ diff --git a/public/images/pokemon/back/555.png b/public/images/pokemon/back/555.png index 8f1a709c5f4..77c04139079 100644 Binary files a/public/images/pokemon/back/555.png and b/public/images/pokemon/back/555.png differ diff --git a/public/images/pokemon/back/567.png b/public/images/pokemon/back/567.png index ca9432a3e71..ec4197fbb92 100644 Binary files a/public/images/pokemon/back/567.png and b/public/images/pokemon/back/567.png differ diff --git a/public/images/pokemon/back/572.png b/public/images/pokemon/back/572.png index d7ddaf62136..4d081564b50 100644 Binary files a/public/images/pokemon/back/572.png and b/public/images/pokemon/back/572.png differ diff --git a/public/images/pokemon/back/573.png b/public/images/pokemon/back/573.png index 03a0093d70d..ef4a8bc14ab 100644 Binary files a/public/images/pokemon/back/573.png and b/public/images/pokemon/back/573.png differ diff --git a/public/images/pokemon/back/626.png b/public/images/pokemon/back/626.png index 05b6514878d..a3098a1c1d3 100644 Binary files a/public/images/pokemon/back/626.png and b/public/images/pokemon/back/626.png differ diff --git a/public/images/pokemon/back/643.png b/public/images/pokemon/back/643.png index 30b32e7902d..597b4bcb189 100644 Binary files a/public/images/pokemon/back/643.png and b/public/images/pokemon/back/643.png differ diff --git a/public/images/pokemon/back/644.png b/public/images/pokemon/back/644.png index ab17e62c2e6..39a4d3499bd 100644 Binary files a/public/images/pokemon/back/644.png and b/public/images/pokemon/back/644.png differ diff --git a/public/images/pokemon/back/645-incarnate.png b/public/images/pokemon/back/645-incarnate.png index 8be36f692f9..d47e03c718b 100644 Binary files a/public/images/pokemon/back/645-incarnate.png and b/public/images/pokemon/back/645-incarnate.png differ diff --git a/public/images/pokemon/back/645-therian.png b/public/images/pokemon/back/645-therian.png index 2e5e6e03e05..127a759f89a 100644 Binary files a/public/images/pokemon/back/645-therian.png and b/public/images/pokemon/back/645-therian.png differ diff --git a/public/images/pokemon/back/646-black.png b/public/images/pokemon/back/646-black.png index aeeb90f147e..7783e4c8cd5 100644 Binary files a/public/images/pokemon/back/646-black.png and b/public/images/pokemon/back/646-black.png differ diff --git a/public/images/pokemon/back/646-white.png b/public/images/pokemon/back/646-white.png index f5db6867e94..1dc659ed6ac 100644 Binary files a/public/images/pokemon/back/646-white.png and b/public/images/pokemon/back/646-white.png differ diff --git a/public/images/pokemon/back/646.png b/public/images/pokemon/back/646.png index 3a36013adec..6ca7f51f01d 100644 Binary files a/public/images/pokemon/back/646.png and b/public/images/pokemon/back/646.png differ diff --git a/public/images/pokemon/back/746-school.png b/public/images/pokemon/back/746-school.png index 55b8f33929b..1884123d82e 100644 Binary files a/public/images/pokemon/back/746-school.png and b/public/images/pokemon/back/746-school.png differ diff --git a/public/images/pokemon/back/746.png b/public/images/pokemon/back/746.png index 3b1b4438f15..cb424c9fbe1 100644 Binary files a/public/images/pokemon/back/746.png and b/public/images/pokemon/back/746.png differ diff --git a/public/images/pokemon/back/782.json b/public/images/pokemon/back/782.json index 64036da7750..564a0c4f13a 100644 --- a/public/images/pokemon/back/782.json +++ b/public/images/pokemon/back/782.json @@ -1,41 +1,1010 @@ -{ - "textures": [ - { - "image": "782.png", - "format": "RGBA8888", - "size": { - "w": 50, - "h": 50 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 46, - "h": 50 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 46, - "h": 50 - }, - "frame": { - "x": 0, - "y": 0, - "w": 46, - "h": 50 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:03129fcf647a44654eebf65e3131032f:56b06453c435e6f8d3648a6836f20d5d:d07862436676aa228a148ee1f1d82a8f$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0002.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0003.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0004.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0005.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0006.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0007.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0008.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0009.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0010.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0011.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0012.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0013.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0014.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0015.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0016.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0017.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0018.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0019.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0020.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0021.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0022.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0023.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0024.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0025.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0026.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0027.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0028.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0029.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0030.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0031.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0032.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0033.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0034.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0035.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0036.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0037.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0038.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0039.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0040.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0041.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0042.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0043.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0044.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0045.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0046.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0047.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0048.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0049.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0050.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0051.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0052.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0053.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0054.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0055.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0056.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0057.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0058.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0059.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0060.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0061.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0062.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0063.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0064.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0065.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0066.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0067.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0068.png", + "frame": { "x": 99, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0069.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0070.png", + "frame": { "x": 148, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0071.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0072.png", + "frame": { "x": 195, "y": 164, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0073.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0074.png", + "frame": { "x": 146, "y": 164, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0075.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0076.png", + "frame": { "x": 1, "y": 166, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0077.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0078.png", + "frame": { "x": 50, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0079.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0080.png", + "frame": { "x": 98, "y": 164, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0081.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0082.png", + "frame": { "x": 50, "y": 111, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0083.png", + "frame": { "x": 201, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0084.png", + "frame": { "x": 201, "y": 55, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0085.png", + "frame": { "x": 1, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0086.png", + "frame": { "x": 51, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0087.png", + "frame": { "x": 101, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0088.png", + "frame": { "x": 101, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0089.png", + "frame": { "x": 1, "y": 56, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0090.png", + "frame": { "x": 50, "y": 56, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0091.png", + "frame": { "x": 99, "y": 56, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0092.png", + "frame": { "x": 148, "y": 56, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0093.png", + "frame": { "x": 151, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0094.png", + "frame": { "x": 151, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0095.png", + "frame": { "x": 101, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0096.png", + "frame": { "x": 101, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0097.png", + "frame": { "x": 197, "y": 109, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0098.png", + "frame": { "x": 197, "y": 109, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0099.png", + "frame": { "x": 148, "y": 56, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0100.png", + "frame": { "x": 148, "y": 56, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0101.png", + "frame": { "x": 151, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0102.png", + "frame": { "x": 151, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0103.png", + "frame": { "x": 151, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0104.png", + "frame": { "x": 101, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0105.png", + "frame": { "x": 101, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0106.png", + "frame": { "x": 197, "y": 109, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0107.png", + "frame": { "x": 197, "y": 109, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0108.png", + "frame": { "x": 99, "y": 56, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0109.png", + "frame": { "x": 1, "y": 111, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0110.png", + "frame": { "x": 201, "y": 55, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0111.png", + "frame": { "x": 201, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "782.png", + "format": "I8", + "size": { "w": 249, "h": 216 }, + "scale": "1" + } } diff --git a/public/images/pokemon/back/782.png b/public/images/pokemon/back/782.png index aa3e05416a2..eb222077d81 100644 Binary files a/public/images/pokemon/back/782.png and b/public/images/pokemon/back/782.png differ diff --git a/public/images/pokemon/back/783.json b/public/images/pokemon/back/783.json index dbdf0832c04..d8f4119f161 100644 --- a/public/images/pokemon/back/783.json +++ b/public/images/pokemon/back/783.json @@ -1,41 +1,965 @@ -{ - "textures": [ - { - "image": "783.png", - "format": "RGBA8888", - "size": { - "w": 69, - "h": 69 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 66, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 66, - "h": 69 - }, - "frame": { - "x": 0, - "y": 0, - "w": 66, - "h": 69 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:7d62b0df753b06fca02f434512c11d99:8e8a5ac9c7d2fc25a02a4d24d5c5b640:aab166e28c744865a0296041224dd01b$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 420, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0002.png", + "frame": { "x": 272, "y": 280, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0003.png", + "frame": { "x": 487, "y": 277, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0004.png", + "frame": { "x": 1, "y": 347, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0005.png", + "frame": { "x": 266, "y": 350, "w": 62, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 0, "w": 62, "h": 71 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0006.png", + "frame": { "x": 66, "y": 349, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0007.png", + "frame": { "x": 347, "y": 279, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0008.png", + "frame": { "x": 134, "y": 282, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0009.png", + "frame": { "x": 1, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0010.png", + "frame": { "x": 200, "y": 347, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0011.png", + "frame": { "x": 329, "y": 350, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0012.png", + "frame": { "x": 1, "y": 418, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0013.png", + "frame": { "x": 519, "y": 418, "w": 61, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 61, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0014.png", + "frame": { "x": 456, "y": 418, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0015.png", + "frame": { "x": 130, "y": 352, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0016.png", + "frame": { "x": 413, "y": 347, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0017.png", + "frame": { "x": 420, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0018.png", + "frame": { "x": 272, "y": 280, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0019.png", + "frame": { "x": 487, "y": 277, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0020.png", + "frame": { "x": 1, "y": 347, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0021.png", + "frame": { "x": 266, "y": 350, "w": 62, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 0, "w": 62, "h": 71 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0022.png", + "frame": { "x": 66, "y": 349, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0023.png", + "frame": { "x": 347, "y": 279, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0024.png", + "frame": { "x": 134, "y": 282, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0025.png", + "frame": { "x": 1, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0026.png", + "frame": { "x": 200, "y": 347, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0027.png", + "frame": { "x": 329, "y": 350, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0028.png", + "frame": { "x": 1, "y": 418, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0029.png", + "frame": { "x": 519, "y": 418, "w": 61, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 61, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0030.png", + "frame": { "x": 456, "y": 418, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0031.png", + "frame": { "x": 130, "y": 352, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0032.png", + "frame": { "x": 413, "y": 347, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0033.png", + "frame": { "x": 420, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0034.png", + "frame": { "x": 272, "y": 280, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0035.png", + "frame": { "x": 487, "y": 277, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0036.png", + "frame": { "x": 1, "y": 347, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0037.png", + "frame": { "x": 266, "y": 350, "w": 62, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 0, "w": 62, "h": 71 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0038.png", + "frame": { "x": 66, "y": 349, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0039.png", + "frame": { "x": 347, "y": 279, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0040.png", + "frame": { "x": 134, "y": 282, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0041.png", + "frame": { "x": 1, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0042.png", + "frame": { "x": 200, "y": 347, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0043.png", + "frame": { "x": 329, "y": 350, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0044.png", + "frame": { "x": 1, "y": 418, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0045.png", + "frame": { "x": 519, "y": 418, "w": 61, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 61, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0046.png", + "frame": { "x": 456, "y": 418, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0047.png", + "frame": { "x": 130, "y": 352, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0048.png", + "frame": { "x": 413, "y": 347, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0049.png", + "frame": { "x": 420, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0050.png", + "frame": { "x": 272, "y": 280, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0051.png", + "frame": { "x": 487, "y": 277, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0052.png", + "frame": { "x": 1, "y": 347, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0053.png", + "frame": { "x": 266, "y": 350, "w": 62, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 0, "w": 62, "h": 71 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0054.png", + "frame": { "x": 66, "y": 349, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0055.png", + "frame": { "x": 347, "y": 279, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0056.png", + "frame": { "x": 134, "y": 282, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0057.png", + "frame": { "x": 1, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0058.png", + "frame": { "x": 200, "y": 347, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0059.png", + "frame": { "x": 329, "y": 350, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0060.png", + "frame": { "x": 1, "y": 418, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0061.png", + "frame": { "x": 519, "y": 418, "w": 61, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 61, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0062.png", + "frame": { "x": 456, "y": 418, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0063.png", + "frame": { "x": 130, "y": 352, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0064.png", + "frame": { "x": 413, "y": 347, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0065.png", + "frame": { "x": 420, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0066.png", + "frame": { "x": 205, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0067.png", + "frame": { "x": 138, "y": 211, "w": 66, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 1, "w": 66, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0068.png", + "frame": { "x": 68, "y": 278, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0069.png", + "frame": { "x": 141, "y": 140, "w": 67, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 67, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0070.png", + "frame": { "x": 294, "y": 1, "w": 69, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 1, "w": 69, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0071.png", + "frame": { "x": 149, "y": 1, "w": 71, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 71, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0072.png", + "frame": { "x": 490, "y": 209, "w": 69, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 4, "w": 69, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0073.png", + "frame": { "x": 143, "y": 71, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0074.png", + "frame": { "x": 506, "y": 1, "w": 69, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 69, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0075.png", + "frame": { "x": 361, "y": 139, "w": 68, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 68, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0076.png", + "frame": { "x": 420, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0077.png", + "frame": { "x": 430, "y": 140, "w": 68, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 68, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0078.png", + "frame": { "x": 436, "y": 1, "w": 69, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 69, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0079.png", + "frame": { "x": 505, "y": 71, "w": 69, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 69, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0080.png", + "frame": { "x": 209, "y": 209, "w": 69, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 69, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0081.png", + "frame": { "x": 420, "y": 209, "w": 69, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 69, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0082.png", + "frame": { "x": 195, "y": 416, "w": 63, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 2, "w": 63, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0083.png", + "frame": { "x": 329, "y": 419, "w": 59, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 59, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0084.png", + "frame": { "x": 64, "y": 420, "w": 58, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 3, "w": 58, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0085.png", + "frame": { "x": 394, "y": 416, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0086.png", + "frame": { "x": 479, "y": 348, "w": 64, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 64, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0087.png", + "frame": { "x": 420, "y": 277, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0088.png", + "frame": { "x": 292, "y": 72, "w": 68, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 68, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0089.png", + "frame": { "x": 221, "y": 1, "w": 72, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 72, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0090.png", + "frame": { "x": 1, "y": 139, "w": 69, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 69, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0091.png", + "frame": { "x": 364, "y": 70, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0092.png", + "frame": { "x": 221, "y": 70, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0093.png", + "frame": { "x": 75, "y": 1, "w": 73, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 73, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0094.png", + "frame": { "x": 71, "y": 139, "w": 69, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 69, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0095.png", + "frame": { "x": 72, "y": 70, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0096.png", + "frame": { "x": 1, "y": 70, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0097.png", + "frame": { "x": 1, "y": 1, "w": 73, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 73, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0098.png", + "frame": { "x": 283, "y": 142, "w": 68, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 3, "w": 68, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0099.png", + "frame": { "x": 499, "y": 140, "w": 68, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 68, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0100.png", + "frame": { "x": 435, "y": 71, "w": 69, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 69, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0101.png", + "frame": { "x": 364, "y": 1, "w": 71, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 71, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0102.png", + "frame": { "x": 1, "y": 208, "w": 68, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 68, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0103.png", + "frame": { "x": 279, "y": 211, "w": 67, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 67, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0104.png", + "frame": { "x": 214, "y": 139, "w": 68, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 68, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0105.png", + "frame": { "x": 70, "y": 208, "w": 67, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 67, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0106.png", + "frame": { "x": 352, "y": 209, "w": 67, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 67, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "783.png", + "format": "I8", + "size": { "w": 581, "h": 489 }, + "scale": "1" + } } diff --git a/public/images/pokemon/back/783.png b/public/images/pokemon/back/783.png index 80b07db3466..ff8c7ca052f 100644 Binary files a/public/images/pokemon/back/783.png and b/public/images/pokemon/back/783.png differ diff --git a/public/images/pokemon/back/784.json b/public/images/pokemon/back/784.json index 8a31743fa63..2be405d5d06 100644 --- a/public/images/pokemon/back/784.json +++ b/public/images/pokemon/back/784.json @@ -1,41 +1,812 @@ -{ - "textures": [ - { - "image": "784.png", - "format": "RGBA8888", - "size": { - "w": 92, - "h": 92 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 92, - "h": 81 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 92, - "h": 81 - }, - "frame": { - "x": 0, - "y": 0, - "w": 92, - "h": 81 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:f20be28706ee0de7538fc5feaf80d0ee:599492666e3be0e6a26e56f7fe23eebd:c2f7ca3ab1075b8c824730653d891244$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 189, "y": 242, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0002.png", + "frame": { "x": 1, "y": 166, "w": 94, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 94, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0003.png", + "frame": { "x": 545, "y": 84, "w": 98, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 98, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0004.png", + "frame": { "x": 545, "y": 1, "w": 103, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 103, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0005.png", + "frame": { "x": 333, "y": 1, "w": 106, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 106, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0006.png", + "frame": { "x": 1, "y": 1, "w": 110, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 6, "w": 110, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0007.png", + "frame": { "x": 220, "y": 1, "w": 110, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 7, "w": 110, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0008.png", + "frame": { "x": 651, "y": 1, "w": 106, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 8, "w": 106, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0009.png", + "frame": { "x": 204, "y": 162, "w": 102, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 8, "w": 102, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0010.png", + "frame": { "x": 309, "y": 165, "w": 97, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 97, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0011.png", + "frame": { "x": 98, "y": 172, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0012.png", + "frame": { "x": 461, "y": 251, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0013.png", + "frame": { "x": 341, "y": 332, "w": 81, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 6, "w": 81, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0014.png", + "frame": { "x": 176, "y": 326, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0015.png", + "frame": { "x": 89, "y": 258, "w": 84, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 84, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0016.png", + "frame": { "x": 1, "y": 250, "w": 85, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 18, "y": 4, "w": 85, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0017.png", + "frame": { "x": 189, "y": 242, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0018.png", + "frame": { "x": 1, "y": 166, "w": 94, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 94, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0019.png", + "frame": { "x": 545, "y": 84, "w": 98, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 98, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0020.png", + "frame": { "x": 545, "y": 1, "w": 103, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 103, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0021.png", + "frame": { "x": 333, "y": 1, "w": 106, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 106, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0022.png", + "frame": { "x": 1, "y": 1, "w": 110, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 6, "w": 110, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0023.png", + "frame": { "x": 220, "y": 1, "w": 110, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 7, "w": 110, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0024.png", + "frame": { "x": 651, "y": 1, "w": 106, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 8, "w": 106, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0025.png", + "frame": { "x": 204, "y": 162, "w": 102, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 8, "w": 102, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0026.png", + "frame": { "x": 309, "y": 165, "w": 97, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 97, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0027.png", + "frame": { "x": 98, "y": 172, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0028.png", + "frame": { "x": 461, "y": 251, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0029.png", + "frame": { "x": 341, "y": 332, "w": 81, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 6, "w": 81, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0030.png", + "frame": { "x": 176, "y": 326, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0031.png", + "frame": { "x": 89, "y": 258, "w": 84, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 84, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0032.png", + "frame": { "x": 1, "y": 250, "w": 85, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 18, "y": 4, "w": 85, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0033.png", + "frame": { "x": 189, "y": 242, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0034.png", + "frame": { "x": 1, "y": 166, "w": 94, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 94, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0035.png", + "frame": { "x": 545, "y": 84, "w": 98, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 98, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0036.png", + "frame": { "x": 545, "y": 1, "w": 103, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 103, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0037.png", + "frame": { "x": 333, "y": 1, "w": 106, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 106, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0038.png", + "frame": { "x": 1, "y": 1, "w": 110, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 6, "w": 110, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0039.png", + "frame": { "x": 220, "y": 1, "w": 110, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 7, "w": 110, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0040.png", + "frame": { "x": 651, "y": 1, "w": 106, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 8, "w": 106, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0041.png", + "frame": { "x": 204, "y": 162, "w": 102, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 8, "w": 102, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0042.png", + "frame": { "x": 309, "y": 165, "w": 97, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 97, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0043.png", + "frame": { "x": 98, "y": 172, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0044.png", + "frame": { "x": 461, "y": 251, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0045.png", + "frame": { "x": 341, "y": 332, "w": 81, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 6, "w": 81, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0046.png", + "frame": { "x": 176, "y": 326, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0047.png", + "frame": { "x": 89, "y": 258, "w": 84, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 84, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0048.png", + "frame": { "x": 1, "y": 250, "w": 85, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 18, "y": 4, "w": 85, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0049.png", + "frame": { "x": 189, "y": 242, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0050.png", + "frame": { "x": 1, "y": 166, "w": 94, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 94, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0051.png", + "frame": { "x": 545, "y": 84, "w": 98, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 98, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0052.png", + "frame": { "x": 545, "y": 1, "w": 103, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 103, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0053.png", + "frame": { "x": 333, "y": 1, "w": 106, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 106, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0054.png", + "frame": { "x": 1, "y": 1, "w": 110, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 6, "w": 110, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0055.png", + "frame": { "x": 220, "y": 1, "w": 110, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 7, "w": 110, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0056.png", + "frame": { "x": 651, "y": 1, "w": 106, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 8, "w": 106, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0057.png", + "frame": { "x": 204, "y": 162, "w": 102, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 8, "w": 102, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0058.png", + "frame": { "x": 309, "y": 165, "w": 97, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 97, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0059.png", + "frame": { "x": 98, "y": 172, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0060.png", + "frame": { "x": 461, "y": 251, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0061.png", + "frame": { "x": 341, "y": 332, "w": 81, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 6, "w": 81, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0062.png", + "frame": { "x": 176, "y": 326, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0063.png", + "frame": { "x": 89, "y": 258, "w": 84, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 84, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0064.png", + "frame": { "x": 1, "y": 250, "w": 85, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 18, "y": 4, "w": 85, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0065.png", + "frame": { "x": 409, "y": 166, "w": 93, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 93, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0066.png", + "frame": { "x": 104, "y": 88, "w": 97, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 97, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0067.png", + "frame": { "x": 1, "y": 83, "w": 100, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 5, "w": 100, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0068.png", + "frame": { "x": 651, "y": 81, "w": 102, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 6, "w": 102, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0069.png", + "frame": { "x": 220, "y": 82, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0070.png", + "frame": { "x": 432, "y": 87, "w": 104, "h": 76 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 9, "w": 104, "h": 76 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0071.png", + "frame": { "x": 327, "y": 84, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0072.png", + "frame": { "x": 646, "y": 163, "w": 96, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 4, "w": 96, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0073.png", + "frame": { "x": 442, "y": 1, "w": 100, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 100, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0074.png", + "frame": { "x": 114, "y": 1, "w": 103, "h": 84 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 103, "h": 84 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0075.png", + "frame": { "x": 505, "y": 168, "w": 92, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 92, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0076.png", + "frame": { "x": 83, "y": 341, "w": 75, "h": 85 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 33, "y": 0, "w": 75, "h": 85 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0077.png", + "frame": { "x": 579, "y": 415, "w": 72, "h": 74 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 36, "y": 12, "w": 72, "h": 74 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0078.png", + "frame": { "x": 504, "y": 413, "w": 72, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 36, "y": 5, "w": 72, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0079.png", + "frame": { "x": 341, "y": 414, "w": 72, "h": 75 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 36, "y": 10, "w": 72, "h": 75 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0080.png", + "frame": { "x": 693, "y": 247, "w": 73, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 35, "y": 5, "w": 73, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0081.png", + "frame": { "x": 161, "y": 409, "w": 74, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 34, "y": 3, "w": 74, "h": 82 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0082.png", + "frame": { "x": 425, "y": 335, "w": 76, "h": 84 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 31, "y": 1, "w": 76, "h": 84 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0083.png", + "frame": { "x": 261, "y": 331, "w": 77, "h": 84 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 29, "y": 1, "w": 77, "h": 84 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0084.png", + "frame": { "x": 632, "y": 330, "w": 79, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 3, "w": 79, "h": 82 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0085.png", + "frame": { "x": 1, "y": 334, "w": 79, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 4, "w": 79, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0086.png", + "frame": { "x": 547, "y": 330, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0087.png", + "frame": { "x": 372, "y": 250, "w": 86, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 17, "y": 6, "w": 86, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0088.png", + "frame": { "x": 282, "y": 248, "w": 87, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 15, "y": 5, "w": 87, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0089.png", + "frame": { "x": 600, "y": 247, "w": 90, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 5, "w": 90, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "784.png", + "format": "I8", + "size": { "w": 767, "h": 494 }, + "scale": "1" + } } diff --git a/public/images/pokemon/back/784.png b/public/images/pokemon/back/784.png index 365f0d0610d..08b953b3351 100644 Binary files a/public/images/pokemon/back/784.png and b/public/images/pokemon/back/784.png differ diff --git a/public/images/pokemon/back/840.png b/public/images/pokemon/back/840.png index f9ff9f11790..a247dc33939 100644 Binary files a/public/images/pokemon/back/840.png and b/public/images/pokemon/back/840.png differ diff --git a/public/images/pokemon/back/841-gigantamax.png b/public/images/pokemon/back/841-gigantamax.png index af30e475002..7c7e9e442b5 100644 Binary files a/public/images/pokemon/back/841-gigantamax.png and b/public/images/pokemon/back/841-gigantamax.png differ diff --git a/public/images/pokemon/back/841.png b/public/images/pokemon/back/841.png index 705b651521b..7b083594ab0 100644 Binary files a/public/images/pokemon/back/841.png and b/public/images/pokemon/back/841.png differ diff --git a/public/images/pokemon/back/842-gigantamax.png b/public/images/pokemon/back/842-gigantamax.png index af30e475002..7c7e9e442b5 100644 Binary files a/public/images/pokemon/back/842-gigantamax.png and b/public/images/pokemon/back/842-gigantamax.png differ diff --git a/public/images/pokemon/back/842.png b/public/images/pokemon/back/842.png index d3f9ff8e12b..f6f72d57b06 100644 Binary files a/public/images/pokemon/back/842.png and b/public/images/pokemon/back/842.png differ diff --git a/public/images/pokemon/back/871.png b/public/images/pokemon/back/871.png index 657da7f864f..73eb65ab089 100644 Binary files a/public/images/pokemon/back/871.png and b/public/images/pokemon/back/871.png differ diff --git a/public/images/pokemon/back/female/332.png b/public/images/pokemon/back/female/332.png index a6940fbaba6..a432b1af4b2 100644 Binary files a/public/images/pokemon/back/female/332.png and b/public/images/pokemon/back/female/332.png differ diff --git a/public/images/pokemon/back/female/396.png b/public/images/pokemon/back/female/396.png index 0222da73920..d18d4c1a99a 100644 Binary files a/public/images/pokemon/back/female/396.png and b/public/images/pokemon/back/female/396.png differ diff --git a/public/images/pokemon/back/female/397.png b/public/images/pokemon/back/female/397.png index a1f7f52a0e4..32768daead2 100644 Binary files a/public/images/pokemon/back/female/397.png and b/public/images/pokemon/back/female/397.png differ diff --git a/public/images/pokemon/back/female/398.png b/public/images/pokemon/back/female/398.png index 57fbb92e12f..bf296c54b91 100644 Binary files a/public/images/pokemon/back/female/398.png and b/public/images/pokemon/back/female/398.png differ diff --git a/public/images/pokemon/back/female/403.png b/public/images/pokemon/back/female/403.png index 68ed4a12507..b730b32f6ee 100644 Binary files a/public/images/pokemon/back/female/403.png and b/public/images/pokemon/back/female/403.png differ diff --git a/public/images/pokemon/back/female/404.png b/public/images/pokemon/back/female/404.png index d6fdef26c83..27602ee0439 100644 Binary files a/public/images/pokemon/back/female/404.png and b/public/images/pokemon/back/female/404.png differ diff --git a/public/images/pokemon/back/female/405.png b/public/images/pokemon/back/female/405.png index 21d28b1fede..1aa669e1fbd 100644 Binary files a/public/images/pokemon/back/female/405.png and b/public/images/pokemon/back/female/405.png differ diff --git a/public/images/pokemon/back/shiny/782.json b/public/images/pokemon/back/shiny/782.json index 326e8fa09de..ed58485e3bd 100644 --- a/public/images/pokemon/back/shiny/782.json +++ b/public/images/pokemon/back/shiny/782.json @@ -1,41 +1,1010 @@ -{ - "textures": [ - { - "image": "782.png", - "format": "RGBA8888", - "size": { - "w": 50, - "h": 50 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 46, - "h": 50 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 46, - "h": 50 - }, - "frame": { - "x": 0, - "y": 0, - "w": 46, - "h": 50 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:ab84568c98e2c8417dfbab0b26bf5b7a:bf5226700592a08e6818638b6aca1b1a:d07862436676aa228a148ee1f1d82a8f$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0002.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0003.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0004.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0005.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0006.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0007.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0008.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0009.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0010.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0011.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0012.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0013.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0014.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0015.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0016.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0017.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0018.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0019.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0020.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0021.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0022.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0023.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0024.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0025.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0026.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0027.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0028.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0029.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0030.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0031.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0032.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0033.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0034.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0035.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0036.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0037.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0038.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0039.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0040.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0041.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0042.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0043.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0044.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0045.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0046.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0047.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0048.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0049.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0050.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0051.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0052.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0053.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0054.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0055.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0056.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0057.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0058.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0059.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0060.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0061.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0062.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0063.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0064.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0065.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0066.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0067.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0068.png", + "frame": { "x": 93, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0069.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0070.png", + "frame": { "x": 139, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0071.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0072.png", + "frame": { "x": 183, "y": 155, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0073.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0074.png", + "frame": { "x": 137, "y": 155, "w": 46, "h": 48 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0075.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0076.png", + "frame": { "x": 1, "y": 157, "w": 45, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0077.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0078.png", + "frame": { "x": 47, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0079.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0080.png", + "frame": { "x": 92, "y": 155, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0081.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0082.png", + "frame": { "x": 47, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0083.png", + "frame": { "x": 189, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0084.png", + "frame": { "x": 189, "y": 52, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0085.png", + "frame": { "x": 1, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0086.png", + "frame": { "x": 48, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0087.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0088.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0089.png", + "frame": { "x": 1, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0090.png", + "frame": { "x": 47, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0091.png", + "frame": { "x": 93, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0092.png", + "frame": { "x": 139, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0093.png", + "frame": { "x": 142, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0094.png", + "frame": { "x": 142, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0095.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0096.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0097.png", + "frame": { "x": 185, "y": 103, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0098.png", + "frame": { "x": 185, "y": 103, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0099.png", + "frame": { "x": 139, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0100.png", + "frame": { "x": 139, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0101.png", + "frame": { "x": 142, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0102.png", + "frame": { "x": 142, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0103.png", + "frame": { "x": 142, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0104.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0105.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0106.png", + "frame": { "x": 185, "y": 103, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0107.png", + "frame": { "x": 185, "y": 103, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0108.png", + "frame": { "x": 93, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0109.png", + "frame": { "x": 1, "y": 105, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0110.png", + "frame": { "x": 189, "y": 52, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0111.png", + "frame": { "x": 189, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "782.png", + "format": "I8", + "size": { "w": 237, "h": 207 }, + "scale": "1" + } } diff --git a/public/images/pokemon/back/shiny/782.png b/public/images/pokemon/back/shiny/782.png index a775abe8bf4..e5bed3d1642 100644 Binary files a/public/images/pokemon/back/shiny/782.png and b/public/images/pokemon/back/shiny/782.png differ diff --git a/public/images/pokemon/back/shiny/783.json b/public/images/pokemon/back/shiny/783.json index 253da2ab9a8..17ec3df99a0 100644 --- a/public/images/pokemon/back/shiny/783.json +++ b/public/images/pokemon/back/shiny/783.json @@ -1,41 +1,965 @@ -{ - "textures": [ - { - "image": "783.png", - "format": "RGBA8888", - "size": { - "w": 69, - "h": 69 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 66, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 66, - "h": 69 - }, - "frame": { - "x": 0, - "y": 0, - "w": 66, - "h": 69 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:e5544237a4fd9ef3e516be84f3a24a8a:dd780189298088c8e8eb741377c46b07:aab166e28c744865a0296041224dd01b$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 414, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0002.png", + "frame": { "x": 268, "y": 276, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0003.png", + "frame": { "x": 480, "y": 273, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0004.png", + "frame": { "x": 1, "y": 342, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0005.png", + "frame": { "x": 262, "y": 345, "w": 62, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 0, "w": 62, "h": 71 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0006.png", + "frame": { "x": 65, "y": 344, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0007.png", + "frame": { "x": 342, "y": 275, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0008.png", + "frame": { "x": 132, "y": 278, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0009.png", + "frame": { "x": 1, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0010.png", + "frame": { "x": 197, "y": 342, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0011.png", + "frame": { "x": 324, "y": 345, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0012.png", + "frame": { "x": 1, "y": 412, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0013.png", + "frame": { "x": 511, "y": 412, "w": 61, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 61, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0014.png", + "frame": { "x": 449, "y": 412, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0015.png", + "frame": { "x": 128, "y": 347, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0016.png", + "frame": { "x": 407, "y": 342, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0017.png", + "frame": { "x": 414, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0018.png", + "frame": { "x": 268, "y": 276, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0019.png", + "frame": { "x": 480, "y": 273, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0020.png", + "frame": { "x": 1, "y": 342, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0021.png", + "frame": { "x": 262, "y": 345, "w": 62, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 0, "w": 62, "h": 71 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0022.png", + "frame": { "x": 65, "y": 344, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0023.png", + "frame": { "x": 342, "y": 275, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0024.png", + "frame": { "x": 132, "y": 278, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0025.png", + "frame": { "x": 1, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0026.png", + "frame": { "x": 197, "y": 342, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0027.png", + "frame": { "x": 324, "y": 345, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0028.png", + "frame": { "x": 1, "y": 412, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0029.png", + "frame": { "x": 511, "y": 412, "w": 61, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 61, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0030.png", + "frame": { "x": 449, "y": 412, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0031.png", + "frame": { "x": 128, "y": 347, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0032.png", + "frame": { "x": 407, "y": 342, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0033.png", + "frame": { "x": 414, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0034.png", + "frame": { "x": 268, "y": 276, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0035.png", + "frame": { "x": 480, "y": 273, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0036.png", + "frame": { "x": 1, "y": 342, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0037.png", + "frame": { "x": 262, "y": 345, "w": 62, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 0, "w": 62, "h": 71 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0038.png", + "frame": { "x": 65, "y": 344, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0039.png", + "frame": { "x": 342, "y": 275, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0040.png", + "frame": { "x": 132, "y": 278, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0041.png", + "frame": { "x": 1, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0042.png", + "frame": { "x": 197, "y": 342, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0043.png", + "frame": { "x": 324, "y": 345, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0044.png", + "frame": { "x": 1, "y": 412, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0045.png", + "frame": { "x": 511, "y": 412, "w": 61, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 61, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0046.png", + "frame": { "x": 449, "y": 412, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0047.png", + "frame": { "x": 128, "y": 347, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0048.png", + "frame": { "x": 407, "y": 342, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0049.png", + "frame": { "x": 414, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0050.png", + "frame": { "x": 268, "y": 276, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0051.png", + "frame": { "x": 480, "y": 273, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0052.png", + "frame": { "x": 1, "y": 342, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0053.png", + "frame": { "x": 262, "y": 345, "w": 62, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 0, "w": 62, "h": 71 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0054.png", + "frame": { "x": 65, "y": 344, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0055.png", + "frame": { "x": 342, "y": 275, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0056.png", + "frame": { "x": 132, "y": 278, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0057.png", + "frame": { "x": 1, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0058.png", + "frame": { "x": 197, "y": 342, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0059.png", + "frame": { "x": 324, "y": 345, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0060.png", + "frame": { "x": 1, "y": 412, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0061.png", + "frame": { "x": 511, "y": 412, "w": 61, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 61, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0062.png", + "frame": { "x": 449, "y": 412, "w": 62, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 62, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0063.png", + "frame": { "x": 128, "y": 347, "w": 64, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 64, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0064.png", + "frame": { "x": 407, "y": 342, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0065.png", + "frame": { "x": 414, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0066.png", + "frame": { "x": 202, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0067.png", + "frame": { "x": 136, "y": 208, "w": 66, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 1, "w": 66, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0068.png", + "frame": { "x": 67, "y": 274, "w": 65, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 1, "w": 65, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0069.png", + "frame": { "x": 139, "y": 138, "w": 67, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 67, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0070.png", + "frame": { "x": 290, "y": 1, "w": 69, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 1, "w": 69, "h": 70 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0071.png", + "frame": { "x": 147, "y": 1, "w": 71, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 71, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0072.png", + "frame": { "x": 483, "y": 206, "w": 69, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 4, "w": 69, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0073.png", + "frame": { "x": 141, "y": 70, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0074.png", + "frame": { "x": 499, "y": 1, "w": 69, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 69, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0075.png", + "frame": { "x": 356, "y": 137, "w": 68, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 68, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0076.png", + "frame": { "x": 414, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0077.png", + "frame": { "x": 424, "y": 138, "w": 68, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 68, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0078.png", + "frame": { "x": 430, "y": 1, "w": 69, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 69, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0079.png", + "frame": { "x": 498, "y": 70, "w": 69, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 69, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0080.png", + "frame": { "x": 206, "y": 206, "w": 69, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 69, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0081.png", + "frame": { "x": 414, "y": 206, "w": 69, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 69, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0082.png", + "frame": { "x": 192, "y": 410, "w": 63, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 2, "w": 63, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0083.png", + "frame": { "x": 324, "y": 413, "w": 59, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 59, "h": 67 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0084.png", + "frame": { "x": 63, "y": 414, "w": 58, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 3, "w": 58, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0085.png", + "frame": { "x": 388, "y": 410, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0086.png", + "frame": { "x": 472, "y": 343, "w": 64, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 64, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0087.png", + "frame": { "x": 414, "y": 273, "w": 66, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 66, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0088.png", + "frame": { "x": 288, "y": 71, "w": 68, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 68, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0089.png", + "frame": { "x": 218, "y": 1, "w": 72, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 72, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0090.png", + "frame": { "x": 1, "y": 137, "w": 69, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 69, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0091.png", + "frame": { "x": 359, "y": 69, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0092.png", + "frame": { "x": 218, "y": 69, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0093.png", + "frame": { "x": 74, "y": 1, "w": 73, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 73, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0094.png", + "frame": { "x": 70, "y": 137, "w": 69, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 69, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0095.png", + "frame": { "x": 71, "y": 69, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0096.png", + "frame": { "x": 1, "y": 69, "w": 70, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 70, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0097.png", + "frame": { "x": 1, "y": 1, "w": 73, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 73, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0098.png", + "frame": { "x": 279, "y": 140, "w": 68, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 3, "w": 68, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0099.png", + "frame": { "x": 492, "y": 138, "w": 68, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 68, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0100.png", + "frame": { "x": 429, "y": 70, "w": 69, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 69, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0101.png", + "frame": { "x": 359, "y": 1, "w": 71, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 71, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0102.png", + "frame": { "x": 1, "y": 205, "w": 68, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 68, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0103.png", + "frame": { "x": 275, "y": 208, "w": 67, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 67, "h": 68 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0104.png", + "frame": { "x": 211, "y": 137, "w": 68, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 68, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0105.png", + "frame": { "x": 69, "y": 205, "w": 67, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 67, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + }, + { + "filename": "0106.png", + "frame": { "x": 347, "y": 206, "w": 67, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 67, "h": 69 }, + "sourceSize": { "w": 75, "h": 71 }, + "duration": 100 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "783.png", + "format": "I8", + "size": { "w": 573, "h": 483 }, + "scale": "1" + } } diff --git a/public/images/pokemon/back/shiny/783.png b/public/images/pokemon/back/shiny/783.png index 6ba2506ecc8..30d6c49f5e0 100644 Binary files a/public/images/pokemon/back/shiny/783.png and b/public/images/pokemon/back/shiny/783.png differ diff --git a/public/images/pokemon/back/shiny/784.json b/public/images/pokemon/back/shiny/784.json index 552fb3c9595..87ddecc06fb 100644 --- a/public/images/pokemon/back/shiny/784.json +++ b/public/images/pokemon/back/shiny/784.json @@ -1,41 +1,812 @@ -{ - "textures": [ - { - "image": "784.png", - "format": "RGBA8888", - "size": { - "w": 92, - "h": 92 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 92, - "h": 81 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 92, - "h": 81 - }, - "frame": { - "x": 0, - "y": 0, - "w": 92, - "h": 81 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:3e83e25b8e7e32a8993a48c7e36af553:6ed75435976e4481fad74457807089c7:c2f7ca3ab1075b8c824730653d891244$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 183, "y": 233, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0002.png", + "frame": { "x": 1, "y": 160, "w": 94, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 94, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0003.png", + "frame": { "x": 530, "y": 81, "w": 98, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 98, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0004.png", + "frame": { "x": 530, "y": 1, "w": 103, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 103, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0005.png", + "frame": { "x": 324, "y": 1, "w": 106, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 106, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0006.png", + "frame": { "x": 1, "y": 1, "w": 110, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 6, "w": 110, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0007.png", + "frame": { "x": 214, "y": 1, "w": 110, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 7, "w": 110, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0008.png", + "frame": { "x": 633, "y": 1, "w": 106, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 8, "w": 106, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0009.png", + "frame": { "x": 198, "y": 156, "w": 102, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 8, "w": 102, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0010.png", + "frame": { "x": 300, "y": 159, "w": 97, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 97, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0011.png", + "frame": { "x": 95, "y": 166, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0012.png", + "frame": { "x": 358, "y": 241, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0013.png", + "frame": { "x": 681, "y": 318, "w": 81, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 6, "w": 81, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0014.png", + "frame": { "x": 87, "y": 249, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0015.png", + "frame": { "x": 441, "y": 242, "w": 84, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 84, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0016.png", + "frame": { "x": 273, "y": 239, "w": 85, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 18, "y": 4, "w": 85, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0017.png", + "frame": { "x": 183, "y": 233, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0018.png", + "frame": { "x": 1, "y": 160, "w": 94, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 94, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0019.png", + "frame": { "x": 530, "y": 81, "w": 98, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 98, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0020.png", + "frame": { "x": 530, "y": 1, "w": 103, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 103, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0021.png", + "frame": { "x": 324, "y": 1, "w": 106, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 106, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0022.png", + "frame": { "x": 1, "y": 1, "w": 110, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 6, "w": 110, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0023.png", + "frame": { "x": 214, "y": 1, "w": 110, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 7, "w": 110, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0024.png", + "frame": { "x": 633, "y": 1, "w": 106, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 8, "w": 106, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0025.png", + "frame": { "x": 198, "y": 156, "w": 102, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 8, "w": 102, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0026.png", + "frame": { "x": 300, "y": 159, "w": 97, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 97, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0027.png", + "frame": { "x": 95, "y": 166, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0028.png", + "frame": { "x": 358, "y": 241, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0029.png", + "frame": { "x": 681, "y": 318, "w": 81, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 6, "w": 81, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0030.png", + "frame": { "x": 87, "y": 249, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0031.png", + "frame": { "x": 441, "y": 242, "w": 84, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 84, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0032.png", + "frame": { "x": 273, "y": 239, "w": 85, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 18, "y": 4, "w": 85, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0033.png", + "frame": { "x": 183, "y": 233, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0034.png", + "frame": { "x": 1, "y": 160, "w": 94, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 94, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0035.png", + "frame": { "x": 530, "y": 81, "w": 98, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 98, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0036.png", + "frame": { "x": 530, "y": 1, "w": 103, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 103, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0037.png", + "frame": { "x": 324, "y": 1, "w": 106, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 106, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0038.png", + "frame": { "x": 1, "y": 1, "w": 110, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 6, "w": 110, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0039.png", + "frame": { "x": 214, "y": 1, "w": 110, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 7, "w": 110, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0040.png", + "frame": { "x": 633, "y": 1, "w": 106, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 8, "w": 106, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0041.png", + "frame": { "x": 198, "y": 156, "w": 102, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 8, "w": 102, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0042.png", + "frame": { "x": 300, "y": 159, "w": 97, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 97, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0043.png", + "frame": { "x": 95, "y": 166, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0044.png", + "frame": { "x": 358, "y": 241, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0045.png", + "frame": { "x": 681, "y": 318, "w": 81, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 6, "w": 81, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0046.png", + "frame": { "x": 87, "y": 249, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0047.png", + "frame": { "x": 441, "y": 242, "w": 84, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 84, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0048.png", + "frame": { "x": 273, "y": 239, "w": 85, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 18, "y": 4, "w": 85, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0049.png", + "frame": { "x": 183, "y": 233, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0050.png", + "frame": { "x": 1, "y": 160, "w": 94, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 94, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0051.png", + "frame": { "x": 530, "y": 81, "w": 98, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 98, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0052.png", + "frame": { "x": 530, "y": 1, "w": 103, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 103, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0053.png", + "frame": { "x": 324, "y": 1, "w": 106, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 106, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0054.png", + "frame": { "x": 1, "y": 1, "w": 110, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 6, "w": 110, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0055.png", + "frame": { "x": 214, "y": 1, "w": 110, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 7, "w": 110, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0056.png", + "frame": { "x": 633, "y": 1, "w": 106, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 8, "w": 106, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0057.png", + "frame": { "x": 198, "y": 156, "w": 102, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 8, "w": 102, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0058.png", + "frame": { "x": 300, "y": 159, "w": 97, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 97, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0059.png", + "frame": { "x": 95, "y": 166, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0060.png", + "frame": { "x": 358, "y": 241, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 25, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0061.png", + "frame": { "x": 681, "y": 318, "w": 81, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 6, "w": 81, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0062.png", + "frame": { "x": 87, "y": 249, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0063.png", + "frame": { "x": 441, "y": 242, "w": 84, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 84, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0064.png", + "frame": { "x": 273, "y": 239, "w": 85, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 18, "y": 4, "w": 85, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0065.png", + "frame": { "x": 397, "y": 160, "w": 93, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 93, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0066.png", + "frame": { "x": 101, "y": 85, "w": 97, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 4, "w": 97, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0067.png", + "frame": { "x": 1, "y": 80, "w": 100, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 5, "w": 100, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0068.png", + "frame": { "x": 633, "y": 78, "w": 102, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 6, "w": 102, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0069.png", + "frame": { "x": 214, "y": 79, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0070.png", + "frame": { "x": 420, "y": 84, "w": 104, "h": 76 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 9, "w": 104, "h": 76 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0071.png", + "frame": { "x": 318, "y": 81, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0072.png", + "frame": { "x": 628, "y": 157, "w": 96, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 4, "w": 96, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0073.png", + "frame": { "x": 430, "y": 1, "w": 100, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 100, "h": 83 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0074.png", + "frame": { "x": 111, "y": 1, "w": 103, "h": 84 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 103, "h": 84 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0075.png", + "frame": { "x": 490, "y": 162, "w": 92, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 13, "y": 5, "w": 92, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0076.png", + "frame": { "x": 327, "y": 322, "w": 75, "h": 85 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 33, "y": 0, "w": 75, "h": 85 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0077.png", + "frame": { "x": 476, "y": 400, "w": 72, "h": 74 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 36, "y": 12, "w": 72, "h": 74 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0078.png", + "frame": { "x": 153, "y": 394, "w": 72, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 36, "y": 5, "w": 72, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0079.png", + "frame": { "x": 681, "y": 397, "w": 72, "h": 75 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 36, "y": 10, "w": 72, "h": 75 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0080.png", + "frame": { "x": 80, "y": 329, "w": 73, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 35, "y": 5, "w": 73, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0081.png", + "frame": { "x": 402, "y": 322, "w": 74, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 34, "y": 3, "w": 74, "h": 82 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0082.png", + "frame": { "x": 251, "y": 320, "w": 76, "h": 84 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 31, "y": 1, "w": 76, "h": 84 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0083.png", + "frame": { "x": 604, "y": 318, "w": 77, "h": 84 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 29, "y": 1, "w": 77, "h": 84 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0084.png", + "frame": { "x": 525, "y": 318, "w": 79, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 3, "w": 79, "h": 82 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0085.png", + "frame": { "x": 1, "y": 320, "w": 79, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 24, "y": 4, "w": 79, "h": 81 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0086.png", + "frame": { "x": 169, "y": 314, "w": 82, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 21, "y": 5, "w": 82, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0087.png", + "frame": { "x": 1, "y": 241, "w": 86, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 17, "y": 6, "w": 86, "h": 79 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0088.png", + "frame": { "x": 672, "y": 238, "w": 87, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 15, "y": 5, "w": 87, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + }, + { + "filename": "0089.png", + "frame": { "x": 582, "y": 238, "w": 90, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 12, "y": 5, "w": 90, "h": 80 }, + "sourceSize": { "w": 112, "h": 86 }, + "duration": 100 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "784.png", + "format": "I8", + "size": { "w": 763, "h": 475 }, + "scale": "1" + } } diff --git a/public/images/pokemon/back/shiny/784.png b/public/images/pokemon/back/shiny/784.png index c32690792ac..51a3962a6ea 100644 Binary files a/public/images/pokemon/back/shiny/784.png and b/public/images/pokemon/back/shiny/784.png differ diff --git a/public/images/pokemon/exp/2038.png b/public/images/pokemon/exp/2038.png index c6fdb999df3..f6295093fcc 100644 Binary files a/public/images/pokemon/exp/2038.png and b/public/images/pokemon/exp/2038.png differ diff --git a/public/images/pokemon/exp/692.png b/public/images/pokemon/exp/692.png index 1e42cbf47fa..a22655931a8 100644 Binary files a/public/images/pokemon/exp/692.png and b/public/images/pokemon/exp/692.png differ diff --git a/public/images/pokemon/exp/780.png b/public/images/pokemon/exp/780.png index 3453365f154..69a13eb3bf6 100644 Binary files a/public/images/pokemon/exp/780.png and b/public/images/pokemon/exp/780.png differ diff --git a/public/images/pokemon/exp/782.json b/public/images/pokemon/exp/782.json deleted file mode 100644 index ea51775cf3e..00000000000 --- a/public/images/pokemon/exp/782.json +++ /dev/null @@ -1,2351 +0,0 @@ -{ - "textures": [ - { - "image": "782.png", - "format": "RGBA8888", - "size": { - "w": 240, - "h": 240 - }, - "scale": 1, - "frames": [ - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0111.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0110.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0089.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 97, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0090.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 50, - "w": 48, - "h": 52 - } - }, - { - "filename": "0091.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 145, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0108.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 145, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0087.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0088.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0095.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0096.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0104.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0105.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0092.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 102, - "w": 48, - "h": 52 - } - }, - { - "filename": "0099.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 102, - "w": 48, - "h": 52 - } - }, - { - "filename": "0100.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 102, - "w": 48, - "h": 52 - } - }, - { - "filename": "0093.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0094.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0101.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0102.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0103.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0097.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0098.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0106.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0107.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0109.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:9772e042208152c03f4677b5a37d739c:828b3c5d233c21ed5ab3c368a1cf1988:d07862436676aa228a148ee1f1d82a8f$" - } -} diff --git a/public/images/pokemon/exp/782.png b/public/images/pokemon/exp/782.png deleted file mode 100644 index 9ca666d0a74..00000000000 Binary files a/public/images/pokemon/exp/782.png and /dev/null differ diff --git a/public/images/pokemon/exp/783.json b/public/images/pokemon/exp/783.json deleted file mode 100644 index 71aeb29890a..00000000000 --- a/public/images/pokemon/exp/783.json +++ /dev/null @@ -1,1154 +0,0 @@ -{ - "textures": [ - { - "image": "783.png", - "format": "RGBA8888", - "size": { - "w": 335, - "h": 335 - }, - "scale": 1, - "frames": [ - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 74, - "h": 67 - }, - "frame": { - "x": 0, - "y": 0, - "w": 74, - "h": 67 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 74, - "h": 67 - }, - "frame": { - "x": 0, - "y": 0, - "w": 74, - "h": 67 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 74, - "h": 67 - }, - "frame": { - "x": 0, - "y": 0, - "w": 74, - "h": 67 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 74, - "h": 67 - }, - "frame": { - "x": 0, - "y": 0, - "w": 74, - "h": 67 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 71, - "h": 68 - }, - "frame": { - "x": 0, - "y": 67, - "w": 71, - "h": 68 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 71, - "h": 68 - }, - "frame": { - "x": 0, - "y": 67, - "w": 71, - "h": 68 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 71, - "h": 68 - }, - "frame": { - "x": 0, - "y": 67, - "w": 71, - "h": 68 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 71, - "h": 68 - }, - "frame": { - "x": 0, - "y": 135, - "w": 71, - "h": 68 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 67, - "h": 69 - }, - "frame": { - "x": 0, - "y": 203, - "w": 67, - "h": 69 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 67, - "h": 69 - }, - "frame": { - "x": 0, - "y": 203, - "w": 67, - "h": 69 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 67, - "h": 69 - }, - "frame": { - "x": 0, - "y": 203, - "w": 67, - "h": 69 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 70, - "h": 66 - }, - "frame": { - "x": 74, - "y": 0, - "w": 70, - "h": 66 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 70, - "h": 66 - }, - "frame": { - "x": 144, - "y": 0, - "w": 70, - "h": 66 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 70, - "h": 66 - }, - "frame": { - "x": 214, - "y": 0, - "w": 70, - "h": 66 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 67, - "y": 203, - "w": 62, - "h": 69 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 67, - "y": 203, - "w": 62, - "h": 69 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 67, - "y": 203, - "w": 62, - "h": 69 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 67, - "y": 203, - "w": 62, - "h": 69 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 64, - "h": 69 - }, - "frame": { - "x": 71, - "y": 67, - "w": 64, - "h": 69 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 64, - "h": 69 - }, - "frame": { - "x": 71, - "y": 67, - "w": 64, - "h": 69 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 64, - "h": 69 - }, - "frame": { - "x": 71, - "y": 67, - "w": 64, - "h": 69 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 64, - "h": 69 - }, - "frame": { - "x": 71, - "y": 67, - "w": 64, - "h": 69 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 64, - "h": 67 - }, - "frame": { - "x": 71, - "y": 136, - "w": 64, - "h": 67 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 64, - "h": 67 - }, - "frame": { - "x": 71, - "y": 136, - "w": 64, - "h": 67 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 64, - "h": 67 - }, - "frame": { - "x": 71, - "y": 136, - "w": 64, - "h": 67 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 64, - "h": 67 - }, - "frame": { - "x": 71, - "y": 136, - "w": 64, - "h": 67 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 67, - "h": 69 - }, - "frame": { - "x": 135, - "y": 66, - "w": 67, - "h": 69 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 70, - "h": 66 - }, - "frame": { - "x": 202, - "y": 66, - "w": 70, - "h": 66 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 69, - "h": 66 - }, - "frame": { - "x": 135, - "y": 135, - "w": 69, - "h": 66 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 69, - "h": 66 - }, - "frame": { - "x": 135, - "y": 135, - "w": 69, - "h": 66 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 69, - "h": 66 - }, - "frame": { - "x": 135, - "y": 135, - "w": 69, - "h": 66 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 69, - "h": 66 - }, - "frame": { - "x": 135, - "y": 135, - "w": 69, - "h": 66 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 69, - "h": 66 - }, - "frame": { - "x": 135, - "y": 135, - "w": 69, - "h": 66 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 69, - "h": 66 - }, - "frame": { - "x": 204, - "y": 132, - "w": 69, - "h": 66 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 273, - "y": 66, - "w": 62, - "h": 69 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 273, - "y": 66, - "w": 62, - "h": 69 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 273, - "y": 66, - "w": 62, - "h": 69 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 273, - "y": 66, - "w": 62, - "h": 69 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 273, - "y": 135, - "w": 62, - "h": 69 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 273, - "y": 135, - "w": 62, - "h": 69 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 273, - "y": 135, - "w": 62, - "h": 69 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 62, - "h": 69 - }, - "frame": { - "x": 273, - "y": 135, - "w": 62, - "h": 69 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 69, - "h": 66 - }, - "frame": { - "x": 204, - "y": 198, - "w": 69, - "h": 66 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 69, - "h": 66 - }, - "frame": { - "x": 135, - "y": 201, - "w": 69, - "h": 66 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 69, - "h": 66 - }, - "frame": { - "x": 135, - "y": 201, - "w": 69, - "h": 66 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 61, - "h": 68 - }, - "frame": { - "x": 273, - "y": 204, - "w": 61, - "h": 68 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 61, - "h": 68 - }, - "frame": { - "x": 273, - "y": 204, - "w": 61, - "h": 68 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 61, - "h": 68 - }, - "frame": { - "x": 273, - "y": 204, - "w": 61, - "h": 68 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 61, - "h": 68 - }, - "frame": { - "x": 273, - "y": 204, - "w": 61, - "h": 68 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 70, - "h": 66 - }, - "frame": { - "x": 129, - "y": 267, - "w": 70, - "h": 66 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 64, - "h": 67 - }, - "frame": { - "x": 199, - "y": 267, - "w": 64, - "h": 67 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 64, - "h": 67 - }, - "frame": { - "x": 199, - "y": 267, - "w": 64, - "h": 67 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 64, - "h": 67 - }, - "frame": { - "x": 199, - "y": 267, - "w": 64, - "h": 67 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 74, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 64, - "h": 67 - }, - "frame": { - "x": 199, - "y": 267, - "w": 64, - "h": 67 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:f33a08a20212ca30a4c442095b0effc2:91a27eccd7f819b29aa8e5f9bc790c41:aab166e28c744865a0296041224dd01b$" - } -} diff --git a/public/images/pokemon/exp/783.png b/public/images/pokemon/exp/783.png deleted file mode 100644 index 58372a977c6..00000000000 Binary files a/public/images/pokemon/exp/783.png and /dev/null differ diff --git a/public/images/pokemon/exp/784.json b/public/images/pokemon/exp/784.json deleted file mode 100644 index 4200616ecef..00000000000 --- a/public/images/pokemon/exp/784.json +++ /dev/null @@ -1,1826 +0,0 @@ -{ - "textures": [ - { - "image": "784.png", - "format": "RGBA8888", - "size": { - "w": 461, - "h": 461 - }, - "scale": 1, - "frames": [ - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 176, - "w": 96, - "h": 88 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 176, - "w": 96, - "h": 88 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 176, - "w": 96, - "h": 88 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 176, - "w": 96, - "h": 88 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 353, - "w": 92, - "h": 89 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 92, - "h": 89 - }, - "frame": { - "x": 92, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 192, - "y": 88, - "w": 89, - "h": 89 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 192, - "y": 88, - "w": 89, - "h": 89 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 192, - "y": 88, - "w": 89, - "h": 89 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 192, - "y": 88, - "w": 89, - "h": 89 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 286, - "y": 0, - "w": 89, - "h": 89 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 286, - "y": 0, - "w": 89, - "h": 89 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 286, - "y": 0, - "w": 89, - "h": 89 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 286, - "y": 0, - "w": 89, - "h": 89 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 86, - "h": 87 - }, - "frame": { - "x": 375, - "y": 0, - "w": 86, - "h": 87 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 86, - "h": 87 - }, - "frame": { - "x": 375, - "y": 87, - "w": 86, - "h": 87 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 188, - "y": 177, - "w": 89, - "h": 89 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 281, - "y": 89, - "w": 89, - "h": 89 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 277, - "y": 178, - "w": 88, - "h": 89 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 277, - "y": 178, - "w": 88, - "h": 89 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 277, - "y": 178, - "w": 88, - "h": 89 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 277, - "y": 178, - "w": 88, - "h": 89 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 184, - "y": 266, - "w": 88, - "h": 89 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 184, - "y": 266, - "w": 88, - "h": 89 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 184, - "y": 266, - "w": 88, - "h": 89 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 184, - "y": 266, - "w": 88, - "h": 89 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 182, - "y": 355, - "w": 88, - "h": 89 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 182, - "y": 355, - "w": 88, - "h": 89 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 182, - "y": 355, - "w": 88, - "h": 89 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 182, - "y": 355, - "w": 88, - "h": 89 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 87, - "h": 89 - }, - "frame": { - "x": 272, - "y": 267, - "w": 87, - "h": 89 - } - }, - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 87, - "h": 89 - }, - "frame": { - "x": 270, - "y": 356, - "w": 87, - "h": 89 - } - }, - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 87, - "h": 87 - }, - "frame": { - "x": 359, - "y": 267, - "w": 87, - "h": 87 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 87, - "h": 87 - }, - "frame": { - "x": 365, - "y": 178, - "w": 87, - "h": 87 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 87, - "h": 87 - }, - "frame": { - "x": 357, - "y": 356, - "w": 87, - "h": 87 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 87, - "h": 87 - }, - "frame": { - "x": 357, - "y": 356, - "w": 87, - "h": 87 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:fd28dfd35a375d4d0d568c72bbbe079f:b186d9a5868eaf1d0a3bd9bcddd90d79:c2f7ca3ab1075b8c824730653d891244$" - } -} diff --git a/public/images/pokemon/exp/784.png b/public/images/pokemon/exp/784.png deleted file mode 100644 index e3e384d4699..00000000000 Binary files a/public/images/pokemon/exp/784.png and /dev/null differ diff --git a/public/images/pokemon/exp/840.png b/public/images/pokemon/exp/840.png index 3e76cd5fff8..86b701fa0d7 100644 Binary files a/public/images/pokemon/exp/840.png and b/public/images/pokemon/exp/840.png differ diff --git a/public/images/pokemon/exp/841.png b/public/images/pokemon/exp/841.png index 2bf0ad3b138..564ffaa0f27 100644 Binary files a/public/images/pokemon/exp/841.png and b/public/images/pokemon/exp/841.png differ diff --git a/public/images/pokemon/exp/842.png b/public/images/pokemon/exp/842.png index 85b9ae30fe0..41c2ebcf7d4 100644 Binary files a/public/images/pokemon/exp/842.png and b/public/images/pokemon/exp/842.png differ diff --git a/public/images/pokemon/exp/871.png b/public/images/pokemon/exp/871.png index d4ffceea07a..8f03d72f0b3 100644 Binary files a/public/images/pokemon/exp/871.png and b/public/images/pokemon/exp/871.png differ diff --git a/public/images/pokemon/exp/back/2038.png b/public/images/pokemon/exp/back/2038.png index 9ad8025933a..f4a022692a1 100644 Binary files a/public/images/pokemon/exp/back/2038.png and b/public/images/pokemon/exp/back/2038.png differ diff --git a/public/images/pokemon/exp/back/692.png b/public/images/pokemon/exp/back/692.png index e3eb957a624..33059d53c05 100644 Binary files a/public/images/pokemon/exp/back/692.png and b/public/images/pokemon/exp/back/692.png differ diff --git a/public/images/pokemon/exp/back/750.png b/public/images/pokemon/exp/back/750.png index 1c9391b5f7a..5ecd848832e 100644 Binary files a/public/images/pokemon/exp/back/750.png and b/public/images/pokemon/exp/back/750.png differ diff --git a/public/images/pokemon/exp/back/782.json b/public/images/pokemon/exp/back/782.json deleted file mode 100644 index aa9698c6554..00000000000 --- a/public/images/pokemon/exp/back/782.json +++ /dev/null @@ -1,2351 +0,0 @@ -{ - "textures": [ - { - "image": "782.png", - "format": "RGBA8888", - "size": { - "w": 239, - "h": 239 - }, - "scale": 1, - "frames": [ - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0111.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0110.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0087.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0088.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0095.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0096.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0104.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0105.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0089.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0090.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0091.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0108.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0092.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0099.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0100.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0093.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0094.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0101.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0102.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0103.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0097.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0098.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0106.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0107.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0109.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:48f53f968d06c5de2d5b76e15505b755:5d901e7ac581518a4fe6730bcf366c83:d07862436676aa228a148ee1f1d82a8f$" - } -} diff --git a/public/images/pokemon/exp/back/782.png b/public/images/pokemon/exp/back/782.png deleted file mode 100644 index 402ac12f53a..00000000000 Binary files a/public/images/pokemon/exp/back/782.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/783.json b/public/images/pokemon/exp/back/783.json deleted file mode 100644 index ea0bcf61b16..00000000000 --- a/public/images/pokemon/exp/back/783.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - "textures": [ - { - "image": "783.png", - "format": "RGBA8888", - "size": { - "w": 170, - "h": 170 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 60, - "h": 69 - }, - "frame": { - "x": 0, - "y": 0, - "w": 60, - "h": 69 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 59, - "h": 70 - }, - "frame": { - "x": 0, - "y": 69, - "w": 59, - "h": 70 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 59, - "h": 70 - }, - "frame": { - "x": 0, - "y": 69, - "w": 59, - "h": 70 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 57, - "h": 70 - }, - "frame": { - "x": 60, - "y": 0, - "w": 57, - "h": 70 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 57, - "h": 70 - }, - "frame": { - "x": 60, - "y": 0, - "w": 57, - "h": 70 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 53, - "h": 70 - }, - "frame": { - "x": 117, - "y": 0, - "w": 53, - "h": 70 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 70 - }, - "frame": { - "x": 59, - "y": 70, - "w": 55, - "h": 70 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 70 - }, - "frame": { - "x": 59, - "y": 70, - "w": 55, - "h": 70 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 70 - }, - "frame": { - "x": 114, - "y": 70, - "w": 55, - "h": 70 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 70 - }, - "frame": { - "x": 114, - "y": 70, - "w": 55, - "h": 70 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:20660c9e03072cd65380bda5628411e8:a05376d2ce003dccda577a6cc48e817b:aab166e28c744865a0296041224dd01b$" - } -} diff --git a/public/images/pokemon/exp/back/783.png b/public/images/pokemon/exp/back/783.png deleted file mode 100644 index ea3deeb1a40..00000000000 Binary files a/public/images/pokemon/exp/back/783.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/784.json b/public/images/pokemon/exp/back/784.json deleted file mode 100644 index 7ff49909f1a..00000000000 --- a/public/images/pokemon/exp/back/784.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - "textures": [ - { - "image": "784.png", - "format": "RGBA8888", - "size": { - "w": 240, - "h": 240 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 87, - "h": 81 - }, - "frame": { - "x": 0, - "y": 0, - "w": 87, - "h": 81 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 84, - "h": 81 - }, - "frame": { - "x": 87, - "y": 0, - "w": 84, - "h": 81 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 84, - "h": 81 - }, - "frame": { - "x": 87, - "y": 0, - "w": 84, - "h": 81 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 81, - "h": 81 - }, - "frame": { - "x": 0, - "y": 81, - "w": 81, - "h": 81 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 81, - "h": 81 - }, - "frame": { - "x": 0, - "y": 81, - "w": 81, - "h": 81 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 0, - "w": 78, - "h": 81 - }, - "frame": { - "x": 81, - "y": 81, - "w": 78, - "h": 81 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 0, - "w": 78, - "h": 81 - }, - "frame": { - "x": 81, - "y": 81, - "w": 78, - "h": 81 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 79, - "h": 79 - }, - "frame": { - "x": 159, - "y": 81, - "w": 79, - "h": 79 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 78, - "h": 80 - }, - "frame": { - "x": 159, - "y": 160, - "w": 78, - "h": 80 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 87, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 78, - "h": 80 - }, - "frame": { - "x": 159, - "y": 160, - "w": 78, - "h": 80 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:e1718793cec57b03b57147eb8c643dea:df6891980c354d7d34cd79ab41de7d58:c2f7ca3ab1075b8c824730653d891244$" - } -} diff --git a/public/images/pokemon/exp/back/784.png b/public/images/pokemon/exp/back/784.png deleted file mode 100644 index 54522e52998..00000000000 Binary files a/public/images/pokemon/exp/back/784.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/840.json b/public/images/pokemon/exp/back/840.json index 4e49422dab7..eb5a925c565 100644 --- a/public/images/pokemon/exp/back/840.json +++ b/public/images/pokemon/exp/back/840.json @@ -1,230 +1,1145 @@ -{ - "textures": [ - { - "image": "840.png", - "format": "RGBA8888", - "size": { - "w": 95, - "h": 95 - }, - "scale": 1, - "frames": [ - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - }, - "frame": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - }, - "frame": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - }, - "frame": { - "x": 0, - "y": 42, - "w": 32, - "h": 42 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - }, - "frame": { - "x": 0, - "y": 42, - "w": 32, - "h": 42 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 32, - "h": 41 - }, - "frame": { - "x": 32, - "y": 0, - "w": 32, - "h": 41 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 32, - "h": 41 - }, - "frame": { - "x": 32, - "y": 0, - "w": 32, - "h": 41 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 31, - "h": 42 - }, - "frame": { - "x": 64, - "y": 0, - "w": 31, - "h": 42 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 31, - "h": 42 - }, - "frame": { - "x": 32, - "y": 41, - "w": 31, - "h": 42 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 31, - "h": 41 - }, - "frame": { - "x": 63, - "y": 42, - "w": 31, - "h": 41 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 31, - "h": 41 - }, - "frame": { - "x": 63, - "y": 42, - "w": 31, - "h": 41 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:b5d6af055845f0bb50dedd55de251612:02858b561d730304d719627e15bc2130:c6a93eb4343acba47be6c18cd2c93ef1$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0002.png", + "frame": { "x": 136, "y": 90, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0003.png", + "frame": { "x": 171, "y": 91, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0004.png", + "frame": { "x": 37, "y": 44, "w": 34, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 34, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0005.png", + "frame": { "x": 79, "y": 2, "w": 35, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 35, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0006.png", + "frame": { "x": 41, "y": 2, "w": 36, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 36, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0007.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0008.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0009.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0010.png", + "frame": { "x": 116, "y": 2, "w": 34, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 34, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0011.png", + "frame": { "x": 35, "y": 131, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0012.png", + "frame": { "x": 136, "y": 132, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0013.png", + "frame": { "x": 171, "y": 133, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0014.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0015.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0016.png", + "frame": { "x": 152, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0017.png", + "frame": { "x": 108, "y": 45, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0018.png", + "frame": { "x": 176, "y": 46, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0019.png", + "frame": { "x": 37, "y": 86, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0020.png", + "frame": { "x": 70, "y": 87, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0021.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0022.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0023.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0024.png", + "frame": { "x": 70, "y": 132, "w": 30, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 30, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0025.png", + "frame": { "x": 103, "y": 89, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0026.png", + "frame": { "x": 142, "y": 46, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0027.png", + "frame": { "x": 187, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0028.png", + "frame": { "x": 2, "y": 44, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0029.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0030.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0031.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0032.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0033.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0034.png", + "frame": { "x": 136, "y": 90, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0035.png", + "frame": { "x": 171, "y": 91, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0036.png", + "frame": { "x": 37, "y": 44, "w": 34, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 34, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0037.png", + "frame": { "x": 79, "y": 2, "w": 35, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 35, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0038.png", + "frame": { "x": 41, "y": 2, "w": 36, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 36, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0039.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0040.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0041.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0042.png", + "frame": { "x": 116, "y": 2, "w": 34, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 34, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0043.png", + "frame": { "x": 35, "y": 131, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0044.png", + "frame": { "x": 136, "y": 132, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0045.png", + "frame": { "x": 171, "y": 133, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0046.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0047.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0048.png", + "frame": { "x": 152, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0049.png", + "frame": { "x": 108, "y": 45, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0050.png", + "frame": { "x": 176, "y": 46, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0051.png", + "frame": { "x": 37, "y": 86, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0052.png", + "frame": { "x": 70, "y": 87, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0053.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0054.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0055.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0056.png", + "frame": { "x": 70, "y": 132, "w": 30, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 30, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0057.png", + "frame": { "x": 103, "y": 89, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0058.png", + "frame": { "x": 142, "y": 46, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0059.png", + "frame": { "x": 187, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0060.png", + "frame": { "x": 2, "y": 44, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0061.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0062.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0063.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0064.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0065.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0066.png", + "frame": { "x": 136, "y": 90, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0067.png", + "frame": { "x": 171, "y": 91, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0068.png", + "frame": { "x": 37, "y": 44, "w": 34, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 34, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0069.png", + "frame": { "x": 79, "y": 2, "w": 35, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 35, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0070.png", + "frame": { "x": 41, "y": 2, "w": 36, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 36, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0071.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0072.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0073.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0074.png", + "frame": { "x": 116, "y": 2, "w": 34, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 34, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0075.png", + "frame": { "x": 35, "y": 131, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0076.png", + "frame": { "x": 136, "y": 132, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0077.png", + "frame": { "x": 171, "y": 133, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0078.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0079.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0080.png", + "frame": { "x": 152, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0081.png", + "frame": { "x": 108, "y": 45, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0082.png", + "frame": { "x": 176, "y": 46, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0083.png", + "frame": { "x": 37, "y": 86, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0084.png", + "frame": { "x": 70, "y": 87, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0085.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0086.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0087.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0088.png", + "frame": { "x": 70, "y": 132, "w": 30, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 30, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0089.png", + "frame": { "x": 103, "y": 89, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0090.png", + "frame": { "x": 142, "y": 46, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0091.png", + "frame": { "x": 187, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0092.png", + "frame": { "x": 2, "y": 44, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0093.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0094.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0095.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0096.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0097.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0098.png", + "frame": { "x": 2, "y": 173, "w": 33, "h": 39 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 33, "h": 39 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0099.png", + "frame": { "x": 2, "y": 133, "w": 30, "h": 34 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 9, "w": 30, "h": 34 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0100.png", + "frame": { "x": 102, "y": 134, "w": 28, "h": 30 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 12, "w": 28, "h": 30 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0101.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0102.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0103.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0104.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 15, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0105.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 13, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0106.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 12, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0107.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 11, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0108.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 11, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0109.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 12, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0110.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 14, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0111.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0112.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0113.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 15, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0114.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 13, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0115.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 12, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0116.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 11, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0117.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 11, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0118.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 12, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0119.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 14, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0120.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0121.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0122.png", + "frame": { "x": 102, "y": 134, "w": 28, "h": 30 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 12, "w": 28, "h": 30 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0123.png", + "frame": { "x": 2, "y": 133, "w": 30, "h": 34 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 9, "w": 30, "h": 34 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0124.png", + "frame": { "x": 2, "y": 173, "w": 33, "h": 39 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 33, "h": 39 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0125.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0126.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "840.png", + "format": "I8", + "size": { "w": 222, "h": 214 }, + "scale": "1" + } } diff --git a/public/images/pokemon/exp/back/840.png b/public/images/pokemon/exp/back/840.png index ac6aa240888..29336b622e3 100644 Binary files a/public/images/pokemon/exp/back/840.png and b/public/images/pokemon/exp/back/840.png differ diff --git a/public/images/pokemon/exp/back/841.png b/public/images/pokemon/exp/back/841.png index 9e6ec5effb1..ecf344211ef 100644 Binary files a/public/images/pokemon/exp/back/841.png and b/public/images/pokemon/exp/back/841.png differ diff --git a/public/images/pokemon/exp/back/842.png b/public/images/pokemon/exp/back/842.png index e38feeb0b42..9258c511d25 100644 Binary files a/public/images/pokemon/exp/back/842.png and b/public/images/pokemon/exp/back/842.png differ diff --git a/public/images/pokemon/exp/back/871.png b/public/images/pokemon/exp/back/871.png index faf12b7d4a2..e20040e8a6a 100644 Binary files a/public/images/pokemon/exp/back/871.png and b/public/images/pokemon/exp/back/871.png differ diff --git a/public/images/pokemon/exp/back/shiny/692.png b/public/images/pokemon/exp/back/shiny/692.png index c1bb353a739..baee2adcd4f 100644 Binary files a/public/images/pokemon/exp/back/shiny/692.png and b/public/images/pokemon/exp/back/shiny/692.png differ diff --git a/public/images/pokemon/exp/back/shiny/782.json b/public/images/pokemon/exp/back/shiny/782.json deleted file mode 100644 index facd127868f..00000000000 --- a/public/images/pokemon/exp/back/shiny/782.json +++ /dev/null @@ -1,2351 +0,0 @@ -{ - "textures": [ - { - "image": "782.png", - "format": "RGBA8888", - "size": { - "w": 239, - "h": 239 - }, - "scale": 1, - "frames": [ - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0111.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0110.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0087.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0088.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0095.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0096.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0104.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0105.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0089.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0090.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0091.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0108.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0092.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0099.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0100.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0093.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0094.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0101.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0102.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0103.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 0, - "w": 47, - "h": 51 - } - }, - { - "filename": "0097.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0098.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0106.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0107.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0109.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 192, - "y": 51, - "w": 47, - "h": 51 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 96, - "y": 156, - "w": 48, - "h": 51 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 144, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 102, - "w": 47, - "h": 50 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 47, - "h": 50 - }, - "frame": { - "x": 192, - "y": 152, - "w": 47, - "h": 50 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 47, - "h": 49 - }, - "frame": { - "x": 144, - "y": 154, - "w": 47, - "h": 49 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:037c9a33b267f5b73f2e7c10c87bf653:509435f895db2af666d45fff3ec043dc:d07862436676aa228a148ee1f1d82a8f$" - } -} diff --git a/public/images/pokemon/exp/back/shiny/782.png b/public/images/pokemon/exp/back/shiny/782.png deleted file mode 100644 index 9ecbcf1f035..00000000000 Binary files a/public/images/pokemon/exp/back/shiny/782.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/shiny/783.json b/public/images/pokemon/exp/back/shiny/783.json deleted file mode 100644 index c23c9116e10..00000000000 --- a/public/images/pokemon/exp/back/shiny/783.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - "textures": [ - { - "image": "783.png", - "format": "RGBA8888", - "size": { - "w": 170, - "h": 170 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 60, - "h": 69 - }, - "frame": { - "x": 0, - "y": 0, - "w": 60, - "h": 69 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 59, - "h": 70 - }, - "frame": { - "x": 0, - "y": 69, - "w": 59, - "h": 70 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 59, - "h": 70 - }, - "frame": { - "x": 0, - "y": 69, - "w": 59, - "h": 70 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 57, - "h": 70 - }, - "frame": { - "x": 60, - "y": 0, - "w": 57, - "h": 70 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 57, - "h": 70 - }, - "frame": { - "x": 60, - "y": 0, - "w": 57, - "h": 70 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 53, - "h": 70 - }, - "frame": { - "x": 117, - "y": 0, - "w": 53, - "h": 70 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 70 - }, - "frame": { - "x": 59, - "y": 70, - "w": 55, - "h": 70 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 70 - }, - "frame": { - "x": 59, - "y": 70, - "w": 55, - "h": 70 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 70 - }, - "frame": { - "x": 114, - "y": 70, - "w": 55, - "h": 70 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 60, - "h": 70 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 70 - }, - "frame": { - "x": 114, - "y": 70, - "w": 55, - "h": 70 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:ceb13eb26bf07b1a43fd9d23cef4895a:399ef100f2226bb28ca73ab82f617bd7:aab166e28c744865a0296041224dd01b$" - } -} diff --git a/public/images/pokemon/exp/back/shiny/783.png b/public/images/pokemon/exp/back/shiny/783.png deleted file mode 100644 index fd57a32b55e..00000000000 Binary files a/public/images/pokemon/exp/back/shiny/783.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/shiny/784.json b/public/images/pokemon/exp/back/shiny/784.json deleted file mode 100644 index 27f3d18b7d6..00000000000 --- a/public/images/pokemon/exp/back/shiny/784.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - "textures": [ - { - "image": "784.png", - "format": "RGBA8888", - "size": { - "w": 240, - "h": 240 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 81 - }, - "frame": { - "x": 0, - "y": 0, - "w": 86, - "h": 81 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 84, - "h": 81 - }, - "frame": { - "x": 86, - "y": 0, - "w": 84, - "h": 81 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 84, - "h": 81 - }, - "frame": { - "x": 86, - "y": 0, - "w": 84, - "h": 81 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 81, - "h": 81 - }, - "frame": { - "x": 0, - "y": 81, - "w": 81, - "h": 81 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 81, - "h": 81 - }, - "frame": { - "x": 0, - "y": 81, - "w": 81, - "h": 81 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 0, - "w": 78, - "h": 81 - }, - "frame": { - "x": 81, - "y": 81, - "w": 78, - "h": 81 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 0, - "w": 78, - "h": 81 - }, - "frame": { - "x": 81, - "y": 81, - "w": 78, - "h": 81 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 79, - "h": 79 - }, - "frame": { - "x": 159, - "y": 81, - "w": 79, - "h": 79 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 78, - "h": 80 - }, - "frame": { - "x": 159, - "y": 160, - "w": 78, - "h": 80 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 81 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 78, - "h": 80 - }, - "frame": { - "x": 159, - "y": 160, - "w": 78, - "h": 80 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:841ddb49f9601ed6f43373fcdfd97a55:abdfda19e619b7f57eb4c9c5d68cc9d9:c2f7ca3ab1075b8c824730653d891244$" - } -} diff --git a/public/images/pokemon/exp/back/shiny/784.png b/public/images/pokemon/exp/back/shiny/784.png deleted file mode 100644 index fdec2486c56..00000000000 Binary files a/public/images/pokemon/exp/back/shiny/784.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/shiny/840.json b/public/images/pokemon/exp/back/shiny/840.json index ccacb7508ff..eb5a925c565 100644 --- a/public/images/pokemon/exp/back/shiny/840.json +++ b/public/images/pokemon/exp/back/shiny/840.json @@ -1,230 +1,1145 @@ -{ - "textures": [ - { - "image": "840.png", - "format": "RGBA8888", - "size": { - "w": 95, - "h": 95 - }, - "scale": 1, - "frames": [ - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - }, - "frame": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - }, - "frame": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - }, - "frame": { - "x": 0, - "y": 42, - "w": 32, - "h": 42 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 32, - "h": 42 - }, - "frame": { - "x": 0, - "y": 42, - "w": 32, - "h": 42 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 32, - "h": 41 - }, - "frame": { - "x": 32, - "y": 0, - "w": 32, - "h": 41 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 32, - "h": 41 - }, - "frame": { - "x": 32, - "y": 0, - "w": 32, - "h": 41 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 31, - "h": 42 - }, - "frame": { - "x": 64, - "y": 0, - "w": 31, - "h": 42 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 31, - "h": 42 - }, - "frame": { - "x": 32, - "y": 41, - "w": 31, - "h": 42 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 31, - "h": 41 - }, - "frame": { - "x": 63, - "y": 42, - "w": 31, - "h": 41 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 42 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 31, - "h": 41 - }, - "frame": { - "x": 63, - "y": 42, - "w": 31, - "h": 41 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:c19a2ef85c7903c2a4c922be93e361d7:7a1608b4463c8ee6cb033125d1c506b4:c6a93eb4343acba47be6c18cd2c93ef1$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0002.png", + "frame": { "x": 136, "y": 90, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0003.png", + "frame": { "x": 171, "y": 91, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0004.png", + "frame": { "x": 37, "y": 44, "w": 34, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 34, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0005.png", + "frame": { "x": 79, "y": 2, "w": 35, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 35, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0006.png", + "frame": { "x": 41, "y": 2, "w": 36, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 36, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0007.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0008.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0009.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0010.png", + "frame": { "x": 116, "y": 2, "w": 34, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 34, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0011.png", + "frame": { "x": 35, "y": 131, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0012.png", + "frame": { "x": 136, "y": 132, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0013.png", + "frame": { "x": 171, "y": 133, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0014.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0015.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0016.png", + "frame": { "x": 152, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0017.png", + "frame": { "x": 108, "y": 45, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0018.png", + "frame": { "x": 176, "y": 46, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0019.png", + "frame": { "x": 37, "y": 86, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0020.png", + "frame": { "x": 70, "y": 87, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0021.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0022.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0023.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0024.png", + "frame": { "x": 70, "y": 132, "w": 30, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 30, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0025.png", + "frame": { "x": 103, "y": 89, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0026.png", + "frame": { "x": 142, "y": 46, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0027.png", + "frame": { "x": 187, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0028.png", + "frame": { "x": 2, "y": 44, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0029.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0030.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0031.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0032.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0033.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0034.png", + "frame": { "x": 136, "y": 90, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0035.png", + "frame": { "x": 171, "y": 91, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0036.png", + "frame": { "x": 37, "y": 44, "w": 34, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 34, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0037.png", + "frame": { "x": 79, "y": 2, "w": 35, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 35, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0038.png", + "frame": { "x": 41, "y": 2, "w": 36, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 36, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0039.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0040.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0041.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0042.png", + "frame": { "x": 116, "y": 2, "w": 34, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 34, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0043.png", + "frame": { "x": 35, "y": 131, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0044.png", + "frame": { "x": 136, "y": 132, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0045.png", + "frame": { "x": 171, "y": 133, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0046.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0047.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0048.png", + "frame": { "x": 152, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0049.png", + "frame": { "x": 108, "y": 45, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0050.png", + "frame": { "x": 176, "y": 46, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0051.png", + "frame": { "x": 37, "y": 86, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0052.png", + "frame": { "x": 70, "y": 87, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0053.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0054.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0055.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0056.png", + "frame": { "x": 70, "y": 132, "w": 30, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 30, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0057.png", + "frame": { "x": 103, "y": 89, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0058.png", + "frame": { "x": 142, "y": 46, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0059.png", + "frame": { "x": 187, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0060.png", + "frame": { "x": 2, "y": 44, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0061.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0062.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0063.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0064.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0065.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0066.png", + "frame": { "x": 136, "y": 90, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0067.png", + "frame": { "x": 171, "y": 91, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0068.png", + "frame": { "x": 37, "y": 44, "w": 34, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 34, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0069.png", + "frame": { "x": 79, "y": 2, "w": 35, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 35, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0070.png", + "frame": { "x": 41, "y": 2, "w": 36, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 36, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0071.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0072.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0073.png", + "frame": { "x": 2, "y": 2, "w": 37, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 37, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0074.png", + "frame": { "x": 116, "y": 2, "w": 34, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 34, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0075.png", + "frame": { "x": 35, "y": 131, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0076.png", + "frame": { "x": 136, "y": 132, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0077.png", + "frame": { "x": 171, "y": 133, "w": 33, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 33, "h": 40 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0078.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0079.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0080.png", + "frame": { "x": 152, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0081.png", + "frame": { "x": 108, "y": 45, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0082.png", + "frame": { "x": 176, "y": 46, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0083.png", + "frame": { "x": 37, "y": 86, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0084.png", + "frame": { "x": 70, "y": 87, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0085.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0086.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0087.png", + "frame": { "x": 2, "y": 88, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0088.png", + "frame": { "x": 70, "y": 132, "w": 30, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 30, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0089.png", + "frame": { "x": 103, "y": 89, "w": 31, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 0, "w": 31, "h": 43 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0090.png", + "frame": { "x": 142, "y": 46, "w": 32, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 32, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0091.png", + "frame": { "x": 187, "y": 2, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0092.png", + "frame": { "x": 2, "y": 44, "w": 33, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 1, "w": 33, "h": 42 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0093.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0094.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0095.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0096.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0097.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0098.png", + "frame": { "x": 2, "y": 173, "w": 33, "h": 39 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 33, "h": 39 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0099.png", + "frame": { "x": 2, "y": 133, "w": 30, "h": 34 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 9, "w": 30, "h": 34 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0100.png", + "frame": { "x": 102, "y": 134, "w": 28, "h": 30 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 12, "w": 28, "h": 30 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0101.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0102.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0103.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0104.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 15, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0105.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 13, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0106.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 12, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0107.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 11, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0108.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 11, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0109.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 12, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0110.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 14, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0111.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0112.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0113.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 15, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0114.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 13, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0115.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 12, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0116.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 11, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0117.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 11, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0118.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 12, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0119.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 14, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0120.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0121.png", + "frame": { "x": 102, "y": 166, "w": 27, "h": 25 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 17, "w": 27, "h": 25 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0122.png", + "frame": { "x": 102, "y": 134, "w": 28, "h": 30 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 12, "w": 28, "h": 30 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0123.png", + "frame": { "x": 2, "y": 133, "w": 30, "h": 34 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 9, "w": 30, "h": 34 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0124.png", + "frame": { "x": 2, "y": 173, "w": 33, "h": 39 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 4, "w": 33, "h": 39 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0125.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + }, + { + "filename": "0126.png", + "frame": { "x": 73, "y": 44, "w": 33, "h": 41 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 33, "h": 41 }, + "sourceSize": { "w": 37, "h": 44 }, + "duration": 80 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "840.png", + "format": "I8", + "size": { "w": 222, "h": 214 }, + "scale": "1" + } } diff --git a/public/images/pokemon/exp/back/shiny/840.png b/public/images/pokemon/exp/back/shiny/840.png index 9a800ab956c..e37bd252d7b 100644 Binary files a/public/images/pokemon/exp/back/shiny/840.png and b/public/images/pokemon/exp/back/shiny/840.png differ diff --git a/public/images/pokemon/exp/shiny/692.png b/public/images/pokemon/exp/shiny/692.png index 3d938d6e64a..d46c585bdfb 100644 Binary files a/public/images/pokemon/exp/shiny/692.png and b/public/images/pokemon/exp/shiny/692.png differ diff --git a/public/images/pokemon/exp/shiny/782.json b/public/images/pokemon/exp/shiny/782.json deleted file mode 100644 index f06c3d4755e..00000000000 --- a/public/images/pokemon/exp/shiny/782.json +++ /dev/null @@ -1,2351 +0,0 @@ -{ - "textures": [ - { - "image": "782.png", - "format": "RGBA8888", - "size": { - "w": 240, - "h": 240 - }, - "scale": 1, - "frames": [ - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0111.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0110.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 104, - "w": 48, - "h": 52 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 0, - "y": 156, - "w": 48, - "h": 52 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 49, - "h": 50 - }, - "frame": { - "x": 48, - "y": 0, - "w": 49, - "h": 50 - } - }, - { - "filename": "0089.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 97, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0090.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 50, - "w": 48, - "h": 52 - } - }, - { - "filename": "0091.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 145, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0108.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 145, - "y": 0, - "w": 48, - "h": 52 - } - }, - { - "filename": "0087.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0088.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0095.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0096.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0104.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0105.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 47, - "h": 52 - }, - "frame": { - "x": 193, - "y": 0, - "w": 47, - "h": 52 - } - }, - { - "filename": "0092.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 102, - "w": 48, - "h": 52 - } - }, - { - "filename": "0099.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 102, - "w": 48, - "h": 52 - } - }, - { - "filename": "0100.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 102, - "w": 48, - "h": 52 - } - }, - { - "filename": "0093.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0094.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0101.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0102.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0103.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 48, - "y": 154, - "w": 48, - "h": 52 - } - }, - { - "filename": "0097.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0098.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0106.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0107.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 96, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0109.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 48, - "h": 52 - }, - "frame": { - "x": 144, - "y": 52, - "w": 48, - "h": 52 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 52, - "w": 48, - "h": 51 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 48, - "h": 51 - }, - "frame": { - "x": 192, - "y": 103, - "w": 48, - "h": 51 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 47, - "h": 51 - }, - "frame": { - "x": 96, - "y": 154, - "w": 47, - "h": 51 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 48, - "h": 50 - }, - "frame": { - "x": 96, - "y": 104, - "w": 48, - "h": 50 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 104, - "w": 48, - "h": 48 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 144, - "y": 152, - "w": 48, - "h": 48 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 49, - "h": 52 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 48, - "h": 48 - }, - "frame": { - "x": 192, - "y": 154, - "w": 48, - "h": 48 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:be0dbbdbd852ebe341842d9712f73e7d:1cd4bec3148a80480f6568f4c8920125:d07862436676aa228a148ee1f1d82a8f$" - } -} diff --git a/public/images/pokemon/exp/shiny/782.png b/public/images/pokemon/exp/shiny/782.png deleted file mode 100644 index 5998d9f9d7a..00000000000 Binary files a/public/images/pokemon/exp/shiny/782.png and /dev/null differ diff --git a/public/images/pokemon/exp/shiny/783.json b/public/images/pokemon/exp/shiny/783.json deleted file mode 100644 index 440e495598b..00000000000 --- a/public/images/pokemon/exp/shiny/783.json +++ /dev/null @@ -1,2204 +0,0 @@ -{ - "textures": [ - { - "image": "783.png", - "format": "RGBA8888", - "size": { - "w": 279, - "h": 279 - }, - "scale": 1, - "frames": [ - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 64, - "h": 71 - }, - "frame": { - "x": 0, - "y": 0, - "w": 64, - "h": 71 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 64, - "h": 71 - }, - "frame": { - "x": 0, - "y": 0, - "w": 64, - "h": 71 - } - }, - { - "filename": "0087.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 64, - "h": 71 - }, - "frame": { - "x": 0, - "y": 0, - "w": 64, - "h": 71 - } - }, - { - "filename": "0092.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 64, - "h": 71 - }, - "frame": { - "x": 64, - "y": 0, - "w": 64, - "h": 71 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 128, - "y": 0, - "w": 63, - "h": 71 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 128, - "y": 0, - "w": 63, - "h": 71 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 191, - "y": 0, - "w": 63, - "h": 71 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 191, - "y": 0, - "w": 63, - "h": 71 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 0, - "y": 71, - "w": 63, - "h": 71 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 0, - "y": 71, - "w": 63, - "h": 71 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 0, - "y": 71, - "w": 63, - "h": 71 - } - }, - { - "filename": "0091.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 0, - "y": 71, - "w": 63, - "h": 71 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 63, - "y": 71, - "w": 63, - "h": 71 - } - }, - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 63, - "y": 71, - "w": 63, - "h": 71 - } - }, - { - "filename": "0088.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 63, - "y": 71, - "w": 63, - "h": 71 - } - }, - { - "filename": "0093.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 63, - "h": 71 - }, - "frame": { - "x": 126, - "y": 71, - "w": 63, - "h": 71 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 62, - "h": 71 - }, - "frame": { - "x": 189, - "y": 71, - "w": 62, - "h": 71 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 62, - "h": 71 - }, - "frame": { - "x": 189, - "y": 71, - "w": 62, - "h": 71 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0094.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0095.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 63, - "h": 70 - }, - "frame": { - "x": 0, - "y": 142, - "w": 63, - "h": 70 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 62, - "h": 71 - }, - "frame": { - "x": 63, - "y": 142, - "w": 62, - "h": 71 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 62, - "h": 71 - }, - "frame": { - "x": 63, - "y": 142, - "w": 62, - "h": 71 - } - }, - { - "filename": "0089.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 62, - "h": 71 - }, - "frame": { - "x": 63, - "y": 142, - "w": 62, - "h": 71 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0099.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0100.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0103.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0104.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 58, - "h": 67 - }, - "frame": { - "x": 0, - "y": 212, - "w": 58, - "h": 67 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0096.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0097.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 62, - "h": 69 - }, - "frame": { - "x": 125, - "y": 142, - "w": 62, - "h": 69 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 60, - "h": 71 - }, - "frame": { - "x": 187, - "y": 142, - "w": 60, - "h": 71 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 60, - "h": 71 - }, - "frame": { - "x": 187, - "y": 142, - "w": 60, - "h": 71 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 60, - "h": 71 - }, - "frame": { - "x": 187, - "y": 142, - "w": 60, - "h": 71 - } - }, - { - "filename": "0090.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 60, - "h": 71 - }, - "frame": { - "x": 187, - "y": 142, - "w": 60, - "h": 71 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0098.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 60, - "h": 68 - }, - "frame": { - "x": 125, - "y": 211, - "w": 60, - "h": 68 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - }, - { - "filename": "0101.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - }, - { - "filename": "0102.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 65, - "h": 71 - }, - "spriteSourceSize": { - "x": 0, - "y": 6, - "w": 55, - "h": 65 - }, - "frame": { - "x": 58, - "y": 213, - "w": 55, - "h": 65 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:0398d2a32d121507cf95d3e4033a4847:6e131e2820d0625f17f5819dbe95feea:aab166e28c744865a0296041224dd01b$" - } -} diff --git a/public/images/pokemon/exp/shiny/783.png b/public/images/pokemon/exp/shiny/783.png deleted file mode 100644 index 92ea294de9f..00000000000 Binary files a/public/images/pokemon/exp/shiny/783.png and /dev/null differ diff --git a/public/images/pokemon/exp/shiny/784.json b/public/images/pokemon/exp/shiny/784.json deleted file mode 100644 index 0d32fcd217e..00000000000 --- a/public/images/pokemon/exp/shiny/784.json +++ /dev/null @@ -1,1826 +0,0 @@ -{ - "textures": [ - { - "image": "784.png", - "format": "RGBA8888", - "size": { - "w": 461, - "h": 461 - }, - "scale": 1, - "frames": [ - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 0, - "w": 96, - "h": 88 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 176, - "w": 96, - "h": 88 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 176, - "w": 96, - "h": 88 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 176, - "w": 96, - "h": 88 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 0, - "y": 176, - "w": 96, - "h": 88 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 96, - "h": 88 - }, - "frame": { - "x": 96, - "y": 88, - "w": 96, - "h": 88 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 94, - "h": 88 - }, - "frame": { - "x": 192, - "y": 0, - "w": 94, - "h": 88 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 92, - "h": 89 - }, - "frame": { - "x": 0, - "y": 353, - "w": 92, - "h": 89 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 92, - "h": 88 - }, - "frame": { - "x": 96, - "y": 176, - "w": 92, - "h": 88 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 92, - "h": 89 - }, - "frame": { - "x": 92, - "y": 264, - "w": 92, - "h": 89 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 90, - "h": 90 - }, - "frame": { - "x": 92, - "y": 353, - "w": 90, - "h": 90 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 192, - "y": 88, - "w": 89, - "h": 89 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 192, - "y": 88, - "w": 89, - "h": 89 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 192, - "y": 88, - "w": 89, - "h": 89 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 192, - "y": 88, - "w": 89, - "h": 89 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 286, - "y": 0, - "w": 89, - "h": 89 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 286, - "y": 0, - "w": 89, - "h": 89 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 286, - "y": 0, - "w": 89, - "h": 89 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 286, - "y": 0, - "w": 89, - "h": 89 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 86, - "h": 87 - }, - "frame": { - "x": 375, - "y": 0, - "w": 86, - "h": 87 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 86, - "h": 87 - }, - "frame": { - "x": 375, - "y": 87, - "w": 86, - "h": 87 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 188, - "y": 177, - "w": 89, - "h": 89 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 89, - "h": 89 - }, - "frame": { - "x": 281, - "y": 89, - "w": 89, - "h": 89 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 277, - "y": 178, - "w": 88, - "h": 89 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 277, - "y": 178, - "w": 88, - "h": 89 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 277, - "y": 178, - "w": 88, - "h": 89 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 277, - "y": 178, - "w": 88, - "h": 89 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 184, - "y": 266, - "w": 88, - "h": 89 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 184, - "y": 266, - "w": 88, - "h": 89 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 184, - "y": 266, - "w": 88, - "h": 89 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 184, - "y": 266, - "w": 88, - "h": 89 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 182, - "y": 355, - "w": 88, - "h": 89 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 182, - "y": 355, - "w": 88, - "h": 89 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 182, - "y": 355, - "w": 88, - "h": 89 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 88, - "h": 89 - }, - "frame": { - "x": 182, - "y": 355, - "w": 88, - "h": 89 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 87, - "h": 89 - }, - "frame": { - "x": 272, - "y": 267, - "w": 87, - "h": 89 - } - }, - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 87, - "h": 89 - }, - "frame": { - "x": 270, - "y": 356, - "w": 87, - "h": 89 - } - }, - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 87, - "h": 87 - }, - "frame": { - "x": 359, - "y": 267, - "w": 87, - "h": 87 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 87, - "h": 87 - }, - "frame": { - "x": 365, - "y": 178, - "w": 87, - "h": 87 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 87, - "h": 87 - }, - "frame": { - "x": 357, - "y": 356, - "w": 87, - "h": 87 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 96, - "h": 91 - }, - "spriteSourceSize": { - "x": 3, - "y": 4, - "w": 87, - "h": 87 - }, - "frame": { - "x": 357, - "y": 356, - "w": 87, - "h": 87 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:ee5ed94dce71b1b77b0e9e09ac1d01d0:89b096ba9193e9faad415ff12ec9d93c:c2f7ca3ab1075b8c824730653d891244$" - } -} diff --git a/public/images/pokemon/exp/shiny/784.png b/public/images/pokemon/exp/shiny/784.png deleted file mode 100644 index 4fe57a70dec..00000000000 Binary files a/public/images/pokemon/exp/shiny/784.png and /dev/null differ diff --git a/public/images/pokemon/female/207.png b/public/images/pokemon/female/207.png index 071b72f9f07..48662a1a516 100644 Binary files a/public/images/pokemon/female/207.png and b/public/images/pokemon/female/207.png differ diff --git a/public/images/pokemon/female/332.png b/public/images/pokemon/female/332.png index 5a199f994eb..2100e4b9a10 100644 Binary files a/public/images/pokemon/female/332.png and b/public/images/pokemon/female/332.png differ diff --git a/public/images/pokemon/female/396.png b/public/images/pokemon/female/396.png index 0adaac1fe42..ee7debc27a9 100644 Binary files a/public/images/pokemon/female/396.png and b/public/images/pokemon/female/396.png differ diff --git a/public/images/pokemon/female/397.png b/public/images/pokemon/female/397.png index ecf63a03748..109a12dad7c 100644 Binary files a/public/images/pokemon/female/397.png and b/public/images/pokemon/female/397.png differ diff --git a/public/images/pokemon/female/398.png b/public/images/pokemon/female/398.png index cd3c1a54df4..d0af82f4f3b 100644 Binary files a/public/images/pokemon/female/398.png and b/public/images/pokemon/female/398.png differ diff --git a/public/images/pokemon/female/404.png b/public/images/pokemon/female/404.png index 67e68318f38..d05821148d4 100644 Binary files a/public/images/pokemon/female/404.png and b/public/images/pokemon/female/404.png differ diff --git a/public/images/pokemon/female/417.png b/public/images/pokemon/female/417.png index be3a2736e18..5b12e357477 100644 Binary files a/public/images/pokemon/female/417.png and b/public/images/pokemon/female/417.png differ diff --git a/public/images/pokemon/icons/7/746-school.png b/public/images/pokemon/icons/7/746-school.png index 837c67d9f63..d421210c2cf 100644 Binary files a/public/images/pokemon/icons/7/746-school.png and b/public/images/pokemon/icons/7/746-school.png differ diff --git a/public/images/pokemon/icons/7/746.png b/public/images/pokemon/icons/7/746.png index 5286054780e..3912ab26688 100644 Binary files a/public/images/pokemon/icons/7/746.png and b/public/images/pokemon/icons/7/746.png differ diff --git a/public/images/pokemon/icons/variant/1/143-gigantamax_2.png b/public/images/pokemon/icons/variant/1/143-gigantamax_2.png new file mode 100644 index 00000000000..036fe6d230d Binary files /dev/null and b/public/images/pokemon/icons/variant/1/143-gigantamax_2.png differ diff --git a/public/images/pokemon/icons/variant/1/143-gigantamax_3.png b/public/images/pokemon/icons/variant/1/143-gigantamax_3.png new file mode 100644 index 00000000000..5a4fe34da7c Binary files /dev/null and b/public/images/pokemon/icons/variant/1/143-gigantamax_3.png differ diff --git a/public/images/pokemon/icons/variant/1/143_2.png b/public/images/pokemon/icons/variant/1/143_2.png new file mode 100644 index 00000000000..a757c202eb6 Binary files /dev/null and b/public/images/pokemon/icons/variant/1/143_2.png differ diff --git a/public/images/pokemon/icons/variant/1/143_3.png b/public/images/pokemon/icons/variant/1/143_3.png new file mode 100644 index 00000000000..0f6da40ca0d Binary files /dev/null and b/public/images/pokemon/icons/variant/1/143_3.png differ diff --git a/public/images/pokemon/icons/variant/1/32_2.png b/public/images/pokemon/icons/variant/1/32_2.png new file mode 100644 index 00000000000..83c7716c509 Binary files /dev/null and b/public/images/pokemon/icons/variant/1/32_2.png differ diff --git a/public/images/pokemon/icons/variant/1/32_3.png b/public/images/pokemon/icons/variant/1/32_3.png new file mode 100644 index 00000000000..9bba8f3d9b9 Binary files /dev/null and b/public/images/pokemon/icons/variant/1/32_3.png differ diff --git a/public/images/pokemon/icons/variant/1/33_2.png b/public/images/pokemon/icons/variant/1/33_2.png new file mode 100644 index 00000000000..151c2091077 Binary files /dev/null and b/public/images/pokemon/icons/variant/1/33_2.png differ diff --git a/public/images/pokemon/icons/variant/1/33_3.png b/public/images/pokemon/icons/variant/1/33_3.png new file mode 100644 index 00000000000..84a8487116b Binary files /dev/null and b/public/images/pokemon/icons/variant/1/33_3.png differ diff --git a/public/images/pokemon/icons/variant/1/34_2.png b/public/images/pokemon/icons/variant/1/34_2.png new file mode 100644 index 00000000000..2d0477f7ff9 Binary files /dev/null and b/public/images/pokemon/icons/variant/1/34_2.png differ diff --git a/public/images/pokemon/icons/variant/1/34_3.png b/public/images/pokemon/icons/variant/1/34_3.png new file mode 100644 index 00000000000..8e844c38605 Binary files /dev/null and b/public/images/pokemon/icons/variant/1/34_3.png differ diff --git a/public/images/pokemon/icons/variant/1/88_2.png b/public/images/pokemon/icons/variant/1/88_2.png new file mode 100644 index 00000000000..164f98f7d80 Binary files /dev/null and b/public/images/pokemon/icons/variant/1/88_2.png differ diff --git a/public/images/pokemon/icons/variant/1/88_3.png b/public/images/pokemon/icons/variant/1/88_3.png new file mode 100644 index 00000000000..6e90ad56d2a Binary files /dev/null and b/public/images/pokemon/icons/variant/1/88_3.png differ diff --git a/public/images/pokemon/icons/variant/1/89_2.png b/public/images/pokemon/icons/variant/1/89_2.png new file mode 100644 index 00000000000..533ebe86c9e Binary files /dev/null and b/public/images/pokemon/icons/variant/1/89_2.png differ diff --git a/public/images/pokemon/icons/variant/1/89_3.png b/public/images/pokemon/icons/variant/1/89_3.png new file mode 100644 index 00000000000..8caf93912d4 Binary files /dev/null and b/public/images/pokemon/icons/variant/1/89_3.png differ diff --git a/public/images/pokemon/icons/variant/2/187_2.png b/public/images/pokemon/icons/variant/2/187_2.png new file mode 100644 index 00000000000..c7da6a46115 Binary files /dev/null and b/public/images/pokemon/icons/variant/2/187_2.png differ diff --git a/public/images/pokemon/icons/variant/2/187_3.png b/public/images/pokemon/icons/variant/2/187_3.png new file mode 100644 index 00000000000..6f118aed4f4 Binary files /dev/null and b/public/images/pokemon/icons/variant/2/187_3.png differ diff --git a/public/images/pokemon/icons/variant/2/188_2.png b/public/images/pokemon/icons/variant/2/188_2.png new file mode 100644 index 00000000000..cbb7b690ff0 Binary files /dev/null and b/public/images/pokemon/icons/variant/2/188_2.png differ diff --git a/public/images/pokemon/icons/variant/2/188_3.png b/public/images/pokemon/icons/variant/2/188_3.png new file mode 100644 index 00000000000..2c4e64cc608 Binary files /dev/null and b/public/images/pokemon/icons/variant/2/188_3.png differ diff --git a/public/images/pokemon/icons/variant/2/189_2.png b/public/images/pokemon/icons/variant/2/189_2.png new file mode 100644 index 00000000000..ca5e127816a Binary files /dev/null and b/public/images/pokemon/icons/variant/2/189_2.png differ diff --git a/public/images/pokemon/icons/variant/2/189_3.png b/public/images/pokemon/icons/variant/2/189_3.png new file mode 100644 index 00000000000..dfee57baf86 Binary files /dev/null and b/public/images/pokemon/icons/variant/2/189_3.png differ diff --git a/public/images/pokemon/icons/variant/2/204_2.png b/public/images/pokemon/icons/variant/2/204_2.png new file mode 100644 index 00000000000..e36cf0af684 Binary files /dev/null and b/public/images/pokemon/icons/variant/2/204_2.png differ diff --git a/public/images/pokemon/icons/variant/2/204_3.png b/public/images/pokemon/icons/variant/2/204_3.png new file mode 100644 index 00000000000..5b5c4a70769 Binary files /dev/null and b/public/images/pokemon/icons/variant/2/204_3.png differ diff --git a/public/images/pokemon/icons/variant/2/205_2.png b/public/images/pokemon/icons/variant/2/205_2.png new file mode 100644 index 00000000000..5bf3cb2c83e Binary files /dev/null and b/public/images/pokemon/icons/variant/2/205_2.png differ diff --git a/public/images/pokemon/icons/variant/2/205_3.png b/public/images/pokemon/icons/variant/2/205_3.png new file mode 100644 index 00000000000..6e8d2e3dc7d Binary files /dev/null and b/public/images/pokemon/icons/variant/2/205_3.png differ diff --git a/public/images/pokemon/icons/variant/2/207_2.png b/public/images/pokemon/icons/variant/2/207_2.png index 206f38f6a0a..c24b731925e 100644 Binary files a/public/images/pokemon/icons/variant/2/207_2.png and b/public/images/pokemon/icons/variant/2/207_2.png differ diff --git a/public/images/pokemon/icons/variant/2/207_3.png b/public/images/pokemon/icons/variant/2/207_3.png index 7a0018836dd..1a5c00992ce 100644 Binary files a/public/images/pokemon/icons/variant/2/207_3.png and b/public/images/pokemon/icons/variant/2/207_3.png differ diff --git a/public/images/pokemon/icons/variant/3/299_2.png b/public/images/pokemon/icons/variant/3/299_2.png new file mode 100644 index 00000000000..fa674c3afda Binary files /dev/null and b/public/images/pokemon/icons/variant/3/299_2.png differ diff --git a/public/images/pokemon/icons/variant/3/299_3.png b/public/images/pokemon/icons/variant/3/299_3.png new file mode 100644 index 00000000000..68d8a893316 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/299_3.png differ diff --git a/public/images/pokemon/icons/variant/3/313_2.png b/public/images/pokemon/icons/variant/3/313_2.png new file mode 100644 index 00000000000..501bb3f859b Binary files /dev/null and b/public/images/pokemon/icons/variant/3/313_2.png differ diff --git a/public/images/pokemon/icons/variant/3/313_3.png b/public/images/pokemon/icons/variant/3/313_3.png new file mode 100644 index 00000000000..89c81375da8 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/313_3.png differ diff --git a/public/images/pokemon/icons/variant/3/314_2.png b/public/images/pokemon/icons/variant/3/314_2.png new file mode 100644 index 00000000000..0242553f41a Binary files /dev/null and b/public/images/pokemon/icons/variant/3/314_2.png differ diff --git a/public/images/pokemon/icons/variant/3/314_3.png b/public/images/pokemon/icons/variant/3/314_3.png new file mode 100644 index 00000000000..716ffccd3f2 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/314_3.png differ diff --git a/public/images/pokemon/icons/variant/3/325_2.png b/public/images/pokemon/icons/variant/3/325_2.png new file mode 100644 index 00000000000..0792a8aa840 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/325_2.png differ diff --git a/public/images/pokemon/icons/variant/3/325_3.png b/public/images/pokemon/icons/variant/3/325_3.png new file mode 100644 index 00000000000..dfd13bd75be Binary files /dev/null and b/public/images/pokemon/icons/variant/3/325_3.png differ diff --git a/public/images/pokemon/icons/variant/3/326_2.png b/public/images/pokemon/icons/variant/3/326_2.png new file mode 100644 index 00000000000..b23be901c9a Binary files /dev/null and b/public/images/pokemon/icons/variant/3/326_2.png differ diff --git a/public/images/pokemon/icons/variant/3/326_3.png b/public/images/pokemon/icons/variant/3/326_3.png new file mode 100644 index 00000000000..6c4025d0842 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/326_3.png differ diff --git a/public/images/pokemon/icons/variant/3/331_2.png b/public/images/pokemon/icons/variant/3/331_2.png new file mode 100644 index 00000000000..19b80296a1e Binary files /dev/null and b/public/images/pokemon/icons/variant/3/331_2.png differ diff --git a/public/images/pokemon/icons/variant/3/331_3.png b/public/images/pokemon/icons/variant/3/331_3.png new file mode 100644 index 00000000000..01b93a1d086 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/331_3.png differ diff --git a/public/images/pokemon/icons/variant/3/332_2.png b/public/images/pokemon/icons/variant/3/332_2.png new file mode 100644 index 00000000000..ff9077cec0a Binary files /dev/null and b/public/images/pokemon/icons/variant/3/332_2.png differ diff --git a/public/images/pokemon/icons/variant/3/332_3.png b/public/images/pokemon/icons/variant/3/332_3.png new file mode 100644 index 00000000000..c1c6cee7947 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/332_3.png differ diff --git a/public/images/pokemon/icons/variant/3/345_2.png b/public/images/pokemon/icons/variant/3/345_2.png new file mode 100644 index 00000000000..015696265f9 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/345_2.png differ diff --git a/public/images/pokemon/icons/variant/3/345_3.png b/public/images/pokemon/icons/variant/3/345_3.png new file mode 100644 index 00000000000..41ba6766c21 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/345_3.png differ diff --git a/public/images/pokemon/icons/variant/3/346_2.png b/public/images/pokemon/icons/variant/3/346_2.png new file mode 100644 index 00000000000..71e233c31cc Binary files /dev/null and b/public/images/pokemon/icons/variant/3/346_2.png differ diff --git a/public/images/pokemon/icons/variant/3/346_3.png b/public/images/pokemon/icons/variant/3/346_3.png new file mode 100644 index 00000000000..14514bb6183 Binary files /dev/null and b/public/images/pokemon/icons/variant/3/346_3.png differ diff --git a/public/images/pokemon/icons/variant/4/396_2.png b/public/images/pokemon/icons/variant/4/396_2.png new file mode 100644 index 00000000000..d7d23b494ab Binary files /dev/null and b/public/images/pokemon/icons/variant/4/396_2.png differ diff --git a/public/images/pokemon/icons/variant/4/396_3.png b/public/images/pokemon/icons/variant/4/396_3.png new file mode 100644 index 00000000000..6725912b199 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/396_3.png differ diff --git a/public/images/pokemon/icons/variant/4/397_2.png b/public/images/pokemon/icons/variant/4/397_2.png new file mode 100644 index 00000000000..f6982eeece4 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/397_2.png differ diff --git a/public/images/pokemon/icons/variant/4/397_3.png b/public/images/pokemon/icons/variant/4/397_3.png new file mode 100644 index 00000000000..83c2755599a Binary files /dev/null and b/public/images/pokemon/icons/variant/4/397_3.png differ diff --git a/public/images/pokemon/icons/variant/4/398_2.png b/public/images/pokemon/icons/variant/4/398_2.png new file mode 100644 index 00000000000..bbe04248c7b Binary files /dev/null and b/public/images/pokemon/icons/variant/4/398_2.png differ diff --git a/public/images/pokemon/icons/variant/4/398_3.png b/public/images/pokemon/icons/variant/4/398_3.png new file mode 100644 index 00000000000..a1d47a95b1a Binary files /dev/null and b/public/images/pokemon/icons/variant/4/398_3.png differ diff --git a/public/images/pokemon/icons/variant/4/403_2.png b/public/images/pokemon/icons/variant/4/403_2.png new file mode 100644 index 00000000000..410d3126e54 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/403_2.png differ diff --git a/public/images/pokemon/icons/variant/4/403_3.png b/public/images/pokemon/icons/variant/4/403_3.png new file mode 100644 index 00000000000..0064c7d7d3f Binary files /dev/null and b/public/images/pokemon/icons/variant/4/403_3.png differ diff --git a/public/images/pokemon/icons/variant/4/404_2.png b/public/images/pokemon/icons/variant/4/404_2.png new file mode 100644 index 00000000000..9bd7a6ed7bf Binary files /dev/null and b/public/images/pokemon/icons/variant/4/404_2.png differ diff --git a/public/images/pokemon/icons/variant/4/404_3.png b/public/images/pokemon/icons/variant/4/404_3.png new file mode 100644 index 00000000000..5ec14183070 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/404_3.png differ diff --git a/public/images/pokemon/icons/variant/4/405_2.png b/public/images/pokemon/icons/variant/4/405_2.png new file mode 100644 index 00000000000..28515b8350b Binary files /dev/null and b/public/images/pokemon/icons/variant/4/405_2.png differ diff --git a/public/images/pokemon/icons/variant/4/405_3.png b/public/images/pokemon/icons/variant/4/405_3.png new file mode 100644 index 00000000000..82f0270bd5b Binary files /dev/null and b/public/images/pokemon/icons/variant/4/405_3.png differ diff --git a/public/images/pokemon/icons/variant/4/417_2.png b/public/images/pokemon/icons/variant/4/417_2.png new file mode 100644 index 00000000000..e1bd9e52bb0 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/417_2.png differ diff --git a/public/images/pokemon/icons/variant/4/417_3.png b/public/images/pokemon/icons/variant/4/417_3.png new file mode 100644 index 00000000000..4f9d1936f78 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/417_3.png differ diff --git a/public/images/pokemon/icons/variant/4/420_2.png b/public/images/pokemon/icons/variant/4/420_2.png new file mode 100644 index 00000000000..194ae1213e3 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/420_2.png differ diff --git a/public/images/pokemon/icons/variant/4/420_3.png b/public/images/pokemon/icons/variant/4/420_3.png new file mode 100644 index 00000000000..71116e40243 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/420_3.png differ diff --git a/public/images/pokemon/icons/variant/4/421-overcast_2.png b/public/images/pokemon/icons/variant/4/421-overcast_2.png new file mode 100644 index 00000000000..0a8260baf49 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/421-overcast_2.png differ diff --git a/public/images/pokemon/icons/variant/4/421-overcast_3.png b/public/images/pokemon/icons/variant/4/421-overcast_3.png new file mode 100644 index 00000000000..91fb8ef3d5f Binary files /dev/null and b/public/images/pokemon/icons/variant/4/421-overcast_3.png differ diff --git a/public/images/pokemon/icons/variant/4/421-sunshine_2.png b/public/images/pokemon/icons/variant/4/421-sunshine_2.png new file mode 100644 index 00000000000..4872654e4be Binary files /dev/null and b/public/images/pokemon/icons/variant/4/421-sunshine_2.png differ diff --git a/public/images/pokemon/icons/variant/4/421-sunshine_3.png b/public/images/pokemon/icons/variant/4/421-sunshine_3.png new file mode 100644 index 00000000000..d615119bdf2 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/421-sunshine_3.png differ diff --git a/public/images/pokemon/icons/variant/4/446_2.png b/public/images/pokemon/icons/variant/4/446_2.png new file mode 100644 index 00000000000..900f3a5996b Binary files /dev/null and b/public/images/pokemon/icons/variant/4/446_2.png differ diff --git a/public/images/pokemon/icons/variant/4/446_3.png b/public/images/pokemon/icons/variant/4/446_3.png new file mode 100644 index 00000000000..04c40204baf Binary files /dev/null and b/public/images/pokemon/icons/variant/4/446_3.png differ diff --git a/public/images/pokemon/icons/variant/4/476_2.png b/public/images/pokemon/icons/variant/4/476_2.png new file mode 100644 index 00000000000..9b36a6f127e Binary files /dev/null and b/public/images/pokemon/icons/variant/4/476_2.png differ diff --git a/public/images/pokemon/icons/variant/4/476_3.png b/public/images/pokemon/icons/variant/4/476_3.png new file mode 100644 index 00000000000..39cb2a72088 Binary files /dev/null and b/public/images/pokemon/icons/variant/4/476_3.png differ diff --git a/public/images/pokemon/icons/variant/5/498_2.png b/public/images/pokemon/icons/variant/5/498_2.png new file mode 100644 index 00000000000..568e7ff7670 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/498_2.png differ diff --git a/public/images/pokemon/icons/variant/5/498_3.png b/public/images/pokemon/icons/variant/5/498_3.png new file mode 100644 index 00000000000..d592f83c9be Binary files /dev/null and b/public/images/pokemon/icons/variant/5/498_3.png differ diff --git a/public/images/pokemon/icons/variant/5/499_2.png b/public/images/pokemon/icons/variant/5/499_2.png new file mode 100644 index 00000000000..992d5edb00a Binary files /dev/null and b/public/images/pokemon/icons/variant/5/499_2.png differ diff --git a/public/images/pokemon/icons/variant/5/499_3.png b/public/images/pokemon/icons/variant/5/499_3.png new file mode 100644 index 00000000000..151185e4556 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/499_3.png differ diff --git a/public/images/pokemon/icons/variant/5/500_2.png b/public/images/pokemon/icons/variant/5/500_2.png new file mode 100644 index 00000000000..e8b8e88c46e Binary files /dev/null and b/public/images/pokemon/icons/variant/5/500_2.png differ diff --git a/public/images/pokemon/icons/variant/5/500_3.png b/public/images/pokemon/icons/variant/5/500_3.png new file mode 100644 index 00000000000..ad82f3d6ced Binary files /dev/null and b/public/images/pokemon/icons/variant/5/500_3.png differ diff --git a/public/images/pokemon/icons/variant/5/511_2.png b/public/images/pokemon/icons/variant/5/511_2.png new file mode 100644 index 00000000000..eea1484725e Binary files /dev/null and b/public/images/pokemon/icons/variant/5/511_2.png differ diff --git a/public/images/pokemon/icons/variant/5/511_3.png b/public/images/pokemon/icons/variant/5/511_3.png new file mode 100644 index 00000000000..fc434170eb2 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/511_3.png differ diff --git a/public/images/pokemon/icons/variant/5/512_2.png b/public/images/pokemon/icons/variant/5/512_2.png new file mode 100644 index 00000000000..b9e0a45c06c Binary files /dev/null and b/public/images/pokemon/icons/variant/5/512_2.png differ diff --git a/public/images/pokemon/icons/variant/5/512_3.png b/public/images/pokemon/icons/variant/5/512_3.png new file mode 100644 index 00000000000..1a53cc12d26 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/512_3.png differ diff --git a/public/images/pokemon/icons/variant/5/513_2.png b/public/images/pokemon/icons/variant/5/513_2.png new file mode 100644 index 00000000000..305903f3162 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/513_2.png differ diff --git a/public/images/pokemon/icons/variant/5/513_3.png b/public/images/pokemon/icons/variant/5/513_3.png new file mode 100644 index 00000000000..6c4592a0f54 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/513_3.png differ diff --git a/public/images/pokemon/icons/variant/5/514_2.png b/public/images/pokemon/icons/variant/5/514_2.png new file mode 100644 index 00000000000..5e39da4c7f7 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/514_2.png differ diff --git a/public/images/pokemon/icons/variant/5/514_3.png b/public/images/pokemon/icons/variant/5/514_3.png new file mode 100644 index 00000000000..ea6224485ce Binary files /dev/null and b/public/images/pokemon/icons/variant/5/514_3.png differ diff --git a/public/images/pokemon/icons/variant/5/515_2.png b/public/images/pokemon/icons/variant/5/515_2.png new file mode 100644 index 00000000000..3d8af4a569f Binary files /dev/null and b/public/images/pokemon/icons/variant/5/515_2.png differ diff --git a/public/images/pokemon/icons/variant/5/515_3.png b/public/images/pokemon/icons/variant/5/515_3.png new file mode 100644 index 00000000000..bfd1a9e0011 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/515_3.png differ diff --git a/public/images/pokemon/icons/variant/5/516_2.png b/public/images/pokemon/icons/variant/5/516_2.png new file mode 100644 index 00000000000..23257ea2c6f Binary files /dev/null and b/public/images/pokemon/icons/variant/5/516_2.png differ diff --git a/public/images/pokemon/icons/variant/5/516_3.png b/public/images/pokemon/icons/variant/5/516_3.png new file mode 100644 index 00000000000..78cb41df064 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/516_3.png differ diff --git a/public/images/pokemon/icons/variant/5/522_2.png b/public/images/pokemon/icons/variant/5/522_2.png new file mode 100644 index 00000000000..111054ca1ab Binary files /dev/null and b/public/images/pokemon/icons/variant/5/522_2.png differ diff --git a/public/images/pokemon/icons/variant/5/522_3.png b/public/images/pokemon/icons/variant/5/522_3.png new file mode 100644 index 00000000000..03476f89139 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/522_3.png differ diff --git a/public/images/pokemon/icons/variant/5/523_2.png b/public/images/pokemon/icons/variant/5/523_2.png new file mode 100644 index 00000000000..238e8d64594 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/523_2.png differ diff --git a/public/images/pokemon/icons/variant/5/523_3.png b/public/images/pokemon/icons/variant/5/523_3.png new file mode 100644 index 00000000000..e2b12513061 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/523_3.png differ diff --git a/public/images/pokemon/icons/variant/5/535_2.png b/public/images/pokemon/icons/variant/5/535_2.png new file mode 100644 index 00000000000..6f2f8a77136 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/535_2.png differ diff --git a/public/images/pokemon/icons/variant/5/535_3.png b/public/images/pokemon/icons/variant/5/535_3.png new file mode 100644 index 00000000000..b97481faa8f Binary files /dev/null and b/public/images/pokemon/icons/variant/5/535_3.png differ diff --git a/public/images/pokemon/icons/variant/5/536_2.png b/public/images/pokemon/icons/variant/5/536_2.png new file mode 100644 index 00000000000..36a4a17dd2b Binary files /dev/null and b/public/images/pokemon/icons/variant/5/536_2.png differ diff --git a/public/images/pokemon/icons/variant/5/536_3.png b/public/images/pokemon/icons/variant/5/536_3.png new file mode 100644 index 00000000000..282864d38e9 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/536_3.png differ diff --git a/public/images/pokemon/icons/variant/5/537_2.png b/public/images/pokemon/icons/variant/5/537_2.png new file mode 100644 index 00000000000..599752ff7f1 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/537_2.png differ diff --git a/public/images/pokemon/icons/variant/5/537_3.png b/public/images/pokemon/icons/variant/5/537_3.png new file mode 100644 index 00000000000..229dd83c8ce Binary files /dev/null and b/public/images/pokemon/icons/variant/5/537_3.png differ diff --git a/public/images/pokemon/icons/variant/5/554_2.png b/public/images/pokemon/icons/variant/5/554_2.png new file mode 100644 index 00000000000..8f5df20db65 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/554_2.png differ diff --git a/public/images/pokemon/icons/variant/5/554_3.png b/public/images/pokemon/icons/variant/5/554_3.png new file mode 100644 index 00000000000..6827ee2b478 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/554_3.png differ diff --git a/public/images/pokemon/icons/variant/5/555-zen_2.png b/public/images/pokemon/icons/variant/5/555-zen_2.png new file mode 100644 index 00000000000..ae18a833759 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/555-zen_2.png differ diff --git a/public/images/pokemon/icons/variant/5/555-zen_3.png b/public/images/pokemon/icons/variant/5/555-zen_3.png new file mode 100644 index 00000000000..692e39985a6 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/555-zen_3.png differ diff --git a/public/images/pokemon/icons/variant/5/555_2.png b/public/images/pokemon/icons/variant/5/555_2.png new file mode 100644 index 00000000000..f408122171a Binary files /dev/null and b/public/images/pokemon/icons/variant/5/555_2.png differ diff --git a/public/images/pokemon/icons/variant/5/555_3.png b/public/images/pokemon/icons/variant/5/555_3.png new file mode 100644 index 00000000000..2994d3da2cf Binary files /dev/null and b/public/images/pokemon/icons/variant/5/555_3.png differ diff --git a/public/images/pokemon/icons/variant/5/566_2.png b/public/images/pokemon/icons/variant/5/566_2.png new file mode 100644 index 00000000000..927757ac240 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/566_2.png differ diff --git a/public/images/pokemon/icons/variant/5/566_3.png b/public/images/pokemon/icons/variant/5/566_3.png new file mode 100644 index 00000000000..450fd247d8b Binary files /dev/null and b/public/images/pokemon/icons/variant/5/566_3.png differ diff --git a/public/images/pokemon/icons/variant/5/567_2.png b/public/images/pokemon/icons/variant/5/567_2.png new file mode 100644 index 00000000000..1050d13123d Binary files /dev/null and b/public/images/pokemon/icons/variant/5/567_2.png differ diff --git a/public/images/pokemon/icons/variant/5/567_3.png b/public/images/pokemon/icons/variant/5/567_3.png new file mode 100644 index 00000000000..c87f3841410 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/567_3.png differ diff --git a/public/images/pokemon/icons/variant/5/572_2.png b/public/images/pokemon/icons/variant/5/572_2.png index b6230a17cbc..1da1f6b953a 100644 Binary files a/public/images/pokemon/icons/variant/5/572_2.png and b/public/images/pokemon/icons/variant/5/572_2.png differ diff --git a/public/images/pokemon/icons/variant/5/572_3.png b/public/images/pokemon/icons/variant/5/572_3.png index c0848deade2..868b7c38585 100644 Binary files a/public/images/pokemon/icons/variant/5/572_3.png and b/public/images/pokemon/icons/variant/5/572_3.png differ diff --git a/public/images/pokemon/icons/variant/5/573_2.png b/public/images/pokemon/icons/variant/5/573_2.png new file mode 100644 index 00000000000..effd7070f7d Binary files /dev/null and b/public/images/pokemon/icons/variant/5/573_2.png differ diff --git a/public/images/pokemon/icons/variant/5/573_3.png b/public/images/pokemon/icons/variant/5/573_3.png new file mode 100644 index 00000000000..019cf83795d Binary files /dev/null and b/public/images/pokemon/icons/variant/5/573_3.png differ diff --git a/public/images/pokemon/icons/variant/5/626_2.png b/public/images/pokemon/icons/variant/5/626_2.png new file mode 100644 index 00000000000..21930c7606e Binary files /dev/null and b/public/images/pokemon/icons/variant/5/626_2.png differ diff --git a/public/images/pokemon/icons/variant/5/626_3.png b/public/images/pokemon/icons/variant/5/626_3.png new file mode 100644 index 00000000000..2183e1426e8 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/626_3.png differ diff --git a/public/images/pokemon/icons/variant/5/641-incarnate_1.png b/public/images/pokemon/icons/variant/5/641-incarnate_1.png deleted file mode 100644 index ddd0ca15c0c..00000000000 Binary files a/public/images/pokemon/icons/variant/5/641-incarnate_1.png and /dev/null differ diff --git a/public/images/pokemon/icons/variant/5/641-therian_1.png b/public/images/pokemon/icons/variant/5/641-therian_1.png deleted file mode 100644 index 8f6f01fd0d7..00000000000 Binary files a/public/images/pokemon/icons/variant/5/641-therian_1.png and /dev/null differ diff --git a/public/images/pokemon/icons/variant/5/642-incarnate_1.png b/public/images/pokemon/icons/variant/5/642-incarnate_1.png deleted file mode 100644 index 55507be70b9..00000000000 Binary files a/public/images/pokemon/icons/variant/5/642-incarnate_1.png and /dev/null differ diff --git a/public/images/pokemon/icons/variant/5/642-therian_1.png b/public/images/pokemon/icons/variant/5/642-therian_1.png deleted file mode 100644 index bea360abb95..00000000000 Binary files a/public/images/pokemon/icons/variant/5/642-therian_1.png and /dev/null differ diff --git a/public/images/pokemon/icons/variant/5/643_2.png b/public/images/pokemon/icons/variant/5/643_2.png new file mode 100644 index 00000000000..24b7ce28a36 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/643_2.png differ diff --git a/public/images/pokemon/icons/variant/5/643_3.png b/public/images/pokemon/icons/variant/5/643_3.png new file mode 100644 index 00000000000..5c124dbb8f6 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/643_3.png differ diff --git a/public/images/pokemon/icons/variant/5/644_2.png b/public/images/pokemon/icons/variant/5/644_2.png new file mode 100644 index 00000000000..13ba216e9ce Binary files /dev/null and b/public/images/pokemon/icons/variant/5/644_2.png differ diff --git a/public/images/pokemon/icons/variant/5/644_3.png b/public/images/pokemon/icons/variant/5/644_3.png new file mode 100644 index 00000000000..a071965f32d Binary files /dev/null and b/public/images/pokemon/icons/variant/5/644_3.png differ diff --git a/public/images/pokemon/icons/variant/5/645-incarnate_1.png b/public/images/pokemon/icons/variant/5/645-incarnate_1.png deleted file mode 100644 index 416fa9ca1db..00000000000 Binary files a/public/images/pokemon/icons/variant/5/645-incarnate_1.png and /dev/null differ diff --git a/public/images/pokemon/icons/variant/5/645-therian_1.png b/public/images/pokemon/icons/variant/5/645-therian_1.png deleted file mode 100644 index c03d4233e29..00000000000 Binary files a/public/images/pokemon/icons/variant/5/645-therian_1.png and /dev/null differ diff --git a/public/images/pokemon/icons/variant/5/646-black_2.png b/public/images/pokemon/icons/variant/5/646-black_2.png new file mode 100644 index 00000000000..825a8bd36c0 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/646-black_2.png differ diff --git a/public/images/pokemon/icons/variant/5/646-black_3.png b/public/images/pokemon/icons/variant/5/646-black_3.png new file mode 100644 index 00000000000..6e854d9ea41 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/646-black_3.png differ diff --git a/public/images/pokemon/icons/variant/5/646-white_2.png b/public/images/pokemon/icons/variant/5/646-white_2.png new file mode 100644 index 00000000000..e38dc504b21 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/646-white_2.png differ diff --git a/public/images/pokemon/icons/variant/5/646-white_3.png b/public/images/pokemon/icons/variant/5/646-white_3.png new file mode 100644 index 00000000000..12bff95a01d Binary files /dev/null and b/public/images/pokemon/icons/variant/5/646-white_3.png differ diff --git a/public/images/pokemon/icons/variant/5/646_2.png b/public/images/pokemon/icons/variant/5/646_2.png new file mode 100644 index 00000000000..064598bfd26 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/646_2.png differ diff --git a/public/images/pokemon/icons/variant/5/646_3.png b/public/images/pokemon/icons/variant/5/646_3.png new file mode 100644 index 00000000000..e258eb4ce91 Binary files /dev/null and b/public/images/pokemon/icons/variant/5/646_3.png differ diff --git a/public/images/pokemon/icons/variant/6/692_2.png b/public/images/pokemon/icons/variant/6/692_2.png new file mode 100644 index 00000000000..fa6cacc70dd Binary files /dev/null and b/public/images/pokemon/icons/variant/6/692_2.png differ diff --git a/public/images/pokemon/icons/variant/6/692_3.png b/public/images/pokemon/icons/variant/6/692_3.png new file mode 100644 index 00000000000..47d0661babe Binary files /dev/null and b/public/images/pokemon/icons/variant/6/692_3.png differ diff --git a/public/images/pokemon/icons/variant/6/693_2.png b/public/images/pokemon/icons/variant/6/693_2.png new file mode 100644 index 00000000000..9d8ea4f56cd Binary files /dev/null and b/public/images/pokemon/icons/variant/6/693_2.png differ diff --git a/public/images/pokemon/icons/variant/6/693_3.png b/public/images/pokemon/icons/variant/6/693_3.png new file mode 100644 index 00000000000..6f0169bb057 Binary files /dev/null and b/public/images/pokemon/icons/variant/6/693_3.png differ diff --git a/public/images/pokemon/icons/variant/7/2037_2.png b/public/images/pokemon/icons/variant/7/2037_2.png new file mode 100644 index 00000000000..528793de5c5 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/2037_2.png differ diff --git a/public/images/pokemon/icons/variant/7/2037_3.png b/public/images/pokemon/icons/variant/7/2037_3.png new file mode 100644 index 00000000000..d79fd1c2369 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/2037_3.png differ diff --git a/public/images/pokemon/icons/variant/7/2038_2.png b/public/images/pokemon/icons/variant/7/2038_2.png new file mode 100644 index 00000000000..d8295be1baf Binary files /dev/null and b/public/images/pokemon/icons/variant/7/2038_2.png differ diff --git a/public/images/pokemon/icons/variant/7/2038_3.png b/public/images/pokemon/icons/variant/7/2038_3.png new file mode 100644 index 00000000000..645c783b43f Binary files /dev/null and b/public/images/pokemon/icons/variant/7/2038_3.png differ diff --git a/public/images/pokemon/icons/variant/7/746-school_2.png b/public/images/pokemon/icons/variant/7/746-school_2.png new file mode 100644 index 00000000000..94d16db5c42 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/746-school_2.png differ diff --git a/public/images/pokemon/icons/variant/7/746-school_3.png b/public/images/pokemon/icons/variant/7/746-school_3.png new file mode 100644 index 00000000000..94d16db5c42 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/746-school_3.png differ diff --git a/public/images/pokemon/icons/variant/7/746_2.png b/public/images/pokemon/icons/variant/7/746_2.png new file mode 100644 index 00000000000..d4897e0acf3 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/746_2.png differ diff --git a/public/images/pokemon/icons/variant/7/746_3.png b/public/images/pokemon/icons/variant/7/746_3.png new file mode 100644 index 00000000000..8746a45310d Binary files /dev/null and b/public/images/pokemon/icons/variant/7/746_3.png differ diff --git a/public/images/pokemon/icons/variant/7/780_2.png b/public/images/pokemon/icons/variant/7/780_2.png new file mode 100644 index 00000000000..fe40d474146 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/780_2.png differ diff --git a/public/images/pokemon/icons/variant/7/780_3.png b/public/images/pokemon/icons/variant/7/780_3.png new file mode 100644 index 00000000000..6d98c750e8e Binary files /dev/null and b/public/images/pokemon/icons/variant/7/780_3.png differ diff --git a/public/images/pokemon/icons/variant/7/782_2.png b/public/images/pokemon/icons/variant/7/782_2.png new file mode 100644 index 00000000000..c036fa45017 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/782_2.png differ diff --git a/public/images/pokemon/icons/variant/7/782_3.png b/public/images/pokemon/icons/variant/7/782_3.png new file mode 100644 index 00000000000..bc1e939e14d Binary files /dev/null and b/public/images/pokemon/icons/variant/7/782_3.png differ diff --git a/public/images/pokemon/icons/variant/7/783_2.png b/public/images/pokemon/icons/variant/7/783_2.png new file mode 100644 index 00000000000..1e686e95017 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/783_2.png differ diff --git a/public/images/pokemon/icons/variant/7/783_3.png b/public/images/pokemon/icons/variant/7/783_3.png new file mode 100644 index 00000000000..6b61fea7298 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/783_3.png differ diff --git a/public/images/pokemon/icons/variant/7/784_2.png b/public/images/pokemon/icons/variant/7/784_2.png new file mode 100644 index 00000000000..5f921735839 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/784_2.png differ diff --git a/public/images/pokemon/icons/variant/7/784_3.png b/public/images/pokemon/icons/variant/7/784_3.png new file mode 100644 index 00000000000..077a6253a19 Binary files /dev/null and b/public/images/pokemon/icons/variant/7/784_3.png differ diff --git a/public/images/pokemon/icons/variant/8/840_2.png b/public/images/pokemon/icons/variant/8/840_2.png new file mode 100644 index 00000000000..796057e93fb Binary files /dev/null and b/public/images/pokemon/icons/variant/8/840_2.png differ diff --git a/public/images/pokemon/icons/variant/8/840_3.png b/public/images/pokemon/icons/variant/8/840_3.png new file mode 100644 index 00000000000..de8206c7fd7 Binary files /dev/null and b/public/images/pokemon/icons/variant/8/840_3.png differ diff --git a/public/images/pokemon/icons/variant/8/841-gigantamax_2.png b/public/images/pokemon/icons/variant/8/841-gigantamax_2.png new file mode 100644 index 00000000000..aaed8081eec Binary files /dev/null and b/public/images/pokemon/icons/variant/8/841-gigantamax_2.png differ diff --git a/public/images/pokemon/icons/variant/8/841-gigantamax_3.png b/public/images/pokemon/icons/variant/8/841-gigantamax_3.png new file mode 100644 index 00000000000..3ae323c8677 Binary files /dev/null and b/public/images/pokemon/icons/variant/8/841-gigantamax_3.png differ diff --git a/public/images/pokemon/icons/variant/8/841_2.png b/public/images/pokemon/icons/variant/8/841_2.png new file mode 100644 index 00000000000..d1a57120993 Binary files /dev/null and b/public/images/pokemon/icons/variant/8/841_2.png differ diff --git a/public/images/pokemon/icons/variant/8/841_3.png b/public/images/pokemon/icons/variant/8/841_3.png new file mode 100644 index 00000000000..5eaf8ea1c57 Binary files /dev/null and b/public/images/pokemon/icons/variant/8/841_3.png differ diff --git a/public/images/pokemon/icons/variant/8/842-gigantamax_2.png b/public/images/pokemon/icons/variant/8/842-gigantamax_2.png new file mode 100644 index 00000000000..aaed8081eec Binary files /dev/null and b/public/images/pokemon/icons/variant/8/842-gigantamax_2.png differ diff --git a/public/images/pokemon/icons/variant/8/842-gigantamax_3.png b/public/images/pokemon/icons/variant/8/842-gigantamax_3.png new file mode 100644 index 00000000000..3ae323c8677 Binary files /dev/null and b/public/images/pokemon/icons/variant/8/842-gigantamax_3.png differ diff --git a/public/images/pokemon/icons/variant/8/842_2.png b/public/images/pokemon/icons/variant/8/842_2.png new file mode 100644 index 00000000000..87de609f819 Binary files /dev/null and b/public/images/pokemon/icons/variant/8/842_2.png differ diff --git a/public/images/pokemon/icons/variant/8/842_3.png b/public/images/pokemon/icons/variant/8/842_3.png new file mode 100644 index 00000000000..15dfe7ea02c Binary files /dev/null and b/public/images/pokemon/icons/variant/8/842_3.png differ diff --git a/public/images/pokemon/icons/variant/8/871_2.png b/public/images/pokemon/icons/variant/8/871_2.png new file mode 100644 index 00000000000..719ee1eb3a9 Binary files /dev/null and b/public/images/pokemon/icons/variant/8/871_2.png differ diff --git a/public/images/pokemon/icons/variant/8/871_3.png b/public/images/pokemon/icons/variant/8/871_3.png new file mode 100644 index 00000000000..0d8227b722a Binary files /dev/null and b/public/images/pokemon/icons/variant/8/871_3.png differ diff --git a/public/images/pokemon/icons/variant/9/1011_2.png b/public/images/pokemon/icons/variant/9/1011_2.png new file mode 100644 index 00000000000..01abc1a8e65 Binary files /dev/null and b/public/images/pokemon/icons/variant/9/1011_2.png differ diff --git a/public/images/pokemon/icons/variant/9/1011_3.png b/public/images/pokemon/icons/variant/9/1011_3.png new file mode 100644 index 00000000000..fa5e3e35135 Binary files /dev/null and b/public/images/pokemon/icons/variant/9/1011_3.png differ diff --git a/public/images/pokemon/icons/variant/9/1019_2.png b/public/images/pokemon/icons/variant/9/1019_2.png new file mode 100644 index 00000000000..671ae3f6552 Binary files /dev/null and b/public/images/pokemon/icons/variant/9/1019_2.png differ diff --git a/public/images/pokemon/icons/variant/9/1019_3.png b/public/images/pokemon/icons/variant/9/1019_3.png new file mode 100644 index 00000000000..0569b3e84b6 Binary files /dev/null and b/public/images/pokemon/icons/variant/9/1019_3.png differ diff --git a/public/images/pokemon/shiny/782.json b/public/images/pokemon/shiny/782.json index 0147fd611c2..8b4336549f1 100644 --- a/public/images/pokemon/shiny/782.json +++ b/public/images/pokemon/shiny/782.json @@ -1,41 +1,1010 @@ -{ - "textures": [ - { - "image": "782.png", - "format": "RGBA8888", - "size": { - "w": 50, - "h": 50 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 46, - "h": 50 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 46, - "h": 50 - }, - "frame": { - "x": 0, - "y": 0, - "w": 46, - "h": 50 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:a551362c468e8c1d1846087d45955da3:43093a2fa7dce85b50a7790b1ef2c6b0:d07862436676aa228a148ee1f1d82a8f$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0002.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0003.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0004.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0005.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0006.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0007.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0008.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0009.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0010.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0011.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0012.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0013.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0014.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0015.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0016.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0017.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0018.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0019.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0020.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0021.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0022.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0023.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0024.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0025.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0026.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0027.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0028.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0029.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0030.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0031.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0032.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0033.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0034.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0035.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0036.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0037.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0038.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0039.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0040.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0041.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0042.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0043.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0044.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0045.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0046.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0047.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0048.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0049.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0050.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0051.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0052.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0053.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0054.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0055.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0056.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0057.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0058.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0059.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0060.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0061.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0062.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0063.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0064.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0065.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0066.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0067.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0068.png", + "frame": { "x": 94, "y": 105, "w": 45, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0069.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0070.png", + "frame": { "x": 47, "y": 155, "w": 46, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0071.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0072.png", + "frame": { "x": 140, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0073.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0074.png", + "frame": { "x": 93, "y": 156, "w": 47, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0075.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0076.png", + "frame": { "x": 186, "y": 156, "w": 46, "h": 47 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0077.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0078.png", + "frame": { "x": 1, "y": 105, "w": 47, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0079.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0080.png", + "frame": { "x": 1, "y": 154, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0081.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0082.png", + "frame": { "x": 48, "y": 105, "w": 46, "h": 50 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0083.png", + "frame": { "x": 142, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0084.png", + "frame": { "x": 189, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0085.png", + "frame": { "x": 1, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0086.png", + "frame": { "x": 48, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0087.png", + "frame": { "x": 185, "y": 104, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0088.png", + "frame": { "x": 185, "y": 104, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0089.png", + "frame": { "x": 142, "y": 52, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0090.png", + "frame": { "x": 188, "y": 52, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0091.png", + "frame": { "x": 1, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0092.png", + "frame": { "x": 47, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0093.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0094.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0095.png", + "frame": { "x": 185, "y": 104, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0096.png", + "frame": { "x": 185, "y": 104, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0097.png", + "frame": { "x": 93, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0098.png", + "frame": { "x": 93, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0099.png", + "frame": { "x": 47, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0100.png", + "frame": { "x": 47, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0101.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0102.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0103.png", + "frame": { "x": 95, "y": 1, "w": 47, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0104.png", + "frame": { "x": 185, "y": 104, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0105.png", + "frame": { "x": 185, "y": 104, "w": 45, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0106.png", + "frame": { "x": 93, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0107.png", + "frame": { "x": 93, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0108.png", + "frame": { "x": 1, "y": 53, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0109.png", + "frame": { "x": 139, "y": 104, "w": 46, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0110.png", + "frame": { "x": 189, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + }, + { + "filename": "0111.png", + "frame": { "x": 142, "y": 1, "w": 47, "h": 51 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, + "sourceSize": { "w": 96, "h": 96 }, + "duration": 50 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "782.png", + "format": "I8", + "size": { "w": 237, "h": 205 }, + "scale": "1" + } } diff --git a/public/images/pokemon/shiny/782.png b/public/images/pokemon/shiny/782.png index 79ce0d6289a..be4689a7cc5 100644 Binary files a/public/images/pokemon/shiny/782.png and b/public/images/pokemon/shiny/782.png differ diff --git a/public/images/pokemon/shiny/783.json b/public/images/pokemon/shiny/783.json index cba4888951b..0d3815a6ecf 100644 --- a/public/images/pokemon/shiny/783.json +++ b/public/images/pokemon/shiny/783.json @@ -1,41 +1,965 @@ -{ - "textures": [ - { - "image": "783.png", - "format": "RGBA8888", - "size": { - "w": 69, - "h": 69 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 61, - "h": 69 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 61, - "h": 69 - }, - "frame": { - "x": 0, - "y": 0, - "w": 61, - "h": 69 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:46608dec6728e687aeafbeda288354f0:c18ca883404bc368fe53932c65d95dd1:aab166e28c744865a0296041224dd01b$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 64, "y": 208, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0002.png", + "frame": { "x": 326, "y": 142, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0003.png", + "frame": { "x": 1, "y": 71, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0004.png", + "frame": { "x": 412, "y": 71, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0005.png", + "frame": { "x": 276, "y": 68, "w": 64, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 0, "w": 64, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0006.png", + "frame": { "x": 340, "y": 72, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0007.png", + "frame": { "x": 476, "y": 137, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0008.png", + "frame": { "x": 403, "y": 141, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0009.png", + "frame": { "x": 308, "y": 211, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0010.png", + "frame": { "x": 299, "y": 280, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0011.png", + "frame": { "x": 471, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0012.png", + "frame": { "x": 415, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0013.png", + "frame": { "x": 228, "y": 413, "w": 56, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 56, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0014.png", + "frame": { "x": 1, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0015.png", + "frame": { "x": 358, "y": 347, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0016.png", + "frame": { "x": 508, "y": 275, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0017.png", + "frame": { "x": 64, "y": 208, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0018.png", + "frame": { "x": 326, "y": 142, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0019.png", + "frame": { "x": 1, "y": 71, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0020.png", + "frame": { "x": 412, "y": 71, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0021.png", + "frame": { "x": 276, "y": 68, "w": 64, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 0, "w": 64, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0022.png", + "frame": { "x": 340, "y": 72, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0023.png", + "frame": { "x": 476, "y": 137, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0024.png", + "frame": { "x": 403, "y": 141, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0025.png", + "frame": { "x": 308, "y": 211, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0026.png", + "frame": { "x": 299, "y": 280, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0027.png", + "frame": { "x": 471, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0028.png", + "frame": { "x": 415, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0029.png", + "frame": { "x": 228, "y": 413, "w": 56, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 56, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0030.png", + "frame": { "x": 1, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0031.png", + "frame": { "x": 358, "y": 347, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0032.png", + "frame": { "x": 508, "y": 275, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0033.png", + "frame": { "x": 64, "y": 208, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0034.png", + "frame": { "x": 326, "y": 142, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0035.png", + "frame": { "x": 1, "y": 71, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0036.png", + "frame": { "x": 412, "y": 71, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0037.png", + "frame": { "x": 276, "y": 68, "w": 64, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 0, "w": 64, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0038.png", + "frame": { "x": 340, "y": 72, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0039.png", + "frame": { "x": 476, "y": 137, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0040.png", + "frame": { "x": 403, "y": 141, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0041.png", + "frame": { "x": 308, "y": 211, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0042.png", + "frame": { "x": 299, "y": 280, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0043.png", + "frame": { "x": 471, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0044.png", + "frame": { "x": 415, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0045.png", + "frame": { "x": 228, "y": 413, "w": 56, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 56, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0046.png", + "frame": { "x": 1, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0047.png", + "frame": { "x": 358, "y": 347, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0048.png", + "frame": { "x": 508, "y": 275, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0049.png", + "frame": { "x": 64, "y": 208, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0050.png", + "frame": { "x": 326, "y": 142, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0051.png", + "frame": { "x": 1, "y": 71, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0052.png", + "frame": { "x": 412, "y": 71, "w": 64, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 64, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0053.png", + "frame": { "x": 276, "y": 68, "w": 64, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 0, "w": 64, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0054.png", + "frame": { "x": 340, "y": 72, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0055.png", + "frame": { "x": 476, "y": 137, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0056.png", + "frame": { "x": 403, "y": 141, "w": 62, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 62, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0057.png", + "frame": { "x": 308, "y": 211, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0058.png", + "frame": { "x": 299, "y": 280, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0059.png", + "frame": { "x": 471, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0060.png", + "frame": { "x": 415, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0061.png", + "frame": { "x": 228, "y": 413, "w": 56, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 5, "w": 56, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0062.png", + "frame": { "x": 1, "y": 412, "w": 56, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 56, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0063.png", + "frame": { "x": 358, "y": 347, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0064.png", + "frame": { "x": 508, "y": 275, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0065.png", + "frame": { "x": 247, "y": 208, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0066.png", + "frame": { "x": 448, "y": 275, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0067.png", + "frame": { "x": 368, "y": 279, "w": 59, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 59, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0068.png", + "frame": { "x": 173, "y": 346, "w": 57, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 57, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0069.png", + "frame": { "x": 239, "y": 277, "w": 60, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 60, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0070.png", + "frame": { "x": 1, "y": 209, "w": 63, "h": 66 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 3, "w": 63, "h": 66 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0071.png", + "frame": { "x": 478, "y": 1, "w": 68, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 3, "w": 68, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0072.png", + "frame": { "x": 276, "y": 1, "w": 70, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 70, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0073.png", + "frame": { "x": 70, "y": 1, "w": 71, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 71, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0074.png", + "frame": { "x": 208, "y": 1, "w": 68, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 68, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0075.png", + "frame": { "x": 208, "y": 70, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0076.png", + "frame": { "x": 64, "y": 208, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0077.png", + "frame": { "x": 65, "y": 138, "w": 63, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 1, "w": 63, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0078.png", + "frame": { "x": 412, "y": 1, "w": 66, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 66, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0079.png", + "frame": { "x": 1, "y": 1, "w": 69, "h": 70 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 69, "h": 70 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0080.png", + "frame": { "x": 141, "y": 1, "w": 67, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 0, "w": 67, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0081.png", + "frame": { "x": 346, "y": 1, "w": 66, "h": 71 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 0, "w": 66, "h": 71 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0082.png", + "frame": { "x": 239, "y": 344, "w": 57, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 57, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0083.png", + "frame": { "x": 57, "y": 414, "w": 54, "h": 67 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 54, "h": 67 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0084.png", + "frame": { "x": 173, "y": 413, "w": 55, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 55, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0085.png", + "frame": { "x": 296, "y": 348, "w": 55, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 55, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0086.png", + "frame": { "x": 59, "y": 345, "w": 57, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 57, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0087.png", + "frame": { "x": 64, "y": 208, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0088.png", + "frame": { "x": 263, "y": 139, "w": 63, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 63, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0089.png", + "frame": { "x": 70, "y": 69, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0090.png", + "frame": { "x": 121, "y": 277, "w": 59, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 59, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0091.png", + "frame": { "x": 186, "y": 208, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0092.png", + "frame": { "x": 200, "y": 139, "w": 63, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 63, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0093.png", + "frame": { "x": 478, "y": 68, "w": 65, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 65, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0094.png", + "frame": { "x": 427, "y": 343, "w": 58, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 58, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0095.png", + "frame": { "x": 125, "y": 208, "w": 61, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 2, "w": 61, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0096.png", + "frame": { "x": 128, "y": 140, "w": 63, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 63, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0097.png", + "frame": { "x": 135, "y": 72, "w": 65, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 65, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0098.png", + "frame": { "x": 1, "y": 344, "w": 58, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 58, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0099.png", + "frame": { "x": 61, "y": 277, "w": 60, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 3, "w": 60, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0100.png", + "frame": { "x": 465, "y": 207, "w": 62, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 62, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0101.png", + "frame": { "x": 1, "y": 141, "w": 63, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 63, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0102.png", + "frame": { "x": 116, "y": 346, "w": 57, "h": 68 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 3, "w": 57, "h": 68 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0103.png", + "frame": { "x": 485, "y": 343, "w": 58, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 58, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0104.png", + "frame": { "x": 180, "y": 277, "w": 59, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 59, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0105.png", + "frame": { "x": 1, "y": 275, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + }, + { + "filename": "0106.png", + "frame": { "x": 388, "y": 210, "w": 60, "h": 69 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 2, "w": 60, "h": 69 }, + "sourceSize": { "w": 76, "h": 71 }, + "duration": 100 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "783.png", + "format": "I8", + "size": { "w": 569, "h": 482 }, + "scale": "1" + } } diff --git a/public/images/pokemon/shiny/783.png b/public/images/pokemon/shiny/783.png index 6d49131f69d..b14d064e998 100644 Binary files a/public/images/pokemon/shiny/783.png and b/public/images/pokemon/shiny/783.png differ diff --git a/public/images/pokemon/shiny/784.json b/public/images/pokemon/shiny/784.json index fdf96d2b111..b69481e9732 100644 --- a/public/images/pokemon/shiny/784.json +++ b/public/images/pokemon/shiny/784.json @@ -1,41 +1,812 @@ -{ - "textures": [ - { - "image": "784.png", - "format": "RGBA8888", - "size": { - "w": 81, - "h": 81 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 79, - "h": 81 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 79, - "h": 81 - }, - "frame": { - "x": 0, - "y": 0, - "w": 79, - "h": 81 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:6096bcc779e33e1df807da48a8d58c7f:483f9130a6e530e32c532c6bacf9c317:c2f7ca3ab1075b8c824730653d891244$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 254, "y": 238, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0002.png", + "frame": { "x": 373, "y": 162, "w": 84, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 84, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0003.png", + "frame": { "x": 285, "y": 157, "w": 88, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 4, "w": 88, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0004.png", + "frame": { "x": 104, "y": 78, "w": 94, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 94, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0005.png", + "frame": { "x": 414, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0006.png", + "frame": { "x": 1, "y": 1, "w": 103, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 103, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0007.png", + "frame": { "x": 104, "y": 1, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0008.png", + "frame": { "x": 208, "y": 1, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0009.png", + "frame": { "x": 310, "y": 77, "w": 96, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 5, "w": 96, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0010.png", + "frame": { "x": 406, "y": 80, "w": 89, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 89, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0011.png", + "frame": { "x": 495, "y": 161, "w": 82, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 82, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0012.png", + "frame": { "x": 649, "y": 324, "w": 77, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 77, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0013.png", + "frame": { "x": 155, "y": 327, "w": 76, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 6, "w": 76, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0014.png", + "frame": { "x": 394, "y": 325, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 5, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0015.png", + "frame": { "x": 571, "y": 324, "w": 78, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 78, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0016.png", + "frame": { "x": 161, "y": 246, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0017.png", + "frame": { "x": 254, "y": 238, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0018.png", + "frame": { "x": 373, "y": 162, "w": 84, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 84, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0019.png", + "frame": { "x": 285, "y": 157, "w": 88, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 4, "w": 88, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0020.png", + "frame": { "x": 104, "y": 78, "w": 94, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 94, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0021.png", + "frame": { "x": 414, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0022.png", + "frame": { "x": 1, "y": 1, "w": 103, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 103, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0023.png", + "frame": { "x": 104, "y": 1, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0024.png", + "frame": { "x": 208, "y": 1, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0025.png", + "frame": { "x": 310, "y": 77, "w": 96, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 5, "w": 96, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0026.png", + "frame": { "x": 406, "y": 80, "w": 89, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 89, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0027.png", + "frame": { "x": 495, "y": 161, "w": 82, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 82, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0028.png", + "frame": { "x": 649, "y": 324, "w": 77, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 77, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0029.png", + "frame": { "x": 155, "y": 327, "w": 76, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 6, "w": 76, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0030.png", + "frame": { "x": 394, "y": 325, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 5, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0031.png", + "frame": { "x": 571, "y": 324, "w": 78, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 78, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0032.png", + "frame": { "x": 161, "y": 246, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0033.png", + "frame": { "x": 254, "y": 238, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0034.png", + "frame": { "x": 373, "y": 162, "w": 84, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 84, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0035.png", + "frame": { "x": 285, "y": 157, "w": 88, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 4, "w": 88, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0036.png", + "frame": { "x": 104, "y": 78, "w": 94, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 94, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0037.png", + "frame": { "x": 414, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0038.png", + "frame": { "x": 1, "y": 1, "w": 103, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 103, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0039.png", + "frame": { "x": 104, "y": 1, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0040.png", + "frame": { "x": 208, "y": 1, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0041.png", + "frame": { "x": 310, "y": 77, "w": 96, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 5, "w": 96, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0042.png", + "frame": { "x": 406, "y": 80, "w": 89, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 89, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0043.png", + "frame": { "x": 495, "y": 161, "w": 82, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 82, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0044.png", + "frame": { "x": 649, "y": 324, "w": 77, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 77, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0045.png", + "frame": { "x": 155, "y": 327, "w": 76, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 6, "w": 76, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0046.png", + "frame": { "x": 394, "y": 325, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 5, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0047.png", + "frame": { "x": 571, "y": 324, "w": 78, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 78, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0048.png", + "frame": { "x": 161, "y": 246, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0049.png", + "frame": { "x": 254, "y": 238, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0050.png", + "frame": { "x": 373, "y": 162, "w": 84, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 4, "w": 84, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0051.png", + "frame": { "x": 285, "y": 157, "w": 88, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 4, "w": 88, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0052.png", + "frame": { "x": 104, "y": 78, "w": 94, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 94, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0053.png", + "frame": { "x": 414, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0054.png", + "frame": { "x": 1, "y": 1, "w": 103, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 103, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0055.png", + "frame": { "x": 104, "y": 1, "w": 104, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 8, "w": 104, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0056.png", + "frame": { "x": 208, "y": 1, "w": 102, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 7, "w": 102, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0057.png", + "frame": { "x": 310, "y": 77, "w": 96, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 1, "y": 5, "w": 96, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0058.png", + "frame": { "x": 406, "y": 80, "w": 89, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 3, "w": 89, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0059.png", + "frame": { "x": 495, "y": 161, "w": 82, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 82, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0060.png", + "frame": { "x": 649, "y": 324, "w": 77, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 77, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0061.png", + "frame": { "x": 155, "y": 327, "w": 76, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 6, "w": 76, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0062.png", + "frame": { "x": 394, "y": 325, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 5, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0063.png", + "frame": { "x": 571, "y": 324, "w": 78, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 78, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0064.png", + "frame": { "x": 161, "y": 246, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0065.png", + "frame": { "x": 81, "y": 240, "w": 80, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 80, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0066.png", + "frame": { "x": 577, "y": 162, "w": 83, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 83, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0067.png", + "frame": { "x": 1, "y": 158, "w": 89, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 5, "w": 89, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0068.png", + "frame": { "x": 1, "y": 79, "w": 95, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 6, "w": 95, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0069.png", + "frame": { "x": 612, "y": 1, "w": 100, "h": 78 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 7, "w": 100, "h": 78 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0070.png", + "frame": { "x": 310, "y": 1, "w": 104, "h": 76 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 9, "w": 104, "h": 76 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0071.png", + "frame": { "x": 513, "y": 1, "w": 99, "h": 79 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 6, "w": 99, "h": 79 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0072.png", + "frame": { "x": 495, "y": 80, "w": 90, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 14, "y": 4, "w": 90, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0073.png", + "frame": { "x": 612, "y": 79, "w": 88, "h": 83 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 2, "w": 88, "h": 83 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0074.png", + "frame": { "x": 198, "y": 79, "w": 87, "h": 85 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 0, "w": 87, "h": 85 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0075.png", + "frame": { "x": 90, "y": 158, "w": 84, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 8, "y": 3, "w": 84, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0076.png", + "frame": { "x": 471, "y": 325, "w": 76, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 5, "w": 76, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0077.png", + "frame": { "x": 77, "y": 403, "w": 75, "h": 74 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 14, "w": 75, "h": 74 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0078.png", + "frame": { "x": 231, "y": 400, "w": 75, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 7, "w": 75, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0079.png", + "frame": { "x": 1, "y": 402, "w": 76, "h": 77 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 9, "w": 76, "h": 77 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0080.png", + "frame": { "x": 317, "y": 325, "w": 77, "h": 80 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 6, "w": 77, "h": 80 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0081.png", + "frame": { "x": 239, "y": 319, "w": 78, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 5, "w": 78, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0082.png", + "frame": { "x": 174, "y": 164, "w": 80, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 4, "w": 80, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0083.png", + "frame": { "x": 1, "y": 238, "w": 80, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 80, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0084.png", + "frame": { "x": 334, "y": 243, "w": 79, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 3, "w": 79, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0085.png", + "frame": { "x": 1, "y": 320, "w": 77, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 3, "w": 77, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0086.png", + "frame": { "x": 78, "y": 321, "w": 77, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 3, "w": 77, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0087.png", + "frame": { "x": 413, "y": 243, "w": 79, "h": 82 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 3, "w": 79, "h": 82 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0088.png", + "frame": { "x": 577, "y": 243, "w": 79, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 4, "w": 79, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + }, + { + "filename": "0089.png", + "frame": { "x": 492, "y": 244, "w": 79, "h": 81 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 4, "w": 79, "h": 81 }, + "sourceSize": { "w": 108, "h": 88 }, + "duration": 100 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.13-x64", + "image": "784.png", + "format": "I8", + "size": { "w": 727, "h": 481 }, + "scale": "1" + } } diff --git a/public/images/pokemon/shiny/784.png b/public/images/pokemon/shiny/784.png index 57cf7a67747..f9f5813e1c2 100644 Binary files a/public/images/pokemon/shiny/784.png and b/public/images/pokemon/shiny/784.png differ diff --git a/public/images/pokemon/variant/1011.json b/public/images/pokemon/variant/1011.json new file mode 100644 index 00000000000..cbb4be4e207 --- /dev/null +++ b/public/images/pokemon/variant/1011.json @@ -0,0 +1,36 @@ +{ + "1": { + "fd9477": "63b9b9", + "e64d3c": "397880", + "a28339": "5a4385", + "477d45": "67698b", + "b09579": "8ea1b4", + "f5e279": "f0d3f9", + "253922": "232b3a", + "345539": "313d4b", + "d1b147": "c998e2", + "9c1e2a": "272a52", + "7eb36a": "9aa0b3", + "9fc164": "9aa0b3", + "8e9960": "67698b", + "c73030": "2b526f", + "61071f": "190e2e" + }, + "2": { + "fd9477": "f3efde", + "e64d3c": "eee0bc", + "a28339": "2e2246", + "477d45": "903c4e", + "b09579": "b49c98", + "f5e279": "589df3", + "253922": "2e0920", + "345539": "4f162a", + "d1b147": "354dbf", + "9c1e2a": "9c564c", + "7eb36a": "e28c95", + "9fc164": "e28c95", + "8e9960": "b0526f", + "c73030": "d1a87e", + "61071f": "571818" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/1019.json b/public/images/pokemon/variant/1019.json new file mode 100644 index 00000000000..2d5a5f699c6 --- /dev/null +++ b/public/images/pokemon/variant/1019.json @@ -0,0 +1,46 @@ +{ + "1": { + "9c0808": "70a2c5", + "b91d1d": "abd7e2", + "746739": "69348b", + "6ba835": "7a7c9e", + "9ce05f": "9aa0b3", + "d43e2d": "4e969e", + "841111": "302752", + "b11717": "663267", + "680606": "065e68", + "ff7a59": "69c5c5", + "c59588": "9c2e72", + "2d6127": "7f58af", + "b72629": "2b526f", + "b59a7d": "a3b9d0", + "82664a": "48476c", + "ffce5e": "d69ae8", + "3e662b": "313846", + "dcbfab": "c55885", + "e9cfb3": "dcebf9", + "3c9b3e": "e8edff" + }, + "2": { + "9c0808": "bfb5ab", + "b91d1d": "dcd9d1", + "746739": "312374", + "6ba835": "a8546e", + "9ce05f": "e28c95", + "d43e2d": "eedfb8", + "841111": "4b211b", + "b11717": "63473b", + "680606": "68403b", + "ff7a59": "f3efde", + "c59588": "402622", + "2d6127": "2e2b8b", + "b72629": "bf9870", + "b59a7d": "cbb4af", + "82664a": "613838", + "ffce5e": "688ce8", + "3e662b": "341c1c", + "dcbfab": "5d4c45", + "e9cfb3": "e2dcd6", + "3c9b3e": "5e75e2" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/143-gigantamax.json b/public/images/pokemon/variant/143-gigantamax.json new file mode 100644 index 00000000000..c6e5312d330 --- /dev/null +++ b/public/images/pokemon/variant/143-gigantamax.json @@ -0,0 +1,50 @@ +{ + "1": { + "101010": "101010", + "5f3c18": "544a41", + "5e3e1d": "351b52", + "31573f": "7b59ba", + "54792b": "c06386", + "103941": "701a55", + "315a7b": "943469", + "bd3740": "c94489", + "a3704e": "522663", + "a47352": "6b6357", + "ad7f5f": "b56564", + "de5656": "d65a8a", + "069f5f": "b083de", + "89b432": "f1a1b2", + "bbe35b": "f1a1b2", + "98a0a0": "98a0a0", + "a0a0a0": "a0a0a0", + "fc8b9f": "ed7794", + "e6c5ac": "cf8880", + "f6e6bd": "f0beb1", + "c9c9c9": "c9c9c9", + "f4f4f4": "f4f4f4" + }, + "2": { + "101010": "101010", + "5f3c18": "ba6632", + "5e3e1d": "c2986e", + "31573f": "4b4c52", + "54792b": "208073", + "103941": "93b5c2", + "315a7b": "b6d6d9", + "bd3740": "9e4619", + "a3704e": "e6cda1", + "a47352": "cf9d48", + "ad7f5f": "284878", + "de5656": "bd742b", + "069f5f": "7c7c82", + "89b432": "37ad82", + "bbe35b": "79e0a2", + "98a0a0": "53738a", + "a0a0a0": "abd1cc", + "fc8b9f": "d9a443", + "e6c5ac": "27538a", + "f6e6bd": "36719c", + "c9c9c9": "b4d3d9", + "f4f4f4": "f4f4f4" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/143.json b/public/images/pokemon/variant/143.json new file mode 100644 index 00000000000..b4e32403fc6 --- /dev/null +++ b/public/images/pokemon/variant/143.json @@ -0,0 +1,38 @@ +{ + "1": { + "000000": "101010", + "634221": "351b52", + "103a42": "701a55", + "3a3d47": "41201e", + "3d3d47": "756363", + "315a7b": "943469", + "8a6455": "91504e", + "a67351": "522663", + "a57352": "9e5755", + "528cad": "ad4b70", + "73a5bd": "cc6c84", + "e6c5ad": "cf8880", + "f7d6bd": "e09f96", + "f7e6bd": "f0beb1", + "cecece": "cbc4c4", + "ffffff": "ffffff" + }, + "2": { + "000000": "101010", + "634221": "c2986e", + "103a42": "85adbc", + "3a3d47": "131d39", + "3d3d47": "2b2b32", + "315a7b": "a3cacd", + "8a6455": "192b59", + "a67351": "e6cda1", + "a57352": "1b2e61", + "528cad": "cbe4e2", + "73a5bd": "edf5f4", + "e6c5ad": "284878", + "f7d6bd": "38638f", + "f7e6bd": "457ca8", + "cecece": "bfc7cb", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/187.json b/public/images/pokemon/variant/187.json new file mode 100644 index 00000000000..7e0d1dca511 --- /dev/null +++ b/public/images/pokemon/variant/187.json @@ -0,0 +1,28 @@ +{ + "1": { + "101010": "101010", + "425a10": "934200", + "52843a": "c27600", + "63bd5a": "efac00", + "8c083a": "012a3e", + "9cde5a": "ffdc46", + "b56373": "003e53", + "ff7b94": "006d7f", + "f79cb5": "00a59b", + "ffc500": "e3396c", + "ffff00": "ffa8b6" + }, + "2": { + "101010": "101010", + "425a10": "5f0052", + "52843a": "960070", + "63bd5a": "960070", + "8c083a": "802600", + "9cde5a": "e01c75", + "b56373": "d8591c", + "ff7b94": "fa9600", + "f79cb5": "ffc93b", + "ffc500": "5ec0ec", + "ffff00": "94ecf9" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/188.json b/public/images/pokemon/variant/188.json new file mode 100644 index 00000000000..03edfeb51ff --- /dev/null +++ b/public/images/pokemon/variant/188.json @@ -0,0 +1,30 @@ +{ + "1": { + "000000": "101010", + "196b00": "c66b31", + "42b521": "e99f23", + "63d631": "ffd953", + "8c5200": "004269", + "8cf74a": "fef579", + "b5d6de": "fa9600", + "f7a519": "005883", + "ff6300": "420c78", + "ffd600": "046c90", + "ffef00": "007b9a", + "ffffff": "ffc93b" + }, + "2": { + "000000": "101010", + "196b00": "2659ad", + "42b521": "5293d5", + "63d631": "79d5fa", + "8c5200": "5f0052", + "8cf74a": "a6eafa", + "b5d6de": "fa9600", + "f7a519": "960070", + "ff6300": "86005c", + "ffd600": "ba0071", + "ffef00": "e01c75", + "ffffff": "ffc93b" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/189.json b/public/images/pokemon/variant/189.json new file mode 100644 index 00000000000..7166d9ac513 --- /dev/null +++ b/public/images/pokemon/variant/189.json @@ -0,0 +1,38 @@ +{ + "1": { + "101010": "101010", + "194a73": "b64d21", + "c53142": "405b8f", + "ef4252": "6781a4", + "29844a": "83839f", + "b58c31": "071a3c", + "d6bd5a": "282773", + "84ce7b": "c1bdd1", + "3a73c5": "e19903", + "ded67b": "ded67b", + "efe69c": "104f80", + "8cb5ff": "f9f870", + "ffffde": "2faac4", + "ffffee": "ffffee", + "fff7b5": "1379a0", + "739cff": "fcd936" + }, + "2": { + "101010": "101010", + "194a73": "680054", + "c53142": "3887d2", + "ef4252": "58c1ea", + "29844a": "3887d3", + "b58c31": "da5014", + "d6bd5a": "f06f22", + "84ce7b": "58c1eb", + "3a73c5": "980062", + "ded67b": "ded67b", + "efe69c": "ffa747", + "8cb5ff": "e4486a", + "ffffde": "f9f29b", + "ffffee": "ffffee", + "fff7b5": "ffd45a", + "739cff": "d20d6a" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/2037.json b/public/images/pokemon/variant/2037.json new file mode 100644 index 00000000000..2c190d5d36a --- /dev/null +++ b/public/images/pokemon/variant/2037.json @@ -0,0 +1,26 @@ +{ + "1": { + "151515": "101010", + "2d57bb": "235dc4", + "558b9f": "9f435d", + "648082": "6e67b0", + "6cb1db": "3daae0", + "97bdd2": "ffa8b8", + "c1d1d2": "b3b8ea", + "d9e9f4": "ffd3e1", + "fdfdfd": "d7d9f9", + "ffffff": "ffffff" + }, + "2": { + "151515": "101010", + "2d57bb": "6e1179", + "558b9f": "90215e", + "648082": "bf4747", + "6cb1db": "8832a0", + "97bdd2": "da4e75", + "c1d1d2": "ffc07b", + "d9e9f4": "ff8489", + "fdfdfd": "ffe6a0", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/2038.json b/public/images/pokemon/variant/2038.json new file mode 100644 index 00000000000..845c45f7887 --- /dev/null +++ b/public/images/pokemon/variant/2038.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "4d5c78": "394880", + "516077": "9f435d", + "007ab5": "2380c4", + "38858d": "e35ea2", + "7a8a9c": "6172ab", + "66b3d7": "3dbfe0", + "86a8c0": "e27495", + "81c2c5": "ff89c0", + "bdcbd7": "a7ade7", + "a1e1de": "ffb6e5", + "b0d3ea": "ffa8b8", + "eafefe": "ffd3e1", + "fdfdfd": "bec6ef", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "4d5c78": "73174a", + "516077": "bb3c3c", + "007ab5": "882493", + "38858d": "572746", + "7a8a9c": "90215e", + "66b3d7": "a044ab", + "86a8c0": "ff824c", + "81c2c5": "75355e", + "bdcbd7": "da426d", + "a1e1de": "93547c", + "b0d3ea": "ffbf6b", + "eafefe": "ffe28c", + "fdfdfd": "ff6f86", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/204.json b/public/images/pokemon/variant/204.json new file mode 100644 index 00000000000..19494090ac5 --- /dev/null +++ b/public/images/pokemon/variant/204.json @@ -0,0 +1,20 @@ +{ + "1": { + "84d6d6": "c1cd7d", + "b5eff7": "e3e796", + "3a73a5": "74a057", + "942900": "cc5c1c", + "294a7b": "4b7641", + "52adb5": "a4b76b", + "ff4a3a": "f68b31" + }, + "2": { + "84d6d6": "eda6ae", + "b5eff7": "f7dcd7", + "3a73a5": "b43469", + "942900": "1eaaaa", + "294a7b": "700a4b", + "52adb5": "d46b84", + "ff4a3a": "36cfbb" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/205.json b/public/images/pokemon/variant/205.json new file mode 100644 index 00000000000..06e56b61f61 --- /dev/null +++ b/public/images/pokemon/variant/205.json @@ -0,0 +1,26 @@ +{ + "1": { + "847b9c": "103b2c", + "f7deef": "5b965b", + "e6cef7": "3e7745", + "6b6b6b": "53af4a", + "ff9c9c": "ffb356", + "ffffff": "91c25e", + "841031": "af3b11", + "f76373": "f68b31", + "bd2942": "d8681e", + "524263": "04211a", + "c5a5de": "205639" + }, + "2": { + "847b9c": "962a41", + "f7deef": "f7e2d7", + "e6cef7": "e9b1a0", + "ff9c9c": "b0f5ee", + "841031": "0e2667", + "f76373": "6bbfd2", + "bd2942": "2c6094", + "524263": "691338", + "c5a5de": "c86554" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/207.json b/public/images/pokemon/variant/207.json index 63e1098713a..7d1ff05493d 100644 --- a/public/images/pokemon/variant/207.json +++ b/public/images/pokemon/variant/207.json @@ -1,32 +1,26 @@ { "1": { - "63314a": "7f4812", - "e6a5ce": "f8dd84", - "101010": "101010", - "ad6394": "b67322", "de84b5": "daa93f", - "4a5a73": "4a5a73", - "ffffff": "ffffff", - "adbdc5": "adbdc5", - "bd6b5a": "49a3d2", + "e6a5ce": "f8dd84", + "63314a": "275487", "4a73bd": "3b426f", - "ffa584": "68caed", "294a7b": "1f2142", - "6b9cef": "596596" + "ad6394": "b67322", + "612f48": "7f4812", + "6b9cef": "596596", + "ffa584": "68caed", + "bd6b5a": "49a3d2" }, "2": { - "63314a": "5f1723", - "e6a5ce": "ef6b58", - "101010": "101010", - "ad6394": "97343c", "de84b5": "c04144", - "4a5a73": "4a5a73", - "ffffff": "ffffff", - "adbdc5": "adbdc5", - "bd6b5a": "c86539", + "e6a5ce": "ef6b58", + "63314a": "752d17", "4a73bd": "42bca0", - "ffa584": "f0a452", "294a7b": "33817e", - "6b9cef": "81e4b3" + "ad6394": "97343c", + "612f48": "5f1723", + "6b9cef": "81e4b3", + "ffa584": "f0a452", + "bd6b5a": "c86539" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/299.json b/public/images/pokemon/variant/299.json new file mode 100644 index 00000000000..3b2cd15e3cd --- /dev/null +++ b/public/images/pokemon/variant/299.json @@ -0,0 +1,28 @@ +{ + "1": { + "000000": "101010", + "5a1921": "1f3a30", + "31314a": "6b2710", + "9c314a": "30594a", + "de5252": "487c60", + "ff6b7b": "5a9170", + "42529c": "a14020", + "637bbd": "c66831", + "ff9494": "7fbc7a", + "8ca5e6": "db8644", + "adbdf7": "e09a65" + }, + "2": { + "000000": "101010", + "5a1921": "28163a", + "31314a": "38619e", + "9c314a": "452b5e", + "de5252": "584282", + "ff6b7b": "675398", + "42529c": "68a2cd", + "637bbd": "99e4ee", + "ff9494": "7282c4", + "8ca5e6": "dcfff8", + "adbdf7": "f3fff6" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/313.json b/public/images/pokemon/variant/313.json new file mode 100644 index 00000000000..574574061ce --- /dev/null +++ b/public/images/pokemon/variant/313.json @@ -0,0 +1,36 @@ +{ + "1": { + "4a526b": "9a4013", + "4a4a52": "731509", + "ffe652": "fffa52", + "7b8ca5": "d66d38", + "8c314a": "491c22", + "8c8c94": "d4301b", + "a5b5c5": "eea256", + "f7df4d": "c0f79b", + "f78473": "864a51", + "8c6b52": "845c46", + "deb552": "edc81f", + "7b5d47": "329c38", + "ce3a52": "491c22", + "e65263": "652d32", + "d0a94c": "65c859" + }, + "2": { + "4a526b": "102b2d", + "4a4a52": "1e711a", + "ffe652": "dde6b1", + "7b8ca5": "1e5256", + "8c314a": "0b4569", + "8c8c94": "0ba905", + "a5b5c5": "26686d", + "f7df4d": "ffe798", + "f78473": "5cc3f5", + "8c6b52": "5c713d", + "deb552": "b6d479", + "7b5d47": "bd7a0c", + "ce3a52": "1b8ad0", + "e65263": "2ba5f1", + "d0a94c": "ffca1a" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/314.json b/public/images/pokemon/variant/314.json new file mode 100644 index 00000000000..87852b5a6fa --- /dev/null +++ b/public/images/pokemon/variant/314.json @@ -0,0 +1,36 @@ +{ + "1": { + "56687b": "6b4448", + "5a6b8c": "9a4013", + "8cadce": "d66d38", + "adc5ef": "eea256", + "fbfafa": "ffffff", + "9c52bd": "57272c", + "9c8452": "c38c26", + "6b5a94": "371c21", + "ffe673": "fffa52", + "83a4c5": "a3d0f5", + "7b7b7b": "b82b18", + "e6b54a": "ffda31", + "3a3a3a": "710d00", + "005ad6": "439fec", + "ce8cde": "6a342c" + }, + "2": { + "56687b": "4badea", + "5a6b8c": "70a84f", + "8cadce": "c1db9c", + "adc5ef": "e5edcc", + "fbfafa": "8bfdea", + "9c52bd": "43a3df", + "9c8452": "074656", + "6b5a94": "255b95", + "ffe673": "3dc5d3", + "83a4c5": "ffde93", + "7b7b7b": "155870", + "e6b54a": "019792", + "3a3a3a": "0a2934", + "005ad6": "edb125", + "ce8cde": "77d4ee" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/32.json b/public/images/pokemon/variant/32.json new file mode 100644 index 00000000000..473edcae2af --- /dev/null +++ b/public/images/pokemon/variant/32.json @@ -0,0 +1,34 @@ +{ + "1": { + "101010": "101010", + "006342": "273161", + "63426b": "944f25", + "b51900": "28678a", + "de4229": "42adc1", + "ff6b52": "78d6d3", + "00a573": "3b4d7a", + "9c4aad": "ab5c24", + "bd63c5": "cf863e", + "19ce9c": "55729e", + "e69cd6": "e0c151", + "efbdef": "ede4ab", + "cecece": "cecece", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "006342": "b0384a", + "63426b": "142440", + "b51900": "b86527", + "de4229": "e1b13b", + "ff6b52": "eddd95", + "00a573": "d65e64", + "9c4aad": "133257", + "bd63c5": "253f5e", + "19ce9c": "ed938e", + "e69cd6": "375c73", + "efbdef": "5d91a1", + "cecece": "cecece", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/325.json b/public/images/pokemon/variant/325.json new file mode 100644 index 00000000000..e8c6641defc --- /dev/null +++ b/public/images/pokemon/variant/325.json @@ -0,0 +1,26 @@ +{ + "1": { + "ef84ad": "5ca0b5", + "f7a5bd": "6ac5c8", + "c5637b": "3c6b95", + "ffd6e6": "b4e6e7", + "6b6b7b": "2e7320", + "7b7b8c": "559b43", + "5a5a73": "7dbc53", + "3a4252": "18340c", + "a53a42": "2b4d7d", + "a5a5ad": "b5d780" + }, + "2": { + "ef84ad": "1f6759", + "f7a5bd": "379a85", + "c5637b": "144844", + "ffd6e6": "8dd6ab", + "6b6b7b": "72442d", + "7b7b8c": "dca878", + "5a5a73": "a7724a", + "3a4252": "72442d", + "a53a42": "0c2625", + "a5a5ad": "fbe3a3" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/326.json b/public/images/pokemon/variant/326.json new file mode 100644 index 00000000000..11e02009a26 --- /dev/null +++ b/public/images/pokemon/variant/326.json @@ -0,0 +1,32 @@ +{ + "1": { + "9c9ca5": "7ecdd1", + "d684ce": "7bb15b", + "636373": "3c6b95", + "ef7b94": "e99e76", + "f7bdf7": "bbfcf8", + "bd63ad": "559b43", + "a5425a": "a84331", + "f7a5b5": "f7d1a0", + "6b426b": "18340c", + "ce5a7b": "d06d50", + "e6a5de": "b5d780", + "4a4a52": "2b4d7d", + "7b7b84": "5ca0b5" + }, + "2": { + "9c9ca5": "fffade", + "d684ce": "67508c", + "636373": "e8bc75", + "ef7b94": "379a85", + "f7bdf7": "b395de", + "bd63ad": "574285", + "a5425a": "144844", + "f7a5b5": "5cba98", + "6b426b": "081f19", + "ce5a7b": "1f6759", + "e6a5de": "7a649c", + "4a4a52": "d08f55", + "7b7b84": "fbefb3" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/33.json b/public/images/pokemon/variant/33.json new file mode 100644 index 00000000000..331220de9ef --- /dev/null +++ b/public/images/pokemon/variant/33.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "5a3a63": "944f25", + "b51900": "b51900", + "de4229": "de4229", + "845a52": "42adc1", + "009463": "273161", + "945ab5": "cf863e", + "4acea5": "55729e", + "848484": "848484", + "ce84de": "e0c151", + "e6adef": "ede4ab", + "c5c5c5": "c5c5c5", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "5a3a63": "142440", + "b51900": "d98943", + "de4229": "edc85a", + "845a52": "e1b13b", + "009463": "b0384a", + "945ab5": "253f5e", + "4acea5": "ed938e", + "848484": "848484", + "ce84de": "375c73", + "e6adef": "5d91a1", + "c5c5c5": "c5c5c5", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/331.json b/public/images/pokemon/variant/331.json new file mode 100644 index 00000000000..abe5e0cfa6d --- /dev/null +++ b/public/images/pokemon/variant/331.json @@ -0,0 +1,30 @@ +{ + "1": { + "4a7310": "9f2a3f", + "ffe63a": "7aa1df", + "31944a": "b73736", + "215200": "69102c", + "003a10": "4e29c6", + "f7bd19": "448bc3", + "63bd6b": "dd6754", + "196b31": "891d2c", + "94c552": "d76868", + "739c3a": "d74f4f", + "8c6b3a": "123a5a", + "bdde7b": "e67f7f" + }, + "2": { + "4a7310": "6d3494", + "ffe63a": "eaa5c6", + "31944a": "caac82", + "215200": "694426", + "003a10": "5e223f", + "f7bd19": "d979b2", + "63bd6b": "e1d39d", + "196b31": "946e51", + "94c552": "9364a5", + "739c3a": "7c558d", + "8c6b3a": "983364", + "bdde7b": "a772bd" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/332.json b/public/images/pokemon/variant/332.json new file mode 100644 index 00000000000..e9b487bca25 --- /dev/null +++ b/public/images/pokemon/variant/332.json @@ -0,0 +1,34 @@ +{ + "1": { + "319452": "831a1f", + "4a7310": "982443", + "7ba563": "b44040", + "bdef84": "ec8c8c", + "8cbd63": "c54b4b", + "215200": "710f2e", + "a5d674": "e16363", + "196b21": "891222", + "f7ce00": "7aa1df", + "525252": "123a5a", + "63b56b": "b2332f", + "a5d673": "df5252", + "8c6b3a": "448bc3", + "4aa552": "9f2f2c" + }, + "2": { + "319452": "b08d72", + "4a7310": "4f3956", + "7ba563": "704e7e", + "bdef84": "a779ba", + "8cbd63": "e3d7a6", + "215200": "583823", + "a5d674": "8c669b", + "196b21": "78582c", + "f7ce00": "f2aacd", + "525252": "a53b6f", + "63b56b": "cfc191", + "a5d673": "d7cda7", + "8c6b3a": "df87bb", + "4aa552": "c5a77f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/34.json b/public/images/pokemon/variant/34.json new file mode 100644 index 00000000000..748658a6a90 --- /dev/null +++ b/public/images/pokemon/variant/34.json @@ -0,0 +1,44 @@ +{ + "1": { + "101010": "101010", + "5a296b": "7a411d", + "004a63": "273161", + "73735a": "3b447a", + "73735b": "73735b", + "ad1000": "ad1000", + "e64231": "e64231", + "297b94": "3b4d7a", + "a55294": "cf863e", + "d673ef": "e0c151", + "4294c5": "55729e", + "c5c5a5": "6272a8", + "c4c4a7": "c4c4a7", + "c7c7a9": "c7c7a9", + "de94f7": "ede4ab", + "e6e6d6": "7687ab", + "fafafa": "8fa2c2", + "fcfcfc": "fcfcfc", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "5a296b": "142440", + "004a63": "b0384a", + "73735a": "85204a", + "73735b": "a37355", + "ad1000": "d98943", + "e64231": "edc85a", + "297b94": "d65e64", + "a55294": "253f5e", + "d673ef": "375c73", + "4294c5": "ed938e", + "c5c5a5": "c43d63", + "c4c4a7": "e0b990", + "c7c7a9": "c7c7a9", + "de94f7": "5d91a1", + "e6e6d6": "d15271", + "fafafa": "de6476", + "fcfcfc": "ede1b4", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/345.json b/public/images/pokemon/variant/345.json new file mode 100644 index 00000000000..dc23adbef64 --- /dev/null +++ b/public/images/pokemon/variant/345.json @@ -0,0 +1,28 @@ +{ + "1": { + "633a84": "611746", + "6b5221": "679e3a", + "efd663": "fcf3a2", + "9c84ce": "bd3167", + "b5ade6": "ff5289", + "d6a531": "d8e374", + "efadb5": "b9f0ff", + "bd5284": "6084bd", + "ce7394": "84aedb", + "843a5a": "394287", + "7363b5": "801f4c" + }, + "2": { + "633a84": "b57c2d", + "6b5221": "661634", + "efd663": "de463e", + "9c84ce": "f5df73", + "b5ade6": "fff8a3", + "d6a531": "942532", + "efadb5": "beed9a", + "bd5284": "429949", + "ce7394": "7fcc68", + "843a5a": "296e47", + "7363b5": "dbb34d" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/346.json b/public/images/pokemon/variant/346.json new file mode 100644 index 00000000000..090feeab922 --- /dev/null +++ b/public/images/pokemon/variant/346.json @@ -0,0 +1,32 @@ +{ + "1": { + "ffd6ef": "deffea", + "3a6b52": "7f183f", + "a57b10": "5e8c29", + "a5e68c": "f38460", + "944263": "304459", + "ce6394": "526f84", + "f7d642": "d8e374", + "7bc573": "eb564b", + "ff9cad": "d2faef", + "fff77b": "fcf3a2", + "529c5a": "b32843", + "cea531": "a7c961", + "ef6b8c": "93c6c5" + }, + "2": { + "ffd6ef": "a3ffc3", + "3a6b52": "96483b", + "a57b10": "661634", + "a5e68c": "ffe6b5", + "944263": "17404a", + "ce6394": "32806f", + "f7d642": "de463e", + "7bc573": "efbd8c", + "ff9cad": "7be3b6", + "fff77b": "ff754f", + "529c5a": "bf815c", + "cea531": "942532", + "ef6b8c": "53b491" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/396.json b/public/images/pokemon/variant/396.json new file mode 100644 index 00000000000..1881572247b --- /dev/null +++ b/public/images/pokemon/variant/396.json @@ -0,0 +1,44 @@ +{ + "1": { + "000000": "101010", + "3a2129": "07332d", + "3f1e27": "b06421", + "4a4343": "751e23", + "4f4747": "dbb070", + "524a4a": "156146", + "736363": "28854d", + "756565": "144a40", + "ff0000": "90cc58", + "9c4a21": "db963b", + "d67300": "edb651", + "8c7373": "bd453c", + "ff9429": "ffcf5e", + "ad9c9c": "ed7f4c", + "b3b3b3": "b3b3b3", + "b5b5b5": "d1a562", + "d6dede": "e3d09d", + "fcfcfc": "f0ebc5", + "ffffff": "ffffff" + }, + "2": { + "000000": "101010", + "3a2129": "111a36", + "3f1e27": "451915", + "4a4343": "163d4d", + "4f4747": "e5c595", + "524a4a": "1b2745", + "736363": "2f436b", + "756565": "e6a647", + "ff0000": "c4568a", + "9c4a21": "52281f", + "d67300": "63362b", + "8c7373": "307b82", + "ff9429": "8c604c", + "ad9c9c": "4da8a1", + "b3b3b3": "b3b3b3", + "b5b5b5": "debd8c", + "d6dede": "f0deaa", + "fcfcfc": "fcfad2", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/397.json b/public/images/pokemon/variant/397.json new file mode 100644 index 00000000000..e5fa30f65bd --- /dev/null +++ b/public/images/pokemon/variant/397.json @@ -0,0 +1,38 @@ +{ + "1": { + "9c4242": "528a3e", + "362d36": "0d4539", + "f75242": "8bba65", + "735a63": "bd453c", + "bd6300": "db963b", + "362c36": "8f431d", + "595759": "256e54", + "b5b5b5": "d9c798", + "523a4a": "751e23", + "5a525a": "28854d", + "7b4221": "b06421", + "9c848c": "ed7f4c", + "3d343d": "144a40", + "ff9429": "ffcf5e", + "3a3a3a": "156146", + "f9f9f9": "f0ebc5" + }, + "2": { + "9c4242": "c4568a", + "362d36": "162040", + "f75242": "f797ad", + "735a63": "307b82", + "bd6300": "63362b", + "362c36": "421917", + "595759": "edcf87", + "b5b5b5": "debd8c", + "523a4a": "163d4d", + "5a525a": "2f436b", + "7b4221": "52281f", + "9c848c": "4da8a1", + "3d343d": "e6a647", + "ff9429": "8c604c", + "3a3a3a": "152039", + "f9f9f9": "fcfad2" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/398.json b/public/images/pokemon/variant/398.json new file mode 100644 index 00000000000..387cddba886 --- /dev/null +++ b/public/images/pokemon/variant/398.json @@ -0,0 +1,36 @@ +{ + "1": { + "735a63": "bd453c", + "5c545c": "144a40", + "5a525a": "156146", + "7b6b7b": "28854d", + "f75242": "90cc58", + "4f3847": "ab5022", + "b5b5b5": "d7be89", + "9c4242": "5fad3b", + "7b4221": "b06421", + "fcfcfc": "e8e3b6", + "3a3a3a": "07332d", + "bd6300": "db963b", + "523a4a": "751e23", + "9c848c": "ed7f4c", + "ff9429": "ffcf5e" + }, + "2": { + "735a63": "307b82", + "5c545c": "e6a647", + "5a525a": "1b2745", + "7b6b7b": "293854", + "f75242": "e6bd4e", + "4f3847": "421917", + "b5b5b5": "debd8c", + "9c4242": "c4833d", + "7b4221": "52281f", + "fcfcfc": "fcfad2", + "3a3a3a": "080d1f", + "bd6300": "63362b", + "523a4a": "163d4d", + "9c848c": "4da8a1", + "ff9429": "8c604c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/403.json b/public/images/pokemon/variant/403.json new file mode 100644 index 00000000000..fac493a40e4 --- /dev/null +++ b/public/images/pokemon/variant/403.json @@ -0,0 +1,26 @@ +{ + "1": { + "b59c5a": "45babf", + "7badf7": "bb5c3a", + "943a52": "472614", + "637bb5": "903325", + "4a4a63": "dcb788", + "ffe65a": "59dcd6", + "313142": "bf8652", + "e64a52": "4f3217", + "42426b": "671919", + "736352": "267789" + }, + "2": { + "b59c5a": "9a31be", + "7badf7": "303465", + "943a52": "614b9a", + "637bb5": "222352", + "4a4a63": "bbc2e5", + "ffe65a": "e25ce8", + "313142": "8883d4", + "e64a52": "6f5dac", + "42426b": "121031", + "736352": "611c7f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/404.json b/public/images/pokemon/variant/404.json new file mode 100644 index 00000000000..b6621d02406 --- /dev/null +++ b/public/images/pokemon/variant/404.json @@ -0,0 +1,28 @@ +{ + "1": { + "736352": "267789", + "4a4a73": "671919", + "63637b": "f1dfb1", + "b59c5a": "45babf", + "637bb5": "903325", + "4a4a63": "dcb788", + "ffe65a": "59dcd6", + "313142": "bf8652", + "943a52": "472614", + "e64a52": "4f3217", + "7badf7": "bb5c3a" + }, + "2": { + "736352": "611c7f", + "4a4a73": "121031", + "63637b": "dee4f4", + "b59c5a": "9a31be", + "637bb5": "222352", + "4a4a63": "bbc2e5", + "ffe65a": "e25ce8", + "313142": "8883d4", + "943a52": "614b9a", + "e64a52": "6f5dac", + "7badf7": "303465" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/405.json b/public/images/pokemon/variant/405.json new file mode 100644 index 00000000000..1f6a0590bb8 --- /dev/null +++ b/public/images/pokemon/variant/405.json @@ -0,0 +1,28 @@ +{ + "1": { + "b59c5a": "45babf", + "7badf7": "bb5c3a", + "63637b": "f1dfb1", + "637bb5": "903325", + "943a52": "472614", + "4a4a63": "dcb788", + "ffe65a": "59dcd6", + "313142": "bf8652", + "4a4a73": "671919", + "e64a52": "4f3217", + "736352": "267789" + }, + "2": { + "b59c5a": "9a31be", + "7badf7": "303465", + "63637b": "dee4f4", + "637bb5": "222352", + "943a52": "614b9a", + "4a4a63": "bbc2e5", + "ffe65a": "e25ce8", + "313142": "8883d4", + "4a4a73": "121031", + "e64a52": "6f5dac", + "736352": "611c7f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/417.json b/public/images/pokemon/variant/417.json new file mode 100644 index 00000000000..27f45e74557 --- /dev/null +++ b/public/images/pokemon/variant/417.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "3e364e": "734430", + "524941": "732e12", + "5a524a": "642f1a", + "4a425a": "5f2618", + "84523a": "9b314f", + "ef845a": "e26e6e", + "c5a563": "e95d6c", + "ffd663": "f17c7c", + "637b9c": "86452b", + "7bb5e6": "a25f37", + "cec5c5": "e8be64", + "f7f7f7": "faeda9", + "ffffff": "ffffff", + "7b7b84": "8e623c" + }, + "2": { + "101010": "101010", + "3e364e": "203243", + "524941": "2d284c", + "5a524a": "0f203a", + "4a425a": "23704c", + "84523a": "693939", + "ef845a": "e1b8ac", + "c5a563": "5ae7f6", + "ffd663": "8ffaff", + "637b9c": "a2dc76", + "7bb5e6": "e4fba1", + "cec5c5": "357577", + "f7f7f7": "5ba297", + "ffffff": "ffffff", + "7b7b84": "1f3f4e" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/420.json b/public/images/pokemon/variant/420.json new file mode 100644 index 00000000000..6910d49d9d2 --- /dev/null +++ b/public/images/pokemon/variant/420.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "423131": "103d47", + "6b3a4a": "09303b", + "314252": "8f3833", + "3a734a": "ab554b", + "843152": "185158", + "ad426b": "368a7f", + "429442": "d98b77", + "52a54a": "f7bfa8", + "73ce5a": "fcdbc7", + "de6384": "51b095", + "ff8cad": "73d9ae", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "423131": "390f26", + "6b3a4a": "29091b", + "314252": "752a4a", + "3a734a": "9c4861", + "843152": "3b0d21", + "ad426b": "571539", + "429442": "a86a79", + "52a54a": "c29597", + "73ce5a": "dec3c3", + "de6384": "752648", + "ff8cad": "ad5168", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/421-overcast.json b/public/images/pokemon/variant/421-overcast.json new file mode 100644 index 00000000000..77c5c18415d --- /dev/null +++ b/public/images/pokemon/variant/421-overcast.json @@ -0,0 +1,34 @@ +{ + "1": { + "101010": "101010", + "105221": "ab554b", + "4a2942": "5e1228", + "7b294a": "103d47", + "7a2a4a": "236e6a", + "427b4a": "d98b77", + "6b427b": "962a3e", + "a53a63": "368a7f", + "ce527b": "51b095", + "52ad5a": "f7bfa8", + "5ac55a": "fcdbc7", + "845aad": "c75058", + "9c7bbd": "db7f7f", + "de7394": "73d9ae" + }, + "2": { + "101010": "101010", + "105221": "995969", + "4a2942": "521d44", + "7b294a": "390f26", + "7a2a4a": "571539", + "427b4a": "ba8087", + "6b427b": "8f4270", + "a53a63": "611c3b", + "ce527b": "752648", + "52ad5a": "cf9d9d", + "5ac55a": "e3cbca", + "845aad": "a86886", + "9c7bbd": "d197ac", + "de7394": "ad5168" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/421-sunshine.json b/public/images/pokemon/variant/421-sunshine.json new file mode 100644 index 00000000000..096641576c9 --- /dev/null +++ b/public/images/pokemon/variant/421-sunshine.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "006310": "e6d590", + "941e3f": "103d47", + "9c6b10": "c4655a", + "941f40": "5c1547", + "942142": "591230", + "ce3a6b": "751a38", + "cf3c6d": "872e5c", + "cf3e6e": "368a7f", + "19943a": "f0f0bd", + "d6b55a": "db8e7d", + "f7de73": "f7bfa8", + "e66394": "51b095", + "de84ad": "962a3e", + "ffa5c5": "c75058", + "ffe6f7": "d0fdf0", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "006310": "72559e", + "941e3f": "390f26", + "9c6b10": "4a2942", + "941f40": "3a234a", + "942142": "804058", + "ce3a6b": "995969", + "cf3c6d": "563666", + "cf3e6e": "571539", + "19943a": "9574b3", + "d6b55a": "914972", + "f7de73": "b35f86", + "e66394": "752648", + "de84ad": "cf9d9d", + "ffa5c5": "e3cbca", + "ffe6f7": "d26393", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/446.json b/public/images/pokemon/variant/446.json new file mode 100644 index 00000000000..60d20fba25a --- /dev/null +++ b/public/images/pokemon/variant/446.json @@ -0,0 +1,38 @@ +{ + "1": { + "000000": "101010", + "104242": "4d0f3f", + "215a73": "701a55", + "317b9c": "943469", + "3194b5": "ad4b70", + "524a10": "91504e", + "73737b": "756363", + "7b5a31": "522663", + "948442": "351b52", + "9c3a42": "714084", + "b5b563": "de9494", + "cccfce": "cbc4c4", + "cecece": "cecece", + "de9494": "a270b5", + "efe684": "f0beb1", + "ffffff": "ffffff" + }, + "2": { + "000000": "101010", + "104242": "6398b7", + "215a73": "a3cacd", + "317b9c": "cbe4e2", + "3194b5": "edf5f4", + "524a10": "233f69", + "73737b": "525266", + "7b5a31": "e6cda1", + "948442": "c2986e", + "9c3a42": "487d43", + "b5b563": "38638f", + "cccfce": "bfc7cb", + "cecece": "cecece", + "de9494": "9cb780", + "efe684": "4781a8", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/472.json b/public/images/pokemon/variant/472.json index 937ea1334de..9e19b9f2353 100644 --- a/public/images/pokemon/variant/472.json +++ b/public/images/pokemon/variant/472.json @@ -1,33 +1,34 @@ { "1": { - "5a63a5": "974d16", - "de3a6b": "4c83a9", - "293163": "5c2a09", - "424252": "2a2752", - "ffde00": "84b8ff", - "b5a5ff": "e9bb57", - "6b6b7b": "48487a", - "737bc5": "b86f27", - "730800": "143262", - "9c8cef": "d28b36", - "ad2131": "2a6197", - "c55294": "5270c5", "ad9400": "4b64ff", - "2a2a2a": "130e27" + "c55294": "5270c5", + "9c8cef": "d28b36", + "424252": "2a2752", + "de3a6b": "4c83a9", + "2a2a2a": "130e27", + "6b6b7b": "48487a", + "b5a5ff": "e9bb57", + "ffde00": "84b8ff", + "ad2131": "2a6197", + "737bc5": "b86f27", + "5a63a5": "974d16", + "293163": "5c2a09", + "730800": "143262" }, "2": { - "5a63a5": "731e37", - "de3a6b": "594b6a", - "293163": "43050d", - "424252": "57b6a6", - "ffde00": "6bffd4", - "b5a5ff": "eb6a64", - "6b6b7b": "81e4c2", - "737bc5": "952b41", - "730800": "262138", - "9c8cef": "b3404a", - "ad2131": "453b57", "ad9400": "16a9c0", - "2a2a2a": "103f47" + "c55294": "e38b3d", + "9c8cef": "b3404a", + "424252": "57b6a6", + "de3a6b": "594b6a", + "2a2a2a": "103f47", + "6b6b7b": "81e4c2", + "b5a5ff": "eb6a64", + "ffde00": "6bffd4", + "ad2131": "453b57", + "737bc5": "952b41", + "5a63a5": "731e37", + "293163": "43050d", + "730800": "262138" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/476.json b/public/images/pokemon/variant/476.json new file mode 100644 index 00000000000..5f54f51d1f9 --- /dev/null +++ b/public/images/pokemon/variant/476.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "5a2921": "0e291d", + "7b3129": "1e3f30", + "293a4a": "352310", + "3a4a5a": "59452f", + "bd3152": "30594a", + "e65a63": "578b6b", + "194a84": "62230e", + "3a63ad": "9d3a18", + "5a7bce": "c76227", + "ef7b8c": "77b472", + "739ce6": "de7f36", + "84adf7": "e68c43", + "c5cede": "c5cede", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "5a2921": "21132c", + "7b3129": "301b3f", + "293a4a": "111b28", + "3a4a5a": "253142", + "bd3152": "482a5e", + "e65a63": "6a5394", + "194a84": "30578e", + "3a63ad": "5b97c1", + "5a7bce": "92dee8", + "ef7b8c": "747fc4", + "739ce6": "dbfff4", + "84adf7": "c2efe5", + "c5cede": "c5cede", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/498.json b/public/images/pokemon/variant/498.json new file mode 100644 index 00000000000..b23a3afec63 --- /dev/null +++ b/public/images/pokemon/variant/498.json @@ -0,0 +1,44 @@ +{ + "1": { + "101010": "101010", + "2e1e1e": "b1a385", + "2e1f1f": "d1c5ab", + "302020": "11241c", + "312121": "1e2a4d", + "47382f": "472770", + "473830": "f7f5e9", + "4a3a31": "2d405c", + "7a3827": "1c2e1b", + "7b3a29": "194737", + "947310": "cc955e", + "bd6331": "3b805f", + "ce423a": "3e4f37", + "a54a42": "2d452b", + "e66b29": "b5cca5", + "efbd08": "f0cc8b", + "ef843a": "65b57c", + "c5ada5": "c1c5a5", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "2e1e1e": "ac8b61", + "2e1f1f": "c4a884", + "302020": "111424", + "312121": "47150e", + "47382f": "456da8", + "473830": "e0d3ab", + "4a3a31": "733421", + "7a3827": "222742", + "7b3a29": "522e2e", + "947310": "828399", + "bd6331": "85564e", + "ce423a": "323754", + "a54a42": "4c5275", + "e66b29": "778aa6", + "efbd08": "c7c8d9", + "ef843a": "ab8274", + "c5ada5": "dddef0", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/499.json b/public/images/pokemon/variant/499.json new file mode 100644 index 00000000000..ad525f3e114 --- /dev/null +++ b/public/images/pokemon/variant/499.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "3a2121": "1e2a4d", + "3a3a3a": "122b18", + "523129": "2d405c", + "7a3827": "1c2e1b", + "7b3a29": "234f3d", + "736310": "ab6441", + "4a4a4a": "264524", + "bd5a31": "41785a", + "ce423a": "3e4f37", + "ef7329": "62a174", + "b59421": "cc955e", + "efc53a": "f0cc8b", + "c5ada5": "c5ada5", + "c4aea7": "c4aea7", + "fcfcfc": "fcfcfc", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "3a2121": "47150e", + "3a3a3a": "1c2245", + "523129": "733421", + "7a3827": "222742", + "7b3a29": "533330", + "736310": "3c3e5b", + "4a4a4a": "272d4f", + "bd5a31": "7a5a56", + "ce423a": "323754", + "ef7329": "967a71", + "b59421": "828399", + "efc53a": "c7c8d9", + "c5ada5": "c4a884", + "c4aea7": "c4aea7", + "fcfcfc": "e0d3ab", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/500.json b/public/images/pokemon/variant/500.json new file mode 100644 index 00000000000..028639cf6bb --- /dev/null +++ b/public/images/pokemon/variant/500.json @@ -0,0 +1,56 @@ +{ + "1": { + "101010": "101010", + "1f1f1f": "0e1a10", + "212121": "1e2a4d", + "313131": "2d405c", + "333333": "2c2f35", + "741910": "472770", + "7a1910": "1c2e1b", + "7b1910": "257036", + "7a1a11": "445e3f", + "732900": "2c473e", + "7b5a08": "ab6441", + "a53a31": "3e4f37", + "e62a29": "1d1151", + "e63127": "58db58", + "e63129": "627556", + "bd5221": "3e6952", + "ef6321": "699676", + "b58c21": "cc955e", + "ef8c08": "86e677", + "efbd08": "f0cc8b", + "f0be0a": "c7f797", + "adadad": "a3a6ad", + "b0b0b0": "b0b0b0", + "f7f7f7": "e4eef5", + "fafafa": "fafafa" + }, + "2": { + "101010": "101010", + "1f1f1f": "0f162a", + "212121": "47150e", + "313131": "733421", + "333333": "3b352b", + "741910": "456da8", + "7a1910": "20243d", + "7b1910": "ba843d", + "7a1a11": "3c3f59", + "732900": "522e2e", + "7b5a08": "3c3e5b", + "a53a31": "2d3250", + "e62a29": "1d3f70", + "e63127": "e6ca65", + "e63129": "464a66", + "bd5221": "7a5a56", + "ef6321": "967a71", + "b58c21": "828399", + "ef8c08": "f2d591", + "efbd08": "c7c8d9", + "f0be0a": "faefc7", + "adadad": "c4a884", + "b0b0b0": "b0b0b0", + "f7f7f7": "e0d3ab", + "fafafa": "fafafa" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/511.json b/public/images/pokemon/variant/511.json new file mode 100644 index 00000000000..5e278b5e0fc --- /dev/null +++ b/public/images/pokemon/variant/511.json @@ -0,0 +1,26 @@ +{ + "1": { + "ffce7b": "edc293", + "f79cad": "f77e94", + "b5637b": "a3415f", + "84ce9c": "e6c545", + "194a29": "912f1c", + "087331": "c45331", + "087030": "8c5915", + "cea55a": "d9a177", + "735221": "bd7653", + "19a552": "d97b41" + }, + "2": { + "ffce7b": "8ecaed", + "f79cad": "f788cb", + "b5637b": "b5539d", + "84ce9c": "ffa8dc", + "194a29": "4c2d7a", + "087331": "683b8c", + "087030": "d16fb9", + "cea55a": "73acde", + "735221": "3f6aa6", + "19a552": "8a53a6" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/512.json b/public/images/pokemon/variant/512.json new file mode 100644 index 00000000000..903ff3906bb --- /dev/null +++ b/public/images/pokemon/variant/512.json @@ -0,0 +1,32 @@ +{ + "1": { + "a57b3a": "a65b3d", + "4f4f4f": "a36e46", + "087331": "c74638", + "194a29": "a12d25", + "c5c5c5": "dbc086", + "735221": "733224", + "ffce7b": "eab68b", + "84ce9c": "ebb54b", + "fcfcfc": "ebe0ab", + "cea55a": "c8895f", + "087030": "9e6426", + "9c9c9c": "cfa067", + "19a552": "ed6f53" + }, + "2": { + "a57b3a": "3762bf", + "4f4f4f": "3073ab", + "087331": "522880", + "194a29": "331961", + "c5c5c5": "5bc6de", + "735221": "2a42a1", + "ffce7b": "58aee0", + "84ce9c": "ffa8dc", + "fcfcfc": "79f7f3", + "cea55a": "4686cf", + "087030": "d16fb9", + "9c9c9c": "4099c2", + "19a552": "6e368f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/513.json b/public/images/pokemon/variant/513.json new file mode 100644 index 00000000000..9a19fbc4977 --- /dev/null +++ b/public/images/pokemon/variant/513.json @@ -0,0 +1,26 @@ +{ + "1": { + "ffce7b": "ffe6c9", + "bd423a": "28629c", + "e65242": "3d9bbe", + "7b3131": "1b3e70", + "a57b3a": "e4907f", + "cea55a": "f9b9a2", + "bd453c": "67bdc7", + "735221": "c3635b", + "f79442": "a6f5e9" + }, + "2": { + "ffce7b": "ed8c7b", + "bd423a": "d5b393", + "e65242": "f4ecd7", + "7b3131": "ad7a63", + "a57b3a": "bc2f2f", + "525252": "22607d", + "cea55a": "d4554c", + "bd453c": "e7613c", + "848484": "368d9e", + "735221": "a1272f", + "f79442": "fe934f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/514.json b/public/images/pokemon/variant/514.json new file mode 100644 index 00000000000..c42a3878cc1 --- /dev/null +++ b/public/images/pokemon/variant/514.json @@ -0,0 +1,37 @@ +{ + "1": { + "999999": "6f94c7", + "bd423a": "265494", + "e65242": "3a7bb5", + "7a3131": "386f94", + "3b3b3b": "465f9e", + "c5c5c5": "97c0e6", + "611b2d": "193170", + "ffce7b": "ffe2bf", + "f79442": "76e2e8", + "fcfcfc": "c0e7fc", + "a57b3a": "d99479", + "cea55a": "edba9a", + "bd4139": "509cbf", + "73572d": "ba6a57" + }, + "2": { + "999999": "cc762b", + "bd423a": "cfb88f", + "e65242": "ede9d1", + "7a3131": "cc592b", + "3b3b3b": "ad4d1d", + "c5c5c5": "e3a13d", + "611b2d": "a88260", + "c7c7c7": "54abb3", + "ffce7b": "cc643b", + "525252": "22607d", + "f79442": "f7ab4d", + "fcfcfc": "f7cc57", + "a57b3a": "782017", + "cea55a": "943722", + "bd4139": "e07a3a", + "9c9c9c": "368d9e", + "73572d": "5c0e0e" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/515.json b/public/images/pokemon/variant/515.json new file mode 100644 index 00000000000..66d23ed94da --- /dev/null +++ b/public/images/pokemon/variant/515.json @@ -0,0 +1,28 @@ +{ + "1": { + "ffce7b": "fff187", + "9ce6ef": "add687", + "188bab": "42753d", + "a57b3a": "b5893c", + "9de8f2": "86e387", + "21739c": "136b3b", + "198cad": "219448", + "29b5de": "34c15e", + "cea55a": "e0c265", + "735221": "735f21", + "003a73": "0a4a2d" + }, + "2": { + "ffce7b": "e76092", + "9ce6ef": "afc3fe", + "188bab": "8490e3", + "a57b3a": "b32e77", + "9de8f2": "f2bbd7", + "21739c": "cc70a4", + "198cad": "eb98bf", + "29b5de": "ffc9dd", + "cea55a": "cc4580", + "735221": "8f1f68", + "003a73": "a64e8b" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/516.json b/public/images/pokemon/variant/516.json new file mode 100644 index 00000000000..c7c8ce95eb9 --- /dev/null +++ b/public/images/pokemon/variant/516.json @@ -0,0 +1,30 @@ +{ + "1": { + "a57b3a": "9c7935", + "106b8c": "08420d", + "003a73": "13571a", + "c5c5c5": "aecf86", + "735221": "7b5e29", + "ffce7b": "fadd73", + "9ce6ef": "cade6f", + "fcfcfc": "edf7c3", + "2290a8": "568c30", + "218ca5": "3c8c22", + "29b5de": "6fad37", + "cea55a": "c4a148" + }, + "2": { + "a57b3a": "b32e77", + "106b8c": "cc70a4", + "003a73": "a64e8b", + "c5c5c5": "59b7d4", + "735221": "8f1f68", + "ffce7b": "e76092", + "9ce6ef": "afc3fe", + "fcfcfc": "7cfcf7", + "2290a8": "8490e3", + "218ca5": "eb98bf", + "29b5de": "ffc9dd", + "cea55a": "cc4580" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/522.json b/public/images/pokemon/variant/522.json new file mode 100644 index 00000000000..ed387dd09bb --- /dev/null +++ b/public/images/pokemon/variant/522.json @@ -0,0 +1,34 @@ +{ + "1": { + "7b7b7b": "505a9b", + "525252": "95355d", + "cecece": "788bcb", + "ffe600": "61e4bf", + "a5a5a5": "7e98dc", + "005a9c": "75c239", + "505050": "3d4488", + "ffffff": "b9cfef", + "191f1f": "2e0d1f", + "3a3a3a": "731f51", + "00adde": "b9e96c", + "8c7321": "33a08a", + "292929": "53173b", + "192121": "43172f" + }, + "2": { + "7b7b7b": "731515", + "525252": "ebc37d", + "cecece": "97221a", + "ffe600": "36c294", + "a5a5a5": "d37047", + "005a9c": "30309d", + "505050": "4e1416", + "ffffff": "c23e2e", + "191f1f": "370b0b", + "3a3a3a": "d3874e", + "00adde": "3e4ddc", + "8c7321": "288278", + "292929": "914824", + "192121": "661212" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/523.json b/public/images/pokemon/variant/523.json new file mode 100644 index 00000000000..daf0e7ec6d6 --- /dev/null +++ b/public/images/pokemon/variant/523.json @@ -0,0 +1,42 @@ +{ + "1": { + "777777": "47548f", + "363d3d": "353573", + "005a9c": "75c239", + "ffffff": "b9cfef", + "171f1f": "430f30", + "797979": "7080c6", + "8c7321": "33a08a", + "293131": "6a1d44", + "5b5b5b": "3d467d", + "8a711e": "33a08a", + "3a4242": "84294f", + "353535": "43172f", + "ffe600": "61e4bf", + "3a3a3a": "5d213a", + "00adde": "b9e96c", + "cecece": "7e91d3", + "a5a5a5": "5265a4", + "192121": "57163d" + }, + "2": { + "777777": "731515", + "363d3d": "4e1416", + "005a9c": "30309d", + "ffffff": "c23e2e", + "171f1f": "661212", + "797979": "da7248", + "8c7321": "288278", + "293131": "c89161", + "5b5b5b": "641818", + "8a711e": "85cd99", + "3a4242": "ebc37d", + "353535": "501a19", + "ffe600": "36c294", + "3a3a3a": "682321", + "00adde": "3e4ddc", + "cecece": "97221a", + "a5a5a5": "861816", + "192121": "9e533b" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/535.json b/public/images/pokemon/variant/535.json new file mode 100644 index 00000000000..bc44b1280dd --- /dev/null +++ b/public/images/pokemon/variant/535.json @@ -0,0 +1,31 @@ +{ + "1": { + "6bbdff": "a9c4d7", + "5b5959": "801941", + "626262": "615757", + "3f3f3f": "3e3838", + "385f87": "801941", + "292929": "420e2d", + "6c8ec1": "b53a57", + "62b4f6": "d65a5a", + "7394c5": "6f8fb1", + "424242": "5e1a39", + "3a638c": "40567d" + }, + "2": { + "6bbdff": "672a23", + "5b5959": "d76d39", + "626262": "5a6363", + "3f3f3f": "363c3e", + "385f87": "ac6634", + "292929": "7d2414", + "6c8ec1": "cd984a", + "945a4a": "52809b", + "62b4f6": "f3cd69", + "ffdebd": "aadfe0", + "7394c5": "54131a", + "424242": "ac4423", + "c59c84": "7fb8c2", + "3a638c": "420f1d" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/536.json b/public/images/pokemon/variant/536.json new file mode 100644 index 00000000000..40d3ea06a02 --- /dev/null +++ b/public/images/pokemon/variant/536.json @@ -0,0 +1,44 @@ +{ + "1": { + "000000": "101010", + "292929": "400a32", + "10427b": "40567d", + "196373": "73163a", + "424242": "5e1246", + "5a5a5a": "58504b", + "615f5f": "906f59", + "636363": "801c4e", + "945a4a": "945a4a", + "296bad": "6f8fb1", + "52a5b5": "b53a57", + "0894d6": "a9c4d7", + "c59c84": "c59c84", + "ffdebd": "e3c998", + "84e6d6": "d65a5a", + "c0c0c0": "c9b38b", + "c5c5c5": "c08031", + "d1d1d1": "ffffff", + "ffffff": "e6b854" + }, + "2": { + "000000": "101010", + "292929": "7d2414", + "10427b": "4a1423", + "196373": "ac6634", + "424242": "ac4423", + "5a5a5a": "114232", + "615f5f": "467692", + "636363": "d76d39", + "945a4a": "44718c", + "296bad": "5d171e", + "52a5b5": "cd984a", + "0894d6": "75332b", + "c59c84": "7fb8c2", + "ffdebd": "aadfe0", + "84e6d6": "f3cd69", + "c0c0c0": "6fa6be", + "c5c5c5": "378c70", + "d1d1d1": "ffffff", + "ffffff": "5bb186" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/537.json b/public/images/pokemon/variant/537.json new file mode 100644 index 00000000000..99c9aaf0382 --- /dev/null +++ b/public/images/pokemon/variant/537.json @@ -0,0 +1,33 @@ +{ + "1": { + "404040": "631739", + "196373": "801941", + "10427b": "40567d", + "52a58c": "b53a57", + "636363": "801c4e", + "0894d6": "a9c4d7", + "ef5a3a": "e6b854", + "296bad": "6f8fb1", + "b53a21": "c08031", + "73e6ce": "d65a5a", + "424242": "5e1246", + "363636": "400a32", + "292929": "440f2f" + }, + "2": { + "404040": "323c39", + "196373": "883e24", + "10427b": "370b10", + "52a58c": "bf8d44", + "636363": "d76d39", + "0894d6": "75332b", + "ef5a3a": "5fc592", + "296bad": "561b21", + "b53a21": "33866c", + "73e6ce": "f9d576", + "c5c5c5": "ffffff", + "424242": "ac4423", + "363636": "611d11", + "292929": "7b2a17" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/554.json b/public/images/pokemon/variant/554.json new file mode 100644 index 00000000000..85cee2b5e73 --- /dev/null +++ b/public/images/pokemon/variant/554.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "3a2919": "946344", + "571515": "2e3573", + "5a1919": "a16012", + "634231": "b0895f", + "5a5a5a": "5a5a5a", + "9c2929": "4e5aa3", + "ce3131": "6c7ec4", + "947310": "bda373", + "ad5a29": "d19628", + "cea519": "cfc191", + "ffce21": "e3e2ba", + "ff9452": "e8c661", + "a5a5ad": "a5a5ad", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "3a2919": "3a2919", + "571515": "bf7558", + "5a1919": "291d1b", + "634231": "941c32", + "5a5a5a": "5a5a5a", + "9c2929": "d6a376", + "ce3131": "f0e2b9", + "947310": "9c1c2b", + "ad5a29": "4a3021", + "cea519": "ba343d", + "ffce21": "d14949", + "ff9452": "614b38", + "a5a5ad": "a5a5ad", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/555-zen.json b/public/images/pokemon/variant/555-zen.json new file mode 100644 index 00000000000..da85df60fdb --- /dev/null +++ b/public/images/pokemon/variant/555-zen.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "215263": "592226", + "3a7b8c": "7d3e3d", + "425a63": "b5775b", + "4a4a52": "4a4a52", + "529cad": "8c5b54", + "7b5229": "3b3f87", + "7ba5bd": "c99d7b", + "9c9ca5": "9c9ca5", + "ad6b29": "5e65b5", + "b5d6ef": "e0c19b", + "e6a563": "7b8dd4", + "f7f7f7": "f7f7f7" + }, + "2": { + "101010": "101010", + "215263": "523273", + "3a7b8c": "805a9c", + "425a63": "2e2a51", + "4a4a52": "4a4a52", + "529cad": "a278b0", + "7b5229": "9e907e", + "7ba5bd": "494162", + "9c9ca5": "9c9ca5", + "ad6b29": "bab5a6", + "b5d6ef": "605375", + "e6a563": "f5f3e9", + "f7f7f7": "f7f7f7" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/555.json b/public/images/pokemon/variant/555.json new file mode 100644 index 00000000000..97d623f0d7d --- /dev/null +++ b/public/images/pokemon/variant/555.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "4a4a52": "4a4a52", + "523a21": "a65f33", + "631919": "222675", + "6b5a10": "b04a21", + "8c1929": "2d3685", + "8c8c9c": "8c8c9c", + "ad2119": "3a4c94", + "b57b4a": "d9a455", + "bd0000": "cfc191", + "bd9429": "c26932", + "ef1010": "e3e2ba", + "efa56b": "e8cd7b", + "efce10": "d9944a", + "f7f7f7": "f7f7f7" + }, + "2": { + "101010": "101010", + "4a4a52": "4a4a52", + "523a21": "291b19", + "631919": "a86722", + "6b5a10": "941c32", + "8c1929": "d6993e", + "8c8c9c": "8c8c9c", + "ad2119": "e8ca5d", + "b57b4a": "4a3021", + "bd0000": "bab5a6", + "bd9429": "ba343d", + "ef1010": "f5f3e9", + "efa56b": "614b38", + "efce10": "d14949", + "f7f7f7": "f7f7f7" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/566.json b/public/images/pokemon/variant/566.json new file mode 100644 index 00000000000..cb2601d4a93 --- /dev/null +++ b/public/images/pokemon/variant/566.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "10316b": "1c4943", + "31529c": "336d60", + "3184f7": "4f9279", + "3a3a3a": "3a3a3a", + "523131": "641b49", + "524229": "2f6934", + "944242": "aa3c79", + "9c9cad": "9c9cad", + "bd9452": "66b562", + "de524a": "eb7fae", + "e6e6e6": "e6e6e6", + "f7ce63": "9be08b" + }, + "2": { + "101010": "101010", + "10316b": "283957", + "31529c": "929bdf", + "3184f7": "c4d3ff", + "3a3a3a": "3a3a3a", + "523131": "284452", + "524229": "211f69", + "944242": "44988f", + "9c9cad": "9c9cad", + "bd9452": "3b4bad", + "de524a": "65cda4", + "e6e6e6": "e6e6e6", + "f7ce63": "557ecd" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/567.json b/public/images/pokemon/variant/567.json new file mode 100644 index 00000000000..f4bb6a76111 --- /dev/null +++ b/public/images/pokemon/variant/567.json @@ -0,0 +1,37 @@ +{ + "1": { + "101010": "101010", + "523131": "454f52", + "635229": "2f6934", + "10316b": "1c4943", + "086b5a": "b3296b", + "9c4a4a": "7b8687", + "844252": "844252", + "de524a": "abb3b3", + "bd9452": "66b562", + "f7ce63": "9be08b", + "31529c": "336d60", + "10a594": "ee609d", + "3184f7": "4f9279", + "9c9cad": "9c9cad", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "523131": "284452", + "635229": "211f69", + "10316b": "283957", + "086b5a": "462d7e", + "9c4a4a": "44988f", + "844252": "844252", + "de524a": "65cda4", + "bd9452": "3b4bad", + "f7ce63": "557ecd", + "31529c": "929bdf", + "10a594": "7346a1", + "3184f7": "c4d3ff", + "9c9cad": "9c9cad", + "ffffff": "ffffff" + + } +} diff --git a/public/images/pokemon/variant/572.json b/public/images/pokemon/variant/572.json index 87200b60097..84a300c590d 100644 --- a/public/images/pokemon/variant/572.json +++ b/public/images/pokemon/variant/572.json @@ -1,24 +1,28 @@ { "1": { - "8c847b": "b2af6e", - "524a42": "525042", - "ffffff": "ffffff", - "decec5": "decec5", - "bdb5a5": "dad7a1", - "bd2929": "f28989", - "101010": "101010", - "d65252": "f8c1c1", - "ef8484": "fab7b7" + "4f473f": "113026", + "4d443e": "428066", + "918b83": "60a37b", + "d65252": "458256", + "47403b": "802b50", + "faf5f5": "b3e8ba", + "8c847b": "b34967", + "decec5": "87cc9a", + "bdb5a5": "cf6b77", + "bd2929": "256145", + "ef8484": "63a86a" }, "2": { - "8c847b": "5f807e", - "524a42": "5f807e", - "ffffff": "d7e8e6", - "decec5": "cbdcda", - "bdb5a5": "aec8c6", - "bd2929": "b08631", - "101010": "101010", - "d65252": "e6c88d", - "ef8484": "dab977" + "4f473f": "19d684", + "4d443e": "466336", + "918b83": "67824d", + "d65252": "82a65e", + "47403b": "101931", + "faf5f5": "d9e3aa", + "8c847b": "193457", + "decec5": "7f915e", + "bdb5a5": "294a6b", + "bd2929": "558f45", + "ef8484": "b4cf88" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/573.json b/public/images/pokemon/variant/573.json new file mode 100644 index 00000000000..3f4ce9e186f --- /dev/null +++ b/public/images/pokemon/variant/573.json @@ -0,0 +1,26 @@ +{ + "1": { + "bdb5b5": "60a67c", + "877e76": "458766", + "decec5": "87cc9a", + "4f473f": "113026", + "bdad9c": "cf6b77", + "faf5f5": "b3e8ba", + "d65252": "256145", + "4d453f": "802b50", + "8a8078": "b34967", + "ef8484": "58a672" + }, + "2": { + "bdb5b5": "597041", + "877e76": "3d542d", + "decec5": "7f915e", + "4f473f": "19d684", + "bdad9c": "294a6b", + "faf5f5": "d9e3aa", + "d65252": "558f45", + "4d453f": "101931", + "8a8078": "193457", + "ef8484": "b4cf88" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/626.json b/public/images/pokemon/variant/626.json new file mode 100644 index 00000000000..2f23c357b34 --- /dev/null +++ b/public/images/pokemon/variant/626.json @@ -0,0 +1,52 @@ +{ + "1": { + "101010": "101010", + "2b231c": "342b22", + "312921": "303120", + "4a3119": "122119", + "593b24": "362126", + "4a4231": "4a4831", + "6b4a29": "565796", + "694b2c": "513236", + "694b2d": "5f3539", + "714d29": "2d4a3a", + "3a3a42": "4d150f", + "6b6b73": "802d1f", + "946b31": "4d6650", + "966d34": "983525", + "ad8c29": "8580c4", + "9c845a": "9e655c", + "9c845c": "9e655e", + "9c855d": "9e655cx", + "bda57b": "bd8c7b", + "ffc54a": "c0b5eb", + "9ca5a5": "a34933", + "f7d69c": "f38d5d", + "fff7ce": "fed292" + }, + "2": { + "101010": "101010", + "2b231c": "443520", + "312921": "962430", + "4a3119": "855168", + "593b24": "905932", + "4a4231": "cc4545", + "6b4a29": "678db8", + "694b2c": "907532", + "694b2d": "907d32", + "714d29": "c17c95", + "3a3a42": "7f5310", + "6b6b73": "d49612", + "946b31": "e4b3b3", + "966d34": "92bcd4", + "ad8c29": "ca8928", + "9c845a": "beab6c", + "9c845c": "d2c084", + "9c855d": "db9a39", + "bda57b": "efeac2", + "ffc54a": "c2e5f0", + "9ca5a5": "e9ca5a", + "f7d69c": "f5cc51", + "fff7ce": "fff1be" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/643.json b/public/images/pokemon/variant/643.json new file mode 100644 index 00000000000..32afc3ef939 --- /dev/null +++ b/public/images/pokemon/variant/643.json @@ -0,0 +1,52 @@ +{ + "1": { + "4b4b6b": "a58419", + "faf5f5": "7b7e8a", + "ff6331": "ffee6b", + "3f3e5c": "374052", + "f7f8ff": "414659", + "616587": "2c2d45", + "ffa531": "fcfade", + "757b96": "d6c563", + "31314d": "1f2230", + "6e7491": "212236", + "3ab5f7": "e0912f", + "454166": "232738", + "de2908": "ffca0a", + "b8b9d1": "f0edc2", + "c1c1d6": "565a69", + "686d8c": "596675", + "424061": "0d0d1a", + "afb1cc": "2f3247", + "d6c5b5": "f2f2d8", + "afb1c7": "97a5b0", + "e6b573": "f2ecaa", + "767e9c": "3c4154", + "f5ebeb": "e6e7ef" + }, + "2": { + "4b4b6b": "19323c", + "faf5f5": "7a8fe7", + "ff6331": "9df377", + "3f3e5c": "19143f", + "f7f8ff": "a9bbff", + "616587": "2d3984", + "ffa531": "5cdca6", + "757b96": "3a6d71", + "31314d": "160837", + "6e7491": "3c50a1", + "3ab5f7": "d95486", + "454166": "2d3984", + "de2908": "3e947c", + "b8b9d1": "4f9290", + "c1c1d6": "647bd9", + "686d8c": "2b2871", + "424061": "18225f", + "afb1cc": "647bd9", + "d6c5b5": "3d8073", + "afb1c7": "343d8e", + "e6b573": "4ba789", + "767e9c": "3c50a1", + "f5ebeb": "4459a2" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/643_2.png b/public/images/pokemon/variant/643_2.png new file mode 100644 index 00000000000..fbd2a6e109c Binary files /dev/null and b/public/images/pokemon/variant/643_2.png differ diff --git a/public/images/pokemon/variant/644.json b/public/images/pokemon/variant/644.json new file mode 100644 index 00000000000..e84e7373389 --- /dev/null +++ b/public/images/pokemon/variant/644.json @@ -0,0 +1,48 @@ +{ + "1": { + "1a1a21": "35296b", + "2c2c35": "c1c8e8", + "103a52": "251076", + "191921": "686c99", + "22222e": "705ba8", + "005da4": "4800e3", + "31313a": "cfd0e6", + "6bf7ff": "b77dff", + "00c5ff": "7626ff", + "1a1821": "7888c2", + "23232f": "8c9bd1", + "ce0000": "a44bf2", + "121212": "54428f", + "940000": "762fcc", + "52525a": "e6e7f2", + "003682": "4c29ab", + "08528c": "3b1899", + "212129": "9b9fc4", + "111111": "5b5f8c", + "009cde": "dbbaff", + "101010": "49568f" + }, + "2": { + "1a1a21": "350707", + "2c2c35": "9c5fa4", + "103a52": "671212", + "191921": "843172", + "22222e": "350707", + "005da4": "c8433a", + "31313a": "ef9dae", + "6bf7ff": "f5e5da", + "00c5ff": "fbd3a8", + "1a1821": "5e286f", + "23232f": "763e7f", + "ce0000": "f3d32c", + "121212": "210214", + "940000": "aa5d0e", + "52525a": "ffc5d1", + "003682": "671212", + "08528c": "821b1b", + "212129": "ca6c94", + "111111": "4a1a4c", + "009cde": "ef806b", + "101010": "3b1a4c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/646-black.json b/public/images/pokemon/variant/646-black.json new file mode 100644 index 00000000000..70094ae228b --- /dev/null +++ b/public/images/pokemon/variant/646-black.json @@ -0,0 +1,59 @@ +{ + "1": { + "2f2f38": "112240", + "6b8c7b": "2b4366", + "524a31": "203c5c", + "191921": "6a6a94", + "648776": "905dcf", + "315a42": "1a2b4d", + "e3e3dc": "d4c3f7", + "e8e8dc": "e6a18a", + "35353d": "c8c9e0", + "786655": "5482b0", + "ededeb": "ebd4c3", + "b3ac8b": "c77161", + "006b94": "4c13a1", + "3b3b42": "9e463f", + "2e5942": "484873", + "addec5": "426585", + "b59400": "b35a3e", + "004b6f": "4c13a1", + "7d6d5b": "b2bdd4", + "ada584": "78a9cc", + "ffff4a": "db966b", + "deddd3": "edc9ff", + "282830": "9b9bc2", + "23232b": "0c142e", + "1e1e26": "15213b", + "00b5ff": "a033ff", + "b6e3ca": "bb8ae3" + }, + "2": { + "2f2f38": "550f0f", + "6b8c7b": "be6e34", + "524a31": "550f0f", + "191921": "3d0d38", + "648776": "ea93a5", + "315a42": "7b2d25", + "e3e3dc": "ffadbe", + "e8e8dc": "e0e0cc", + "35353d": "913a7d", + "786655": "982222", + "b3ac8b": "cec7a7", + "006b94": "6b3773", + "3b3b42": "423f30", + "2e5942": "ca6c94", + "addec5": "e6b45b", + "b59400": "166a2d", + "004b6f": "411d46", + "7d6d5b": "982222", + "ada584": "c23232", + "ffff4a": "6ae649", + "deddd3": "ffc5d1", + "282830": "6c245b", + "23232b": "521610", + "1e1e26": "480b0b", + "00b5ff": "b464bf", + "b6e3ca": "ea93a5" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/646-white.json b/public/images/pokemon/variant/646-white.json new file mode 100644 index 00000000000..ff46920d000 --- /dev/null +++ b/public/images/pokemon/variant/646-white.json @@ -0,0 +1,52 @@ +{ + "1": { + "101010": "101010", + "741a18": "9c5528", + "4a4a29": "2a446b", + "4a4a2d": "181930", + "4c4a2c": "1b2547", + "315a42": "1b2547", + "7b7b5a": "779fbf", + "73737b": "222342", + "942921": "d49748", + "e64a42": "ffe587", + "6b8c7b": "2e466b", + "cc9827": "b35a3e", + "ffde38": "db966b", + "ffde3a": "ffde3a", + "ffad63": "fff7c4", + "ada584": "b7dbeb", + "bdbdc5": "292b40", + "addec5": "45678a", + "f7f3f3": "f7f3f3", + "fbf8f8": "414659", + "fdf9f9": "fcfcfc", + "fcfcfc": "fcfcfc", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "741a18": "1f504d", + "4a4a29": "550f0f", + "4a4a2d": "1f1544", + "4c4a2c": "7b2d25", + "315a42": "7b2d25", + "7b7b5a": "982222", + "73737b": "2b2871", + "942921": "3d8073", + "e64a42": "4ba789", + "6b8c7b": "be6e34", + "cc9827": "166a2d", + "ffde38": "6ae649", + "ffde3a": "9df377", + "ffad63": "5cdca6", + "ada584": "c23232", + "bdbdc5": "3d458f", + "addec5": "e6b45b", + "f7f3f3": "f7f3f3", + "fbf8f8": "5870c4", + "fdf9f9": "4f9290", + "fcfcfc": "e2f9b5", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/646.json b/public/images/pokemon/variant/646.json new file mode 100644 index 00000000000..c8a0453a135 --- /dev/null +++ b/public/images/pokemon/variant/646.json @@ -0,0 +1,38 @@ +{ + "1": { + "8c7329": "b35a3e", + "949cad": "a6cfe0", + "3b3b4a": "39444c", + "103a52": "121836", + "ffe600": "db966b", + "73737b": "6394b0", + "373746": "121836", + "bde6ff": "3c5878", + "424252": "3d6285", + "696973": "606a73", + "ceb500": "a55c39", + "cecece": "bec9ce", + "def7ff": "577c96", + "6d737b": "a55c39", + "6b8494": "1a2647", + "ffffff": "edfcff", + "a5b5ce": "293c5e" + }, + "2": { + "8c7329": "166a2d", + "949cad": "c23232", + "3b3b4a": "4a3b3b", + "103a52": "7b2d25", + "ffe600": "6ae649", + "73737b": "982222", + "373746": "7b2d25", + "bde6ff": "e6b45b", + "424252": "550f0f", + "696973": "736969", + "ceb500": "2aac2b", + "def7ff": "f7ec88", + "6d737b": "2aac2b", + "6b8494": "974626", + "a5b5ce": "be6e34" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/692.json b/public/images/pokemon/variant/692.json new file mode 100644 index 00000000000..954dcffb3e9 --- /dev/null +++ b/public/images/pokemon/variant/692.json @@ -0,0 +1,26 @@ +{ + "1": { + "b3f2ff": "fada7f", + "44a2b4": "af6a37", + "2f7280": "783a1d", + "cd9d3a": "53be53", + "575757": "c85b5b", + "72561c": "20734c", + "60dbf2": "e1ac53", + "b4b4b4": "c8ba6d", + "3d3d3d": "7d182d", + "ffc549": "a9f076" + }, + "2": { + "b3f2ff": "faf8d7", + "44a2b4": "968144", + "2f7280": "5f3c23", + "cd9d3a": "7743be", + "575757": "88cd56", + "72561c": "371c72", + "60dbf2": "e1d6b6", + "b4b4b4": "68a7aa", + "3d3d3d": "1c873e", + "ffc549": "a36feb" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/693.json b/public/images/pokemon/variant/693.json new file mode 100644 index 00000000000..2e80795d2a0 --- /dev/null +++ b/public/images/pokemon/variant/693.json @@ -0,0 +1,30 @@ +{ + "1": { + "23a2c8": "c87a23", + "ffc859": "6ccd80", + "224b73": "552813", + "404040": "3c171b", + "262626": "230808", + "5f5f5f": "6e2e3b", + "cc9c3d": "1b3c17", + "61daf2": "f2bd61", + "735822": "08230e", + "3674b3": "7d3e21", + "ffc44c": "426e2e", + "4595e5": "aa6839" + }, + "2": { + "23a2c8": "beb099", + "ffc859": "f5b281", + "224b73": "5f463a", + "404040": "2a8c53", + "262626": "295a1c", + "5f5f5f": "51c85d", + "cc9c3d": "6259af", + "61daf2": "f0eadb", + "735822": "36235f", + "3674b3": "9b8265", + "ffc44c": "a39afa", + "4595e5": "c8b493" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/746-school.json b/public/images/pokemon/variant/746-school.json new file mode 100644 index 00000000000..a76aca2921f --- /dev/null +++ b/public/images/pokemon/variant/746-school.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "0a1627": "5f2112", + "113650": "0b3d3a", + "123954": "75351b", + "10437d": "16574d", + "134884": "934f26", + "1766c6": "b77736", + "3d66d8": "d39c63", + "416adf": "2c9572", + "79848a": "a67834", + "749cf6": "5ce09d", + "43ebf3": "824388", + "72f0f6": "27133f", + "9cd3fd": "78f389", + "a6c5f7": "aafe94", + "cfd1d3": "d5ab51", + "fbfbfb": "f7d76b" + }, + "2": { + "101010": "101010", + "0a1627": "160523", + "113650": "846228", + "123954": "28071a", + "10437d": "b7904d", + "134884": "350b19", + "1766c6": "4a1111", + "3d66d8": "622222", + "416adf": "dec284", + "79848a": "4a1111", + "749cf6": "f8ecc5", + "43ebf3": "4378eb", + "72f0f6": "31238e", + "9cd3fd": "fefed9", + "a6c5f7": "fefeef", + "cfd1d3": "5f291c", + "fbfbfb": "844232" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/746.json b/public/images/pokemon/variant/746.json new file mode 100644 index 00000000000..5b183b10e5d --- /dev/null +++ b/public/images/pokemon/variant/746.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "1f2161": "16574d", + "5d666d": "75391b", + "616b72": "a67834", + "9c455b": "308c9d", + "374793": "2c9572", + "4764c9": "5ce09d", + "3e9cbb": "27133f", + "61c8de": "824388", + "8c9c9d": "935926", + "8d9c9d": "c69b3f", + "d88394": "65cfe2", + "b0c5c6": "d5ab51", + "ccd2ce": "b77736", + "d8d9da": "d8d9da", + "eeeeee": "f7d76b", + "fefefe": "fefefe" + }, + "2": { + "101010": "101010", + "1f2161": "b7904d", + "5d666d": "1e0726", + "616b72": "4a1111", + "9c455b": "b9682d", + "374793": "dec284", + "4764c9": "f8ecc5", + "3e9cbb": "4378eb", + "61c8de": "5787f1", + "8c9c9d": "350b19", + "8d9c9d": "531917", + "d88394": "e4d85f", + "b0c5c6": "5f291c", + "ccd2ce": "4a1111", + "d8d9da": "d8d9da", + "eeeeee": "844232", + "fefefe": "fefefe" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/780.json b/public/images/pokemon/variant/780.json new file mode 100644 index 00000000000..0399d3567bf --- /dev/null +++ b/public/images/pokemon/variant/780.json @@ -0,0 +1,40 @@ +{ + "1": { + "8d541b": "bd8955", + "297b8b": "1a316b", + "606f55": "496375", + "ffc4d7": "f29d9d", + "105262": "0e194a", + "b4cda4": "9ab5b8", + "f5ae07": "e8c987", + "ce5b9b": "cf4654", + "faf550": "faf0b1", + "e67b9c": "e65757", + "bd3983": "bd3341", + "eea6bc": "f06e6e", + "5aa4a4": "284c80", + "b8b7a3": "cf8d38", + "726d5c": "a36026", + "91a37c": "7798a1", + "eeeeee": "e6c15e" + }, + "2": { + "8d541b": "157d36", + "297b8b": "4e4f73", + "606f55": "8f825d", + "ffc4d7": "f2e396", + "105262": "3f3c61", + "b4cda4": "d6dbba", + "f5ae07": "24ab2b", + "ce5b9b": "d9ae5d", + "faf550": "3ec435", + "e67b9c": "e3b656", + "bd3983": "c27529", + "eea6bc": "f2d98d", + "5aa4a4": "6a708a", + "b8b7a3": "254e59", + "726d5c": "162d3d", + "91a37c": "b5b48b", + "eeeeee": "3e7a76" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/782.json b/public/images/pokemon/variant/782.json new file mode 100644 index 00000000000..bd04ccc0c70 --- /dev/null +++ b/public/images/pokemon/variant/782.json @@ -0,0 +1,34 @@ +{ + "1": { + "f13035": "48bd8c", + "bec6cb": "e8cea0", + "fdfdfd": "fcf2ca", + "f8f236": "e77b57", + "504e4b": "2b130b", + "aba5ad": "336340", + "7b766f": "472d1d", + "7a756d": "a67e5b", + "726475": "214a33", + "4f4d4b": "8a5b41", + "940a0d": "258067", + "dbdbdb": "4e8759", + "957509": "a63424", + "fff7cc": "f7c4b5" + }, + "2": { + "f13035": "b8c0fc", + "bec6cb": "b7ddeb", + "fdfdfd": "d5f4f7", + "f8f236": "52d9ac", + "504e4b": "132040", + "aba5ad": "5e3e75", + "7b766f": "273959", + "7a756d": "8ab7cf", + "726475": "412959", + "4f4d4b": "567496", + "940a0d": "636a94", + "dbdbdb": "855d99", + "957509": "258085", + "fff7cc": "baf7dc" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/783.json b/public/images/pokemon/variant/783.json new file mode 100644 index 00000000000..0748d5ff79e --- /dev/null +++ b/public/images/pokemon/variant/783.json @@ -0,0 +1,32 @@ +{ + "1": { + "f13035": "48bd8c", + "6c6968": "472d1d", + "97938c": "2a573e", + "4d4644": "2b130b", + "940a0d": "258067", + "fdfdfd": "fcf2ca", + "6e6a69": "8a5b41", + "fff5ae": "f7c4b5", + "c2c1c0": "42754f", + "d7aa22": "c25236", + "957509": "a63424", + "69625c": "133027", + "f4da42": "e77b57" + }, + "2": { + "f13035": "d9ddfc", + "6c6968": "2e4266", + "97938c": "543666", + "4d4644": "151e38", + "940a0d": "636a94", + "fdfdfd": "d5f4f7", + "6e6a69": "567496", + "fff5ae": "baf7dc", + "c2c1c0": "744e87", + "d7aa22": "37ad94", + "957509": "258085", + "69625c": "2d1c3d", + "f4da42": "52d9ac" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/784.json b/public/images/pokemon/variant/784.json new file mode 100644 index 00000000000..0bd28476e98 --- /dev/null +++ b/public/images/pokemon/variant/784.json @@ -0,0 +1,50 @@ +{ + "1": { + "c99f21": "c25236", + "4b4657": "8a5b41", + "544747": "517d37", + "d0d2d5": "77a353", + "fafafa": "f7c4b5", + "d4d6d9": "e8cea0", + "9d6702": "9c3c27", + "f4da42": "e77b57", + "f13035": "48bd8c", + "2d2b28": "2b130b", + "c59c21": "b5482f", + "cb0e12": "258067", + "47444e": "472d1d", + "f7f7f7": "fcf2ca", + "a7a29e": "336142", + "807673": "a67e5b", + "504444": "123028", + "885902": "a63424", + "7e7572": "204736", + "d7d9db": "548752", + "4d4946": "447835", + "fdfdfd": "bbd477" + }, + "2": { + "c99f21": "37ad94", + "4b4657": "567496", + "544747": "558ea3", + "d0d2d5": "7ec2cc", + "fafafa": "daf2e7", + "d4d6d9": "b7ddeb", + "9d6702": "227880", + "f4da42": "52d9ac", + "f13035": "d9ddfc", + "2d2b28": "151e38", + "c59c21": "34a897", + "cb0e12": "636a94", + "47444e": "2e4266", + "f7f7f7": "d5f4f7", + "a7a29e": "6c457a", + "807673": "8ab7cf", + "504444": "2d1840", + "885902": "2b8c8b", + "7e7572": "4e2e61", + "d7d9db": "ac7fb3", + "4d4946": "558fa6", + "fdfdfd": "adedf0" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/840.json b/public/images/pokemon/variant/840.json new file mode 100644 index 00000000000..255e2e7689a --- /dev/null +++ b/public/images/pokemon/variant/840.json @@ -0,0 +1,34 @@ +{ + "1": { + "e2244a": "70a2c5", + "8d4229": "570749", + "94d84a": "e5e8ee", + "5fab1d": "7a7c9e", + "d39a52": "9c2e72", + "e32b50": "4e77a2", + "357912": "313846", + "fe455c": "abd7e2", + "5bab1d": "acb0c3", + "247912": "48485d", + "a50534": "3e6085", + "a4d84a": "9aa0b3", + "f2c171": "c55885", + "fa6f8b": "c1f3f3" + }, + "2": { + "e2244a": "bfb5ab", + "8d4229": "230808", + "94d84a": "589df3", + "5fab1d": "a8546e", + "d39a52": "291411", + "e32b50": "807770", + "357912": "823455", + "fe455c": "dcd9d1", + "5bab1d": "354dbf", + "247912": "2e2246", + "a50534": "68645f", + "a4d84a": "e28c95", + "f2c171": "463731", + "fa6f8b": "eeedea" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/841-gigantamax.json b/public/images/pokemon/variant/841-gigantamax.json new file mode 100644 index 00000000000..5d3b8c49133 --- /dev/null +++ b/public/images/pokemon/variant/841-gigantamax.json @@ -0,0 +1,52 @@ +{ + "1": { + "101010": "101010", + "772628": "3e6085", + "2c4828": "291634", + "427638": "7a7c9e", + "872d23": "460c4d", + "8b3329": "2c255d", + "913c3c": "5b4585", + "a63139": "70a2c5", + "8d4229": "272a52", + "bf6c31": "b668a0", + "d2394d": "abd7e2", + "d54456": "751680", + "c57741": "9c2e72", + "e84466": "8666ae", + "39a43d": "9aa0b3", + "b3ac62": "95aec9", + "c68a48": "2b526f", + "e2bb56": "c55885", + "e9c558": "397880", + "ffc66a": "eeb4cb", + "dad08b": "dcebf9", + "fff1ab": "63b9b9", + "f9f9f9": "f9f9f9" + }, + "2": { + "101010": "101010", + "772628": "695d57", + "2c4828": "341c1c", + "427638": "a54e69", + "872d23": "2e2246", + "8b3329": "3a2222", + "913c3c": "682d2d", + "a63139": "baada1", + "8d4229": "9c564c", + "bf6c31": "354dbf", + "d2394d": "dcd9d1", + "d54456": "2e38bf", + "c57741": "291411", + "e84466": "915a41", + "39a43d": "e28c95", + "b3ac62": "c1a39c", + "c68a48": "d1a87e", + "e2bb56": "463731", + "e9c558": "eee0bc", + "ffc66a": "589df3", + "dad08b": "e2dcd6", + "fff1ab": "fdf3c0", + "f9f9f9": "f9f9f9" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/841.json b/public/images/pokemon/variant/841.json new file mode 100644 index 00000000000..3f1c756da5e --- /dev/null +++ b/public/images/pokemon/variant/841.json @@ -0,0 +1,38 @@ +{ + "1": { + "df6655": "c55885", + "b5915b": "34123a", + "9b2629": "70a2c5", + "8d764b": "110723", + "56ab32": "a59ab3", + "f0bda6": "c1f3f3", + "c3a965": "b3b1d6", + "f1c950": "f3c5dd", + "ccca71": "e6dcf9", + "ccb468": "5d2654", + "612324": "3e6085", + "d72d31": "abd7e2", + "874c23": "613863", + "ebe381": "854774", + "488235": "8e7a9e", + "395a2e": "383146" + }, + "2": { + "df6655": "463731", + "b5915b": "541711", + "9b2629": "bfb5ab", + "8d764b": "230313", + "56ab32": "e28c95", + "f0bda6": "eeedea", + "c3a965": "cbb4af", + "f1c950": "589df3", + "ccca71": "e2dcd6", + "ccb468": "8b4332", + "612324": "68645f", + "d72d31": "dcd9d1", + "874c23": "2e2246", + "ebe381": "c68862", + "488235": "a8546e", + "395a2e": "4f0e30" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/842-gigantamax.json b/public/images/pokemon/variant/842-gigantamax.json new file mode 100644 index 00000000000..5d3b8c49133 --- /dev/null +++ b/public/images/pokemon/variant/842-gigantamax.json @@ -0,0 +1,52 @@ +{ + "1": { + "101010": "101010", + "772628": "3e6085", + "2c4828": "291634", + "427638": "7a7c9e", + "872d23": "460c4d", + "8b3329": "2c255d", + "913c3c": "5b4585", + "a63139": "70a2c5", + "8d4229": "272a52", + "bf6c31": "b668a0", + "d2394d": "abd7e2", + "d54456": "751680", + "c57741": "9c2e72", + "e84466": "8666ae", + "39a43d": "9aa0b3", + "b3ac62": "95aec9", + "c68a48": "2b526f", + "e2bb56": "c55885", + "e9c558": "397880", + "ffc66a": "eeb4cb", + "dad08b": "dcebf9", + "fff1ab": "63b9b9", + "f9f9f9": "f9f9f9" + }, + "2": { + "101010": "101010", + "772628": "695d57", + "2c4828": "341c1c", + "427638": "a54e69", + "872d23": "2e2246", + "8b3329": "3a2222", + "913c3c": "682d2d", + "a63139": "baada1", + "8d4229": "9c564c", + "bf6c31": "354dbf", + "d2394d": "dcd9d1", + "d54456": "2e38bf", + "c57741": "291411", + "e84466": "915a41", + "39a43d": "e28c95", + "b3ac62": "c1a39c", + "c68a48": "d1a87e", + "e2bb56": "463731", + "e9c558": "eee0bc", + "ffc66a": "589df3", + "dad08b": "e2dcd6", + "fff1ab": "fdf3c0", + "f9f9f9": "f9f9f9" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/842.json b/public/images/pokemon/variant/842.json new file mode 100644 index 00000000000..9563715745e --- /dev/null +++ b/public/images/pokemon/variant/842.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "1f4329": "313846", + "1f5829": "852560", + "2c743e": "7a7c9e", + "9f7034": "9aa0b3", + "ac6b20": "110723", + "af2348": "67829e", + "e75574": "70a2c5", + "39a45f": "92cbd9", + "7de755": "9aa0b3", + "e78422": "1f1946", + "ffa63b": "2d3d68", + "f1cf6d": "a3b9d0", + "f9d56d": "698db4", + "ffc575": "2b526f", + "f18e8e": "c1f3f3", + "fcff86": "397880" + }, + "2": { + "101010": "101010", + "1f4329": "511c2d", + "1f5829": "2e2246", + "2c743e": "a8546e", + "9f7034": "3a130d", + "ac6b20": "68645f", + "af2348": "bfb5ab", + "e75574": "dcd9d1", + "39a45f": "e28c95", + "7de755": "589df3", + "e78422": "4b211b", + "ffa63b": "63473b", + "f1cf6d": "cbb4af", + "f9d56d": "b9937a", + "ffc575": "d1a87e", + "f18e8e": "eeedea", + "fcff86": "eee0bc" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/871.json b/public/images/pokemon/variant/871.json new file mode 100644 index 00000000000..5004d3013b5 --- /dev/null +++ b/public/images/pokemon/variant/871.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "2e2732": "1b3334", + "281f2e": "2a2732", + "46384c": "504540", + "493d4e": "3a5d57", + "665272": "62857c", + "544947": "7d320e", + "7a7270": "a8501b", + "9e9a96": "cd7930", + "7b4e1c": "5b0d3f", + "d58815": "a02c58", + "fdba2f": "c45858", + "fdf22f": "f1e8e8" + }, + "2": { + "101010": "101010", + "2e2732": "8b4738", + "281f2e": "212232", + "46384c": "504740", + "493d4e": "ce8a66", + "665272": "eac69b", + "544947": "1a1730", + "7a7270": "27223b", + "9e9a96": "3a3449", + "7b4e1c": "222c58", + "d58815": "343f7f", + "fdba2f": "67729f", + "fdf22f": "8e9fc9" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/88.json b/public/images/pokemon/variant/88.json new file mode 100644 index 00000000000..61b7ca3b802 --- /dev/null +++ b/public/images/pokemon/variant/88.json @@ -0,0 +1,28 @@ +{ + "1": { + "101010": "101010", + "424a5a": "5b3a1d", + "5a3173": "6a010c", + "848c9c": "9b7c48", + "944a9c": "b1160e", + "adb5bd": "e9de8c", + "bd7bbd": "d55021", + "ce8cc5": "e98a47", + "d6d6de": "ded7ce", + "ffffff": "ffffff", + "efade6": "f8be70" + }, + "2": { + "101010": "101010", + "424a5a": "2d7351", + "5a3173": "a21851", + "848c9c": "69b17b", + "944a9c": "d04569", + "adb5bd": "b0e4a9", + "bd7bbd": "ed8ea2", + "ce8cc5": "f4bfbf", + "d6d6de": "d6d6de", + "ffffff": "ffffff", + "efade6": "f8d8cf" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/89.json b/public/images/pokemon/variant/89.json new file mode 100644 index 00000000000..eda3558d7c2 --- /dev/null +++ b/public/images/pokemon/variant/89.json @@ -0,0 +1,30 @@ +{ + "1": { + "101010": "101010", + "424a5a": "5b3a1d", + "5a3173": "6a010c", + "848c9c": "9b7c48", + "944a9c": "b1160e", + "adb5bd": "e9de8c", + "bd7bbd": "d55021", + "ce8cc5": "e98a47", + "d6d6de": "ded7ce", + "ffffff": "ffffff", + "efade6": "f8be70", + "ad63ad": "c63a17" + }, + "2": { + "101010": "101010", + "424a5a": "2d7351", + "5a3173": "a21851", + "848c9c": "69b17b", + "944a9c": "d04569", + "adb5bd": "b0e4a9", + "bd7bbd": "ed8ea2", + "ce8cc5": "f4bfbf", + "d6d6de": "d6d6de", + "ffffff": "ffffff", + "efade6": "f8d8cf", + "ad63ad": "e5728a" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/_exp_masterlist.json b/public/images/pokemon/variant/_exp_masterlist.json new file mode 100644 index 00000000000..e588be59073 --- /dev/null +++ b/public/images/pokemon/variant/_exp_masterlist.json @@ -0,0 +1,678 @@ +{ + "3-mega": [0, 2, 2], + "6-mega-x": [0, 2, 2], + "6-mega-y": [0, 2, 2], + "80-mega": [0, 1, 1], + "94-mega": [2, 2, 2], + "127-mega": [0, 1, 1], + "130-mega": [0, 1, 1], + "142-mega": [0, 1, 1], + "150-mega-x": [0, 1, 1], + "150-mega-y": [0, 1, 1], + "181-mega": [0, 1, 2], + "212-mega": [1, 1, 2], + "229-mega": [0, 1, 1], + "248-mega": [0, 1, 1], + "257-mega": [0, 1, 1], + "282-mega": [0, 2, 2], + "302-mega": [0, 1, 1], + "303-mega": [0, 1, 1], + "306-mega": [1, 1, 1], + "308-mega": [0, 1, 1], + "310-mega": [0, 1, 1], + "334-mega": [0, 2, 1], + "354-mega": [0, 1, 1], + "359-mega": [0, 1, 1], + "362-mega": [0, 1, 1], + "373-mega": [0, 1, 1], + "376-mega": [0, 1, 1], + "380-mega": [0, 1, 1], + "381-mega": [0, 1, 1], + "382-primal": [0, 1, 1], + "383-primal": [0, 1, 1], + "384-mega": [0, 2, 1], + "428-mega": [0, 1, 1], + "445-mega": [1, 1, 1], + "448-mega": [1, 1, 1], + "475-mega": [0, 2, 2], + "531-mega": [0, 1, 1], + "653": [0, 1, 1], + "654": [0, 1, 1], + "655": [0, 1, 1], + "656": [0, 1, 1], + "657": [0, 1, 1], + "658": [0, 1, 1], + "658-ash": [0, 1, 1], + "664": [0, 1, 1], + "665": [0, 1, 1], + "666-archipelago": [0, 1, 1], + "666-continental": [0, 1, 1], + "666-elegant": [0, 1, 1], + "666-fancy": [0, 1, 1], + "666-garden": [0, 1, 1], + "666-high-plains": [0, 1, 1], + "666-icy-snow": [0, 1, 1], + "666-jungle": [0, 1, 1], + "666-marine": [0, 1, 1], + "666-meadow": [0, 1, 1], + "666-modern": [0, 1, 1], + "666-monsoon": [0, 1, 1], + "666-ocean": [0, 1, 1], + "666-poke-ball": [0, 1, 1], + "666-polar": [0, 1, 1], + "666-river": [0, 1, 1], + "666-sandstorm": [0, 1, 1], + "666-savanna": [0, 1, 1], + "666-sun": [0, 1, 1], + "666-tundra": [0, 1, 1], + "669-red": [0, 2, 2], + "669-blue": [0, 1, 1], + "669-white": [0, 1, 1], + "669-yellow": [0, 1, 1], + "669-orange": [0, 2, 2], + "670-white": [0, 1, 1], + "670-blue": [0, 1, 1], + "670-orange": [0, 1, 1], + "670-red": [0, 1, 1], + "670-yellow": [0, 1, 1], + "671-red": [0, 1, 2], + "671-blue": [0, 1, 2], + "671-yellow": [0, 1, 1], + "671-white": [0, 1, 2], + "671-orange": [0, 1, 2], + "672": [0, 1, 1], + "673": [0, 1, 1], + "676": [0, 1, 1], + "677": [0, 1, 1], + "678-female": [0, 1, 1], + "678": [0, 1, 1], + "682": [0, 1, 1], + "683": [0, 1, 1], + "684": [0, 1, 1], + "685": [0, 1, 1], + "688": [0, 1, 1], + "689": [0, 1, 1], + "690": [0, 1, 1], + "691": [0, 1, 1], + "692": [0, 1, 1], + "693": [0, 1, 1], + "696": [0, 1, 1], + "697": [0, 1, 1], + "699": [0, 1, 1], + "700": [0, 1, 1], + "702": [0, 1, 1], + "704": [0, 1, 1], + "705": [0, 1, 1], + "706": [0, 1, 1], + "709": [0, 1, 1], + "710": [0, 1, 1], + "711": [1, 1, 1], + "712": [0, 1, 1], + "713": [0, 1, 1], + "715": [0, 1, 1], + "716-active": [0, 1, 1], + "716-neutral": [0, 1, 1], + "717": [0, 2, 2], + "720-unbound": [1, 1, 1], + "720": [1, 1, 1], + "728": [0, 1, 1], + "729": [0, 1, 1], + "730": [0, 1, 1], + "734": [0, 1, 1], + "735": [0, 1, 1], + "742": [0, 2, 2], + "743": [0, 2, 2], + "746": [0, 1, 1], + "746-school": [0, 1, 1], + "747": [0, 2, 2], + "748": [0, 1, 1], + "751": [0, 1, 1], + "752": [0, 1, 1], + "753": [0, 1, 1], + "754": [0, 2, 2], + "755": [0, 1, 1], + "756": [0, 1, 1], + "761": [0, 1, 1], + "762": [0, 1, 1], + "763": [0, 1, 1], + "767": [0, 1, 1], + "768": [0, 1, 1], + "770": [0, 0, 0], + "771": [0, 2, 2], + "772": [0, 1, 1], + "773-fighting": [0, 1, 1], + "773-psychic": [0, 1, 1], + "773-poison": [0, 1, 1], + "773-ground": [0, 1, 1], + "773-ghost": [0, 1, 1], + "773-steel": [0, 1, 1], + "773-rock": [0, 1, 1], + "773-grass": [0, 1, 1], + "773-dragon": [0, 1, 1], + "773-bug": [0, 1, 1], + "773-ice": [0, 1, 1], + "773-dark": [0, 1, 1], + "773": [0, 1, 1], + "773-fairy": [0, 1, 1], + "773-water": [0, 1, 1], + "773-electric": [0, 1, 1], + "773-flying": [0, 1, 1], + "773-fire": [0, 1, 1], + "776": [0, 1, 1], + "777": [0, 1, 1], + "778-busted": [0, 1, 1], + "778-disguised": [0, 1, 1], + "779": [0, 1, 1], + "780": [0, 1, 1], + "789": [1, 1, 1], + "790": [0, 1, 1], + "791": [2, 1, 1], + "792": [0, 1, 1], + "793": [0, 2, 2], + "797": [0, 1, 1], + "798": [0, 1, 1], + "800-dawn-wings": [0, 1, 1], + "800-dusk-mane": [0, 1, 1], + "800-ultra": [0, 1, 1], + "800": [0, 1, 1], + "802": [1, 1, 1], + "803": [0, 1, 1], + "804": [0, 1, 1], + "807": [0, 1, 1], + "808": [0, 1, 1], + "809": [0, 1, 1], + "816": [0, 1, 1], + "817": [0, 1, 1], + "818": [1, 1, 1], + "821": [0, 2, 2], + "822": [0, 1, 1], + "823": [0, 1, 1], + "829": [0, 1, 1], + "830": [0, 1, 1], + "835": [0, 1, 1], + "836": [0, 2, 2], + "840": [0, 1, 1], + "841": [0, 1, 1], + "842": [0, 1, 1], + "850": [0, 1, 1], + "851": [0, 1, 1], + "854": [0, 1, 1], + "855": [0, 1, 1], + "856": [0, 1, 1], + "857": [0, 2, 2], + "858": [0, 1, 1], + "859": [0, 1, 1], + "860": [0, 1, 1], + "861": [0, 1, 1], + "862": [0, 1, 1], + "863": [0, 1, 1], + "864": [0, 1, 1], + "867": [0, 1, 1], + "871": [0, 1, 1], + "872": [1, 1, 1], + "873": [1, 1, 1], + "876-female": [0, 1, 1], + "876": [0, 1, 1], + "877-hangry": [1, 1, 1], + "877": [1, 1, 1], + "880": [0, 1, 1], + "881": [0, 1, 1], + "882": [0, 2, 1], + "883": [0, 1, 1], + "884": [0, 1, 1], + "885": [1, 1, 1], + "886": [1, 1, 1], + "887": [1, 1, 1], + "888": [0, 1, 1], + "888-crowned": [0, 1, 1], + "889": [0, 1, 1], + "889-crowned": [0, 1, 1], + "890": [0, 2, 1], + "890-eternamax": [0, 1, 1], + "891": [1, 1, 1], + "892-rapid-strike": [1, 1, 1], + "892": [1, 1, 1], + "894": [0, 1, 1], + "895": [0, 1, 1], + "896": [1, 1, 1], + "897": [1, 1, 1], + "898": [1, 1, 1], + "898-ice": [1, 1, 1], + "898-shadow": [1, 1, 1], + "900": [0, 1, 1], + "901": [0, 1, 1], + "903": [0, 1, 1], + "909": [0, 1, 1], + "910": [0, 2, 2], + "911": [0, 2, 2], + "912": [0, 1, 2], + "913": [0, 1, 2], + "914": [0, 2, 1], + "919": [1, 1, 1], + "920": [1, 1, 1], + "924": [1, 1, 1], + "925-four": [1, 2, 2], + "925-three": [1, 2, 2], + "932": [0, 2, 2], + "933": [0, 2, 2], + "934": [0, 1, 1], + "935": [1, 1, 2], + "936": [2, 2, 2], + "937": [2, 2, 2], + "940": [0, 1, 1], + "941": [0, 1, 1], + "944": [0, 1, 1], + "945": [0, 1, 1], + "948": [0, 1, 1], + "949": [0, 1, 1], + "951": [0, 1, 1], + "952": [0, 1, 1], + "953": [0, 1, 1], + "954": [0, 1, 1], + "957": [2, 2, 2], + "958": [2, 2, 2], + "959": [2, 2, 2], + "962": [1, 1, 1], + "967": [0, 1, 1], + "968": [0, 1, 1], + "969": [0, 1, 1], + "970": [0, 1, 1], + "973": [1, 1, 1], + "974": [0, 1, 1], + "975": [0, 1, 1], + "978-curly": [0, 2, 2], + "978-droopy": [0, 2, 2], + "978-stretchy": [0, 2, 2], + "979": [2, 2, 2], + "981": [0, 1, 1], + "982": [0, 1, 1], + "982-three-segment": [0, 1, 1], + "987": [1, 1, 1], + "988": [0, 1, 2], + "993": [0, 1, 1], + "994": [0, 1, 2], + "995": [0, 1, 1], + "996": [0, 1, 1], + "997": [0, 2, 2], + "998": [0, 2, 2], + "999": [2, 1, 1], + "1000": [1, 1, 1], + "1001": [0, 1, 1], + "1003": [0, 1, 1], + "1004": [0, 1, 1], + "1006": [0, 2, 1], + "1007-apex-build": [0, 2, 2], + "1008-ultimate-mode": [1, 1, 1], + "2026": [0, 1, 1], + "2027": [0, 1, 1], + "2028": [0, 1, 1], + "2037": [0, 1, 1], + "2038": [0, 1, 1], + "2052": [0, 1, 1], + "2053": [0, 1, 0], + "2103": [0, 1, 1], + "4052": [0, 1, 1], + "4077": [0, 1, 1], + "4078": [0, 1, 1], + "4079": [0, 1, 1], + "4080": [2, 1, 1], + "4144": [0, 1, 1], + "4145": [0, 1, 1], + "4146": [0, 1, 1], + "4199": [2, 1, 1], + "4222": [0, 1, 1], + "4263": [0, 1, 1], + "4264": [0, 1, 1], + "4562": [0, 1, 1], + "6100": [0, 1, 1], + "6101": [0, 1, 1], + "6215": [0, 1, 1], + "6503": [0, 1, 1], + "6549": [0, 1, 1], + "6570": [0, 1, 1], + "6571": [0, 1, 1], + "6705": [0, 1, 1], + "6706": [0, 1, 1], + "6713": [0, 1, 1], + "female": { + "6215": [0, 1, 1] + }, + "back": { + "3-mega": [0, 2, 2], + "6-mega-x": [0, 2, 2], + "6-mega-y": [0, 1, 2], + "80-mega": [0, 1, 1], + "94-mega": [1, 1, 1], + "127-mega": [0, 1, 1], + "130-mega": [0, 1, 1], + "142-mega": [0, 1, 1], + "150-mega-x": [0, 1, 1], + "150-mega-y": [0, 1, 1], + "181-mega": [0, 1, 2], + "212-mega": [1, 2, 2], + "229-mega": [0, 1, 1], + "248-mega": [0, 1, 1], + "257-mega": [0, 1, 1], + "282-mega": [0, 1, 1], + "302-mega": [0, 1, 1], + "303-mega": [0, 1, 1], + "306-mega": [1, 1, 1], + "308-mega": [0, 1, 1], + "310-mega": [0, 1, 1], + "334-mega": [0, 1, 1], + "354-mega": [0, 1, 1], + "359-mega": [0, 1, 1], + "362-mega": [0, 1, 1], + "373-mega": [0, 1, 1], + "376-mega": [0, 1, 1], + "380-mega": [0, 1, 1], + "381-mega": [0, 1, 1], + "382-primal": [0, 1, 1], + "383-primal": [0, 1, 1], + "384-mega": [0, 1, 1], + "428-mega": [0, 1, 1], + "445-mega": [1, 1, 1], + "448-mega": [1, 1, 1], + "475-mega": [0, 2, 2], + "531-mega": [0, 1, 1], + "653": [0, 1, 1], + "654": [0, 1, 1], + "655": [0, 1, 1], + "656": [0, 1, 1], + "657": [0, 1, 1], + "658": [0, 1, 1], + "658-ash": [0, 1, 1], + "664": [0, 1, 1], + "665": [0, 1, 1], + "666-archipelago": [0, 1, 1], + "666-continental": [0, 1, 1], + "666-elegant": [0, 1, 1], + "666-fancy": [0, 1, 1], + "666-garden": [0, 1, 1], + "666-high-plains": [0, 1, 1], + "666-icy-snow": [0, 1, 1], + "666-jungle": [0, 1, 1], + "666-marine": [0, 1, 1], + "666-meadow": [0, 1, 1], + "666-modern": [0, 1, 1], + "666-monsoon": [0, 1, 1], + "666-ocean": [0, 1, 1], + "666-poke-ball": [0, 1, 1], + "666-polar": [0, 1, 1], + "666-river": [0, 1, 1], + "666-sandstorm": [0, 1, 1], + "666-savanna": [0, 1, 1], + "666-sun": [0, 1, 1], + "666-tundra": [0, 1, 1], + "669-red": [0, 2, 2], + "669-blue": [0, 2, 2], + "669-white": [0, 2, 2], + "669-yellow": [0, 2, 2], + "669-orange": [0, 2, 2], + "670-white": [0, 1, 1], + "670-blue": [0, 2, 2], + "670-orange": [0, 1, 1], + "670-red": [0, 1, 1], + "670-yellow": [0, 1, 1], + "671-red": [0, 1, 1], + "671-blue": [0, 1, 1], + "671-yellow": [0, 1, 1], + "671-white": [0, 1, 1], + "671-orange": [0, 1, 1], + "672": [0, 1, 1], + "673": [0, 1, 1], + "676": [0, 1, 1], + "677": [0, 1, 1], + "678-female": [0, 1, 1], + "678": [0, 1, 1], + "682": [0, 1, 1], + "683": [0, 1, 1], + "684": [0, 1, 1], + "685": [0, 1, 1], + "688": [0, 1, 1], + "689": [0, 1, 1], + "690": [0, 1, 1], + "691": [0, 1, 1], + "692": [0, 1, 1], + "693": [0, 1, 1], + "696": [0, 1, 1], + "697": [0, 1, 1], + "699": [0, 2, 2], + "700": [0, 1, 1], + "702": [0, 1, 1], + "704": [0, 1, 1], + "705": [0, 1, 1], + "706": [0, 1, 1], + "709": [0, 1, 1], + "710": [0, 1, 1], + "711": [1, 1, 1], + "712": [0, 1, 1], + "713": [0, 1, 1], + "715": [0, 1, 1], + "716-active": [0, 1, 1], + "716-neutral": [0, 1, 1], + "717": [0, 1, 1], + "720-unbound": [1, 1, 1], + "720": [1, 1, 1], + "728": [0, 1, 1], + "729": [0, 1, 1], + "730": [0, 1, 1], + "734": [0, 1, 1], + "735": [0, 1, 1], + "742": [0, 2, 2], + "743": [0, 2, 2], + "746": [0, 1, 1], + "746-school": [0, 1, 1], + "747": [0, 2, 2], + "748": [0, 1, 1], + "751": [0, 1, 1], + "752": [0, 1, 1], + "753": [0, 1, 1], + "754": [0, 2, 2], + "755": [0, 1, 1], + "756": [0, 1, 1], + "761": [0, 1, 1], + "762": [0, 1, 1], + "763": [0, 1, 1], + "767": [0, 1, 1], + "768": [0, 1, 1], + "771": [0, 1, 1], + "772": [0, 1, 1], + "773-fighting": [0, 1, 1], + "773-psychic": [0, 1, 1], + "773-poison": [0, 1, 1], + "773-ground": [0, 1, 1], + "773-ghost": [0, 1, 1], + "773-steel": [0, 1, 1], + "773-rock": [0, 1, 1], + "773-grass": [0, 1, 1], + "773-dragon": [0, 1, 1], + "773-bug": [0, 1, 1], + "773-ice": [0, 1, 1], + "773-dark": [0, 1, 1], + "773": [0, 1, 1], + "773-fairy": [0, 1, 1], + "773-water": [0, 1, 1], + "773-electric": [0, 1, 1], + "773-flying": [0, 1, 1], + "773-fire": [0, 1, 1], + "776": [0, 2, 2], + "777": [0, 1, 1], + "778-busted": [0, 1, 1], + "778-disguised": [0, 1, 1], + "779": [0, 1, 1], + "780": [0, 1, 1], + "789": [1, 1, 1], + "790": [0, 1, 1], + "791": [1, 1, 1], + "792": [0, 1, 1], + "793": [0, 1, 1], + "797": [0, 1, 1], + "798": [0, 1, 1], + "800-dawn-wings": [0, 1, 1], + "800-dusk-mane": [0, 1, 1], + "800-ultra": [0, 1, 1], + "800": [0, 1, 1], + "802": [1, 1, 1], + "803": [0, 1, 1], + "804": [0, 1, 1], + "807": [0, 1, 1], + "808": [0, 1, 1], + "809": [0, 1, 1], + "816": [0, 1, 1], + "817": [0, 1, 1], + "818": [0, 1, 1], + "821": [0, 1, 1], + "822": [0, 1, 1], + "823": [0, 1, 1], + "829": [0, 1, 1], + "830": [0, 1, 1], + "835": [0, 1, 1], + "836": [0, 1, 1], + "840": [0, 1, 1], + "841": [0, 1, 1], + "842": [0, 1, 1], + "850": [0, 1, 1], + "851": [0, 1, 1], + "854": [0, 1, 1], + "855": [0, 1, 1], + "856": [0, 1, 1], + "857": [0, 2, 2], + "858": [0, 1, 1], + "859": [0, 1, 1], + "860": [0, 1, 1], + "861": [0, 1, 1], + "862": [0, 1, 1], + "863": [0, 1, 1], + "864": [0, 1, 1], + "867": [0, 1, 1], + "871": [0, 1, 1], + "872": [1, 1, 1], + "873": [1, 1, 1], + "876-female": [0, 1, 1], + "876": [0, 1, 1], + "877-hangry": [1, 1, 1], + "877": [1, 1, 1], + "880": [0, 1, 1], + "881": [0, 1, 1], + "882": [0, 1, 1], + "883": [0, 1, 1], + "884": [0, 1, 1], + "885": [1, 1, 1], + "886": [1, 1, 1], + "887": [1, 1, 1], + "888": [0, 1, 1], + "888-crowned": [0, 1, 1], + "889": [0, 1, 1], + "889-crowned": [0, 1, 1], + "890": [0, 1, 1], + "891": [1, 1, 1], + "892-rapid-strike": [1, 1, 1], + "892": [1, 1, 1], + "894": [0, 1, 1], + "895": [0, 1, 1], + "896": [1, 1, 1], + "897": [1, 1, 1], + "898": [1, 1, 1], + "898-ice": [1, 1, 1], + "898-shadow": [1, 1, 1], + "900": [0, 1, 1], + "901": [0, 1, 1], + "903": [0, 1, 1], + "909": [0, 1, 1], + "910": [0, 2, 2], + "911": [0, 1, 1], + "912": [0, 1, 1], + "913": [0, 1, 1], + "914": [0, 2, 2], + "919": [1, 1, 1], + "920": [1, 1, 1], + "924": [1, 1, 1], + "925-four": [1, 2, 2], + "925-three": [1, 2, 2], + "932": [0, 1, 1], + "933": [0, 1, 1], + "934": [0, 1, 1], + "935": [2, 2, 2], + "936": [2, 2, 2], + "937": [2, 2, 2], + "940": [0, 1, 1], + "941": [0, 1, 1], + "944": [0, 1, 1], + "945": [0, 1, 1], + "948": [0, 1, 1], + "949": [0, 1, 1], + "951": [0, 1, 1], + "952": [0, 2, 1], + "953": [0, 1, 1], + "954": [0, 1, 1], + "957": [1, 1, 1], + "958": [1, 1, 1], + "959": [1, 1, 1], + "962": [1, 1, 1], + "967": [0, 1, 1], + "968": [0, 2, 2], + "969": [0, 1, 1], + "970": [0, 1, 1], + "973": [1, 1, 1], + "974": [0, 1, 1], + "975": [0, 1, 1], + "978-curly": [0, 2, 2], + "978-droopy": [0, 2, 2], + "978-stretchy": [0, 1, 1], + "979": [1, 1, 1], + "981": [0, 1, 1], + "982": [0, 1, 1], + "982-three-segment": [0, 1, 1], + "987": [1, 1, 1], + "988": [0, 1, 1], + "993": [0, 1, 1], + "994": [0, 1, 1], + "995": [0, 1, 1], + "996": [0, 1, 1], + "997": [0, 1, 1], + "998": [0, 1, 1], + "999": [1, 1, 1], + "1000": [1, 1, 1], + "1001": [0, 1, 1], + "1003": [0, 1, 1], + "1004": [0, 1, 1], + "1006": [0, 2, 2], + "1007-apex-build": [0, 2, 2], + "1008-ultimate-mode": [1, 1, 1], + "2026": [0, 1, 1], + "2027": [0, 1, 1], + "2028": [0, 1, 1], + "2037": [0, 1, 1], + "2038": [0, 1, 1], + "2052": [0, 1, 1], + "2053": [0, 1, 1], + "2103": [0, 1, 1], + "4052": [0, 1, 1], + "4077": [0, 1, 1], + "4078": [0, 1, 1], + "4079": [0, 1, 1], + "4080": [2, 2, 2], + "4144": [0, 1, 1], + "4145": [0, 1, 1], + "4146": [0, 1, 1], + "4199": [2, 1, 1], + "4222": [0, 1, 1], + "4263": [0, 1, 1], + "4264": [0, 1, 1], + "4562": [0, 1, 1], + "6100": [0, 1, 1], + "6101": [0, 1, 1], + "6215": [0, 1, 1], + "6503": [0, 1, 1], + "6549": [0, 1, 1], + "6570": [0, 1, 1], + "6571": [0, 1, 1], + "6705": [0, 1, 1], + "6706": [0, 1, 1], + "6713": [0, 1, 1], + "female": { + "6215": [0, 1, 1] + } + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/_masterlist.json b/public/images/pokemon/variant/_masterlist.json index 175b56139a6..719f3db3d86 100644 --- a/public/images/pokemon/variant/_masterlist.json +++ b/public/images/pokemon/variant/_masterlist.json @@ -32,6 +32,9 @@ "29": [0, 1, 1], "30": [0, 1, 1], "31": [1, 1, 1], + "32": [0, 1, 1], + "33": [0, 1, 1], + "34": [0, 1, 1], "35": [0, 1, 2], "36": [0, 1, 1], "37": [0, 1, 1], @@ -67,6 +70,8 @@ "85": [1, 1, 1], "86": [1, 1, 1], "87": [1, 1, 1], + "88": [0, 1, 1], + "89": [0, 1, 1], "92": [2, 2, 2], "93": [1, 1, 1], "94-gigantamax": [1, 2, 2], @@ -113,6 +118,8 @@ "141": [0, 2, 2], "142-mega": [0, 1, 1], "142": [0, 1, 1], + "143-gigantamax": [0, 1, 1], + "143": [0, 1, 1], "144": [1, 2, 2], "145": [1, 1, 1], "146": [1, 1, 1], @@ -154,6 +161,9 @@ "183": [0, 1, 2], "184": [0, 2, 2], "185": [0, 1, 1], + "187": [0, 1, 1], + "188": [0, 1, 1], + "189": [0, 1, 1], "190": [0, 1, 1], "193": [0, 1, 1], "194": [0, 1, 1], @@ -192,6 +202,8 @@ "201-w": [0, 1, 1], "201-o": [0, 1, 1], "203": [0, 1, 1], + "204": [0, 1, 1], + "205": [0, 1, 1], "206": [0, 1, 1], "207": [0, 1, 1], "211": [0, 1, 1], @@ -247,6 +259,7 @@ "291": [2, 2, 2], "292": [2, 1, 2], "298": [0, 2, 2], + "299": [0, 1, 1], "300": [1, 1, 1], "301": [1, 1, 1], "302": [0, 1, 1], @@ -265,13 +278,19 @@ "310": [0, 1, 1], "311": [1, 1, 1], "312": [0, 1, 1], + "313": [0, 1, 1], + "314": [0, 1, 1], "315": [0, 1, 1], "320": [0, 1, 1], "321": [0, 1, 1], + "325": [0, 1, 1], + "326": [0, 1, 1], "327": [0, 1, 1], "328": [0, 1, 1], "329": [0, 1, 2], "330": [0, 1, 1], + "331": [0, 1, 1], + "332": [0, 1, 1], "333": [0, 1, 1], "334-mega": [0, 2, 1], "334": [0, 2, 2], @@ -283,6 +302,8 @@ "340": [0, 1, 2], "341": [0, 2, 2], "342": [0, 2, 2], + "345": [0, 1, 1], + "346": [0, 1, 1], "351-rainy": [1, 2, 2], "351-snowy": [1, 1, 1], "351-sunny": [1, 2, 2], @@ -331,10 +352,16 @@ "393": [0, 1, 1], "394": [0, 1, 1], "395": [0, 1, 1], + "396": [0, 1, 1], + "397": [0, 1, 1], + "398": [0, 1, 1], "399": [0, 1, 1], "400": [0, 1, 1], "401": [0, 1, 1], "402": [0, 1, 1], + "403": [0, 1, 1], + "404": [0, 1, 1], + "405": [0, 1, 1], "406": [0, 1, 1], "407": [0, 1, 1], "412-sandy": [2, 2, 2], @@ -344,8 +371,12 @@ "413-trash": [1, 1, 1], "413-sandy": [1, 1, 1], "414": [0, 1, 1], + "417": [0, 1, 1], "418": [0, 1, 1], "419": [0, 1, 1], + "420": [0, 1, 1], + "421-overcast": [0, 1, 1], + "421-sunshine": [0, 1, 1], "422-west": [1, 1, 1], "422-east": [1, 1, 1], "423-west": [1, 1, 1], @@ -369,6 +400,7 @@ "444": [1, 1, 1], "445-mega": [1, 1, 1], "445": [1, 1, 1], + "446": [0, 1, 1], "447": [1, 1, 1], "448-mega": [1, 1, 1], "448": [1, 1, 1], @@ -392,6 +424,7 @@ "474": [0, 1, 1], "475-mega": [0, 2, 2], "475": [0, 1, 1], + "476": [0, 1, 1], "478": [0, 2, 1], "479-heat": [0, 1, 1], "479-wash": [0, 1, 1], @@ -416,11 +449,22 @@ "495": [0, 1, 1], "496": [0, 1, 1], "497": [0, 1, 1], + "498": [0, 1, 1], + "499": [0, 1, 1], + "500": [0, 1, 1], "501": [0, 1, 1], "502": [0, 1, 1], "503": [0, 1, 1], + "511": [0, 1, 1], + "512": [0, 1, 1], + "513": [0, 1, 1], + "514": [0, 1, 1], + "515": [0, 1, 1], + "516": [0, 1, 1], "517": [0, 1, 1], "518": [0, 1, 1], + "522": [0, 1, 1], + "523": [0, 1, 1], "524": [0, 1, 1], "525": [0, 1, 1], "526": [0, 2, 2], @@ -433,6 +477,9 @@ "532": [0, 1, 1], "533": [0, 1, 1], "534": [0, 1, 1], + "535": [0, 1, 1], + "536": [0, 1, 1], + "537": [0, 1, 1], "538": [0, 1, 1], "539": [0, 2, 2], "540": [0, 1, 1], @@ -448,17 +495,23 @@ "551": [0, 1, 1], "552": [0, 1, 1], "553": [0, 1, 1], + "554": [0, 1, 1], + "555": [0, 1, 1], + "555-zen": [0, 1, 1], "556": [0, 1, 1], "559": [1, 1, 1], "560": [1, 1, 1], "562": [0, 1, 1], "563": [0, 1, 1], + "566": [0, 1, 1], + "567": [0, 1, 1], "568": [0, 2, 2], "569-gigantamax": [0, 1, 1], "569": [0, 1, 1], "570": [0, 1, 1], "571": [0, 1, 1], "572": [0, 1, 1], + "573": [0, 1, 1], "577": [1, 1, 1], "578": [1, 1, 1], "579": [1, 1, 1], @@ -499,6 +552,7 @@ "621": [0, 1, 1], "622": [0, 1, 1], "623": [0, 1, 1], + "626": [0, 1, 1], "631": [0, 2, 2], "632": [0, 1, 1], "633": [0, 1, 1], @@ -507,6 +561,11 @@ "636": [0, 1, 1], "637": [0, 1, 1], "640": [0, 1, 1], + "643": [0, 1, 1], + "644": [0, 1, 1], + "646-black": [0, 1, 1], + "646-white": [0, 1, 1], + "646": [0, 1, 1], "647-resolute": [0, 1, 1], "647-ordinary": [0, 1, 1], "648-aria": [0, 1, 1], @@ -583,6 +642,8 @@ "689": [0, 1, 1], "690": [0, 1, 1], "691": [0, 1, 1], + "692": [0, 1, 1], + "693": [0, 1, 1], "696": [0, 1, 1], "697": [0, 1, 1], "698": [0, 1, 1], @@ -613,6 +674,8 @@ "735": [0, 1, 1], "742": [0, 2, 2], "743": [0, 2, 2], + "746": [0, 1, 1], + "746-school": [0, 1, 1], "747": [0, 1, 1], "748": [0, 1, 1], "751": [0, 1, 1], @@ -651,6 +714,10 @@ "778-busted": [0, 1, 1], "778-disguised": [0, 1, 1], "779": [0, 1, 1], + "780": [0, 1, 1], + "782": [0, 1, 1], + "783": [0, 1, 1], + "784": [0, 1, 1], "789": [1, 1, 1], "790": [0, 1, 1], "791-radiant-sun": [0, 1, 1], @@ -683,6 +750,11 @@ "830": [0, 1, 1], "835": [0, 1, 1], "836": [0, 2, 2], + "840": [0, 1, 1], + "841-gigantamax": [0, 1, 1], + "841": [0, 1, 1], + "842-gigantamax": [0, 1, 1], + "842": [0, 1, 1], "850": [0, 1, 1], "851-gigantamax": [0, 1, 1], "851": [0, 1, 1], @@ -700,6 +772,7 @@ "863": [0, 1, 1], "864": [0, 1, 1], "867": [0, 1, 1], + "871": [0, 1, 1], "872": [1, 1, 1], "873": [1, 1, 1], "876-female": [0, 1, 1], @@ -798,14 +871,18 @@ "1007-apex-build": [0, 2, 2], "1008-ultimate-mode": [1, 1, 1], "1010": [0, 1, 1], + "1011": [0, 1, 1], "1012-counterfeit": [0, 1, 1], "1013-unremarkable": [0, 1, 1], "1018": [0, 1, 1], + "1019": [0, 1, 1], "1022": [0, 1, 1], "1023": [0, 1, 1], "2026": [0, 1, 1], "2027": [0, 1, 1], "2028": [0, 1, 1], + "2037": [0, 1, 1], + "2038": [0, 1, 1], "2052": [0, 1, 1], "2053": [0, 1, 1], "2103": [0, 1, 1], @@ -880,12 +957,20 @@ "307": [0, 1, 1], "308": [0, 1, 1], "315": [0, 1, 1], + "332": [0, 1, 1], "369": [0, 1, 1], + "396": [0, 1, 1], + "397": [0, 1, 1], + "398": [0, 1, 1], "399": [0, 1, 1], "400": [0, 1, 1], "401": [0, 1, 1], "402": [0, 2, 2], + "403": [0, 1, 1], + "404": [0, 1, 1], + "405": [0, 1, 1], "407": [0, 1, 1], + "417": [0, 1, 1], "418": [0, 1, 1], "419": [0, 2, 1], "424": [0, 1, 1], @@ -937,6 +1022,9 @@ "29": [0, 1, 1], "30": [0, 1, 1], "31": [1, 1, 1], + "32": [0, 1, 1], + "33": [0, 1, 1], + "34": [0, 1, 1], "35": [0, 1, 1], "36": [0, 2, 1], "37": [0, 1, 1], @@ -972,6 +1060,8 @@ "85": [1, 1, 1], "86": [1, 1, 1], "87": [1, 1, 1], + "88": [0, 1, 1], + "89": [0, 1, 1], "92": [2, 2, 2], "93": [1, 1, 1], "94-gigantamax": [1, 1, 1], @@ -1018,6 +1108,8 @@ "141": [0, 1, 1], "142-mega": [0, 1, 1], "142": [0, 1, 1], + "143-gigantamax": [0, 1, 1], + "143": [0, 1, 1], "144": [1, 1, 1], "145": [1, 1, 1], "146": [1, 1, 1], @@ -1059,6 +1151,9 @@ "183": [0, 1, 1], "184": [0, 1, 1], "185": [0, 1, 1], + "187": [0, 1, 1], + "188": [0, 1, 1], + "189": [0, 1, 1], "190": [0, 1, 1], "193": [0, 1, 1], "194": [0, 1, 1], @@ -1097,6 +1192,8 @@ "201-w": [0, 1, 1], "201-o": [0, 1, 1], "203": [0, 1, 1], + "204": [0, 1, 1], + "205": [0, 1, 1], "206": [0, 1, 1], "207": [0, 1, 1], "211": [0, 1, 1], @@ -1152,6 +1249,7 @@ "291": [2, 2, 2], "292": [2, 2, 2], "298": [0, 1, 1], + "299": [0, 1, 1], "300": [1, 1, 1], "301": [1, 1, 1], "302": [0, 1, 1], @@ -1170,13 +1268,19 @@ "310": [0, 1, 1], "311": [1, 1, 1], "312": [0, 1, 1], + "313": [0, 1, 1], + "314": [0, 1, 1], "315": [0, 1, 1], "320": [0, 1, 1], "321": [0, 1, 1], + "325": [0, 1, 1], + "326": [0, 1, 1], "327": [0, 1, 1], "328": [0, 1, 1], "329": [0, 1, 1], "330": [0, 1, 1], + "331": [0, 1, 1], + "332": [0, 1, 1], "333": [0, 1, 1], "334-mega": [0, 1, 1], "334": [0, 1, 1], @@ -1188,6 +1292,8 @@ "340": [0, 1, 2], "341": [0, 1, 1], "342": [0, 2, 2], + "345": [0, 1, 1], + "346": [0, 1, 1], "351-rainy": [1, 1, 1], "351-snowy": [1, 1, 1], "351-sunny": [1, 1, 2], @@ -1236,10 +1342,16 @@ "393": [0, 1, 1], "394": [0, 1, 1], "395": [0, 1, 1], + "396": [0, 1, 1], + "397": [0, 1, 1], + "398": [0, 1, 1], "399": [0, 2, 1], "400": [0, 1, 1], "401": [0, 1, 1], "402": [0, 1, 1], + "403": [0, 1, 1], + "404": [0, 1, 1], + "405": [0, 1, 1], "406": [0, 1, 1], "407": [0, 1, 1], "412-sandy": [2, 2, 2], @@ -1249,8 +1361,12 @@ "413-trash": [1, 1, 1], "413-sandy": [1, 1, 1], "414": [0, 1, 1], + "417": [0, 1, 1], "418": [0, 1, 1], "419": [0, 1, 1], + "420": [0, 1, 1], + "421-overcast": [0, 1, 1], + "421-sunshine": [0, 1, 1], "422-west": [1, 1, 1], "422-east": [1, 1, 1], "423-west": [1, 1, 1], @@ -1274,6 +1390,7 @@ "444": [1, 1, 1], "445-mega": [1, 1, 1], "445": [1, 1, 1], + "446": [0, 1, 1], "447": [1, 1, 1], "448-mega": [1, 1, 1], "448": [1, 1, 1], @@ -1297,6 +1414,7 @@ "474": [0, 1, 1], "475-mega": [0, 2, 2], "475": [0, 1, 1], + "476": [0, 1, 1], "478": [0, 2, 1], "479-heat": [0, 1, 1], "479-wash": [0, 1, 1], @@ -1307,8 +1425,9 @@ "480": [1, 1, 1], "481": [1, 1, 1], "482": [1, 1, 1], - "485": [0, 1, 1], "486": [0, 1 , 1 - ] ,"487-altered": [0, 1, 1], + "485": [0, 1, 1], + "486": [0, 1 , 1] , + "487-altered": [0, 1, 1], "487-origin": [0, 1, 1], "488": [0, 1, 1], "489": [1, 1, 1], @@ -1320,11 +1439,22 @@ "495": [0, 1, 1], "496": [0, 1, 1], "497": [0, 1, 1], + "498": [0, 1, 1], + "499": [0, 1, 1], + "500": [0, 1, 1], "501": [0, 1, 1], "502": [0, 1, 1], "503": [0, 1, 1], + "511": [0, 1, 1], + "512": [0, 1, 1], + "513": [0, 1, 1], + "514": [0, 1, 1], + "515": [0, 1, 1], + "516": [0, 1, 1], "517": [0, 1, 1], "518": [0, 1, 1], + "522": [0, 1, 1], + "523": [0, 1, 1], "524": [0, 1, 1], "525": [0, 1, 1], "526": [0, 1, 1], @@ -1337,6 +1467,9 @@ "532": [0, 1, 1], "533": [0, 1, 1], "534": [0, 1, 1], + "535": [0, 1, 1], + "536": [0, 1, 1], + "537": [0, 1, 1], "538": [0, 1, 1], "539": [0, 2, 2], "540": [0, 1, 1], @@ -1352,17 +1485,23 @@ "551": [0, 1, 1], "552": [0, 1, 1], "553": [0, 1, 1], + "554": [0, 1, 1], + "555": [0, 1, 1], + "555-zen": [0, 1, 1], "556": [0, 1, 1], "559": [1, 1, 1], "560": [1, 1, 1], "562": [0, 1, 1], "563": [0, 1, 1], + "566": [0, 1, 1], + "567": [0, 1, 1], "568": [0, 1, 1], "569-gigantamax": [0, 1, 1], "569": [0, 1, 1], "570": [0, 1, 1], "571": [0, 1, 1], "572": [0, 1, 1], + "573": [0, 1, 1], "577": [1, 1, 1], "578": [1, 1, 1], "579": [1, 1, 1], @@ -1403,6 +1542,7 @@ "621": [0, 1, 1], "622": [0, 1, 1], "623": [0, 1, 1], + "626": [0, 1, 1], "631": [0, 2, 2], "632": [0, 1, 1], "633": [0, 1, 1], @@ -1411,12 +1551,11 @@ "636": [0, 1, 1], "637": [0, 1, 1], "640": [0, 1, 1], - "641-incarnate": [0, 0, 0], - "641-therian": [0, 0, 0], - "642-incarnate": [0, 0, 0], - "642-therian": [0, 0, 0], - "645-incarnate": [0, 0, 0], - "645-therian": [0, 0, 0], + "643": [0, 1, 1], + "644": [0, 1, 1], + "646-black": [0, 1, 1], + "646-white": [0, 1, 1], + "646": [0, 1, 1], "647-resolute": [0, 1, 1], "647-ordinary": [0, 1, 1], "648-aria": [0, 1, 1], @@ -1493,6 +1632,8 @@ "689": [0, 1, 1], "690": [0, 1, 1], "691": [0, 1, 1], + "692": [0, 1, 1], + "693": [0, 1, 1], "696": [0, 1, 1], "697": [0, 1, 1], "698": [0, 1, 1], @@ -1523,6 +1664,8 @@ "735": [0, 1, 1], "742": [0, 2, 2], "743": [0, 2, 2], + "746": [0, 1, 1], + "746-school": [0, 1, 1], "747": [0, 1, 1], "748": [0, 1, 1], "751": [0, 1, 1], @@ -1561,6 +1704,10 @@ "778-busted": [0, 1, 1], "778-disguised": [0, 1, 1], "779": [0, 1, 1], + "780": [0, 1, 1], + "782": [0, 1, 1], + "783": [0, 1, 1], + "784": [0, 1, 1], "789": [1, 1, 1], "790": [0, 1, 1], "791-radiant-sun": [0, 1, 1], @@ -1593,6 +1740,11 @@ "830": [0, 1, 1], "835": [0, 1, 1], "836": [0, 1, 1], + "840": [0, 1, 1], + "841-gigantamax": [0, 1, 1], + "841": [0, 1, 1], + "842-gigantamax": [0, 1, 1], + "842": [0, 1, 1], "850": [0, 1, 1], "851-gigantamax": [0, 1, 1], "851": [0, 1, 1], @@ -1610,6 +1762,7 @@ "863": [0, 1, 1], "864": [0, 1, 1], "867": [0, 1, 1], + "871": [0, 1, 1], "872": [1, 1, 1], "873": [1, 1, 1], "876-female": [0, 1, 1], @@ -1708,14 +1861,18 @@ "1007-apex-build": [0, 2, 2], "1008-ultimate-mode": [1, 1, 1], "1010": [0, 1, 1], + "1011": [0, 1, 1], "1012-counterfeit": [0, 1, 1], "1013-unremarkable": [0, 1, 1], "1018": [0, 1, 1], + "1019": [0, 1, 1], "1022": [0, 2, 2], "1023": [0, 1, 1], "2026": [0, 1, 1], "2027": [0, 1, 1], "2028": [0, 1, 1], + "2037": [0, 1, 1], + "2038": [0, 1, 1], "2052": [0, 1, 1], "2053": [0, 1, 1], "2103": [0, 1, 1], @@ -1790,12 +1947,20 @@ "307": [0, 1, 1], "308": [0, 1, 1], "315": [0, 1, 1], + "332": [0, 1, 1], "369": [0, 1, 1], + "396": [0, 1, 1], + "397": [0, 1, 1], + "398": [0, 1, 1], "399": [0, 2, 1], "400": [0, 1, 1], "401": [0, 1, 1], "402": [0, 1, 1], + "403": [0, 1, 1], + "404": [0, 1, 1], + "405": [0, 1, 1], "407": [0, 1, 1], + "417": [0, 1, 1], "418": [0, 2, 2], "419": [0, 1, 1], "424": [0, 1, 1], @@ -1813,669 +1978,5 @@ "593": [1, 1, 1], "6215": [0, 1, 1] } - }, - "exp": { - "3-mega": [0, 2, 2], - "6-mega-x": [0, 2, 2], - "6-mega-y": [0, 2, 2], - "80-mega": [0, 1, 1], - "94-mega": [2, 2, 2], - "127-mega": [0, 1, 1], - "130-mega": [0, 1, 1], - "142-mega": [0, 1, 1], - "150-mega-x": [0, 1, 1], - "150-mega-y": [0, 1, 1], - "181-mega": [0, 1, 2], - "212-mega": [1, 1, 2], - "229-mega": [0, 1, 1], - "248-mega": [0, 1, 1], - "257-mega": [0, 1, 1], - "282-mega": [0, 2, 2], - "302-mega": [0, 1, 1], - "303-mega": [0, 1, 1], - "306-mega": [1, 1, 1], - "308-mega": [0, 1, 1], - "310-mega": [0, 1, 1], - "334-mega": [0, 2, 1], - "354-mega": [0, 1, 1], - "359-mega": [0, 1, 1], - "362-mega": [0, 1, 1], - "373-mega": [0, 1, 1], - "376-mega": [0, 1, 1], - "380-mega": [0, 1, 1], - "381-mega": [0, 1, 1], - "382-primal": [0, 1, 1], - "383-primal": [0, 1, 1], - "384-mega": [0, 2, 1], - "428-mega": [0, 1, 1], - "445-mega": [1, 1, 1], - "448-mega": [1, 1, 1], - "475-mega": [0, 2, 2], - "531-mega": [0, 1, 1], - "653": [0, 1, 1], - "654": [0, 1, 1], - "655": [0, 1, 1], - "656": [0, 1, 1], - "657": [0, 1, 1], - "658": [0, 1, 1], - "658-ash": [0, 1, 1], - "664": [0, 1, 1], - "665": [0, 1, 1], - "666-archipelago": [0, 1, 1], - "666-continental": [0, 1, 1], - "666-elegant": [0, 1, 1], - "666-fancy": [0, 1, 1], - "666-garden": [0, 1, 1], - "666-high-plains": [0, 1, 1], - "666-icy-snow": [0, 1, 1], - "666-jungle": [0, 1, 1], - "666-marine": [0, 1, 1], - "666-meadow": [0, 1, 1], - "666-modern": [0, 1, 1], - "666-monsoon": [0, 1, 1], - "666-ocean": [0, 1, 1], - "666-poke-ball": [0, 1, 1], - "666-polar": [0, 1, 1], - "666-river": [0, 1, 1], - "666-sandstorm": [0, 1, 1], - "666-savanna": [0, 1, 1], - "666-sun": [0, 1, 1], - "666-tundra": [0, 1, 1], - "669-red": [0, 2, 2], - "669-blue": [0, 1, 1], - "669-white": [0, 1, 1], - "669-yellow": [0, 1, 1], - "669-orange": [0, 2, 2], - "670-white": [0, 1, 1], - "670-blue": [0, 1, 1], - "670-orange": [0, 1, 1], - "670-red": [0, 1, 1], - "670-yellow": [0, 1, 1], - "671-red": [0, 1, 2], - "671-blue": [0, 1, 2], - "671-yellow": [0, 1, 1], - "671-white": [0, 1, 2], - "671-orange": [0, 1, 2], - "672": [0, 1, 1], - "673": [0, 1, 1], - "676": [0, 1, 1], - "677": [0, 1, 1], - "678-female": [0, 1, 1], - "678": [0, 1, 1], - "682": [0, 1, 1], - "683": [0, 1, 1], - "684": [0, 1, 1], - "685": [0, 1, 1], - "688": [0, 1, 1], - "689": [0, 1, 1], - "690": [0, 1, 1], - "691": [0, 1, 1], - "696": [0, 1, 1], - "697": [0, 1, 1], - "698": [0, 1, 1], - "699": [0, 1, 1], - "700": [0, 1, 1], - "702": [0, 1, 1], - "703": [0, 1, 1], - "704": [0, 1, 1], - "705": [0, 1, 1], - "706": [0, 1, 1], - "708": [0, 1, 1], - "709": [0, 1, 1], - "710": [0, 1, 1], - "711": [1, 1, 1], - "712": [0, 1, 1], - "713": [0, 1, 1], - "714": [0, 1, 1], - "715": [0, 1, 1], - "716-active": [0, 1, 1], - "716-neutral": [0, 1, 1], - "717": [0, 2, 2], - "720-unbound": [1, 1, 1], - "720": [1, 1, 1], - "728": [0, 1, 1], - "729": [0, 1, 1], - "730": [0, 1, 1], - "734": [0, 1, 1], - "735": [0, 1, 1], - "742": [0, 2, 2], - "743": [0, 2, 2], - "747": [0, 2, 2], - "748": [0, 1, 1], - "751": [0, 1, 1], - "752": [0, 1, 1], - "753": [0, 1, 1], - "754": [0, 2, 2], - "755": [0, 1, 1], - "756": [0, 1, 1], - "761": [0, 1, 1], - "762": [0, 1, 1], - "763": [0, 1, 1], - "767": [0, 1, 1], - "768": [0, 1, 1], - "770": [0, 0, 0], - "771": [0, 2, 2], - "772": [0, 1, 1], - "773-fighting": [0, 1, 1], - "773-psychic": [0, 1, 1], - "773-poison": [0, 1, 1], - "773-ground": [0, 1, 1], - "773-ghost": [0, 1, 1], - "773-steel": [0, 1, 1], - "773-rock": [0, 1, 1], - "773-grass": [0, 1, 1], - "773-dragon": [0, 1, 1], - "773-bug": [0, 1, 1], - "773-ice": [0, 1, 1], - "773-dark": [0, 1, 1], - "773": [0, 1, 1], - "773-fairy": [0, 1, 1], - "773-water": [0, 1, 1], - "773-electric": [0, 1, 1], - "773-flying": [0, 1, 1], - "773-fire": [0, 1, 1], - "776": [0, 1, 1], - "777": [0, 1, 1], - "778-busted": [0, 1, 1], - "778-disguised": [0, 1, 1], - "779": [0, 1, 1], - "789": [1, 1, 1], - "790": [0, 1, 1], - "791": [2, 1, 1], - "792": [0, 1, 1], - "793": [0, 2, 2], - "797": [0, 1, 1], - "798": [0, 1, 1], - "800-dawn-wings": [0, 1, 1], - "800-dusk-mane": [0, 1, 1], - "800-ultra": [0, 1, 1], - "800": [0, 1, 1], - "802": [1, 1, 1], - "803": [0, 1, 1], - "804": [0, 1, 1], - "807": [0, 1, 1], - "808": [0, 1, 1], - "809": [0, 1, 1], - "816": [0, 1, 1], - "817": [0, 1, 1], - "818": [1, 1, 1], - "821": [0, 2, 2], - "822": [0, 1, 1], - "823": [0, 1, 1], - "829": [0, 1, 1], - "830": [0, 1, 1], - "835": [0, 1, 1], - "836": [0, 2, 2], - "850": [0, 1, 1], - "851": [0, 1, 1], - "854": [0, 1, 1], - "855": [0, 1, 1], - "856": [0, 1, 1], - "857": [0, 2, 2], - "858": [0, 1, 1], - "859": [0, 1, 1], - "860": [0, 1, 1], - "861": [0, 1, 1], - "862": [0, 1, 1], - "863": [0, 1, 1], - "864": [0, 1, 1], - "867": [0, 1, 1], - "872": [1, 1, 1], - "873": [1, 1, 1], - "876-female": [0, 1, 1], - "876": [0, 1, 1], - "877-hangry": [1, 1, 1], - "877": [1, 1, 1], - "880": [0, 1, 1], - "881": [0, 1, 1], - "882": [0, 2, 1], - "883": [0, 1, 1], - "884": [0, 1, 1], - "885": [1, 1, 1], - "886": [1, 1, 1], - "887": [1, 1, 1], - "888": [0, 1, 1], - "888-crowned": [0, 1, 1], - "889": [0, 1, 1], - "889-crowned": [0, 1, 1], - "890": [0, 2, 1], - "890-eternamax": [0, 1, 1], - "891": [1, 1, 1], - "892-rapid-strike": [1, 1, 1], - "892": [1, 1, 1], - "894": [0, 1, 1], - "895": [0, 1, 1], - "896": [1, 1, 1], - "897": [1, 1, 1], - "898": [1, 1, 1], - "898-ice": [1, 1, 1], - "898-shadow": [1, 1, 1], - "900": [0, 1, 1], - "901": [0, 1, 1], - "903": [0, 1, 1], - "909": [0, 1, 1], - "910": [0, 2, 2], - "911": [0, 2, 2], - "912": [0, 1, 2], - "913": [0, 1, 2], - "914": [0, 2, 1], - "919": [1, 1, 1], - "920": [1, 1, 1], - "924": [1, 1, 1], - "925-four": [1, 2, 2], - "925-three": [1, 2, 2], - "932": [0, 2, 2], - "933": [0, 2, 2], - "934": [0, 1, 1], - "935": [1, 1, 2], - "936": [2, 2, 2], - "937": [2, 2, 2], - "940": [0, 1, 1], - "941": [0, 1, 1], - "944": [0, 1, 1], - "945": [0, 1, 1], - "948": [0, 1, 1], - "949": [0, 1, 1], - "951": [0, 1, 1], - "952": [0, 1, 1], - "953": [0, 1, 1], - "954": [0, 1, 1], - "957": [2, 2, 2], - "958": [2, 2, 2], - "959": [2, 2, 2], - "962": [1, 1, 1], - "967": [0, 1, 1], - "968": [0, 1, 1], - "969": [0, 1, 1], - "970": [0, 1, 1], - "973": [1, 1, 1], - "974": [0, 1, 1], - "975": [0, 1, 1], - "978-curly": [0, 2, 2], - "978-droopy": [0, 2, 2], - "978-stretchy": [0, 2, 2], - "979": [2, 2, 2], - "981": [0, 1, 1], - "982": [0, 1, 1], - "982-three-segment": [0, 1, 1], - "987": [1, 1, 1], - "988": [0, 1, 2], - "993": [0, 1, 1], - "994": [0, 1, 2], - "995": [0, 1, 1], - "996": [0, 1, 1], - "997": [0, 2, 2], - "998": [0, 2, 2], - "999": [2, 1, 1], - "1000": [1, 1, 1], - "1001": [0, 1, 1], - "1003": [0, 1, 1], - "1004": [0, 1, 1], - "1006": [0, 2, 1], - "1007-apex-build": [0, 2, 2], - "1008-ultimate-mode": [1, 1, 1], - "2026": [0, 1, 1], - "2027": [0, 1, 1], - "2028": [0, 1, 1], - "2052": [0, 1, 1], - "2053": [0, 1, 0], - "2103": [0, 1, 1], - "4052": [0, 1, 1], - "4077": [0, 1, 1], - "4078": [0, 1, 1], - "4079": [0, 1, 1], - "4080": [2, 1, 1], - "4144": [0, 1, 1], - "4145": [0, 1, 1], - "4146": [0, 1, 1], - "4199": [2, 1, 1], - "4222": [0, 1, 1], - "4263": [0, 1, 1], - "4264": [0, 1, 1], - "4562": [0, 1, 1], - "6100": [0, 1, 1], - "6101": [0, 1, 1], - "6215": [0, 1, 1], - "6503": [0, 1, 1], - "6549": [0, 1, 1], - "6570": [0, 1, 1], - "6571": [0, 1, 1], - "6705": [0, 1, 1], - "6706": [0, 1, 1], - "6713": [0, 1, 1], - "female": { - "6215": [0, 1, 1] - }, - "back": { - "3-mega": [0, 2, 2], - "6-mega-x": [0, 2, 2], - "6-mega-y": [0, 1, 2], - "80-mega": [0, 1, 1], - "94-mega": [1, 1, 1], - "127-mega": [0, 1, 1], - "130-mega": [0, 1, 1], - "142-mega": [0, 1, 1], - "150-mega-x": [0, 1, 1], - "150-mega-y": [0, 1, 1], - "181-mega": [0, 1, 2], - "212-mega": [1, 2, 2], - "229-mega": [0, 1, 1], - "248-mega": [0, 1, 1], - "257-mega": [0, 1, 1], - "282-mega": [0, 1, 1], - "302-mega": [0, 1, 1], - "303-mega": [0, 1, 1], - "306-mega": [1, 1, 1], - "308-mega": [0, 1, 1], - "310-mega": [0, 1, 1], - "334-mega": [0, 1, 1], - "354-mega": [0, 1, 1], - "359-mega": [0, 1, 1], - "362-mega": [0, 1, 1], - "373-mega": [0, 1, 1], - "376-mega": [0, 1, 1], - "380-mega": [0, 1, 1], - "381-mega": [0, 1, 1], - "382-primal": [0, 1, 1], - "383-primal": [0, 1, 1], - "384-mega": [0, 1, 1], - "428-mega": [0, 1, 1], - "445-mega": [1, 1, 1], - "448-mega": [1, 1, 1], - "475-mega": [0, 2, 2], - "531-mega": [0, 1, 1], - "653": [0, 1, 1], - "654": [0, 1, 1], - "655": [0, 1, 1], - "656": [0, 1, 1], - "657": [0, 1, 1], - "658": [0, 1, 1], - "658-ash": [0, 1, 1], - "664": [0, 1, 1], - "665": [0, 1, 1], - "666-archipelago": [0, 1, 1], - "666-continental": [0, 1, 1], - "666-elegant": [0, 1, 1], - "666-fancy": [0, 1, 1], - "666-garden": [0, 1, 1], - "666-high-plains": [0, 1, 1], - "666-icy-snow": [0, 1, 1], - "666-jungle": [0, 1, 1], - "666-marine": [0, 1, 1], - "666-meadow": [0, 1, 1], - "666-modern": [0, 1, 1], - "666-monsoon": [0, 1, 1], - "666-ocean": [0, 1, 1], - "666-poke-ball": [0, 1, 1], - "666-polar": [0, 1, 1], - "666-river": [0, 1, 1], - "666-sandstorm": [0, 1, 1], - "666-savanna": [0, 1, 1], - "666-sun": [0, 1, 1], - "666-tundra": [0, 1, 1], - "669-red": [0, 2, 2], - "669-blue": [0, 2, 2], - "669-white": [0, 2, 2], - "669-yellow": [0, 2, 2], - "669-orange": [0, 2, 2], - "670-white": [0, 1, 1], - "670-blue": [0, 2, 2], - "670-orange": [0, 1, 1], - "670-red": [0, 1, 1], - "670-yellow": [0, 1, 1], - "671-red": [0, 1, 1], - "671-blue": [0, 1, 1], - "671-yellow": [0, 1, 1], - "671-white": [0, 1, 1], - "671-orange": [0, 1, 1], - "672": [0, 1, 1], - "673": [0, 1, 1], - "676": [0, 1, 1], - "677": [0, 1, 1], - "678-female": [0, 1, 1], - "678": [0, 1, 1], - "682": [0, 1, 1], - "683": [0, 1, 1], - "684": [0, 1, 1], - "685": [0, 1, 1], - "688": [0, 1, 1], - "689": [0, 1, 1], - "690": [0, 1, 1], - "691": [0, 1, 1], - "696": [0, 1, 1], - "697": [0, 1, 1], - "698": [0, 1, 1], - "699": [0, 2, 2], - "700": [0, 1, 1], - "702": [0, 1, 1], - "703": [0, 1, 1], - "704": [0, 1, 1], - "705": [0, 1, 1], - "706": [0, 1, 1], - "708": [0, 1, 1], - "709": [0, 1, 1], - "710": [0, 1, 1], - "711": [1, 1, 1], - "712": [0, 1, 1], - "713": [0, 1, 1], - "714": [0, 1, 1], - "715": [0, 1, 1], - "716-active": [0, 1, 1], - "716-neutral": [0, 1, 1], - "717": [0, 1, 1], - "720-unbound": [1, 1, 1], - "720": [1, 1, 1], - "728": [0, 1, 1], - "729": [0, 1, 1], - "730": [0, 1, 1], - "734": [0, 1, 1], - "735": [0, 1, 1], - "742": [0, 2, 2], - "743": [0, 2, 2], - "747": [0, 2, 2], - "748": [0, 1, 1], - "751": [0, 1, 1], - "752": [0, 1, 1], - "753": [0, 1, 1], - "754": [0, 2, 2], - "755": [0, 1, 1], - "756": [0, 1, 1], - "761": [0, 1, 1], - "762": [0, 1, 1], - "763": [0, 1, 1], - "767": [0, 1, 1], - "768": [0, 1, 1], - "771": [0, 1, 1], - "772": [0, 1, 1], - "773-fighting": [0, 1, 1], - "773-psychic": [0, 1, 1], - "773-poison": [0, 1, 1], - "773-ground": [0, 1, 1], - "773-ghost": [0, 1, 1], - "773-steel": [0, 1, 1], - "773-rock": [0, 1, 1], - "773-grass": [0, 1, 1], - "773-dragon": [0, 1, 1], - "773-bug": [0, 1, 1], - "773-ice": [0, 1, 1], - "773-dark": [0, 1, 1], - "773": [0, 1, 1], - "773-fairy": [0, 1, 1], - "773-water": [0, 1, 1], - "773-electric": [0, 1, 1], - "773-flying": [0, 1, 1], - "773-fire": [0, 1, 1], - "776": [0, 2, 2], - "777": [0, 1, 1], - "778-busted": [0, 1, 1], - "778-disguised": [0, 1, 1], - "779": [0, 1, 1], - "789": [1, 1, 1], - "790": [0, 1, 1], - "791": [1, 1, 1], - "792": [0, 1, 1], - "793": [0, 1, 1], - "797": [0, 1, 1], - "798": [0, 1, 1], - "800-dawn-wings": [0, 1, 1], - "800-dusk-mane": [0, 1, 1], - "800-ultra": [0, 1, 1], - "800": [0, 1, 1], - "802": [1, 1, 1], - "803": [0, 1, 1], - "804": [0, 1, 1], - "807": [0, 1, 1], - "808": [0, 1, 1], - "809": [0, 1, 1], - "816": [0, 1, 1], - "817": [0, 1, 1], - "818": [0, 1, 1], - "821": [0, 1, 1], - "822": [0, 1, 1], - "823": [0, 1, 1], - "829": [0, 1, 1], - "830": [0, 1, 1], - "835": [0, 1, 1], - "836": [0, 1, 1], - "850": [0, 1, 1], - "851": [0, 1, 1], - "854": [0, 1, 1], - "855": [0, 1, 1], - "856": [0, 1, 1], - "857": [0, 2, 2], - "858": [0, 1, 1], - "859": [0, 1, 1], - "860": [0, 1, 1], - "861": [0, 1, 1], - "862": [0, 1, 1], - "863": [0, 1, 1], - "864": [0, 1, 1], - "867": [0, 1, 1], - "872": [1, 1, 1], - "873": [1, 1, 1], - "876-female": [0, 1, 1], - "876": [0, 1, 1], - "877-hangry": [1, 1, 1], - "877": [1, 1, 1], - "880": [0, 1, 1], - "881": [0, 1, 1], - "882": [0, 1, 1], - "883": [0, 1, 1], - "884": [0, 1, 1], - "885": [1, 1, 1], - "886": [1, 1, 1], - "887": [1, 1, 1], - "888": [0, 1, 1], - "888-crowned": [0, 1, 1], - "889": [0, 1, 1], - "889-crowned": [0, 1, 1], - "890": [0, 1, 1], - "891": [1, 1, 1], - "892-rapid-strike": [1, 1, 1], - "892": [1, 1, 1], - "894": [0, 1, 1], - "895": [0, 1, 1], - "896": [1, 1, 1], - "897": [1, 1, 1], - "898": [1, 1, 1], - "898-ice": [1, 1, 1], - "898-shadow": [1, 1, 1], - "900": [0, 1, 1], - "901": [0, 1, 1], - "903": [0, 1, 1], - "909": [0, 1, 1], - "910": [0, 2, 2], - "911": [0, 1, 1], - "912": [0, 1, 1], - "913": [0, 1, 1], - "914": [0, 2, 2], - "919": [1, 1, 1], - "920": [1, 1, 1], - "924": [1, 1, 1], - "925-four": [1, 2, 2], - "925-three": [1, 2, 2], - "932": [0, 1, 1], - "933": [0, 1, 1], - "934": [0, 1, 1], - "935": [2, 2, 2], - "936": [2, 2, 2], - "937": [2, 2, 2], - "940": [0, 1, 1], - "941": [0, 1, 1], - "944": [0, 1, 1], - "945": [0, 1, 1], - "948": [0, 1, 1], - "949": [0, 1, 1], - "951": [0, 1, 1], - "952": [0, 2, 1], - "953": [0, 1, 1], - "954": [0, 1, 1], - "957": [1, 1, 1], - "958": [1, 1, 1], - "959": [1, 1, 1], - "962": [1, 1, 1], - "967": [0, 1, 1], - "968": [0, 2, 2], - "969": [0, 1, 1], - "970": [0, 1, 1], - "973": [1, 1, 1], - "974": [0, 1, 1], - "975": [0, 1, 1], - "978-curly": [0, 2, 2], - "978-droopy": [0, 2, 2], - "978-stretchy": [0, 1, 1], - "979": [1, 1, 1], - "981": [0, 1, 1], - "982": [0, 1, 1], - "982-three-segment": [0, 1, 1], - "987": [1, 1, 1], - "988": [0, 1, 1], - "993": [0, 1, 1], - "994": [0, 1, 1], - "995": [0, 1, 1], - "996": [0, 1, 1], - "997": [0, 1, 1], - "998": [0, 1, 1], - "999": [1, 1, 1], - "1000": [1, 1, 1], - "1001": [0, 1, 1], - "1003": [0, 1, 1], - "1004": [0, 1, 1], - "1006": [0, 2, 2], - "1007-apex-build": [0, 2, 2], - "1008-ultimate-mode": [1, 1, 1], - "2026": [0, 1, 1], - "2027": [0, 1, 1], - "2028": [0, 1, 1], - "2052": [0, 1, 1], - "2053": [0, 1, 1], - "2103": [0, 1, 1], - "4052": [0, 1, 1], - "4077": [0, 1, 1], - "4078": [0, 1, 1], - "4079": [0, 1, 1], - "4080": [2, 2, 2], - "4144": [0, 1, 1], - "4145": [0, 1, 1], - "4146": [0, 1, 1], - "4199": [2, 1, 1], - "4222": [0, 1, 1], - "4263": [0, 1, 1], - "4264": [0, 1, 1], - "4562": [0, 1, 1], - "6100": [0, 1, 1], - "6101": [0, 1, 1], - "6215": [0, 1, 1], - "6503": [0, 1, 1], - "6549": [0, 1, 1], - "6570": [0, 1, 1], - "6571": [0, 1, 1], - "6705": [0, 1, 1], - "6706": [0, 1, 1], - "6713": [0, 1, 1], - "female": { - "6215": [0, 1, 1] - } - } } } \ No newline at end of file diff --git a/public/images/pokemon/variant/back/1011.json b/public/images/pokemon/variant/back/1011.json new file mode 100644 index 00000000000..d8cffc4d587 --- /dev/null +++ b/public/images/pokemon/variant/back/1011.json @@ -0,0 +1,29 @@ +{ + "1": { + "b09579": "7b91a7", + "253922": "232b3a", + "fd9477": "63b9b9", + "345539": "313d4b", + "9c1e2a": "272a52", + "7eb36a": "9aa0b3", + "9fc164": "9aa0b3", + "8e9960": "67698b", + "c73030": "2b526f", + "e64d3c": "397880", + "477d45": "67698b", + "61071f": "190e2e" + }, + "2": { + "253922": "2e0920", + "fd9477": "f3efde", + "345539": "4f162a", + "9c1e2a": "9c564c", + "7eb36a": "e8838d", + "9fc164": "e28c95", + "8e9960": "9e4553", + "c73030": "d1a87e", + "e64d3c": "eee0bc", + "477d45": "903c4e", + "61071f": "4f0a1d" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/1019.json b/public/images/pokemon/variant/back/1019.json new file mode 100644 index 00000000000..b8e674f2357 --- /dev/null +++ b/public/images/pokemon/variant/back/1019.json @@ -0,0 +1,44 @@ +{ + "1": { + "8b1313": "302752", + "746739": "582c74", + "6ba835": "7a7c9e", + "b49779": "9c2e72", + "9ce05f": "9aa0b3", + "bf2b2e": "abd7e2", + "d43e2d": "4e969e", + "841111": "302752", + "ae2124": "663267", + "ff7a59": "69c5c5", + "680606": "27103c", + "b72629": "2b526f", + "b59a7d": "a3b9d0", + "3e662b": "313846", + "e8cfb4": "c55885", + "82664a": "48476c", + "a60b0b": "70a2c5", + "e9cfb3": "dcebf9", + "3c9b3e": "e8edff" + }, + "2": { + "8b1313": "413534", + "746739": "312374", + "6ba835": "a8546e", + "b49779": "402622", + "9ce05f": "e28c95", + "bf2b2e": "e8e5de", + "d43e2d": "eedfb8", + "841111": "4b211b", + "ae2124": "63473b", + "ff7a59": "f3efde", + "680606": "4b211b", + "b72629": "bf9870", + "b59a7d": "cbb4af", + "3e662b": "341c1c", + "e8cfb4": "5d4c45", + "82664a": "613838", + "a60b0b": "c7c2bc", + "e9cfb3": "e2dcd6", + "3c9b3e": "5e75e2" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/143-gigantamax.json b/public/images/pokemon/variant/back/143-gigantamax.json new file mode 100644 index 00000000000..ffe8e7a31cd --- /dev/null +++ b/public/images/pokemon/variant/back/143-gigantamax.json @@ -0,0 +1,62 @@ +{ + "1": { + "101010": "101010", + "624120": "544a41", + "5e3e1d": "351b52", + "31573f": "7b59ba", + "54792b": "c06386", + "103941": "701a55", + "315a7b": "943469", + "bd3740": "c94489", + "a3704e": "522663", + "a47352": "6b6357", + "ad7f5f": "b56564", + "de5656": "d65a8a", + "069f5f": "b083de", + "89b432": "f1a1b2", + "bbe35b": "f1a1b2", + "98a0a0": "98a0a0", + "a0a0a0": "a0a0a0", + "fc8b9f": "ed7794", + "e6c5ac": "cf8880", + "f6e6bd": "f0beb1", + "c9c9c9": "c9c9c9", + "f4f4f4": "f4f4f4", + "4d6e27": "5c9bb8", + "91ba3d": "6bc7c7", + "93bf39": "74c2cf", + "bee366": "8de3d7", + "d95b7f": "c24a6c", + "fc92a6": "fc92a6" + }, + "2": { + "101010": "101010", + "624120": "ba6632", + "5e3e1d": "c2986e", + "31573f": "4b4c52", + "54792b": "208073", + "103941": "93b5c2", + "315a7b": "b6d6d9", + "bd3740": "9e4619", + "a3704e": "e6cda1", + "a47352": "cf9d48", + "ad7f5f": "284878", + "de5656": "bd742b", + "069f5f": "7c7c82", + "89b432": "37ad82", + "bbe35b": "79e0a2", + "98a0a0": "53738a", + "a0a0a0": "abd1cc", + "fc8b9f": "d9a443", + "e6c5ac": "27538a", + "f6e6bd": "36719c", + "c9c9c9": "b4d3d9", + "f4f4f4": "f4f4f4", + "4d6e27": "964117", + "91ba3d": "d9a65b", + "93bf39": "d9a250", + "bee366": "e6cf5e", + "d95b7f": "b77727", + "fc92a6": "d9b64c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/143.json b/public/images/pokemon/variant/back/143.json new file mode 100644 index 00000000000..7dc08d72559 --- /dev/null +++ b/public/images/pokemon/variant/back/143.json @@ -0,0 +1,32 @@ +{ + "1": { + "000000": "101010", + "103a42": "701a55", + "315a7b": "943469", + "528cad": "ad4b70", + "735a21": "91504e", + "737373": "756363", + "a57352": "b36462", + "c59c5a": "b36462", + "cecece": "cbc4c4", + "e6c5ad": "cf8880", + "f7d6bd": "e09f96", + "f7e6bd": "f0beb1", + "ffffff": "ffffff" + }, + "2": { + "000000": "101010", + "103a42": "93b5c2", + "315a7b": "b6d6d9", + "528cad": "d5e8e7", + "735a21": "1b2e61", + "737373": "525266", + "a57352": "1b2e61", + "c59c5a": "20386e", + "cecece": "bfc7cb", + "e6c5ad": "284878", + "f7d6bd": "38638f", + "f7e6bd": "457ca8", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/187.json b/public/images/pokemon/variant/back/187.json new file mode 100644 index 00000000000..7e0d1dca511 --- /dev/null +++ b/public/images/pokemon/variant/back/187.json @@ -0,0 +1,28 @@ +{ + "1": { + "101010": "101010", + "425a10": "934200", + "52843a": "c27600", + "63bd5a": "efac00", + "8c083a": "012a3e", + "9cde5a": "ffdc46", + "b56373": "003e53", + "ff7b94": "006d7f", + "f79cb5": "00a59b", + "ffc500": "e3396c", + "ffff00": "ffa8b6" + }, + "2": { + "101010": "101010", + "425a10": "5f0052", + "52843a": "960070", + "63bd5a": "960070", + "8c083a": "802600", + "9cde5a": "e01c75", + "b56373": "d8591c", + "ff7b94": "fa9600", + "f79cb5": "ffc93b", + "ffc500": "5ec0ec", + "ffff00": "94ecf9" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/188.json b/public/images/pokemon/variant/back/188.json new file mode 100644 index 00000000000..a674bbf244e --- /dev/null +++ b/public/images/pokemon/variant/back/188.json @@ -0,0 +1,30 @@ +{ + "1": { + "000000": "101010", + "196b00": "c66b31", + "42b521": "e99f23", + "63d631": "ffd953", + "8c5200": "004269", + "8cf74a": "fef579", + "b5d6de": "fa9600", + "ce8400": "075976", + "f7a519": "005883", + "ffd600": "046c90", + "ffef00": "007b9a", + "ffffff": "ffc93b" + }, + "2": { + "000000": "101010", + "196b00": "2659ad", + "42b521": "5293d5", + "63d631": "79d5fa", + "8c5200": "5f0052", + "8cf74a": "a6eafa", + "b5d6de": "fa9600", + "ce8400": "9d0562", + "f7a519": "960070", + "ffd600": "ba0071", + "ffef00": "e01c75", + "ffffff": "ffc93b" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/189.json b/public/images/pokemon/variant/back/189.json new file mode 100644 index 00000000000..ed1e40ed4b3 --- /dev/null +++ b/public/images/pokemon/variant/back/189.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "194a73": "b64d21", + "29844a": "83839f", + "3a73c5": "e19903", + "739cff": "fcd936", + "84ce7b": "c1bdd1", + "8cb5ff": "f9f870", + "b58c31": "071a3c", + "d6bd5a": "282773", + "ded67b": "2192b2", + "efe69c": "104f80", + "fff7b5": "1379a0", + "ffffde": "2faac4" + }, + "2": { + "101010": "101010", + "194a73": "680054", + "29844a": "3887d3", + "3a73c5": "980062", + "739cff": "d20d6a", + "84ce7b": "58c1eb", + "8cb5ff": "e4486a", + "b58c31": "da5014", + "d6bd5a": "f06f22", + "ded67b": "fce37b", + "efe69c": "ffa747", + "fff7b5": "ffd45a", + "ffffde": "f9f29b" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/2037.json b/public/images/pokemon/variant/back/2037.json new file mode 100644 index 00000000000..0d2c02cf980 --- /dev/null +++ b/public/images/pokemon/variant/back/2037.json @@ -0,0 +1,22 @@ +{ + "1": { + "151515": "101010", + "558b9f": "9f435d", + "648082": "6e67b0", + "97bdd2": "ffa8b8", + "c1d1d2": "b3b8ea", + "d9e9f4": "ffd3e1", + "fdfdfd": "d7d9f9", + "ffffff": "ffffff" + }, + "2": { + "151515": "101010", + "558b9f": "90215e", + "648082": "bf4747", + "97bdd2": "da4e75", + "c1d1d2": "ffc07b", + "d9e9f4": "ff8489", + "fdfdfd": "ffe6a0", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/2038.json b/public/images/pokemon/variant/back/2038.json new file mode 100644 index 00000000000..845c45f7887 --- /dev/null +++ b/public/images/pokemon/variant/back/2038.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "4d5c78": "394880", + "516077": "9f435d", + "007ab5": "2380c4", + "38858d": "e35ea2", + "7a8a9c": "6172ab", + "66b3d7": "3dbfe0", + "86a8c0": "e27495", + "81c2c5": "ff89c0", + "bdcbd7": "a7ade7", + "a1e1de": "ffb6e5", + "b0d3ea": "ffa8b8", + "eafefe": "ffd3e1", + "fdfdfd": "bec6ef", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "4d5c78": "73174a", + "516077": "bb3c3c", + "007ab5": "882493", + "38858d": "572746", + "7a8a9c": "90215e", + "66b3d7": "a044ab", + "86a8c0": "ff824c", + "81c2c5": "75355e", + "bdcbd7": "da426d", + "a1e1de": "93547c", + "b0d3ea": "ffbf6b", + "eafefe": "ffe28c", + "fdfdfd": "ff6f86", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/204.json b/public/images/pokemon/variant/back/204.json new file mode 100644 index 00000000000..1e4007149cb --- /dev/null +++ b/public/images/pokemon/variant/back/204.json @@ -0,0 +1,16 @@ +{ + "1": { + "52adb5": "a4b76b", + "84d6d6": "c1cd7d", + "294a7b": "4b7641", + "b5eff7": "e3e796", + "3a73a5": "74a057" + }, + "2": { + "52adb5": "d46b84", + "84d6d6": "eda6ae", + "294a7b": "700a4b", + "b5eff7": "f7dcd7", + "3a73a5": "b43469" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/205.json b/public/images/pokemon/variant/back/205.json new file mode 100644 index 00000000000..5a3e2d61606 --- /dev/null +++ b/public/images/pokemon/variant/back/205.json @@ -0,0 +1,22 @@ +{ + "1": { + "847b9c": "103b2c", + "e6cef7": "3e7745", + "ff9c9c": "ffb356", + "c5a5de": "205639", + "f76373": "f68b31", + "bd2942": "d8681e", + "524263": "04211a", + "841031": "af3b11" + }, + "2": { + "847b9c": "962a41", + "e6cef7": "e9b1a0", + "ff9c9c": "b0f5ee", + "c5a5de": "c86554", + "f76373": "6bbfd2", + "bd2942": "2c6094", + "524263": "691338", + "841031": "0e2667" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/299.json b/public/images/pokemon/variant/back/299.json new file mode 100644 index 00000000000..3b2cd15e3cd --- /dev/null +++ b/public/images/pokemon/variant/back/299.json @@ -0,0 +1,28 @@ +{ + "1": { + "000000": "101010", + "5a1921": "1f3a30", + "31314a": "6b2710", + "9c314a": "30594a", + "de5252": "487c60", + "ff6b7b": "5a9170", + "42529c": "a14020", + "637bbd": "c66831", + "ff9494": "7fbc7a", + "8ca5e6": "db8644", + "adbdf7": "e09a65" + }, + "2": { + "000000": "101010", + "5a1921": "28163a", + "31314a": "38619e", + "9c314a": "452b5e", + "de5252": "584282", + "ff6b7b": "675398", + "42529c": "68a2cd", + "637bbd": "99e4ee", + "ff9494": "7282c4", + "8ca5e6": "dcfff8", + "adbdf7": "f3fff6" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/313.json b/public/images/pokemon/variant/back/313.json new file mode 100644 index 00000000000..65a1cfe9eae --- /dev/null +++ b/public/images/pokemon/variant/back/313.json @@ -0,0 +1,28 @@ +{ + "1": { + "a5b5c5": "eea256", + "4a4a52": "9c1200", + "deb552": "ffda31", + "7b8ca5": "d66d38", + "ce3a52": "491c22", + "f78473": "643a35", + "8c6b52": "845c46", + "ffe652": "fffa52", + "8c314a": "2b1419", + "8c8c94": "ff3b21", + "e65263": "57272c" + }, + "2": { + "a5b5c5": "3a767b", + "4a4a52": "175614", + "deb552": "b6d479", + "7b8ca5": "1e5256", + "ce3a52": "1585cc", + "f78473": "77d4ee", + "8c6b52": "5c713d", + "ffe652": "dde6b1", + "8c314a": "0c4275", + "8c8c94": "0ba905", + "e65263": "32b0ff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/314.json b/public/images/pokemon/variant/back/314.json new file mode 100644 index 00000000000..f77165c7b15 --- /dev/null +++ b/public/images/pokemon/variant/back/314.json @@ -0,0 +1,30 @@ +{ + "1": { + "9c8452": "ac6f0e", + "5a6b8c": "9a4013", + "8cadce": "d66d38", + "ce8cde": "6a342c", + "ffe673": "fbf650", + "7b7b7b": "b82b18", + "e6b54a": "efcb26", + "3a3a3a": "6b180d", + "9c52bd": "57272c", + "adc5ef": "eea256", + "3a3152": "2d0723", + "6b5a94": "2b1419" + }, + "2": { + "9c8452": "074656", + "5a6b8c": "70a84f", + "8cadce": "c1db9c", + "ce8cde": "77d4ee", + "ffe673": "3dc5d3", + "7b7b7b": "155870", + "e6b54a": "019792", + "3a3a3a": "0a2934", + "9c52bd": "43a3df", + "adc5ef": "e5edcc", + "3a3152": "051b37", + "6b5a94": "255b95" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/32.json b/public/images/pokemon/variant/back/32.json new file mode 100644 index 00000000000..473edcae2af --- /dev/null +++ b/public/images/pokemon/variant/back/32.json @@ -0,0 +1,34 @@ +{ + "1": { + "101010": "101010", + "006342": "273161", + "63426b": "944f25", + "b51900": "28678a", + "de4229": "42adc1", + "ff6b52": "78d6d3", + "00a573": "3b4d7a", + "9c4aad": "ab5c24", + "bd63c5": "cf863e", + "19ce9c": "55729e", + "e69cd6": "e0c151", + "efbdef": "ede4ab", + "cecece": "cecece", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "006342": "b0384a", + "63426b": "142440", + "b51900": "b86527", + "de4229": "e1b13b", + "ff6b52": "eddd95", + "00a573": "d65e64", + "9c4aad": "133257", + "bd63c5": "253f5e", + "19ce9c": "ed938e", + "e69cd6": "375c73", + "efbdef": "5d91a1", + "cecece": "cecece", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/325.json b/public/images/pokemon/variant/back/325.json new file mode 100644 index 00000000000..1918b48adfd --- /dev/null +++ b/public/images/pokemon/variant/back/325.json @@ -0,0 +1,24 @@ +{ + "1": { + "ef84ad": "5ca0b5", + "f7a5bd": "6ac5c8", + "c5637b": "3c6b95", + "ffd6e6": "b4e6e7", + "7b7b8c": "559b43", + "5a5a73": "2e7320", + "a5a5ad": "b5d780", + "a53a42": "2b4d7d", + "3a4252": "18340c" + }, + "2": { + "ef84ad": "1f6759", + "f7a5bd": "379a85", + "c5637b": "144844", + "ffd6e6": "8dd6ab", + "7b7b8c": "dca878", + "5a5a73": "a7724a", + "a5a5ad": "fbe3a3", + "a53a42": "0c2625", + "3a4252": "72442d" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/326.json b/public/images/pokemon/variant/back/326.json new file mode 100644 index 00000000000..eb1c4954208 --- /dev/null +++ b/public/images/pokemon/variant/back/326.json @@ -0,0 +1,30 @@ +{ + "1": { + "9c9ca5": "7ecdd1", + "d684ce": "7bb15b", + "636373": "3c6b95", + "6b426b": "559b43", + "ce5a7b": "d06d50", + "a5425a": "a84331", + "f7a5b5": "f7d1a0", + "ef7b94": "e99e76", + "bd63ad": "559b43", + "e6a5de": "b5d780", + "4a4a52": "2b4d7d", + "7b7b84": "5ca0b5" + }, + "2": { + "9c9ca5": "fffade", + "d684ce": "67508c", + "636373": "e8bc75", + "6b426b": "081f19", + "ce5a7b": "1f6759", + "a5425a": "144844", + "f7a5b5": "5cba98", + "ef7b94": "379a85", + "bd63ad": "574285", + "e6a5de": "7a649c", + "4a4a52": "d08f55", + "7b7b84": "fbefb3" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/33.json b/public/images/pokemon/variant/back/33.json new file mode 100644 index 00000000000..331220de9ef --- /dev/null +++ b/public/images/pokemon/variant/back/33.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "5a3a63": "944f25", + "b51900": "b51900", + "de4229": "de4229", + "845a52": "42adc1", + "009463": "273161", + "945ab5": "cf863e", + "4acea5": "55729e", + "848484": "848484", + "ce84de": "e0c151", + "e6adef": "ede4ab", + "c5c5c5": "c5c5c5", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "5a3a63": "142440", + "b51900": "d98943", + "de4229": "edc85a", + "845a52": "e1b13b", + "009463": "b0384a", + "945ab5": "253f5e", + "4acea5": "ed938e", + "848484": "848484", + "ce84de": "375c73", + "e6adef": "5d91a1", + "c5c5c5": "c5c5c5", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/331.json b/public/images/pokemon/variant/back/331.json new file mode 100644 index 00000000000..7dcb633affb --- /dev/null +++ b/public/images/pokemon/variant/back/331.json @@ -0,0 +1,30 @@ +{ + "1": { + "003a10": "601130", + "ffe63a": "7aa1df", + "31944a": "b73736", + "215200": "69102c", + "63bd6b": "dd6754", + "f7bd19": "448bc3", + "4a7310": "9f2a3f", + "196b31": "891d2c", + "94c552": "d76868", + "739c3a": "d74f4f", + "8c6b3a": "123a5a", + "bdde7b": "e67f7f" + }, + "2": { + "003a10": "684531", + "ffe63a": "eaa5c6", + "31944a": "c09e6c", + "215200": "694426", + "63bd6b": "d9c985", + "f7bd19": "d979b2", + "4a7310": "6d3494", + "196b31": "946e51", + "94c552": "9364a5", + "739c3a": "7c558d", + "8c6b3a": "983364", + "bdde7b": "a772bd" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/332.json b/public/images/pokemon/variant/back/332.json new file mode 100644 index 00000000000..c13c07c34b4 --- /dev/null +++ b/public/images/pokemon/variant/back/332.json @@ -0,0 +1,28 @@ +{ + "1": { + "319452": "831a1f", + "4aa552": "9f2f2c", + "7ba563": "b44040", + "8cbd63": "c54b4b", + "215200": "710f2f", + "196b21": "831a1f", + "a5d674": "df5252", + "4a7310": "982443", + "a5d673": "e16363", + "63b56b": "b2332f", + "215201": "630d28" + }, + "2": { + "319452": "b08d72", + "4aa552": "c5a77f", + "7ba563": "704e7e", + "8cbd63": "e3d7a6", + "215200": "3f3249", + "196b21": "b08d72", + "a5d674": "d7cda7", + "4a7310": "4f3956", + "a5d673": "8c669b", + "63b56b": "cfc191", + "215201": "583823" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/34.json b/public/images/pokemon/variant/back/34.json new file mode 100644 index 00000000000..953d0276777 --- /dev/null +++ b/public/images/pokemon/variant/back/34.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "5a296b": "7a411d", + "73735a": "696342", + "73735b": "73735b", + "73735c": "3b447a", + "a55294": "cf863e", + "d673ef": "e0c151", + "c5c5a5": "6272a8", + "c7c7a9": "c7c7a9", + "c4c4a7": "c4c4a7", + "de94f7": "ede4ab", + "fcfcfc": "fcfcfc", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "5a296b": "142440", + "73735a": "a37355", + "73735b": "73735b", + "73735c": "85204a", + "a55294": "253f5e", + "d673ef": "375c73", + "c5c5a5": "c43d63", + "c7c7a9": "e0b990", + "c4c4a7": "c4c4a7", + "de94f7": "5d91a1", + "fcfcfc": "fcfcfc", + "ffffff": "ede1b4" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/345.json b/public/images/pokemon/variant/back/345.json new file mode 100644 index 00000000000..c7b0d665e29 --- /dev/null +++ b/public/images/pokemon/variant/back/345.json @@ -0,0 +1,28 @@ +{ + "1": { + "633a84": "611746", + "efd663": "fcf3a2", + "bd5284": "6084bd", + "6b5221": "679e3a", + "b5ade6": "ff5289", + "d6a531": "d8e374", + "efadb5": "b9f0ff", + "7363b5": "801f4c", + "ce7394": "84aedb", + "843a5a": "394287", + "9c84ce": "bd3167" + }, + "2": { + "633a84": "b57c2d", + "efd663": "de463e", + "bd5284": "429949", + "6b5221": "661634", + "b5ade6": "fff8a3", + "d6a531": "942532", + "efadb5": "beed9a", + "7363b5": "dbb34d", + "ce7394": "7fcc68", + "843a5a": "296e47", + "9c84ce": "f5df73" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/346.json b/public/images/pokemon/variant/back/346.json new file mode 100644 index 00000000000..d2b5406f75a --- /dev/null +++ b/public/images/pokemon/variant/back/346.json @@ -0,0 +1,30 @@ +{ + "1": { + "ffd6ef": "deffea", + "3a6b52": "7f183f", + "a57b10": "5e8c29", + "a5e68c": "f38460", + "ce6394": "526f84", + "ef6b8c": "93c6c5", + "7bc573": "eb564b", + "ff9cad": "d2faef", + "f7d642": "d8e374", + "cea531": "a7c961", + "944263": "304459", + "529c5a": "b32843" + }, + "2": { + "ffd6ef": "a3ffc3", + "3a6b52": "96483b", + "a57b10": "661634", + "a5e68c": "ffe6b5", + "ce6394": "32806f", + "ef6b8c": "53b491", + "7bc573": "efbd8c", + "ff9cad": "7be3b6", + "f7d642": "de463e", + "cea531": "942532", + "944263": "17404a", + "529c5a": "bf815c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/396.json b/public/images/pokemon/variant/back/396.json new file mode 100644 index 00000000000..00ffa97fd19 --- /dev/null +++ b/public/images/pokemon/variant/back/396.json @@ -0,0 +1,36 @@ +{ + "1": { + "d6dede": "e3d09d", + "949494": "dbb070", + "736363": "28854d", + "ffffff": "f0ecd3", + "382028": "751e23", + "d67300": "db963b", + "b5b5b5": "d4b27f", + "808080": "c48c51", + "9c4a21": "b06421", + "8c7373": "bd453c", + "3a2129": "07332d", + "524a4a": "156146", + "4f4747": "144a40", + "ad9c9c": "ed7f4c", + "ff9429": "ffcf5e" + }, + "2": { + "d6dede": "f0deaa", + "949494": "c29b72", + "736363": "2f436b", + "ffffff": "fcfad2", + "382028": "163d4d", + "d67300": "52281f", + "b5b5b5": "debd8c", + "808080": "a67c5d", + "9c4a21": "451915", + "8c7373": "307b82", + "3a2129": "0f1730", + "524a4a": "1b2745", + "4f4747": "e6a647", + "ad9c9c": "4da8a1", + "ff9429": "8c604c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/397.json b/public/images/pokemon/variant/back/397.json new file mode 100644 index 00000000000..d1f7e646649 --- /dev/null +++ b/public/images/pokemon/variant/back/397.json @@ -0,0 +1,36 @@ +{ + "1": { + "735a63": "bd453c", + "574f57": "144a40", + "5a525a": "28854d", + "f75242": "8bba65", + "878787": "bda377", + "b5b5b5": "d9c798", + "ff9429": "ffcf5e", + "382f38": "0c3331", + "3a313a": "156146", + "362d36": "572e14", + "fcfcfc": "f0ebc5", + "bd6300": "994c1c", + "7b4221": "c47a2f", + "523a4a": "751e23", + "9c848c": "ed7f4c" + }, + "2": { + "735a63": "307b82", + "574f57": "e6a647", + "5a525a": "2f436b", + "f75242": "f797ad", + "878787": "ba946e", + "b5b5b5": "debd8c", + "ff9429": "8c604c", + "382f38": "c27b34", + "3a313a": "1b2745", + "362d36": "421917", + "fcfcfc": "fcfad2", + "bd6300": "63362b", + "7b4221": "52281f", + "523a4a": "163d4d", + "9c848c": "4da8a1" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/398.json b/public/images/pokemon/variant/back/398.json new file mode 100644 index 00000000000..ed678a4c4f3 --- /dev/null +++ b/public/images/pokemon/variant/back/398.json @@ -0,0 +1,35 @@ +{ + "1": { + "9c4242": "5fad3b", + "5c545c": "144a40", + "3a313a": "0b3634", + "7b4221": "b06421", + "bd6300": "db963b", + "5a525a": "156146", + "7b6b7b": "28854d", + "f75242": "90cc58", + "735a63": "bd453c", + "ffffff": "e8e3b6", + "523a4a": "751e23", + "3a3a3a": "07332d", + "b5b5b5": "d7be89", + "9c848c": "ed7f4c", + "ff9429": "ffcf5e" + }, + "2": { + "9c4242": "c4833d", + "5c545c": "e6a647", + "7b4221": "421917", + "bd6300": "63362b", + "5a525a": "1b2745", + "7b6b7b": "293854", + "f75242": "e6bd4e", + "735a63": "307b82", + "ffffff": "fcfad2", + "523a4a": "163d4d", + "3a3a3a": "080d1f", + "b5b5b5": "debd8c", + "9c848c": "4da8a1", + "ff9429": "8c604c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/403.json b/public/images/pokemon/variant/back/403.json new file mode 100644 index 00000000000..4b8d7b52070 --- /dev/null +++ b/public/images/pokemon/variant/back/403.json @@ -0,0 +1,22 @@ +{ + "1": { + "b59c5a": "45babf", + "7badf7": "bb5c3a", + "637bb5": "903325", + "4a4a63": "dcb788", + "ffe65a": "59dcd6", + "313142": "bf8652", + "42426b": "671919", + "736352": "267789" + }, + "2": { + "b59c5a": "9a31be", + "7badf7": "303465", + "637bb5": "222352", + "4a4a63": "bbc2e5", + "ffe65a": "e25ce8", + "313142": "8883d4", + "42426b": "121031", + "736352": "611c7f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/404.json b/public/images/pokemon/variant/back/404.json new file mode 100644 index 00000000000..32ab9ea8a1d --- /dev/null +++ b/public/images/pokemon/variant/back/404.json @@ -0,0 +1,24 @@ +{ + "1": { + "736352": "267789", + "4a4a73": "671919", + "63637b": "f1dfb1", + "637bb5": "903325", + "4a4a63": "dcb788", + "ffe65a": "59dcd6", + "313142": "bf8652", + "b59c5a": "45babf", + "7badf7": "bb5c3a" + }, + "2": { + "736352": "611c7f", + "4a4a73": "121031", + "63637b": "dee4f4", + "637bb5": "222352", + "4a4a63": "bbc2e5", + "ffe65a": "e25ce8", + "313142": "8883d4", + "b59c5a": "9a31be", + "7badf7": "303465" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/405.json b/public/images/pokemon/variant/back/405.json new file mode 100644 index 00000000000..46a38cfd243 --- /dev/null +++ b/public/images/pokemon/variant/back/405.json @@ -0,0 +1,30 @@ +{ + "1": { + "b59c5a": "45babf", + "7badf7": "bb5c3a", + "63637b": "f1dfb1", + "4a4a73": "671919", + "637bb5": "903325", + "353255": "4a0e15", + "4a4a63": "dcb788", + "ffe65a": "59dcd6", + "313142": "bf8652", + "943a52": "472614", + "e64a52": "4f3217", + "736352": "267789" + }, + "2": { + "b59c5a": "9a31be", + "7badf7": "303465", + "63637b": "dee4f4", + "4a4a73": "121031", + "637bb5": "222352", + "353255": "06051b", + "4a4a63": "bbc2e5", + "ffe65a": "e25ce8", + "313142": "8883d4", + "943a52": "614b9a", + "e64a52": "6f5dac", + "736352": "611c7f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/417.json b/public/images/pokemon/variant/back/417.json new file mode 100644 index 00000000000..27f45e74557 --- /dev/null +++ b/public/images/pokemon/variant/back/417.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "3e364e": "734430", + "524941": "732e12", + "5a524a": "642f1a", + "4a425a": "5f2618", + "84523a": "9b314f", + "ef845a": "e26e6e", + "c5a563": "e95d6c", + "ffd663": "f17c7c", + "637b9c": "86452b", + "7bb5e6": "a25f37", + "cec5c5": "e8be64", + "f7f7f7": "faeda9", + "ffffff": "ffffff", + "7b7b84": "8e623c" + }, + "2": { + "101010": "101010", + "3e364e": "203243", + "524941": "2d284c", + "5a524a": "0f203a", + "4a425a": "23704c", + "84523a": "693939", + "ef845a": "e1b8ac", + "c5a563": "5ae7f6", + "ffd663": "8ffaff", + "637b9c": "a2dc76", + "7bb5e6": "e4fba1", + "cec5c5": "357577", + "f7f7f7": "5ba297", + "ffffff": "ffffff", + "7b7b84": "1f3f4e" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/420.json b/public/images/pokemon/variant/back/420.json new file mode 100644 index 00000000000..3177603d799 --- /dev/null +++ b/public/images/pokemon/variant/back/420.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "423131": "103d47", + "6b3a4a": "09303b", + "314252": "8f3833", + "3a734a": "ab554b", + "843152": "185158", + "ad426b": "368a7f", + "429442": "d98b77", + "52a54a": "f7bfa8", + "73ce5a": "fcdbc7", + "de6384": "51b095", + "ff8cad": "73d9ae", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "423131": "390f26", + "6b3a4a": "29091b", + "314252": "752a4a", + "3a734a": "9c4861", + "843152": "3b0d21", + "ad426b": "571539", + "429442": "a86a79", + "52a54a": "c29597", + "73ce5a": "dec3c3", + "de6384": "752648", + "ff8cad": "ad5168", + "ffffff": "ffffff" + } + } \ No newline at end of file diff --git a/public/images/pokemon/variant/back/421-overcast.json b/public/images/pokemon/variant/back/421-overcast.json new file mode 100644 index 00000000000..77c5c18415d --- /dev/null +++ b/public/images/pokemon/variant/back/421-overcast.json @@ -0,0 +1,34 @@ +{ + "1": { + "101010": "101010", + "105221": "ab554b", + "4a2942": "5e1228", + "7b294a": "103d47", + "7a2a4a": "236e6a", + "427b4a": "d98b77", + "6b427b": "962a3e", + "a53a63": "368a7f", + "ce527b": "51b095", + "52ad5a": "f7bfa8", + "5ac55a": "fcdbc7", + "845aad": "c75058", + "9c7bbd": "db7f7f", + "de7394": "73d9ae" + }, + "2": { + "101010": "101010", + "105221": "995969", + "4a2942": "521d44", + "7b294a": "390f26", + "7a2a4a": "571539", + "427b4a": "ba8087", + "6b427b": "8f4270", + "a53a63": "611c3b", + "ce527b": "752648", + "52ad5a": "cf9d9d", + "5ac55a": "e3cbca", + "845aad": "a86886", + "9c7bbd": "d197ac", + "de7394": "ad5168" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/421-sunshine.json b/public/images/pokemon/variant/back/421-sunshine.json new file mode 100644 index 00000000000..096641576c9 --- /dev/null +++ b/public/images/pokemon/variant/back/421-sunshine.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "006310": "e6d590", + "941e3f": "103d47", + "9c6b10": "c4655a", + "941f40": "5c1547", + "942142": "591230", + "ce3a6b": "751a38", + "cf3c6d": "872e5c", + "cf3e6e": "368a7f", + "19943a": "f0f0bd", + "d6b55a": "db8e7d", + "f7de73": "f7bfa8", + "e66394": "51b095", + "de84ad": "962a3e", + "ffa5c5": "c75058", + "ffe6f7": "d0fdf0", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "006310": "72559e", + "941e3f": "390f26", + "9c6b10": "4a2942", + "941f40": "3a234a", + "942142": "804058", + "ce3a6b": "995969", + "cf3c6d": "563666", + "cf3e6e": "571539", + "19943a": "9574b3", + "d6b55a": "914972", + "f7de73": "b35f86", + "e66394": "752648", + "de84ad": "cf9d9d", + "ffa5c5": "e3cbca", + "ffe6f7": "d26393", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/446.json b/public/images/pokemon/variant/back/446.json new file mode 100644 index 00000000000..1f6d43127bb --- /dev/null +++ b/public/images/pokemon/variant/back/446.json @@ -0,0 +1,38 @@ +{ + "1": { + "000000": "101010", + "104242": "4d0f3f", + "215a73": "701a55", + "317b9c": "943469", + "3194b5": "ad4b70", + "524a10": "91504e", + "73737b": "756363", + "7b5a31": "522663", + "948442": "bf777a", + "9c3a42": "714084", + "b5b563": "de9494", + "cccfce": "cbc4c4", + "cecece": "cecece", + "de9494": "a270b5", + "efe684": "f0beb1", + "ffffff": "ffffff" + }, + "2": { + "000000": "101010", + "104242": "6398b7", + "215a73": "a3cacd", + "317b9c": "cbe4e2", + "3194b5": "edf5f4", + "524a10": "233f69", + "73737b": "525266", + "7b5a31": "e6cda1", + "948442": "2f4d80", + "9c3a42": "487d43", + "b5b563": "38638f", + "cccfce": "bfc7cb", + "cecece": "cecece", + "de9494": "9cb780", + "efe684": "4781a8", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/476.json b/public/images/pokemon/variant/back/476.json new file mode 100644 index 00000000000..5f54f51d1f9 --- /dev/null +++ b/public/images/pokemon/variant/back/476.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "5a2921": "0e291d", + "7b3129": "1e3f30", + "293a4a": "352310", + "3a4a5a": "59452f", + "bd3152": "30594a", + "e65a63": "578b6b", + "194a84": "62230e", + "3a63ad": "9d3a18", + "5a7bce": "c76227", + "ef7b8c": "77b472", + "739ce6": "de7f36", + "84adf7": "e68c43", + "c5cede": "c5cede", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "5a2921": "21132c", + "7b3129": "301b3f", + "293a4a": "111b28", + "3a4a5a": "253142", + "bd3152": "482a5e", + "e65a63": "6a5394", + "194a84": "30578e", + "3a63ad": "5b97c1", + "5a7bce": "92dee8", + "ef7b8c": "747fc4", + "739ce6": "dbfff4", + "84adf7": "c2efe5", + "c5cede": "c5cede", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/498.json b/public/images/pokemon/variant/back/498.json new file mode 100644 index 00000000000..ecc0ccf7a98 --- /dev/null +++ b/public/images/pokemon/variant/back/498.json @@ -0,0 +1,44 @@ +{ + "1": { + "101010": "101010", + "2e1e1e": "b1a385", + "2e1f1f": "d1c5ab", + "302020": "194737", + "312121": "1e2a4d", + "473830": "f7f5e9", + "4a3a31": "2d405c", + "7a3827": "1c2e1b", + "7b3a29": "194737", + "947310": "cc955e", + "bd6331": "3b805f", + "ce423a": "3e4f37", + "a54a42": "2d452b", + "e66b29": "b5cca5", + "efbd08": "f0cc8b", + "ef843a": "65b57c", + "c5ada5": "c1c5a5", + "ffffff": "ffffff", + "47382f": "472770" + }, + "2": { + "101010": "101010", + "2e1e1e": "ac8b61", + "2e1f1f": "c4a884", + "302020": "522e2e", + "312121": "47150e", + "473830": "e0d3ab", + "4a3a31": "733421", + "7a3827": "222742", + "7b3a29": "522e2e", + "947310": "828399", + "bd6331": "85564e", + "ce423a": "323754", + "a54a42": "4c5275", + "e66b29": "778aa6", + "efbd08": "c7c8d9", + "ef843a": "ab8274", + "c5ada5": "dddef0", + "ffffff": "ffffff", + "47382f": "456da8" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/499.json b/public/images/pokemon/variant/back/499.json new file mode 100644 index 00000000000..ad525f3e114 --- /dev/null +++ b/public/images/pokemon/variant/back/499.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "3a2121": "1e2a4d", + "3a3a3a": "122b18", + "523129": "2d405c", + "7a3827": "1c2e1b", + "7b3a29": "234f3d", + "736310": "ab6441", + "4a4a4a": "264524", + "bd5a31": "41785a", + "ce423a": "3e4f37", + "ef7329": "62a174", + "b59421": "cc955e", + "efc53a": "f0cc8b", + "c5ada5": "c5ada5", + "c4aea7": "c4aea7", + "fcfcfc": "fcfcfc", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "3a2121": "47150e", + "3a3a3a": "1c2245", + "523129": "733421", + "7a3827": "222742", + "7b3a29": "533330", + "736310": "3c3e5b", + "4a4a4a": "272d4f", + "bd5a31": "7a5a56", + "ce423a": "323754", + "ef7329": "967a71", + "b59421": "828399", + "efc53a": "c7c8d9", + "c5ada5": "c4a884", + "c4aea7": "c4aea7", + "fcfcfc": "e0d3ab", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/500.json b/public/images/pokemon/variant/back/500.json new file mode 100644 index 00000000000..55e8d8b6548 --- /dev/null +++ b/public/images/pokemon/variant/back/500.json @@ -0,0 +1,46 @@ +{ + "1": { + "101010": "101010", + "212121": "1e2a4d", + "313131": "2d405c", + "333333": "2c2f35", + "7b1910": "257036", + "7a1a11": "1c2e1b", + "732900": "2c473e", + "7b5a08": "ab6441", + "a33a31": "35963e", + "a53a31": "3e4f37", + "bd5221": "3e6952", + "ef6321": "699676", + "b58c21": "cc955e", + "ef8c08": "86e677", + "efbd08": "c7f797", + "f0be0a": "f0cc8b", + "adadad": "a3a6ad", + "f7f7f7": "e4eef5", + "e63129": "58db58", + "e33229": "627556" + }, + "2": { + "101010": "101010", + "212121": "47150e", + "313131": "733421", + "333333": "3b352b", + "7b1910": "ba843d", + "7a1a11": "20243d", + "732900": "522e2e", + "7b5a08": "3c3e5b", + "a33a31": "cfa255", + "a53a31": "2d3250", + "bd5221": "7a5a56", + "ef6321": "967a71", + "b58c21": "828399", + "ef8c08": "f2d591", + "efbd08": "faefc7", + "f0be0a": "c7c8d9", + "adadad": "c4a884", + "f7f7f7": "e0d3ab", + "e63129": "e3c65c", + "e33229": "464a66" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/511.json b/public/images/pokemon/variant/back/511.json new file mode 100644 index 00000000000..a5ca6fa862f --- /dev/null +++ b/public/images/pokemon/variant/back/511.json @@ -0,0 +1,20 @@ +{ + "1": { + "a57b3a": "c58869", + "ffce7b": "edc293", + "735221": "bd7653", + "cea55a": "d9a177", + "194a29": "912f1c", + "087331": "c45331", + "19a552": "d97b41" + }, + "2": { + "a57b3a": "5580bf", + "ffce7b": "8ecaed", + "735221": "3f6aa6", + "cea55a": "73acde", + "194a29": "4c2d7a", + "087331": "683b8c", + "19a552": "8a53a6" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/512.json b/public/images/pokemon/variant/back/512.json new file mode 100644 index 00000000000..8d75727c3f0 --- /dev/null +++ b/public/images/pokemon/variant/back/512.json @@ -0,0 +1,26 @@ +{ + "1": { + "ffce7b": "eab68b", + "525252": "a36e46", + "087331": "c74638", + "194a29": "a12d25", + "ffffff": "dbc086", + "a57b3a": "a65b3d", + "cea55a": "c8895f", + "9c9c9c": "cfa067", + "735221": "733224", + "19a552": "ed6f53" + }, + "2": { + "ffce7b": "58aee0", + "525252": "3073ab", + "087331": "522880", + "194a29": "331961", + "ffffff": "5bc6de", + "a57b3a": "3762bf", + "cea55a": "4686cf", + "9c9c9c": "4099c2", + "735221": "2a42a1", + "19a552": "6e368f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/513.json b/public/images/pokemon/variant/back/513.json new file mode 100644 index 00000000000..5a8f4847bc9 --- /dev/null +++ b/public/images/pokemon/variant/back/513.json @@ -0,0 +1,20 @@ +{ + "1": { + "a57b3a": "e4907f", + "ffce7b": "ffe6c9", + "bd423a": "28629c", + "e65242": "3d9bbe", + "7b3131": "1b3e70", + "735221": "c3635b", + "cea55a": "f9b9a2" + }, + "2": { + "a57b3a": "bc2f2f", + "ffce7b": "ed8c7b", + "bd423a": "d5b393", + "e65242": "f4ecd7", + "7b3131": "ad7a63", + "735221": "a1272f", + "cea55a": "d4554c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/514.json b/public/images/pokemon/variant/back/514.json new file mode 100644 index 00000000000..90e7c698f29 --- /dev/null +++ b/public/images/pokemon/variant/back/514.json @@ -0,0 +1,27 @@ +{ + "1": { + "ffce7b": "ffe2bf", + "bd423a": "265494", + "e65242": "3a7bb5", + "7b3131": "193170", + "ffffff": "c0e7fc", + "735221": "ba6a57", + "c5c5c5": "97c0e6", + "cea55a": "edba9a", + "9c9c9c": "6f94c7", + "525252": "465f9e" + }, + "2": { + "ffce7b": "cc643b", + "bd423a": "cfb88f", + "e65242": "ede9d1", + "7b3131": "a88260", + "a57b3a": "782017", + "ffffff": "f7cc57", + "735221": "5c0e0e", + "c5c5c5": "e3a13d", + "cea55a": "943722", + "9c9c9c": "cc762b", + "525252": "ad4d1d" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/515.json b/public/images/pokemon/variant/back/515.json new file mode 100644 index 00000000000..d8a7c4e9136 --- /dev/null +++ b/public/images/pokemon/variant/back/515.json @@ -0,0 +1,22 @@ +{ + "1": { + "ffce7b": "fff187", + "003a73": "0a4a2d", + "21739c": "136b3b", + "198cad": "219448", + "29b5de": "34c15e", + "cea55a": "e0c265", + "735221": "735f21", + "a57b3a": "b5893c" + }, + "2": { + "ffce7b": "e76092", + "003a73": "a64e8b", + "21739c": "cc70a4", + "198cad": "eb98bf", + "29b5de": "ffc9dd", + "cea55a": "cc4580", + "735221": "8f1f68", + "a57b3a": "b32e77" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/516.json b/public/images/pokemon/variant/back/516.json new file mode 100644 index 00000000000..ae188e87625 --- /dev/null +++ b/public/images/pokemon/variant/back/516.json @@ -0,0 +1,24 @@ +{ + "1": { + "ffce7b": "fadd73", + "106b8c": "13571a", + "003a73": "08420d", + "9c9c9c": "aecf86", + "a57b3a": "9c7935", + "cea55a": "c4a148", + "218ca5": "3c8c22", + "735221": "7b5e29", + "29b5de": "6fad37" + }, + "2": { + "ffce7b": "e76092", + "106b8c": "cc70a4", + "003a73": "a64e8b", + "9c9c9c": "59b7d4", + "a57b3a": "b32e77", + "cea55a": "cc4580", + "218ca5": "eb98bf", + "735221": "8f1f68", + "29b5de": "ffc9dd" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/522.json b/public/images/pokemon/variant/back/522.json new file mode 100644 index 00000000000..9c301bca713 --- /dev/null +++ b/public/images/pokemon/variant/back/522.json @@ -0,0 +1,36 @@ +{ + "1": { + "a5a5a5": "676fc2", + "7b7b7b": "505a9b", + "525252": "95355d", + "cecece": "788bcb", + "161d1d": "2e0d1f", + "797878": "676fc2", + "005a9c": "75c239", + "505050": "3d4488", + "ffffff": "b9cfef", + "ffe600": "61e4bf", + "3a3a3a": "731f51", + "00adde": "b9e96c", + "8c7321": "33a08a", + "292929": "53173b", + "192121": "43172f" + }, + "2": { + "a5a5a5": "cb6a3a", + "7b7b7b": "731515", + "525252": "ebc37d", + "cecece": "97221a", + "161d1d": "370b0b", + "797878": "cb6a3a", + "005a9c": "30309d", + "505050": "4e1416", + "ffffff": "c23e2e", + "ffe600": "36c294", + "3a3a3a": "cd8a58", + "00adde": "3e4ddc", + "8c7321": "288278", + "292929": "914824", + "192121": "661212" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/523.json b/public/images/pokemon/variant/back/523.json new file mode 100644 index 00000000000..e8e37d6b7ab --- /dev/null +++ b/public/images/pokemon/variant/back/523.json @@ -0,0 +1,44 @@ +{ + "1": { + "373737": "43172f", + "373f3f": "353573", + "a5a5a5": "7080c6", + "5d4802": "1f8076", + "ffffff": "b9cfef", + "181f1f": "3d467d", + "8c7321": "33a08a", + "293131": "6a1d44", + "8c721f": "3d9197", + "7b7b7b": "5265a4", + "797878": "5265a4", + "182121": "430f30", + "cecece": "7e91d3", + "5a5a5a": "47548f", + "ffe600": "61e4bf", + "3a3a3a": "5d213a", + "00adde": "b9e96c", + "3a4242": "84294f", + "192121": "57163d" + }, + "2": { + "373737": "501a19", + "373f3f": "4e1416", + "a5a5a5": "861816", + "5d4802": "145b5d", + "ffffff": "c23e2e", + "181f1f": "5e1717", + "8c7321": "288278", + "293131": "c89161", + "8c721f": "54a48a", + "7b7b7b": "731515", + "797878": "da7248", + "182121": "661212", + "cecece": "97221a", + "5a5a5a": "611616", + "ffe600": "36c294", + "3a3a3a": "682321", + "00adde": "3e4ddc", + "3a4242": "ebc37d", + "192121": "9e533b" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/535.json b/public/images/pokemon/variant/back/535.json new file mode 100644 index 00000000000..2d1a18e3b9a --- /dev/null +++ b/public/images/pokemon/variant/back/535.json @@ -0,0 +1,26 @@ +{ + "1": { + "6bbdff": "a9c4d7", + "366089": "801941", + "636363": "8b2b4b", + "66bafd": "d65a5a", + "3a638c": "40567d", + "191919": "330821", + "7394c5": "6f8fb1", + "6f90c1": "b53a57", + "292929": "420e2d", + "424242": "671e3f" + }, + "2": { + "6bbdff": "672a23", + "366089": "ac6634", + "636363": "d76d39", + "66bafd": "f3cd69", + "3a638c": "420f1d", + "191919": "4f150a", + "7394c5": "54131a", + "6f90c1": "cd984a", + "292929": "7d2414", + "424242": "ac4423" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/536.json b/public/images/pokemon/variant/back/536.json new file mode 100644 index 00000000000..78a59fb699c --- /dev/null +++ b/public/images/pokemon/variant/back/536.json @@ -0,0 +1,32 @@ +{ + "1": { + "196373": "801941", + "404040": "874330", + "84e6d6": "d65a5a", + "10427b": "40567d", + "52a5b5": "b53a57", + "292929": "400a32", + "5e5e5e": "a96147", + "ffffff": "e3c998", + "296bad": "6f8fb1", + "c5c5c5": "ca9470", + "424242": "5e1246", + "0894d6": "a9c4d7", + "636363": "801c4e" + }, + "2": { + "196373": "ac6634", + "404040": "365a72", + "84e6d6": "f3cd69", + "10427b": "4a1423", + "52a5b5": "cd984a", + "292929": "7d2414", + "5e5e5e": "52809b", + "ffffff": "aadfe0", + "296bad": "5d171e", + "c5c5c5": "7fb8c2", + "424242": "ac4423", + "0894d6": "75332b", + "636363": "d76d39" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/537.json b/public/images/pokemon/variant/back/537.json new file mode 100644 index 00000000000..757d692bd40 --- /dev/null +++ b/public/images/pokemon/variant/back/537.json @@ -0,0 +1,24 @@ +{ + "1": { + "196373": "801941", + "52a58c": "b53a57", + "636363": "801c4e", + "10427b": "40567d", + "73e6ce": "d65a5a", + "292929": "400a32", + "424242": "5e1246", + "296bad": "6f8fb1", + "0894d6": "a9c4d7" + }, + "2": { + "196373": "ac6634", + "52a58c": "cd984a", + "636363": "d76d39", + "10427b": "4a1423", + "73e6ce": "f3cd69", + "292929": "7d2414", + "424242": "ac4423", + "296bad": "5d171e", + "0894d6": "75332b" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/554.json b/public/images/pokemon/variant/back/554.json new file mode 100644 index 00000000000..803721e4f0d --- /dev/null +++ b/public/images/pokemon/variant/back/554.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "5a1919": "2e3573", + "66311a": "a16012", + "634231": "946344", + "9c2929": "4e5aa3", + "ce3131": "6c7ec4", + "947310": "b0895f", + "ad5a2b": "a17a50", + "a75625": "d19628", + "cea519": "bda373", + "ffce21": "e3e2ba", + "ff9452": "e8c661", + "b15c29": "a17a50" + }, + "2": { + "101010": "101010", + "5a1919": "bf7558", + "66311a": "291d1b", + "634231": "75102a", + "9c2929": "d6a376", + "ce3131": "f0e2b9", + "947310": "9c1c2b", + "ad5a2b": "4a3021", + "a75625": "4a3021", + "cea519": "ba343d", + "ffce21": "d14949", + "ff9452": "614b38", + "b15c29": "b15c29" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/555-zen.json b/public/images/pokemon/variant/back/555-zen.json new file mode 100644 index 00000000000..9df761c1833 --- /dev/null +++ b/public/images/pokemon/variant/back/555-zen.json @@ -0,0 +1,24 @@ +{ + "1": { + "101010": "101010", + "215263": "592226", + "3a7b8c": "7d3e3d", + "425a63": "b5775b", + "529cad": "8c5b54", + "7ba5bd": "c99d7b", + "ad6b29": "3b3f87", + "b5d6ef": "e0c19b", + "e6a563": "7b8dd4" + }, + "2": { + "101010": "101010", + "215263": "523273", + "3a7b8c": "805a9c", + "425a63": "2e2a51", + "529cad": "a278b0", + "7ba5bd": "494162", + "ad6b29": "9e907e", + "b5d6ef": "605375", + "e6a563": "f5f3e9" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/555.json b/public/images/pokemon/variant/back/555.json new file mode 100644 index 00000000000..b83ca9fb88b --- /dev/null +++ b/public/images/pokemon/variant/back/555.json @@ -0,0 +1,30 @@ +{ + "1": { + "101010": "101010", + "523a21": "a65f33", + "631919": "222675", + "6b5a10": "b04a21", + "8c1929": "2d3685", + "ad2119": "3a4c94", + "b57b4a": "d9a455", + "bd0000": "cfc191", + "bd9429": "c26932", + "ef1010": "e3e2ba", + "efa56b": "e8cd7b", + "efce10": "d9944a" + }, + "2": { + "101010": "101010", + "523a21": "291b19", + "631919": "a86722", + "6b5a10": "941c32", + "8c1929": "d6993e", + "ad2119": "e8ca5d", + "b57b4a": "4a3021", + "bd0000": "bab5a6", + "bd9429": "ba343d", + "ef1010": "f5f3e9", + "efa56b": "614b38", + "efce10": "d14949" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/566.json b/public/images/pokemon/variant/back/566.json new file mode 100644 index 00000000000..cb2601d4a93 --- /dev/null +++ b/public/images/pokemon/variant/back/566.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "10316b": "1c4943", + "31529c": "336d60", + "3184f7": "4f9279", + "3a3a3a": "3a3a3a", + "523131": "641b49", + "524229": "2f6934", + "944242": "aa3c79", + "9c9cad": "9c9cad", + "bd9452": "66b562", + "de524a": "eb7fae", + "e6e6e6": "e6e6e6", + "f7ce63": "9be08b" + }, + "2": { + "101010": "101010", + "10316b": "283957", + "31529c": "929bdf", + "3184f7": "c4d3ff", + "3a3a3a": "3a3a3a", + "523131": "284452", + "524229": "211f69", + "944242": "44988f", + "9c9cad": "9c9cad", + "bd9452": "3b4bad", + "de524a": "65cda4", + "e6e6e6": "e6e6e6", + "f7ce63": "557ecd" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/567.json b/public/images/pokemon/variant/back/567.json new file mode 100644 index 00000000000..f4bb6a76111 --- /dev/null +++ b/public/images/pokemon/variant/back/567.json @@ -0,0 +1,37 @@ +{ + "1": { + "101010": "101010", + "523131": "454f52", + "635229": "2f6934", + "10316b": "1c4943", + "086b5a": "b3296b", + "9c4a4a": "7b8687", + "844252": "844252", + "de524a": "abb3b3", + "bd9452": "66b562", + "f7ce63": "9be08b", + "31529c": "336d60", + "10a594": "ee609d", + "3184f7": "4f9279", + "9c9cad": "9c9cad", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "523131": "284452", + "635229": "211f69", + "10316b": "283957", + "086b5a": "462d7e", + "9c4a4a": "44988f", + "844252": "844252", + "de524a": "65cda4", + "bd9452": "3b4bad", + "f7ce63": "557ecd", + "31529c": "929bdf", + "10a594": "7346a1", + "3184f7": "c4d3ff", + "9c9cad": "9c9cad", + "ffffff": "ffffff" + + } +} diff --git a/public/images/pokemon/variant/back/572.json b/public/images/pokemon/variant/back/572.json index e305e231ec0..5e74f55850d 100644 --- a/public/images/pokemon/variant/back/572.json +++ b/public/images/pokemon/variant/back/572.json @@ -1,18 +1,20 @@ { "1": { - "8c847b": "b2af6e", - "524a42": "524a42", - "ffffff": "feffd9", - "decec5": "decec5", - "bdb5a5": "dad7a1", - "101010": "101010" + "ffffff": "b3e8ba", + "4d473d": "802b50", + "524940": "428066", + "decec5": "87cc9a", + "bdb5a5": "cf6b77", + "918a83": "60a37b", + "8c847b": "b34967" }, "2": { - "8c847b": "86aaa7", - "524a42": "5f807e", - "ffffff": "ffffff", - "decec5": "d7e8e6", - "bdb5a5": "aec8c6", - "101010": "101010" + "ffffff": "d9e3aa", + "4d473d": "101931", + "524940": "466336", + "decec5": "7f915e", + "bdb5a5": "294a6b", + "918a83": "67824d", + "8c847b": "193457" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/back/573.json b/public/images/pokemon/variant/back/573.json new file mode 100644 index 00000000000..d3ceaf257b4 --- /dev/null +++ b/public/images/pokemon/variant/back/573.json @@ -0,0 +1,24 @@ +{ + "1": { + "524a42": "802b50", + "bdb5b5": "60a67c", + "847b73": "b34967", + "ffffff": "b3e8ba", + "bdad9c": "cf6b77", + "decec5": "87cc9a", + "d65252": "256145", + "807871": "458766", + "ef8484": "58a672" + }, + "2": { + "524a42": "101931", + "bdb5b5": "597041", + "847b73": "193457", + "ffffff": "d9e3aa", + "bdad9c": "294a6b", + "decec5": "7f915e", + "d65252": "558f45", + "807871": "3d542d", + "ef8484": "b4cf88" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/626.json b/public/images/pokemon/variant/back/626.json new file mode 100644 index 00000000000..3a709763542 --- /dev/null +++ b/public/images/pokemon/variant/back/626.json @@ -0,0 +1,46 @@ +{ + "1": { + "101010": "101010", + "312921": "303120", + "36363c": "362126", + "4a3119": "122119", + "4a4131": "4a4831", + "6b4a29": "2d4a3a", + "6b4a2a": "5f3539", + "6e4c2a": "565796", + "3a3a42": "4d150f", + "6b6b73": "802d1f", + "946a31": "4d6650", + "946a33": "513236", + "9a6f33": "716fab", + "ad8c29": "8580c4", + "9c845a": "9e655c", + "9c845c": "9e655c", + "bda57b": "bd8c7b", + "ffc54a": "c0b5eb", + "9ca5a5": "a34933", + "f7d69c": "f38d5d" + }, + "2": { + "101010": "101010", + "312921": "962430", + "36363c": "905932", + "4a3119": "855168", + "4a4131": "cc4545", + "6b4a29": "c17c95", + "6b4a2a": "907d32", + "6e4c2a": "678db8", + "3a3a42": "7f5310", + "6b6b73": "d49612", + "946a31": "e4b3b3", + "946a33": "946a33", + "9a6f33": "7da2c5", + "ad8c29": "92bcd4", + "9c845a": "beab6c", + "9c845c": "db9a39", + "bda57b": "efeac2", + "ffc54a": "c2e5f0", + "9ca5a5": "e9ca5a", + "f7d69c": "f5cc51" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/643.json b/public/images/pokemon/variant/back/643.json new file mode 100644 index 00000000000..08e6a2dd694 --- /dev/null +++ b/public/images/pokemon/variant/back/643.json @@ -0,0 +1,50 @@ +{ + "1": { + "196ba5": "e0912f", + "857c9c": "3c4154", + "54517a": "232738", + "c2c1db": "e6e7ef", + "fffffa": "fffffc", + "767ca8": "97a5b0", + "4a4a6b": "0d0d1a", + "504f75": "a58419", + "c3c1e0": "f0edc2", + "ffa531": "fcfade", + "767da3": "d6c563", + "d3d3e0": "2f3247", + "fff5f9": "565a69", + "c1c1d6": "454959", + "cacadb": "bfbfd6", + "ff6331": "ffee6b", + "d6c5b5": "f2f2d8", + "757d9e": "212236", + "e6b573": "f2ecaa", + "565280": "596675", + "ffffff": "414659", + "de2908": "ffca0a" + }, + "2": { + "196ba5": "b33a68", + "857c9c": "3c50a1", + "54517a": "2d3984", + "c2c1db": "343d8e", + "fffffa": "4459a2", + "767ca8": "2b2871", + "4a4a6b": "2d3984", + "504f75": "19323c", + "c3c1e0": "4f9290", + "ffa531": "e2f9b5", + "767da3": "3a6d71", + "d3d3e0": "647bd9", + "fff5f9": "a9bbff", + "c1c1d6": "647bd9", + "cacadb": "ffffff", + "ff6331": "9df377", + "d6c5b5": "3d8073", + "757d9e": "3c50a1", + "e6b573": "4ba789", + "565280": "19143f", + "ffffff": "a9bbff", + "de2908": "5cdca6" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/644.json b/public/images/pokemon/variant/back/644.json new file mode 100644 index 00000000000..01475c838c7 --- /dev/null +++ b/public/images/pokemon/variant/back/644.json @@ -0,0 +1,44 @@ +{ + "1": { + "1a1a21": "705ba8", + "2c2c35": "c1c8e8", + "103a52": "251076", + "191921": "686c99", + "16161d": "7687c2", + "6bf7ff": "dbbaff", + "00c5ff": "b77dff", + "0f0d13": "49568f", + "006bbd": "4800e3", + "121212": "54428f", + "940000": "762fcc", + "52525a": "7175a3", + "ce0000": "a44bf2", + "31313a": "cfd0e6", + "08528c": "3b1899", + "004275": "8742ff", + "111111": "5b5f8c", + "009cde": "7626ff", + "212129": "9b9fc4" + }, + "2": { + "1a1a21": "350707", + "2c2c35": "884290", + "103a52": "671212", + "191921": "843172", + "16161d": "5e286f", + "6bf7ff": "f5e5da", + "00c5ff": "f5b698", + "0f0d13": "3b1a4c", + "006bbd": "c8433a", + "121212": "210214", + "940000": "cc8215", + "52525a": "ffc5d1", + "ce0000": "f3d32c", + "31313a": "ef9dae", + "08528c": "821b1b", + "004275": "821b1b", + "111111": "4a1a4c", + "009cde": "ef806b", + "212129": "ca6c94" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/646-black.json b/public/images/pokemon/variant/back/646-black.json new file mode 100644 index 00000000000..28baffd5690 --- /dev/null +++ b/public/images/pokemon/variant/back/646-black.json @@ -0,0 +1,49 @@ +{ + "1": { + "ebebe8": "edc9ff", + "6b8c7b": "2b4366", + "7b6b5a": "5482b0", + "315a42": "1a2b4d", + "292930": "9b9bc2", + "31313a": "c8c9e0", + "e6e6de": "e6a18a", + "006b94": "4c13a1", + "23232b": "1c1c24", + "191921": "6a6a94", + "addec5": "426585", + "b59400": "b35a3e", + "355e45": "484873", + "2c2c36": "15213b", + "00b5ff": "a033ff", + "ffff4a": "db966b", + "524a31": "112240", + "b6e3c7": "bb8ae3", + "004b6f": "2f0e75", + "1e1e26": "1b1b24", + "719180": "905dcf", + "ada584": "78a9cc" + }, + "2": { + "ebebe8": "ffc5d1", + "6b8c7b": "be6e34", + "7b6b5a": "982222", + "315a42": "7b2d25", + "292930": "6c245b", + "31313a": "913a7d", + "006b94": "6b3773", + "23232b": "2b050a", + "191921": "3d0d38", + "addec5": "e6b45b", + "b59400": "166a2d", + "355e45": "ca6c94", + "2c2c36": "480b0b", + "00b5ff": "b464bf", + "ffff4a": "6ae649", + "524a31": "550f0f", + "b6e3c7": "ffadbe", + "004b6f": "411d46", + "1e1e26": "7b2d25", + "719180": "ea93a5", + "ada584": "c23232" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/646-white.json b/public/images/pokemon/variant/back/646-white.json new file mode 100644 index 00000000000..b2951e6fc38 --- /dev/null +++ b/public/images/pokemon/variant/back/646-white.json @@ -0,0 +1,46 @@ +{ + "1": { + "101010": "101010", + "741a18": "7a3418", + "4a4a29": "2a446b", + "4c4a2c": "0d0d1a", + "4a4a2d": "0d1030", + "315a42": "172247", + "7b7b5a": "779fbf", + "73737b": "120e1f", + "942921": "d49748", + "e64a42": "ffe587", + "6b8c7b": "2e466b", + "cc9827": "cc9827", + "ffde3a": "f0d897", + "ffad63": "fff7c4", + "ada584": "b7dbeb", + "bdbdc5": "232538", + "addec5": "45678a", + "e6e8f2": "414659", + "f5f5fa": "f5f5fa", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "741a18": "1f504d", + "4a4a29": "550f0f", + "4c4a2c": "1f1544", + "4a4a2d": "7b2d25", + "315a42": "7b2d25", + "7b7b5a": "982222", + "73737b": "2b2871", + "942921": "3d8073", + "e64a42": "4ba789", + "6b8c7b": "be6e34", + "cc9827": "166a2d", + "ffde3a": "9df377", + "ffad63": "5cdca6", + "ada584": "c23232", + "bdbdc5": "3d458f", + "addec5": "e6b45b", + "e6e8f2": "5870c4", + "f5f5fa": "f5f5fa", + "ffffff": "e2f9b5" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/646.json b/public/images/pokemon/variant/back/646.json new file mode 100644 index 00000000000..c509a0cda9c --- /dev/null +++ b/public/images/pokemon/variant/back/646.json @@ -0,0 +1,33 @@ +{ + "1": { + "8c7329": "b35a3e", + "949cad": "a6cfe0", + "6d737b": "a55c39", + "103a52": "121836", + "ffe600": "db966b", + "73737b": "6394b0", + "bde6ff": "3c5878", + "424252": "3d6285", + "696973": "6394b0", + "ceb500": "c46f52", + "a5b5ce": "293c5e", + "3b3b4a": "3d6285", + "6b8494": "1a2647" + }, + "2": { + "8c7329": "166a2d", + "949cad": "c23232", + "6d737b": "1a791b", + "103a52": "7b2d25", + "ffe600": "6ae649", + "73737b": "982222", + "bde6ff": "e6b45b", + "424252": "550f0f", + "696973": "736969", + "ceb500": "2aac2b", + "def7ff": "f7ec88", + "a5b5ce": "be6e34", + "3b3b4a": "4a3b3b", + "6b8494": "974626" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/692.json b/public/images/pokemon/variant/back/692.json new file mode 100644 index 00000000000..d4c85f37c9d --- /dev/null +++ b/public/images/pokemon/variant/back/692.json @@ -0,0 +1,28 @@ +{ + "1": { + "337380": "783a1d", + "b3b3b3": "c8ba6d", + "595959": "c85b5b", + "61daf2": "e1ac53", + "cc9c3d": "53be53", + "404040": "7d182d", + "ffc44c": "a9f076", + "b2f2ff": "fada7f", + "47a1b3": "af6a37", + "101010": "070707", + "735822": "20734c" + }, + "2": { + "337380": "5f3c23", + "b3b3b3": "68a7aa", + "595959": "88cd56", + "61daf2": "e1d6b6", + "cc9c3d": "7743be", + "404040": "1c873e", + "ffc44c": "a36feb", + "b2f2ff": "faf8d7", + "47a1b3": "968144", + "101010": "070707", + "735822": "371c72" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/693.json b/public/images/pokemon/variant/back/693.json new file mode 100644 index 00000000000..3187a81e0c0 --- /dev/null +++ b/public/images/pokemon/variant/back/693.json @@ -0,0 +1,28 @@ +{ + "1": { + "224b73": "552813", + "4595e5": "aa6839", + "23a2c8": "c87a23", + "262626": "230808", + "cc9c3d": "1b3c17", + "404040": "3c171b", + "5f5f5f": "6e2e3b", + "61daf2": "f2bd61", + "3674b3": "7d3e21", + "ffc44c": "426e2e", + "735822": "08230e" + }, + "2": { + "224b73": "5f463a", + "4595e5": "c8b493", + "23a2c8": "beb099", + "262626": "295a1c", + "cc9c3d": "6259af", + "404040": "2a8c53", + "5f5f5f": "51c85d", + "61daf2": "f0eadb", + "3674b3": "9b8265", + "ffc44c": "a39afa", + "735822": "36235f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/746-school.json b/public/images/pokemon/variant/back/746-school.json new file mode 100644 index 00000000000..d8fa61a3829 --- /dev/null +++ b/public/images/pokemon/variant/back/746-school.json @@ -0,0 +1,38 @@ +{ + "1": { + "101010": "101010", + "0a1627": "5f2112", + "123954": "75391b", + "134884": "935926", + "134d84": "16574d", + "1766c6": "b77736", + "416adf": "2c9572", + "79848a": "a67834", + "749cf6": "5ce09d", + "73dcf5": "27133f", + "73e5f5": "552b64", + "72f0f6": "824388", + "9cd3fd": "aafe94", + "a6c5f7": "78f389", + "cfd1d3": "d5ab51", + "fbfbfb": "f7d76b" + }, + "2": { + "101010": "101010", + "0a1627": "0f0523", + "123954": "28071a", + "134884": "350b19", + "134d84": "b7904d", + "1766c6": "4a1111", + "416adf": "dec284", + "79848a": "4a1111", + "749cf6": "f8ecc5", + "73dcf5": "31238e", + "73e5f5": "3a4ebd", + "72f0f6": "6492f7", + "9cd3fd": "fefeef", + "a6c5f7": "fefed9", + "cfd1d3": "5f291c", + "fbfbfb": "844232" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/746.json b/public/images/pokemon/variant/back/746.json new file mode 100644 index 00000000000..5b183b10e5d --- /dev/null +++ b/public/images/pokemon/variant/back/746.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "1f2161": "16574d", + "5d666d": "75391b", + "616b72": "a67834", + "9c455b": "308c9d", + "374793": "2c9572", + "4764c9": "5ce09d", + "3e9cbb": "27133f", + "61c8de": "824388", + "8c9c9d": "935926", + "8d9c9d": "c69b3f", + "d88394": "65cfe2", + "b0c5c6": "d5ab51", + "ccd2ce": "b77736", + "d8d9da": "d8d9da", + "eeeeee": "f7d76b", + "fefefe": "fefefe" + }, + "2": { + "101010": "101010", + "1f2161": "b7904d", + "5d666d": "1e0726", + "616b72": "4a1111", + "9c455b": "b9682d", + "374793": "dec284", + "4764c9": "f8ecc5", + "3e9cbb": "4378eb", + "61c8de": "5787f1", + "8c9c9d": "350b19", + "8d9c9d": "531917", + "d88394": "e4d85f", + "b0c5c6": "5f291c", + "ccd2ce": "4a1111", + "d8d9da": "d8d9da", + "eeeeee": "844232", + "fefefe": "fefefe" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/780.json b/public/images/pokemon/variant/back/780.json new file mode 100644 index 00000000000..f55158dcabb --- /dev/null +++ b/public/images/pokemon/variant/back/780.json @@ -0,0 +1,28 @@ +{ + "1": { + "8d541b": "bd8955", + "297b8b": "1a316b", + "5aa4a4": "284c80", + "f5ae07": "faf0b1", + "606f55": "496375", + "726d5c": "a36026", + "105262": "0e194a", + "b8b7a3": "cf8d38", + "b4cda4": "9ab5b8", + "91a37c": "7798a1", + "eeeeee": "e6c15e" + }, + "2": { + "8d541b": "157d36", + "297b8b": "4e4f73", + "5aa4a4": "6a708a", + "f5ae07": "3ec435", + "606f55": "8f825d", + "726d5c": "162d3d", + "105262": "3f3c61", + "b8b7a3": "254e59", + "b4cda4": "d6dbba", + "91a37c": "b5b48b", + "eeeeee": "3e7a76" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/782.json b/public/images/pokemon/variant/back/782.json new file mode 100644 index 00000000000..f2bc20ecfba --- /dev/null +++ b/public/images/pokemon/variant/back/782.json @@ -0,0 +1,30 @@ +{ + "1": { + "f13035": "48bd8c", + "f8f236": "e77b57", + "504e4b": "472d1d", + "aba5ad": "336340", + "7b766f": "a67e5b", + "fdfdfd": "fcf2ca", + "726475": "214a33", + "bec6cb": "e8cea0", + "957509": "a63424", + "dbdbdb": "4e8759", + "940a0d": "258067", + "4d4b48": "8a5b41" + }, + "2": { + "f13035": "b8c0fc", + "f8f236": "52d9ac", + "504e4b": "273959", + "aba5ad": "5e3e75", + "7b766f": "8ab7cf", + "fdfdfd": "d5f4f7", + "726475": "412959", + "bec6cb": "b7ddeb", + "957509": "258085", + "dbdbdb": "855d99", + "940a0d": "636a94", + "4d4b48": "567496" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/783.json b/public/images/pokemon/variant/back/783.json new file mode 100644 index 00000000000..d91ccb51133 --- /dev/null +++ b/public/images/pokemon/variant/back/783.json @@ -0,0 +1,32 @@ +{ + "1": { + "f13035": "48bd8c", + "6c6968": "472d1d", + "97938c": "2a573e", + "957509": "a63424", + "fff5ae": "f7c4b5", + "4d4644": "2b130b", + "fdfdfd": "fcf2ca", + "6b6968": "8a5b41", + "940a0d": "258067", + "c2c1c0": "42754f", + "d7aa22": "c25236", + "69625c": "133027", + "f4da42": "e77b57" + }, + "2": { + "f13035": "d9ddfc", + "6c6968": "2e4266", + "97938c": "543666", + "957509": "258085", + "fff5ae": "baf7dc", + "4d4644": "151e38", + "fdfdfd": "d5f4f7", + "6b6968": "567496", + "940a0d": "636a94", + "c2c1c0": "744e87", + "d7aa22": "37ad94", + "69625c": "2d1c3d", + "f4da42": "52d9ac" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/784.json b/public/images/pokemon/variant/back/784.json new file mode 100644 index 00000000000..74a18ff0d3d --- /dev/null +++ b/public/images/pokemon/variant/back/784.json @@ -0,0 +1,42 @@ +{ + "1": { + "c99f21": "bf5841", + "2d2b28": "2b130b", + "d0d2d5": "77a353", + "a8a4a0": "517d37", + "fafafa": "fcf2ca", + "d4d6d9": "e8cea0", + "4a4743": "8a5b41", + "f4da42": "e77b57", + "f13035": "48bd8c", + "cb0e12": "258067", + "4d4040": "123028", + "a7a29e": "336142", + "523e41": "447835", + "885902": "87281b", + "9d6702": "993d26", + "7e7572": "204736", + "fdfdfd": "bbd477", + "4b4845": "472d1d" + }, + "2": { + "c99f21": "3aba9c", + "2d2b28": "151e38", + "d0d2d5": "7ec2cc", + "a8a4a0": "558ea3", + "fafafa": "d5f4f7", + "d4d6d9": "b7ddeb", + "4a4743": "567496", + "f4da42": "2a918e", + "f13035": "d9ddfc", + "cb0e12": "636a94", + "4d4040": "2d1840", + "a7a29e": "6c457a", + "523e41": "558fa6", + "885902": "1f6b6e", + "9d6702": "37ad94", + "7e7572": "4e2e61", + "fdfdfd": "adedf0", + "4b4845": "2e4266" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/840.json b/public/images/pokemon/variant/back/840.json new file mode 100644 index 00000000000..3129592abb3 --- /dev/null +++ b/public/images/pokemon/variant/back/840.json @@ -0,0 +1,28 @@ +{ + "1": { + "e2244a": "70a2c5", + "5fab1d": "7a7c9e", + "d39a52": "a22f76", + "e32b50": "4e77a2", + "fe455c": "abd7e2", + "fa6f8b": "c1f3f3", + "a4d84a": "9aa0b3", + "357912": "48485d", + "d3ee77": "d2d8df", + "8d4229": "741163", + "a50534": "3e6085" + }, + "2": { + "e2244a": "bfb5ab", + "5fab1d": "993c63", + "d39a52": "463731", + "e32b50": "807770", + "fe455c": "dcd9d1", + "fa6f8b": "eeedea", + "a4d84a": "c76886", + "357912": "6b2041", + "d3ee77": "e28c95", + "8d4229": "291411", + "a50534": "68645f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/841-gigantamax.json b/public/images/pokemon/variant/back/841-gigantamax.json new file mode 100644 index 00000000000..6526fec9b4d --- /dev/null +++ b/public/images/pokemon/variant/back/841-gigantamax.json @@ -0,0 +1,36 @@ +{ + "1": { + "39a43d": "9aa0b3", + "d2394d": "abd7e2", + "61112d": "2c255d", + "a63139": "70a2c5", + "d54456": "8666ae", + "427638": "7a7c9e", + "c68a48": "9c2e72", + "8d4229": "272a52", + "eec856": "397880", + "cb8a42": "2b526f", + "b3ac62": "a3b9d0", + "dad08b": "dcebf9", + "2c4828": "243c63", + "e9c558": "c55885", + "772628": "1e1a4a" + }, + "2": { + "39a43d": "e28c95", + "d2394d": "dcd9d1", + "61112d": "3a2222", + "a63139": "bfb5ab", + "d54456": "915a41", + "427638": "b04f6d", + "c68a48": "2a1310", + "8d4229": "79392f", + "eec856": "eee0bc", + "cb8a42": "d1a87e", + "b3ac62": "cbb4af", + "dad08b": "e2dcd6", + "2c4828": "2e2246", + "e9c558": "463731", + "772628": "4f4840" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/841.json b/public/images/pokemon/variant/back/841.json new file mode 100644 index 00000000000..8cccd7dd76b --- /dev/null +++ b/public/images/pokemon/variant/back/841.json @@ -0,0 +1,34 @@ +{ + "1": { + "df6655": "c1f3f3", + "56ab32": "a59ab3", + "9b2629": "70a2c5", + "488235": "8e7a9e", + "ebe381": "854774", + "ccb468": "5d2654", + "ccca71": "cbb4af", + "8d764b": "110723", + "612324": "3e6085", + "da5245": "c55885", + "c3a965": "e2dcd6", + "b5915b": "34123a", + "d72d31": "abd7e2", + "395a2e": "383146" + }, + "2": { + "df6655": "e2dcd6", + "56ab32": "e28c95", + "9b2629": "bfb5ab", + "488235": "a8546e", + "ebe381": "be7b53", + "ccb468": "743527", + "ccca71": "cbb4af", + "8d764b": "230313", + "612324": "68645f", + "da5245": "463731", + "c3a965": "e2dcd6", + "b5915b": "541711", + "d72d31": "dcd9d1", + "395a2e": "4f0e30" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/842-gigantamax.json b/public/images/pokemon/variant/back/842-gigantamax.json new file mode 100644 index 00000000000..6526fec9b4d --- /dev/null +++ b/public/images/pokemon/variant/back/842-gigantamax.json @@ -0,0 +1,36 @@ +{ + "1": { + "39a43d": "9aa0b3", + "d2394d": "abd7e2", + "61112d": "2c255d", + "a63139": "70a2c5", + "d54456": "8666ae", + "427638": "7a7c9e", + "c68a48": "9c2e72", + "8d4229": "272a52", + "eec856": "397880", + "cb8a42": "2b526f", + "b3ac62": "a3b9d0", + "dad08b": "dcebf9", + "2c4828": "243c63", + "e9c558": "c55885", + "772628": "1e1a4a" + }, + "2": { + "39a43d": "e28c95", + "d2394d": "dcd9d1", + "61112d": "3a2222", + "a63139": "bfb5ab", + "d54456": "915a41", + "427638": "b04f6d", + "c68a48": "2a1310", + "8d4229": "79392f", + "eec856": "eee0bc", + "cb8a42": "d1a87e", + "b3ac62": "cbb4af", + "dad08b": "e2dcd6", + "2c4828": "2e2246", + "e9c558": "463731", + "772628": "4f4840" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/842.json b/public/images/pokemon/variant/back/842.json new file mode 100644 index 00000000000..3fdccc629c8 --- /dev/null +++ b/public/images/pokemon/variant/back/842.json @@ -0,0 +1,36 @@ +{ + "1": { + "39a45f": "9aa0b3", + "ffcd88": "698db4", + "621522": "3e6085", + "9f7034": "110723", + "f9be6b": "a3b9d0", + "fcff86": "397880", + "2c743e": "7a7c9e", + "af2348": "70a2c5", + "1f4329": "313846", + "ffc575": "2b526f", + "ffa63b": "2d3d68", + "275734": "852560", + "e78422": "1f1946", + "e75574": "abd7e2", + "7de755": "d66f9a" + }, + "2": { + "39a45f": "e28c95", + "ffcd88": "b9937a", + "621522": "68645f", + "9f7034": "2e0e09", + "f9be6b": "cbb4af", + "fcff86": "eee0bc", + "2c743e": "a8546e", + "af2348": "bfb5ab", + "1f4329": "341c1c", + "ffc575": "d1a87e", + "ffa63b": "63473b", + "275734": "2e2246", + "e78422": "4b211b", + "e75574": "dcd9d1", + "7de755": "589df3" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/871.json b/public/images/pokemon/variant/back/871.json new file mode 100644 index 00000000000..5004d3013b5 --- /dev/null +++ b/public/images/pokemon/variant/back/871.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "2e2732": "1b3334", + "281f2e": "2a2732", + "46384c": "504540", + "493d4e": "3a5d57", + "665272": "62857c", + "544947": "7d320e", + "7a7270": "a8501b", + "9e9a96": "cd7930", + "7b4e1c": "5b0d3f", + "d58815": "a02c58", + "fdba2f": "c45858", + "fdf22f": "f1e8e8" + }, + "2": { + "101010": "101010", + "2e2732": "8b4738", + "281f2e": "212232", + "46384c": "504740", + "493d4e": "ce8a66", + "665272": "eac69b", + "544947": "1a1730", + "7a7270": "27223b", + "9e9a96": "3a3449", + "7b4e1c": "222c58", + "d58815": "343f7f", + "fdba2f": "67729f", + "fdf22f": "8e9fc9" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/88.json b/public/images/pokemon/variant/back/88.json new file mode 100644 index 00000000000..61b7ca3b802 --- /dev/null +++ b/public/images/pokemon/variant/back/88.json @@ -0,0 +1,28 @@ +{ + "1": { + "101010": "101010", + "424a5a": "5b3a1d", + "5a3173": "6a010c", + "848c9c": "9b7c48", + "944a9c": "b1160e", + "adb5bd": "e9de8c", + "bd7bbd": "d55021", + "ce8cc5": "e98a47", + "d6d6de": "ded7ce", + "ffffff": "ffffff", + "efade6": "f8be70" + }, + "2": { + "101010": "101010", + "424a5a": "2d7351", + "5a3173": "a21851", + "848c9c": "69b17b", + "944a9c": "d04569", + "adb5bd": "b0e4a9", + "bd7bbd": "ed8ea2", + "ce8cc5": "f4bfbf", + "d6d6de": "d6d6de", + "ffffff": "ffffff", + "efade6": "f8d8cf" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/89.json b/public/images/pokemon/variant/back/89.json new file mode 100644 index 00000000000..eda3558d7c2 --- /dev/null +++ b/public/images/pokemon/variant/back/89.json @@ -0,0 +1,30 @@ +{ + "1": { + "101010": "101010", + "424a5a": "5b3a1d", + "5a3173": "6a010c", + "848c9c": "9b7c48", + "944a9c": "b1160e", + "adb5bd": "e9de8c", + "bd7bbd": "d55021", + "ce8cc5": "e98a47", + "d6d6de": "ded7ce", + "ffffff": "ffffff", + "efade6": "f8be70", + "ad63ad": "c63a17" + }, + "2": { + "101010": "101010", + "424a5a": "2d7351", + "5a3173": "a21851", + "848c9c": "69b17b", + "944a9c": "d04569", + "adb5bd": "b0e4a9", + "bd7bbd": "ed8ea2", + "ce8cc5": "f4bfbf", + "d6d6de": "d6d6de", + "ffffff": "ffffff", + "efade6": "f8d8cf", + "ad63ad": "e5728a" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/207.json b/public/images/pokemon/variant/back/female/207.json index 52c582cf1a8..89ed15e95c5 100644 --- a/public/images/pokemon/variant/back/female/207.json +++ b/public/images/pokemon/variant/back/female/207.json @@ -1,16 +1,14 @@ { "1": { - "63314a": "7f4812", - "e6a5ce": "f8dd84", - "de84b5": "daa93f", - "101010": "101010", - "ad6394": "b67322" + "de84b5": "e3784d", + "e6a5ce": "f7a565", + "63314a": "802019", + "ad6394": "ba4732" }, "2": { - "63314a": "5f1723", - "e6a5ce": "ef6b58", - "de84b5": "c04144", - "101010": "101010", - "ad6394": "97343c" + "de84b5": "42bca0", + "e6a5ce": "70e0b7", + "63314a": "134e5e", + "ad6394": "27868a" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/332.json b/public/images/pokemon/variant/back/female/332.json new file mode 100644 index 00000000000..9ec50cb7e92 --- /dev/null +++ b/public/images/pokemon/variant/back/female/332.json @@ -0,0 +1,28 @@ +{ + "1": { + "319452": "780d4a", + "4aa552": "8a1652", + "7ba563": "b44040", + "8cbd63": "bf3d64", + "215200": "710f2f", + "196b21": "780d4a", + "a5d674": "de5b6f", + "4a7310": "982443", + "a5d673": "e16363", + "63b56b": "9e2056", + "215201": "710f2e" + }, + "2": { + "319452": "b59c72", + "4aa552": "c9b991", + "7ba563": "805a9c", + "8cbd63": "ebe9ca", + "215200": "41334d", + "196b21": "b59c72", + "a5d674": "f6f7df", + "4a7310": "4f3956", + "a5d673": "a473ba", + "63b56b": "e3ddb8", + "215201": "694d37" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/396.json b/public/images/pokemon/variant/back/female/396.json new file mode 100644 index 00000000000..429adbc8791 --- /dev/null +++ b/public/images/pokemon/variant/back/female/396.json @@ -0,0 +1,36 @@ +{ + "1": { + "d6dede": "e3d09d", + "949494": "dbb070", + "736363": "89ad57", + "ffffff": "f0ecd3", + "382028": "731e22", + "d67300": "db963b", + "b5b5b5": "d4b27f", + "808080": "c48c51", + "9c4a21": "b06421", + "8c7373": "b53f36", + "3a2129": "2a4f19", + "524a4a": "558033", + "4f4747": "144a40", + "ad9c9c": "ed7b61", + "ff9429": "ffcf5e" + }, + "2": { + "d6dede": "f0deaa", + "949494": "cca472", + "736363": "4da8a1", + "ffffff": "fcfad2", + "382028": "0d142e", + "d67300": "52281f", + "b5b5b5": "debd8c", + "808080": "bf8d62", + "9c4a21": "451915", + "8c7373": "1b2745", + "3a2129": "235a6b", + "524a4a": "307b82", + "4f4747": "e0703d", + "ad9c9c": "2f436b", + "ff9429": "8c604c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/397.json b/public/images/pokemon/variant/back/female/397.json new file mode 100644 index 00000000000..0eef3be33d9 --- /dev/null +++ b/public/images/pokemon/variant/back/female/397.json @@ -0,0 +1,36 @@ +{ + "1": { + "735a63": "b53f36", + "574f57": "144a40", + "5a525a": "739e49", + "f75242": "8bba65", + "878787": "baa277", + "b5b5b5": "d9c798", + "ff9429": "ffcf5e", + "382f38": "0c3330", + "3a313a": "496e2e", + "362d36": "612e10", + "fcfcfc": "f0ebc5", + "bd6300": "b06421", + "7b4221": "965318", + "523a4a": "731e22", + "9c848c": "ed7b61" + }, + "2": { + "735a63": "1b2745", + "574f57": "e0703d", + "5a525a": "4da8a1", + "f75242": "f797ad", + "878787": "d4b885", + "b5b5b5": "f0deaa", + "ff9429": "8c604c", + "382f38": "b04a28", + "3a313a": "307b82", + "362d36": "421917", + "fcfcfc": "fcfad2", + "bd6300": "66362b", + "7b4221": "52281f", + "523a4a": "0d142e", + "9c848c": "2f436b" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/398.json b/public/images/pokemon/variant/back/female/398.json new file mode 100644 index 00000000000..0c987cf37b0 --- /dev/null +++ b/public/images/pokemon/variant/back/female/398.json @@ -0,0 +1,36 @@ +{ + "1": { + "9c4242": "09302d", + "5c545c": "144a40", + "3a313a": "0d3236", + "7b4221": "965318", + "bd6300": "db963b", + "5a525a": "558033", + "7b6b7b": "89ad57", + "f75242": "144a40", + "735a63": "d94f45", + "ffffff": "e8e3b6", + "523a4a": "872328", + "3a3a3a": "2a4f19", + "b5b5b5": "d7be89", + "9c848c": "ed7b61", + "ff9429": "ffcf5e" + }, + "2": { + "9c4242": "c94a2a", + "5c545c": "e0703d", + "3a313a": "a64221", + "7b4221": "421917", + "bd6300": "63362b", + "5a525a": "307b82", + "7b6b7b": "4da8a1", + "f75242": "f78a4a", + "735a63": "1b2745", + "ffffff": "fcfad2", + "523a4a": "080d1f", + "3a3a3a": "235a6b", + "b5b5b5": "f0deaa", + "9c848c": "293854", + "ff9429": "8c604c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/403.json b/public/images/pokemon/variant/back/female/403.json new file mode 100644 index 00000000000..4eb1da93a49 --- /dev/null +++ b/public/images/pokemon/variant/back/female/403.json @@ -0,0 +1,22 @@ +{ + "1": { + "b59c5a": "3763b8", + "7badf7": "bf403a", + "637bb5": "962a2f", + "4a4a63": "dcb788", + "ffe65a": "4881cc", + "313142": "bd8254", + "42426b": "63121d", + "736352": "234085" + }, + "2": { + "b59c5a": "36b88a", + "7badf7": "324663", + "637bb5": "222f4d", + "4a4a63": "bbe5e5", + "ffe65a": "46d382", + "313142": "73bec9", + "42426b": "161b36", + "736352": "298e7d" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/404.json b/public/images/pokemon/variant/back/female/404.json new file mode 100644 index 00000000000..1ebec7af6be --- /dev/null +++ b/public/images/pokemon/variant/back/female/404.json @@ -0,0 +1,24 @@ +{ + "1": { + "736352": "234085", + "4a4a73": "63121d", + "63637b": "f1dbb1", + "637bb5": "962a2f", + "4a4a63": "dcb788", + "ffe65a": "4881cc", + "313142": "bd8254", + "b59c5a": "3763b8", + "7badf7": "bf403a" + }, + "2": { + "736352": "298e7d", + "4a4a73": "161b36", + "63637b": "def4f0", + "637bb5": "222f4d", + "4a4a63": "bbe5e5", + "ffe65a": "46d382", + "313142": "73bec9", + "b59c5a": "36b88a", + "7badf7": "324663" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/405.json b/public/images/pokemon/variant/back/female/405.json new file mode 100644 index 00000000000..c70567e0728 --- /dev/null +++ b/public/images/pokemon/variant/back/female/405.json @@ -0,0 +1,30 @@ +{ + "1": { + "b59c5a": "3763b8", + "7badf7": "bf403a", + "63637b": "f1dbb1", + "3a3859": "430917", + "637bb5": "962a2f", + "4a4a73": "63121d", + "4a4a63": "dcb488", + "ffe65a": "4881cc", + "313142": "bd7e54", + "943a52": "5a2d0f", + "e64a52": "3e2711", + "736352": "234085" + }, + "2": { + "b59c5a": "36b88a", + "7badf7": "324663", + "63637b": "def4f0", + "3a3859": "0f0f26", + "637bb5": "222f4d", + "4a4a73": "161b36", + "4a4a63": "bbe5e5", + "ffe65a": "46d382", + "313142": "73bec9", + "943a52": "3a5e80", + "e64a52": "4a7c92", + "736352": "298e7d" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/417.json b/public/images/pokemon/variant/back/female/417.json new file mode 100644 index 00000000000..42b3180ee3c --- /dev/null +++ b/public/images/pokemon/variant/back/female/417.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "3e364e": "734430", + "524941": "732e12", + "5a524a": "642f1a", + "4a425a": "5f2618", + "84523a": "9b314f", + "ef845a": "e26e6e", + "c5a563": "e95d6c", + "ffd663": "f17c7c", + "637b9c": "86452b", + "7bb5e6": "a25f37", + "cec5c5": "e8be64", + "f7f7f7": "faeda9", + "ffffff": "ffffff", + "7b7b84": "8e623c" + }, + "2": { + "101010": "101010", + "3e364e": "203243", + "524941": "2d284c", + "5a524a": "0f203a", + "4a425a": "23704c", + "84523a": "693939", + "ef845a": "e1b8ac", + "c5a563": "8fecf7", + "ffd663": "d0fdff", + "637b9c": "a2dc76", + "7bb5e6": "e4fba1", + "cec5c5": "357577", + "f7f7f7": "5ba297", + "ffffff": "ffffff", + "7b7b84": "1f3f4e" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/2037.json b/public/images/pokemon/variant/exp/2037.json new file mode 100644 index 00000000000..2c190d5d36a --- /dev/null +++ b/public/images/pokemon/variant/exp/2037.json @@ -0,0 +1,26 @@ +{ + "1": { + "151515": "101010", + "2d57bb": "235dc4", + "558b9f": "9f435d", + "648082": "6e67b0", + "6cb1db": "3daae0", + "97bdd2": "ffa8b8", + "c1d1d2": "b3b8ea", + "d9e9f4": "ffd3e1", + "fdfdfd": "d7d9f9", + "ffffff": "ffffff" + }, + "2": { + "151515": "101010", + "2d57bb": "6e1179", + "558b9f": "90215e", + "648082": "bf4747", + "6cb1db": "8832a0", + "97bdd2": "da4e75", + "c1d1d2": "ffc07b", + "d9e9f4": "ff8489", + "fdfdfd": "ffe6a0", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/2038.json b/public/images/pokemon/variant/exp/2038.json new file mode 100644 index 00000000000..845c45f7887 --- /dev/null +++ b/public/images/pokemon/variant/exp/2038.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "4d5c78": "394880", + "516077": "9f435d", + "007ab5": "2380c4", + "38858d": "e35ea2", + "7a8a9c": "6172ab", + "66b3d7": "3dbfe0", + "86a8c0": "e27495", + "81c2c5": "ff89c0", + "bdcbd7": "a7ade7", + "a1e1de": "ffb6e5", + "b0d3ea": "ffa8b8", + "eafefe": "ffd3e1", + "fdfdfd": "bec6ef", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "4d5c78": "73174a", + "516077": "bb3c3c", + "007ab5": "882493", + "38858d": "572746", + "7a8a9c": "90215e", + "66b3d7": "a044ab", + "86a8c0": "ff824c", + "81c2c5": "75355e", + "bdcbd7": "da426d", + "a1e1de": "93547c", + "b0d3ea": "ffbf6b", + "eafefe": "ffe28c", + "fdfdfd": "ff6f86", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/692.json b/public/images/pokemon/variant/exp/692.json new file mode 100644 index 00000000000..954dcffb3e9 --- /dev/null +++ b/public/images/pokemon/variant/exp/692.json @@ -0,0 +1,26 @@ +{ + "1": { + "b3f2ff": "fada7f", + "44a2b4": "af6a37", + "2f7280": "783a1d", + "cd9d3a": "53be53", + "575757": "c85b5b", + "72561c": "20734c", + "60dbf2": "e1ac53", + "b4b4b4": "c8ba6d", + "3d3d3d": "7d182d", + "ffc549": "a9f076" + }, + "2": { + "b3f2ff": "faf8d7", + "44a2b4": "968144", + "2f7280": "5f3c23", + "cd9d3a": "7743be", + "575757": "88cd56", + "72561c": "371c72", + "60dbf2": "e1d6b6", + "b4b4b4": "68a7aa", + "3d3d3d": "1c873e", + "ffc549": "a36feb" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/693.json b/public/images/pokemon/variant/exp/693.json new file mode 100644 index 00000000000..2e80795d2a0 --- /dev/null +++ b/public/images/pokemon/variant/exp/693.json @@ -0,0 +1,30 @@ +{ + "1": { + "23a2c8": "c87a23", + "ffc859": "6ccd80", + "224b73": "552813", + "404040": "3c171b", + "262626": "230808", + "5f5f5f": "6e2e3b", + "cc9c3d": "1b3c17", + "61daf2": "f2bd61", + "735822": "08230e", + "3674b3": "7d3e21", + "ffc44c": "426e2e", + "4595e5": "aa6839" + }, + "2": { + "23a2c8": "beb099", + "ffc859": "f5b281", + "224b73": "5f463a", + "404040": "2a8c53", + "262626": "295a1c", + "5f5f5f": "51c85d", + "cc9c3d": "6259af", + "61daf2": "f0eadb", + "735822": "36235f", + "3674b3": "9b8265", + "ffc44c": "a39afa", + "4595e5": "c8b493" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/698.json b/public/images/pokemon/variant/exp/698.json deleted file mode 100644 index daf9b8c6f84..00000000000 --- a/public/images/pokemon/variant/exp/698.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "1": { - "cbaa84": "44827c", - "b3747e": "4b7465", - "eeffbf": "cdffb5", - "dcffb2": "8eeab9", - "ffbfca": "43bf8d", - "b7ffb2": "72d8ce", - "fff2b2": "9bffa9", - "85b4cc": "cf755d", - "a6e1ff": "efab87", - "101010": "101010", - "cacaca": "cacaca", - "537180": "b04f4b", - "2eaeec": "4dc796", - "1f75a0": "29988e", - "fdfdfd": "fdfdfd", - "d197a1": "d197a1", - "ffdce6": "ffdce6", - "217aa6": "7f99e1", - "30b2f2": "b5dcff", - "f9f9f9": "e6e3b4", - "c0c0c0": "d7cca0" - }, - "2": { - "cbaa84": "cc78db", - "b3747e": "c452a6", - "eeffbf": "ed9ff2", - "dcffb2": "d7bbf4", - "ffbfca": "faccff", - "b7ffb2": "dceeff", - "fff2b2": "eb88b9", - "85b4cc": "654a8a", - "a6e1ff": "936daa", - "101010": "101010", - "cacaca": "cacaca", - "537180": "392d65", - "2eaeec": "ad4e6e", - "1f75a0": "8d2656", - "fdfdfd": "fdfdfd", - "d197a1": "d197a1", - "ffdce6": "ffdce6", - "217aa6": "efaa51", - "30b2f2": "ffd169", - "f9f9f9": "373453", - "c0c0c0": "282747" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/703.json b/public/images/pokemon/variant/exp/703.json deleted file mode 100644 index c024feb1b30..00000000000 --- a/public/images/pokemon/variant/exp/703.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "1": { - "535763": "292638", - "306090": "c35b2a", - "c3c7d3": "68638e", - "88aacc": "e67c37", - "fefefe": "fefefe", - "a3a7b3": "4d496b", - "737783": "37344e", - "101010": "101010", - "bbddff": "ffa633", - "1fbfdf": "ff9b44", - "5f6060": "e6ac60", - "fcfefe": "ffeed6", - "bfbbbb": "ffd3a1" - }, - "2": { - "535763": "976ba9", - "306090": "a03c69", - "c3c7d3": "faecff", - "88aacc": "e25493", - "fefefe": "ffe2ee", - "a3a7b3": "e4cdf9", - "737783": "cca1db", - "101010": "101010", - "bbddff": "f591bd", - "1fbfdf": "de5f8e", - "5f6060": "5a3d84", - "fcfefe": "a473bf", - "bfbbbb": "8359a7" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/708.json b/public/images/pokemon/variant/exp/708.json deleted file mode 100644 index b32bbb79cd9..00000000000 --- a/public/images/pokemon/variant/exp/708.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "1": { - "101010": "101010", - "2b2a3a": "722023", - "603d2b": "36384f", - "215738": "4d362e", - "48484a": "a14743", - "c18760": "7c808c", - "3fa76c": "907f76", - "915e45": "575a6a", - "0b0c0b": "0b0c0b", - "da585b": "5996d2", - "ff8c8f": "87d1ff" - }, - "2": { - "101010": "101010", - "2b2a3a": "6f5f80", - "603d2b": "31161d", - "215738": "a94079", - "48484a": "9c92a4", - "c18760": "7e5658", - "3fa76c": "da7ea8", - "915e45": "56323a", - "0b0c0b": "0b0c0b", - "da585b": "e18933", - "ff8c8f": "ffc875" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/714.json b/public/images/pokemon/variant/exp/714.json deleted file mode 100644 index 018366c5381..00000000000 --- a/public/images/pokemon/variant/exp/714.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "1": { - "6a3f73": "731338", - "bd70cc": "a42c54", - "101010": "101010", - "bfacbf": "7047ba", - "8e5499": "8e1d4b", - "f2daf2": "8d7be3", - "404040": "202558", - "665c66": "2f386b", - "ccb43d": "ff8a58", - "f8f8f8": "8d7be3", - "595959": "2f386b", - "ffe14c": "ffc182", - "000000": "101010" - }, - "2": { - "6a3f73": "5f151c", - "bd70cc": "c24430", - "101010": "101010", - "bfacbf": "f9e8dd", - "8e5499": "882c27", - "f2daf2": "f8f8f8", - "404040": "5b1922", - "665c66": "7c2928", - "ccb43d": "33d8d0", - "f8f8f8": "f8f8f8", - "595959": "7c2928", - "ffe14c": "49ffcd", - "000000": "101010" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/746-school.json b/public/images/pokemon/variant/exp/746-school.json new file mode 100644 index 00000000000..a76aca2921f --- /dev/null +++ b/public/images/pokemon/variant/exp/746-school.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "0a1627": "5f2112", + "113650": "0b3d3a", + "123954": "75351b", + "10437d": "16574d", + "134884": "934f26", + "1766c6": "b77736", + "3d66d8": "d39c63", + "416adf": "2c9572", + "79848a": "a67834", + "749cf6": "5ce09d", + "43ebf3": "824388", + "72f0f6": "27133f", + "9cd3fd": "78f389", + "a6c5f7": "aafe94", + "cfd1d3": "d5ab51", + "fbfbfb": "f7d76b" + }, + "2": { + "101010": "101010", + "0a1627": "160523", + "113650": "846228", + "123954": "28071a", + "10437d": "b7904d", + "134884": "350b19", + "1766c6": "4a1111", + "3d66d8": "622222", + "416adf": "dec284", + "79848a": "4a1111", + "749cf6": "f8ecc5", + "43ebf3": "4378eb", + "72f0f6": "31238e", + "9cd3fd": "fefed9", + "a6c5f7": "fefeef", + "cfd1d3": "5f291c", + "fbfbfb": "844232" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/746.json b/public/images/pokemon/variant/exp/746.json new file mode 100644 index 00000000000..5b183b10e5d --- /dev/null +++ b/public/images/pokemon/variant/exp/746.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "1f2161": "16574d", + "5d666d": "75391b", + "616b72": "a67834", + "9c455b": "308c9d", + "374793": "2c9572", + "4764c9": "5ce09d", + "3e9cbb": "27133f", + "61c8de": "824388", + "8c9c9d": "935926", + "8d9c9d": "c69b3f", + "d88394": "65cfe2", + "b0c5c6": "d5ab51", + "ccd2ce": "b77736", + "d8d9da": "d8d9da", + "eeeeee": "f7d76b", + "fefefe": "fefefe" + }, + "2": { + "101010": "101010", + "1f2161": "b7904d", + "5d666d": "1e0726", + "616b72": "4a1111", + "9c455b": "b9682d", + "374793": "dec284", + "4764c9": "f8ecc5", + "3e9cbb": "4378eb", + "61c8de": "5787f1", + "8c9c9d": "350b19", + "8d9c9d": "531917", + "d88394": "e4d85f", + "b0c5c6": "5f291c", + "ccd2ce": "4a1111", + "d8d9da": "d8d9da", + "eeeeee": "844232", + "fefefe": "fefefe" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/780.json b/public/images/pokemon/variant/exp/780.json new file mode 100644 index 00000000000..0399d3567bf --- /dev/null +++ b/public/images/pokemon/variant/exp/780.json @@ -0,0 +1,40 @@ +{ + "1": { + "8d541b": "bd8955", + "297b8b": "1a316b", + "606f55": "496375", + "ffc4d7": "f29d9d", + "105262": "0e194a", + "b4cda4": "9ab5b8", + "f5ae07": "e8c987", + "ce5b9b": "cf4654", + "faf550": "faf0b1", + "e67b9c": "e65757", + "bd3983": "bd3341", + "eea6bc": "f06e6e", + "5aa4a4": "284c80", + "b8b7a3": "cf8d38", + "726d5c": "a36026", + "91a37c": "7798a1", + "eeeeee": "e6c15e" + }, + "2": { + "8d541b": "157d36", + "297b8b": "4e4f73", + "606f55": "8f825d", + "ffc4d7": "f2e396", + "105262": "3f3c61", + "b4cda4": "d6dbba", + "f5ae07": "24ab2b", + "ce5b9b": "d9ae5d", + "faf550": "3ec435", + "e67b9c": "e3b656", + "bd3983": "c27529", + "eea6bc": "f2d98d", + "5aa4a4": "6a708a", + "b8b7a3": "254e59", + "726d5c": "162d3d", + "91a37c": "b5b48b", + "eeeeee": "3e7a76" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/840.json b/public/images/pokemon/variant/exp/840.json new file mode 100644 index 00000000000..5a6a81a887e --- /dev/null +++ b/public/images/pokemon/variant/exp/840.json @@ -0,0 +1,34 @@ +{ + "1": { + "e2244a": "70a2c5", + "8d4229": "570749", + "94d84a": "fefefe", + "a4d84a": "9aa0b3", + "d39a52": "9c2e72", + "e32b50": "4e77a2", + "5fab1d": "7a7c9e", + "fe455c": "abd7e2", + "5bab1d": "acb0c3", + "247912": "48485d", + "a50534": "3e6085", + "357912": "313846", + "f2c171": "c55885", + "fa6f8b": "c1f3f3" + }, + "2": { + "e2244a": "bfb5ab", + "8d4229": "230808", + "94d84a": "589df3", + "a4d84a": "9aa0b3", + "d39a52": "291411", + "e32b50": "807770", + "5fab1d": "7a7c9e", + "fe455c": "dcd9d1", + "5bab1d": "354dbf", + "247912": "2e2246", + "a50534": "68645f", + "357912": "313846", + "f2c171": "463731", + "fa6f8b": "eeedea" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/841.json b/public/images/pokemon/variant/exp/841.json new file mode 100644 index 00000000000..aa68f322f29 --- /dev/null +++ b/public/images/pokemon/variant/exp/841.json @@ -0,0 +1,42 @@ +{ + "1": { + "101010": "101010", + "612324": "3e6085", + "395a2e": "383146", + "9b2629": "70a2c5", + "d72d31": "abd7e2", + "874c23": "453157", + "8d764b": "110723", + "d9695a": "c55885", + "488235": "8e7a9e", + "56ab32": "a59ab3", + "b08c51": "b3b1d6", + "b5915b": "34123a", + "ccb468": "5d2654", + "f1c950": "f3c5dd", + "ccca71": "e6dcf9", + "f0bda6": "c1f3f3", + "ebe381": "854774", + "fcfcfc": "fcfcfc" + }, + "2": { + "101010": "101010", + "612324": "827466", + "395a2e": "4f0e30", + "9b2629": "bfb5ab", + "d72d31": "dcd9d1", + "874c23": "2e2246", + "8d764b": "230313", + "d9695a": "463731", + "488235": "a8546e", + "56ab32": "e28c95", + "b08c51": "cbb4af", + "b5915b": "541711", + "ccb468": "8b4332", + "f1c950": "589df3", + "ccca71": "e2dcd6", + "f0bda6": "eeedea", + "ebe381": "c68862", + "fcfcfc": "fcfcfc" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/842.json b/public/images/pokemon/variant/exp/842.json new file mode 100644 index 00000000000..0629adc139a --- /dev/null +++ b/public/images/pokemon/variant/exp/842.json @@ -0,0 +1,43 @@ +{ + "1": { + "101010": "101010", + "1f4329": "313846", + "1f5829": "852560", + "2c743e": "7a7c9e", + "9f7034": "230f47", + "ac6b20": "110723", + "af2348": "67829e", + "e75574": "70a2c5", + "39a45f": "92cbd9", + "7de755": "d66f9a", + "e78422": "1f1946", + "ffa63b": "2d3d68", + "f1cf6d": "a3b9d0", + "f9d56d": "698db4", + "ffc575": "2b526f", + "f18e8e": "c1f3f3", + "fcff86": "397880", + "621522": "204063" + + }, + "2": { + "101010": "101010", + "1f4329": "511c2d", + "1f5829": "2e2246", + "2c743e": "a8546e", + "9f7034": "3a130d", + "ac6b20": "68645f", + "af2348": "bfb5ab", + "e75574": "dcd9d1", + "39a45f": "e28c95", + "7de755": "589df3", + "e78422": "4b211b", + "ffa63b": "63473b", + "f1cf6d": "cbb4af", + "f9d56d": "b9937a", + "ffc575": "d1a87e", + "f18e8e": "eeedea", + "fcff86": "eee0bc", + "621522": "68645f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/871.json b/public/images/pokemon/variant/exp/871.json new file mode 100644 index 00000000000..5004d3013b5 --- /dev/null +++ b/public/images/pokemon/variant/exp/871.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "2e2732": "1b3334", + "281f2e": "2a2732", + "46384c": "504540", + "493d4e": "3a5d57", + "665272": "62857c", + "544947": "7d320e", + "7a7270": "a8501b", + "9e9a96": "cd7930", + "7b4e1c": "5b0d3f", + "d58815": "a02c58", + "fdba2f": "c45858", + "fdf22f": "f1e8e8" + }, + "2": { + "101010": "101010", + "2e2732": "8b4738", + "281f2e": "212232", + "46384c": "504740", + "493d4e": "ce8a66", + "665272": "eac69b", + "544947": "1a1730", + "7a7270": "27223b", + "9e9a96": "3a3449", + "7b4e1c": "222c58", + "d58815": "343f7f", + "fdba2f": "67729f", + "fdf22f": "8e9fc9" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/2037.json b/public/images/pokemon/variant/exp/back/2037.json new file mode 100644 index 00000000000..0d2c02cf980 --- /dev/null +++ b/public/images/pokemon/variant/exp/back/2037.json @@ -0,0 +1,22 @@ +{ + "1": { + "151515": "101010", + "558b9f": "9f435d", + "648082": "6e67b0", + "97bdd2": "ffa8b8", + "c1d1d2": "b3b8ea", + "d9e9f4": "ffd3e1", + "fdfdfd": "d7d9f9", + "ffffff": "ffffff" + }, + "2": { + "151515": "101010", + "558b9f": "90215e", + "648082": "bf4747", + "97bdd2": "da4e75", + "c1d1d2": "ffc07b", + "d9e9f4": "ff8489", + "fdfdfd": "ffe6a0", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/2038.json b/public/images/pokemon/variant/exp/back/2038.json new file mode 100644 index 00000000000..845c45f7887 --- /dev/null +++ b/public/images/pokemon/variant/exp/back/2038.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "4d5c78": "394880", + "516077": "9f435d", + "007ab5": "2380c4", + "38858d": "e35ea2", + "7a8a9c": "6172ab", + "66b3d7": "3dbfe0", + "86a8c0": "e27495", + "81c2c5": "ff89c0", + "bdcbd7": "a7ade7", + "a1e1de": "ffb6e5", + "b0d3ea": "ffa8b8", + "eafefe": "ffd3e1", + "fdfdfd": "bec6ef", + "ffffff": "ffffff" + }, + "2": { + "101010": "101010", + "4d5c78": "73174a", + "516077": "bb3c3c", + "007ab5": "882493", + "38858d": "572746", + "7a8a9c": "90215e", + "66b3d7": "a044ab", + "86a8c0": "ff824c", + "81c2c5": "75355e", + "bdcbd7": "da426d", + "a1e1de": "93547c", + "b0d3ea": "ffbf6b", + "eafefe": "ffe28c", + "fdfdfd": "ff6f86", + "ffffff": "ffffff" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/692.json b/public/images/pokemon/variant/exp/back/692.json new file mode 100644 index 00000000000..d4c85f37c9d --- /dev/null +++ b/public/images/pokemon/variant/exp/back/692.json @@ -0,0 +1,28 @@ +{ + "1": { + "337380": "783a1d", + "b3b3b3": "c8ba6d", + "595959": "c85b5b", + "61daf2": "e1ac53", + "cc9c3d": "53be53", + "404040": "7d182d", + "ffc44c": "a9f076", + "b2f2ff": "fada7f", + "47a1b3": "af6a37", + "101010": "070707", + "735822": "20734c" + }, + "2": { + "337380": "5f3c23", + "b3b3b3": "68a7aa", + "595959": "88cd56", + "61daf2": "e1d6b6", + "cc9c3d": "7743be", + "404040": "1c873e", + "ffc44c": "a36feb", + "b2f2ff": "faf8d7", + "47a1b3": "968144", + "101010": "070707", + "735822": "371c72" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/693.json b/public/images/pokemon/variant/exp/back/693.json new file mode 100644 index 00000000000..3187a81e0c0 --- /dev/null +++ b/public/images/pokemon/variant/exp/back/693.json @@ -0,0 +1,28 @@ +{ + "1": { + "224b73": "552813", + "4595e5": "aa6839", + "23a2c8": "c87a23", + "262626": "230808", + "cc9c3d": "1b3c17", + "404040": "3c171b", + "5f5f5f": "6e2e3b", + "61daf2": "f2bd61", + "3674b3": "7d3e21", + "ffc44c": "426e2e", + "735822": "08230e" + }, + "2": { + "224b73": "5f463a", + "4595e5": "c8b493", + "23a2c8": "beb099", + "262626": "295a1c", + "cc9c3d": "6259af", + "404040": "2a8c53", + "5f5f5f": "51c85d", + "61daf2": "f0eadb", + "3674b3": "9b8265", + "ffc44c": "a39afa", + "735822": "36235f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/698.json b/public/images/pokemon/variant/exp/back/698.json deleted file mode 100644 index af193c3bc0c..00000000000 --- a/public/images/pokemon/variant/exp/back/698.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "1": { - "b3747e": "4b7465", - "ffbfca": "43bf8d", - "fff2b2": "9bffa9", - "537180": "b04f4b", - "a6e1ff": "efab87", - "101010": "101010", - "85b4cc": "cf755d", - "217aa6": "7f99e1", - "30b2f2": "b5dcff", - "fdfdfd": "fdfdfd", - "c0c0c0": "d7cca0", - "cacaca": "cacaca", - "cbaa84": "44827c", - "dcffb2": "8eeab9", - "eeffbf": "cdffb5", - "b7ffb2": "72d8ce" - }, - "2": { - "b3747e": "c452a6", - "ffbfca": "faccff", - "fff2b2": "eb88b9", - "537180": "392d65", - "a6e1ff": "936daa", - "101010": "101010", - "85b4cc": "654a8a", - "217aa6": "efaa51", - "30b2f2": "ffd169", - "fdfdfd": "fdfdfd", - "c0c0c0": "282747", - "cacaca": "cacaca", - "cbaa84": "cc78db", - "dcffb2": "d7bbf4", - "eeffbf": "ed9ff2", - "b7ffb2": "dceeff" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/703.json b/public/images/pokemon/variant/exp/back/703.json deleted file mode 100644 index 376abd466d2..00000000000 --- a/public/images/pokemon/variant/exp/back/703.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "1": { - "306090": "c35b2a", - "88aacc": "e67c37", - "fefefe": "fefefe", - "535763": "292638", - "a3a7b3": "4d496b", - "737783": "37344e", - "bbddff": "ffa633", - "101010": "101010", - "5f6060": "e6ac60", - "bfbbbb": "ffd3a1", - "fcfefe": "ffeed6" - }, - "2": { - "306090": "a03c69", - "88aacc": "e25493", - "fefefe": "ffe2ee", - "535763": "976ba9", - "a3a7b3": "e4cdf9", - "737783": "cca1db", - "bbddff": "f591bd", - "101010": "101010", - "5f6060": "5a3d84", - "bfbbbb": "8359a7", - "fcfefe": "a473bf" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/708.json b/public/images/pokemon/variant/exp/back/708.json deleted file mode 100644 index 7d41d6d24b0..00000000000 --- a/public/images/pokemon/variant/exp/back/708.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "1": { - "1a1a1c": "1a1a1c", - "686665": "646085", - "103222": "802c26", - "221b17": "221b17", - "090606": "090606", - "4ab38e": "a14743", - "38956f": "a14743", - "ab9074": "7c808c", - "4e4e4e": "494e5b", - "917860": "7c808c", - "424244": "2b303c", - "78604c": "575a6a", - "6b5442": "40435a", - "5f4939": "36384f", - "4f2a09": "292929", - "6c4513": "36384f", - "353638": "353638" - }, - "2": { - "1a1a1c": "1a1a1c", - "686665": "ccc3cf", - "103222": "a94079", - "221b17": "221b17", - "090606": "090606", - "4ab38e": "da7ea8", - "38956f": "da7ea8", - "ab9074": "7e5658", - "4e4e4e": "9c92a4", - "917860": "7e5658", - "424244": "6f5f80", - "78604c": "56323a", - "6b5442": "47232b", - "5f4939": "31161d", - "4f2a09": "250e14", - "6c4513": "31161d", - "353638": "57496b" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/714.json b/public/images/pokemon/variant/exp/back/714.json deleted file mode 100644 index 22933e71338..00000000000 --- a/public/images/pokemon/variant/exp/back/714.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "1": { - "101010": "101010", - "6a3f73": "500a25", - "bd70cc": "a42c54", - "8e5499": "8e1d4b", - "404040": "202558", - "595959": "2f386b", - "bfacbf": "8d7be3", - "665c66": "2f386b", - "f2daf2": "8d7be3" - }, - "2": { - "101010": "101010", - "6a3f73": "5f151c", - "bd70cc": "c24430", - "8e5499": "882c27", - "404040": "5b1922", - "595959": "7c2928", - "bfacbf": "f9e8dd", - "665c66": "7c2928", - "f2daf2": "f9e8dd" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/746-school.json b/public/images/pokemon/variant/exp/back/746-school.json new file mode 100644 index 00000000000..d8fa61a3829 --- /dev/null +++ b/public/images/pokemon/variant/exp/back/746-school.json @@ -0,0 +1,38 @@ +{ + "1": { + "101010": "101010", + "0a1627": "5f2112", + "123954": "75391b", + "134884": "935926", + "134d84": "16574d", + "1766c6": "b77736", + "416adf": "2c9572", + "79848a": "a67834", + "749cf6": "5ce09d", + "73dcf5": "27133f", + "73e5f5": "552b64", + "72f0f6": "824388", + "9cd3fd": "aafe94", + "a6c5f7": "78f389", + "cfd1d3": "d5ab51", + "fbfbfb": "f7d76b" + }, + "2": { + "101010": "101010", + "0a1627": "0f0523", + "123954": "28071a", + "134884": "350b19", + "134d84": "b7904d", + "1766c6": "4a1111", + "416adf": "dec284", + "79848a": "4a1111", + "749cf6": "f8ecc5", + "73dcf5": "31238e", + "73e5f5": "3a4ebd", + "72f0f6": "6492f7", + "9cd3fd": "fefeef", + "a6c5f7": "fefed9", + "cfd1d3": "5f291c", + "fbfbfb": "844232" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/746.json b/public/images/pokemon/variant/exp/back/746.json new file mode 100644 index 00000000000..5b183b10e5d --- /dev/null +++ b/public/images/pokemon/variant/exp/back/746.json @@ -0,0 +1,40 @@ +{ + "1": { + "101010": "101010", + "1f2161": "16574d", + "5d666d": "75391b", + "616b72": "a67834", + "9c455b": "308c9d", + "374793": "2c9572", + "4764c9": "5ce09d", + "3e9cbb": "27133f", + "61c8de": "824388", + "8c9c9d": "935926", + "8d9c9d": "c69b3f", + "d88394": "65cfe2", + "b0c5c6": "d5ab51", + "ccd2ce": "b77736", + "d8d9da": "d8d9da", + "eeeeee": "f7d76b", + "fefefe": "fefefe" + }, + "2": { + "101010": "101010", + "1f2161": "b7904d", + "5d666d": "1e0726", + "616b72": "4a1111", + "9c455b": "b9682d", + "374793": "dec284", + "4764c9": "f8ecc5", + "3e9cbb": "4378eb", + "61c8de": "5787f1", + "8c9c9d": "350b19", + "8d9c9d": "531917", + "d88394": "e4d85f", + "b0c5c6": "5f291c", + "ccd2ce": "4a1111", + "d8d9da": "d8d9da", + "eeeeee": "844232", + "fefefe": "fefefe" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/780.json b/public/images/pokemon/variant/exp/back/780.json new file mode 100644 index 00000000000..f55158dcabb --- /dev/null +++ b/public/images/pokemon/variant/exp/back/780.json @@ -0,0 +1,28 @@ +{ + "1": { + "8d541b": "bd8955", + "297b8b": "1a316b", + "5aa4a4": "284c80", + "f5ae07": "faf0b1", + "606f55": "496375", + "726d5c": "a36026", + "105262": "0e194a", + "b8b7a3": "cf8d38", + "b4cda4": "9ab5b8", + "91a37c": "7798a1", + "eeeeee": "e6c15e" + }, + "2": { + "8d541b": "157d36", + "297b8b": "4e4f73", + "5aa4a4": "6a708a", + "f5ae07": "3ec435", + "606f55": "8f825d", + "726d5c": "162d3d", + "105262": "3f3c61", + "b8b7a3": "254e59", + "b4cda4": "d6dbba", + "91a37c": "b5b48b", + "eeeeee": "3e7a76" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/840.json b/public/images/pokemon/variant/exp/back/840.json new file mode 100644 index 00000000000..c60e9aaa3a7 --- /dev/null +++ b/public/images/pokemon/variant/exp/back/840.json @@ -0,0 +1,28 @@ +{ + "1": { + "e2244a": "4e77a2", + "5fab1d": "7a7c9e", + "d39a52": "c55885", + "e32b50": "70a2c5", + "fe455c": "abd7e2", + "fa6f8b": "c1f3f3", + "a4d84a": "9aa0b3", + "357912": "313846", + "d3ee77": "c0cbd6", + "8d4229": "9c2e72", + "a50534": "3e6085" + }, + "2": { + "e2244a": "bfb5ab", + "5fab1d": "7a7c9e", + "d39a52": "463731", + "e32b50": "807770", + "fe455c": "dcd9d1", + "fa6f8b": "eeedea", + "a4d84a": "9aa0b3", + "357912": "313846", + "d3ee77": "afc6d2", + "8d4229": "291411", + "a50534": "68645f" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/841.json b/public/images/pokemon/variant/exp/back/841.json new file mode 100644 index 00000000000..11e45f3fc34 --- /dev/null +++ b/public/images/pokemon/variant/exp/back/841.json @@ -0,0 +1,34 @@ +{ + "1": { + "df6655": "c1f3f3", + "56ab32": "a59ab3", + "9b2629": "70a2c5", + "d9695a": "c55885", + "ebe381": "854774", + "ccb468": "5d2654", + "8d764b": "110723", + "ccca71": "b3b1d6", + "612324": "3e6085", + "488235": "8e7a9e", + "c3a965": "e6dcf9", + "b5915b": "34123a", + "d72d31": "abd7e2", + "395a2e": "383146" + }, + "2": { + "df6655": "eeedea", + "56ab32": "e28c95", + "9b2629": "bfb5ab", + "d9695a": "463731", + "ebe381": "854774", + "ccb468": "5d2654", + "8d764b": "110723", + "ccca71": "e2dcd6", + "612324": "68645f", + "488235": "a8546e", + "c3a965": "cbb4af", + "b5915b": "34123a", + "d72d31": "dcd9d1", + "395a2e": "4f0e30" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/842.json b/public/images/pokemon/variant/exp/back/842.json new file mode 100644 index 00000000000..926d558357b --- /dev/null +++ b/public/images/pokemon/variant/exp/back/842.json @@ -0,0 +1,38 @@ +{ + "1": { + "ac6b20": "101010", + "1f4329": "313846", + "9f7034": "110723", + "cfb07a": "a3b9d0", + "fcff86": "397880", + "7de755": "d66f9a", + "244d1f": "852560", + "fed26e": "698db4", + "39a45f": "9aa0b3", + "ffa63b": "2d3d68", + "e78422": "1f1946", + "e75574": "abd7e2", + "af2348": "70a2c5", + "621522": "3e6085", + "ffc575": "2b526f", + "2c743e": "7a7c9e" + }, + "2": { + "ac6b20": "101010", + "1f4329": "341c1c", + "9f7034": "2e0e09", + "cfb07a": "cbb4af", + "fcff86": "eee0bc", + "7de755": "589df3", + "244d1f": "2e2246", + "fed26e": "b9937a", + "39a45f": "e28c95", + "ffa63b": "63473b", + "e78422": "4b211b", + "e75574": "dcd9d1", + "af2348": "bfb5ab", + "621522": "68645f", + "ffc575": "d1a87e", + "2c743e": "a8546e" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/871.json b/public/images/pokemon/variant/exp/back/871.json new file mode 100644 index 00000000000..5004d3013b5 --- /dev/null +++ b/public/images/pokemon/variant/exp/back/871.json @@ -0,0 +1,32 @@ +{ + "1": { + "101010": "101010", + "2e2732": "1b3334", + "281f2e": "2a2732", + "46384c": "504540", + "493d4e": "3a5d57", + "665272": "62857c", + "544947": "7d320e", + "7a7270": "a8501b", + "9e9a96": "cd7930", + "7b4e1c": "5b0d3f", + "d58815": "a02c58", + "fdba2f": "c45858", + "fdf22f": "f1e8e8" + }, + "2": { + "101010": "101010", + "2e2732": "8b4738", + "281f2e": "212232", + "46384c": "504740", + "493d4e": "ce8a66", + "665272": "eac69b", + "544947": "1a1730", + "7a7270": "27223b", + "9e9a96": "3a3449", + "7b4e1c": "222c58", + "d58815": "343f7f", + "fdba2f": "67729f", + "fdf22f": "8e9fc9" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/female/207.json b/public/images/pokemon/variant/female/207.json index b0ae8e84102..b1e3582ae5c 100644 --- a/public/images/pokemon/variant/female/207.json +++ b/public/images/pokemon/variant/female/207.json @@ -1,32 +1,26 @@ { "1": { - "63314a": "7f4812", - "e6a5ce": "f8dd84", - "101010": "101010", - "ad6394": "b67322", - "de84b5": "daa93f", - "4a5a73": "4a5a73", - "ffffff": "ffffff", - "adbdc5": "adbdc5", - "bd6b5a": "bd6b5a", + "de84b5": "e3784d", + "e6a5ce": "f7a565", + "63314a": "2b8199", "4a73bd": "3b426f", - "ffa584": "ffa584", "294a7b": "1f2142", - "6b9cef": "596596" + "ad6394": "ba4732", + "612f48": "802019", + "6b9cef": "596596", + "ffa584": "68edca", + "bd6b5a": "44c5c9" }, "2": { - "63314a": "5f1723", - "e6a5ce": "ef6b58", - "101010": "101010", - "ad6394": "97343c", - "de84b5": "c04144", - "4a5a73": "4a5a73", - "ffffff": "ffffff", - "adbdc5": "adbdc5", - "bd6b5a": "c86539", - "4a73bd": "42bca0", + "de84b5": "42bca0", + "e6a5ce": "70e0b7", + "63314a": "752d17", + "4a73bd": "de597e", + "294a7b": "8a2b54", + "ad6394": "27868a", + "612f48": "134e5e", + "6b9cef": "f78f96", "ffa584": "f0a452", - "294a7b": "33817e", - "6b9cef": "81e4b3" + "bd6b5a": "c86539" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/female/332.json b/public/images/pokemon/variant/female/332.json new file mode 100644 index 00000000000..c86429d13c4 --- /dev/null +++ b/public/images/pokemon/variant/female/332.json @@ -0,0 +1,34 @@ +{ + "1": { + "319452": "780d4a", + "4a7310": "982443", + "7ba563": "b44040", + "bdef84": "ec8c8c", + "8cbd63": "bf3d64", + "215200": "710f2e", + "a5d674": "e16363", + "196b21": "7d1157", + "f7ce00": "5bcfc3", + "525252": "20668c", + "63b56b": "9e2056", + "a5d673": "de5b6f", + "8c6b3a": "33a3b0", + "4aa552": "8a1652" + }, + "2": { + "319452": "b59c72", + "4a7310": "4f3956", + "7ba563": "805a9c", + "bdef84": "c193cf", + "8cbd63": "f6f7df", + "215200": "694d37", + "a5d674": "a473ba", + "196b21": "9c805f", + "f7ce00": "f2aab6", + "525252": "983364", + "63b56b": "e3ddb8", + "a5d673": "ebe9ca", + "8c6b3a": "df879f", + "4aa552": "c9b991" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/female/396.json b/public/images/pokemon/variant/female/396.json new file mode 100644 index 00000000000..f811a4e002d --- /dev/null +++ b/public/images/pokemon/variant/female/396.json @@ -0,0 +1,38 @@ +{ + "1": { + "d6dede": "e3d09d", + "736363": "89ad57", + "3f1e27": "965318", + "d67300": "edb651", + "b5b5b5": "d1a562", + "9c4a21": "db963b", + "ff9429": "ffcf5e", + "3a2129": "2a4f19", + "524a4a": "558033", + "4f4747": "dbb070", + "fcfcfc": "f0ebc5", + "ff0000": "5da848", + "4a4343": "731e22", + "ad9c9c": "ed7b61", + "756565": "144a40", + "8c7373": "b53f36" + }, + "2": { + "d6dede": "f0deaa", + "736363": "4da8a1", + "3f1e27": "451915", + "d67300": "63362b", + "b5b5b5": "debd8c", + "9c4a21": "52281f", + "ff9429": "8c604c", + "3a2129": "235a6b", + "524a4a": "307b82", + "4f4747": "e3c896", + "fcfcfc": "fcfad2", + "ff0000": "c4568a", + "4a4343": "0d142e", + "ad9c9c": "2f436b", + "756565": "e0703d", + "8c7373": "1b2745" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/female/397.json b/public/images/pokemon/variant/female/397.json new file mode 100644 index 00000000000..8f266f191c6 --- /dev/null +++ b/public/images/pokemon/variant/female/397.json @@ -0,0 +1,38 @@ +{ + "1": { + "ff9429": "ffcf5e", + "3a3a3a": "558033", + "7b4221": "965318", + "523a4a": "731e22", + "9c848c": "ed7b61", + "5a525a": "739e49", + "735a63": "b53f36", + "f75242": "8bba65", + "b5b5b5": "d9c798", + "bd6300": "db963b", + "9c4242": "528a3e", + "3b303d": "144a40", + "4d464d": "256e54", + "2e222e": "3c5e24", + "3b333b": "753510", + "fcfcfc": "f0ebc5" + }, + "2": { + "ff9429": "8c604c", + "3a3a3a": "307b82", + "7b4221": "52281f", + "523a4a": "0d142e", + "9c848c": "2f436b", + "5a525a": "4da8a1", + "735a63": "1b2745", + "f75242": "f797ad", + "b5b5b5": "f0deaa", + "bd6300": "63362b", + "9c4242": "c4568a", + "3b303d": "e0703d", + "4d464d": "e68e57", + "2e222e": "235a6b", + "3b333b": "421917", + "fcfcfc": "fcfad2" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/female/398.json b/public/images/pokemon/variant/female/398.json new file mode 100644 index 00000000000..d4e72672103 --- /dev/null +++ b/public/images/pokemon/variant/female/398.json @@ -0,0 +1,36 @@ +{ + "1": { + "735a63": "b53f36", + "5c545c": "144a40", + "5a525a": "558033", + "7b6b7b": "89ad57", + "f75242": "156146", + "4f3847": "753510", + "b5b5b5": "d7be89", + "9c4242": "0c403b", + "7b4221": "965318", + "fcfcfc": "e8e3b6", + "3a3a3a": "2a4f19", + "bd6300": "db963b", + "523a4a": "731e22", + "9c848c": "ed7b61", + "ff9429": "ffcf5e" + }, + "2": { + "735a63": "1b2745", + "5c545c": "e0703d", + "5a525a": "307b82", + "7b6b7b": "4da8a1", + "f75242": "f78a4a", + "4f3847": "421917", + "b5b5b5": "f0deaa", + "9c4242": "c94a2a", + "7b4221": "52281f", + "fcfcfc": "fcfad2", + "3a3a3a": "235a6b", + "bd6300": "63362b", + "523a4a": "080d1f", + "9c848c": "293854", + "ff9429": "8c604c" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/female/403.json b/public/images/pokemon/variant/female/403.json new file mode 100644 index 00000000000..4f8bd43540c --- /dev/null +++ b/public/images/pokemon/variant/female/403.json @@ -0,0 +1,26 @@ +{ + "1": { + "b59c5a": "3763b8", + "7badf7": "bf403a", + "943a52": "33190a", + "637bb5": "962a2f", + "4a4a63": "dcb788", + "ffe65a": "4881cc", + "313142": "bd8254", + "e64a52": "3e2711", + "42426b": "63121d", + "736352": "234085" + }, + "2": { + "b59c5a": "36b88a", + "7badf7": "324663", + "943a52": "3a5e80", + "637bb5": "222f4d", + "4a4a63": "bbe5e5", + "ffe65a": "46d382", + "313142": "73bec9", + "e64a52": "4a7c92", + "42426b": "161b36", + "736352": "298e7d" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/female/404.json b/public/images/pokemon/variant/female/404.json new file mode 100644 index 00000000000..1c96dd11832 --- /dev/null +++ b/public/images/pokemon/variant/female/404.json @@ -0,0 +1,28 @@ +{ + "1": { + "736352": "234085", + "4a4a73": "63121d", + "63637b": "f1dbb1", + "b59c5a": "3763b8", + "637bb5": "962a2f", + "4a4a63": "dcb788", + "ffe65a": "4881cc", + "313142": "bd8254", + "943a52": "5a2d0f", + "e64a52": "3e2711", + "7badf7": "bf403a" + }, + "2": { + "736352": "298e7d", + "4a4a73": "161b36", + "63637b": "def4f0", + "b59c5a": "36b88a", + "637bb5": "222f4d", + "4a4a63": "bbe5e5", + "ffe65a": "46d382", + "313142": "73bec9", + "943a52": "3a5e80", + "e64a52": "4a7c92", + "7badf7": "324663" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/female/405.json b/public/images/pokemon/variant/female/405.json new file mode 100644 index 00000000000..c873cceb259 --- /dev/null +++ b/public/images/pokemon/variant/female/405.json @@ -0,0 +1,28 @@ +{ + "1": { + "b59c5a": "3763b8", + "7badf7": "bf403a", + "63637b": "f1dbb1", + "637bb5": "962a2f", + "943a52": "5a2d0f", + "4a4a63": "dcb488", + "ffe65a": "4881cc", + "313142": "bd7e54", + "4a4a73": "63121d", + "e64a52": "3e2711", + "736352": "234085" + }, + "2": { + "b59c5a": "36b88a", + "7badf7": "324663", + "63637b": "def4f0", + "637bb5": "222f4d", + "943a52": "3a5e80", + "4a4a63": "bbe5e5", + "ffe65a": "46d382", + "313142": "73bec9", + "4a4a73": "161b36", + "e64a52": "4a7c92", + "736352": "298e7d" + } +} \ No newline at end of file diff --git a/public/images/pokemon/variant/female/417.json b/public/images/pokemon/variant/female/417.json new file mode 100644 index 00000000000..42b3180ee3c --- /dev/null +++ b/public/images/pokemon/variant/female/417.json @@ -0,0 +1,36 @@ +{ + "1": { + "101010": "101010", + "3e364e": "734430", + "524941": "732e12", + "5a524a": "642f1a", + "4a425a": "5f2618", + "84523a": "9b314f", + "ef845a": "e26e6e", + "c5a563": "e95d6c", + "ffd663": "f17c7c", + "637b9c": "86452b", + "7bb5e6": "a25f37", + "cec5c5": "e8be64", + "f7f7f7": "faeda9", + "ffffff": "ffffff", + "7b7b84": "8e623c" + }, + "2": { + "101010": "101010", + "3e364e": "203243", + "524941": "2d284c", + "5a524a": "0f203a", + "4a425a": "23704c", + "84523a": "693939", + "ef845a": "e1b8ac", + "c5a563": "8fecf7", + "ffd663": "d0fdff", + "637b9c": "a2dc76", + "7bb5e6": "e4fba1", + "cec5c5": "357577", + "f7f7f7": "5ba297", + "ffffff": "ffffff", + "7b7b84": "1f3f4e" + } +} \ No newline at end of file diff --git a/public/images/pokemon_icons_1v.json b/public/images/pokemon_icons_1v.json index de66db65eb7..f5023b98a4b 100644 --- a/public/images/pokemon_icons_1v.json +++ b/public/images/pokemon_icons_1v.json @@ -13,2287 +13,6287 @@ "filename": "1_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "1_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "2_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "2_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "3-gigantamax_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "3-gigantamax_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "3-mega_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "3-mega_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "3_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "3_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "4_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "4_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "5_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "5_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "6-gigantamax_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 0, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 0, + "w": 40, + "h": 30 + } }, { "filename": "6-gigantamax_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "6-mega-x_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "6-mega-x_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "6-mega-y_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "6-mega-y_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "6_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "6_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "7_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "7_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "8_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "8_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "9-gigantamax_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "9-gigantamax_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "9-mega_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "9-mega_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 30, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 30, + "w": 40, + "h": 30 + } }, { "filename": "9_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "9_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "19_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "19_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "20_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "20_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "23_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "23_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "24_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "24_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "25-beauty-cosplay_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "25-beauty-cosplay_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "25-cool-cosplay_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "25-cool-cosplay_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "25-cosplay_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 60, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 60, + "w": 40, + "h": 30 + } }, { "filename": "25-cosplay_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-cute-cosplay_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-cute-cosplay_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-gigantamax_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-gigantamax_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-partner_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-partner_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-smart-cosplay_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-smart-cosplay_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-tough-cosplay_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25-tough-cosplay_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "25_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "26_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "26_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 90, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 90, + "w": 40, + "h": 30 + } }, { "filename": "29_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 120, + "w": 40, + "h": 30 + } }, { "filename": "29_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 120, + "w": 40, + "h": 30 + } }, { "filename": "29_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 120, + "w": 40, + "h": 30 + } }, { "filename": "30_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 120, + "w": 40, + "h": 30 + } }, { "filename": "30_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 120, + "w": 40, + "h": 30 + } }, { "filename": "31_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 120, + "w": 40, + "h": 30 + } }, { "filename": "31_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 120, + "w": 40, + "h": 30 + } }, { "filename": "31_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "32_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "32_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "33_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "33_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "34_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "34_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 120, + "w": 40, + "h": 30 + } }, { "filename": "35_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 120, + "w": 40, + "h": 30 + } }, { "filename": "35_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "36_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "36_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "37_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "37_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "38_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 120, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "38_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "39_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "39_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "40_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "40_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "41_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "41_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "41_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "42_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 150, + "w": 40, + "h": 30 + } }, { "filename": "42_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "42_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "43_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "43_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "44_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "44_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 150, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "45_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "45_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "46_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "46_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "46_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "47_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "47_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "47_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "50_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 180, + "w": 40, + "h": 30 + } }, { "filename": "50_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "51_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "51_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "52-gigantamax_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "52-gigantamax_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "52-gigantamax_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 180, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "52_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "52_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "52_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "53_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "53_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "53_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "56_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "56_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "56_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 210, + "w": 40, + "h": 30 + } }, { "filename": "57_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "57_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "57_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "69_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "69_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "70_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 210, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "70_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "71_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "71_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "77_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "77_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "78_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "78_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "79_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "79_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 240, + "w": 40, + "h": 30 + } }, { "filename": "79_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "80-mega_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "80-mega_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "80_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "80_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "81_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 240, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "81_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "82_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "82_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "83_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "83_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "84-f_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 270, "w": 40, "h": 30} - }, - { - "filename": "84-f_2", - "rotated": false, - "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 270, "w": 40, "h": 30} - }, - { - "filename": "84-f_3", - "rotated": false, - "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "84_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "84-f_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "84-f_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "84_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 270, + "w": 40, + "h": 30 + } }, { "filename": "84_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "85-f_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 270, "w": 40, "h": 30} - }, - { - "filename": "85-f_2", - "rotated": false, - "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 270, "w": 40, "h": 30} - }, - { - "filename": "85-f_3", - "rotated": false, - "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "85_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 270, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "85-f_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "85-f_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "85_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "85_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "86_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "86_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "86_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "87_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "87_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 300, + "w": 40, + "h": 30 + } }, { "filename": "87_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "88_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "88_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "89_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "89_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "92_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "92_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "92_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "93_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "93_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "93_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "94-gigantamax_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 300, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "94-gigantamax_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "94-gigantamax_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "94-mega_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "94-mega_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "94-mega_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "94_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "94_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 330, + "w": 40, + "h": 30 + } }, { "filename": "94_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "98_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "98_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "99-gigantamax_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "99-gigantamax_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "99_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "99_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "100_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 330, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "100_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "101_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "101_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "102_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "102_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "103_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "103_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 360, + "w": 40, + "h": 30 + } }, { "filename": "111_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "111_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "112_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "112_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "113_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "113_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "113_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "114_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 360, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "114_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "116_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "116_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "117_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "117_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "118_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "118_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 390, + "w": 40, + "h": 30 + } }, { "filename": "118_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "119_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "119_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "119_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "120_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "120_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "121_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "121_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 390, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "123_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "123_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "123_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "125_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "125_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "125_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "126_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 420, + "w": 40, + "h": 30 + } }, { "filename": "126_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "127-mega_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "127-mega_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "127_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "127_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "128_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "128_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "129_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 420, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "129_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "130-mega_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "130-mega_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "130_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "130_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "131-gigantamax_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "131-gigantamax_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 450, + "w": 40, + "h": 30 + } }, { "filename": "131_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "131_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "132_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "132_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "133-partner_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "133-partner_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "133_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "133_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 450, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "134_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "134_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "135_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "135_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "135_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "136_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "136_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 480, + "w": 40, + "h": 30 + } }, { "filename": "136_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "137_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "137_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "138_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "138_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "139_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "139_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "140_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 480, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "140_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "141_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "141_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "142-mega_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "142-mega_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "142_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 510, + "w": 40, + "h": 30 + } }, { "filename": "142_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "143-gigantamax_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 540, + "w": 40, + "h": 30 + } + }, + { + "filename": "143-gigantamax_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 540, + "w": 40, + "h": 30 + } + }, + { + "filename": "143_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 540, + "w": 40, + "h": 30 + } + }, + { + "filename": "143_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "144_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "144_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "144_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "145_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "145_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "145_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "146_1", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "146_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 510, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "146_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 0, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "147_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 40, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "147_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 80, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 560, + "y": 540, + "w": 40, + "h": 30 + } }, { "filename": "148_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 120, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "148_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 160, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "149_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 200, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "149_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 240, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "150-mega-x_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 280, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "150-mega-x_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 320, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "150-mega-y_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 360, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "150-mega-y_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 400, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "150_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 440, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "150_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 480, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "151_2", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 520, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 570, + "w": 40, + "h": 30 + } }, { "filename": "151_3", "rotated": false, "trimmed": false, - "sourceSize": {"w": 40, "h": 30}, - "spriteSourceSize": {"x": 0, "y": 0, "w": 40, "h": 30}, - "frame": {"x": 560, "y": 540, "w": 40, "h": 30} + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 570, + "w": 40, + "h": 30 + } } ] } ], "meta": { - "app": "texturepacker", - "version": "3.0" + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:3447489444000034526be9543e0a03fb:c9244ec22fd9b63bdc7e97bf457f1266:2fc2d7db306a93e9369e20846ccef45c$" } } diff --git a/public/images/pokemon_icons_1v.png b/public/images/pokemon_icons_1v.png index d6b1bc0cf7e..025c1ab025a 100644 Binary files a/public/images/pokemon_icons_1v.png and b/public/images/pokemon_icons_1v.png differ diff --git a/public/images/pokemon_icons_2v.json b/public/images/pokemon_icons_2v.json index 23eec483b42..519ea6c62f2 100644 --- a/public/images/pokemon_icons_2v.json +++ b/public/images/pokemon_icons_2v.json @@ -4,8 +4,8 @@ "image": "pokemon_icons_2v.png", "format": "RGBA8888", "size": { - "w": 520, - "h": 520 + "w": 540, + "h": 540 }, "scale": 1, "frames": [ @@ -1417,7 +1417,7 @@ } }, { - "filename": "190_2", + "filename": "187_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -1437,6 +1437,132 @@ "h": 30 } }, + { + "filename": "187_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "188_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "188_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "189_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "189_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "190_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 150, + "w": 40, + "h": 30 + } + }, { "filename": "190_3", "rotated": false, @@ -1452,7 +1578,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 360, "y": 150, "w": 40, "h": 30 @@ -1473,7 +1599,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 400, "y": 150, "w": 40, "h": 30 @@ -1494,7 +1620,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 440, "y": 150, "w": 40, "h": 30 @@ -1515,7 +1641,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 480, "y": 150, "w": 40, "h": 30 @@ -1536,8 +1662,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 150, + "x": 0, + "y": 180, "w": 40, "h": 30 } @@ -1557,8 +1683,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 150, + "x": 40, + "y": 180, "w": 40, "h": 30 } @@ -1578,8 +1704,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 150, + "x": 80, + "y": 180, "w": 40, "h": 30 } @@ -1599,8 +1725,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 150, + "x": 120, + "y": 180, "w": 40, "h": 30 } @@ -1620,8 +1746,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 150, + "x": 160, + "y": 180, "w": 40, "h": 30 } @@ -1641,8 +1767,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 150, + "x": 200, + "y": 180, "w": 40, "h": 30 } @@ -1662,7 +1788,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 240, "y": 180, "w": 40, "h": 30 @@ -1683,7 +1809,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 280, "y": 180, "w": 40, "h": 30 @@ -1704,7 +1830,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 320, "y": 180, "w": 40, "h": 30 @@ -1725,7 +1851,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 320, "y": 180, "w": 40, "h": 30 @@ -1746,7 +1872,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 360, "y": 180, "w": 40, "h": 30 @@ -1767,7 +1893,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 360, "y": 180, "w": 40, "h": 30 @@ -1788,7 +1914,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 400, "y": 180, "w": 40, "h": 30 @@ -1809,7 +1935,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 440, "y": 180, "w": 40, "h": 30 @@ -1830,7 +1956,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 480, "y": 180, "w": 40, "h": 30 @@ -1851,8 +1977,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 180, + "x": 0, + "y": 210, "w": 40, "h": 30 } @@ -1872,8 +1998,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 180, + "x": 40, + "y": 210, "w": 40, "h": 30 } @@ -1893,8 +2019,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 180, + "x": 80, + "y": 210, "w": 40, "h": 30 } @@ -1914,8 +2040,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 180, + "x": 120, + "y": 210, "w": 40, "h": 30 } @@ -1935,8 +2061,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 180, + "x": 160, + "y": 210, "w": 40, "h": 30 } @@ -1956,8 +2082,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 180, + "x": 200, + "y": 210, "w": 40, "h": 30 } @@ -1977,7 +2103,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 240, "y": 210, "w": 40, "h": 30 @@ -1998,7 +2124,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 280, "y": 210, "w": 40, "h": 30 @@ -2019,7 +2145,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 320, "y": 210, "w": 40, "h": 30 @@ -2040,7 +2166,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 360, "y": 210, "w": 40, "h": 30 @@ -2061,7 +2187,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 400, "y": 210, "w": 40, "h": 30 @@ -2082,7 +2208,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 440, "y": 210, "w": 40, "h": 30 @@ -2103,7 +2229,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 480, "y": 210, "w": 40, "h": 30 @@ -2124,8 +2250,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 210, + "x": 0, + "y": 240, "w": 40, "h": 30 } @@ -2145,8 +2271,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 210, + "x": 40, + "y": 240, "w": 40, "h": 30 } @@ -2166,8 +2292,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 210, + "x": 80, + "y": 240, "w": 40, "h": 30 } @@ -2187,8 +2313,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 210, + "x": 120, + "y": 240, "w": 40, "h": 30 } @@ -2208,8 +2334,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 210, + "x": 160, + "y": 240, "w": 40, "h": 30 } @@ -2229,8 +2355,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 210, + "x": 200, + "y": 240, "w": 40, "h": 30 } @@ -2250,7 +2376,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 240, "y": 240, "w": 40, "h": 30 @@ -2271,7 +2397,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 280, "y": 240, "w": 40, "h": 30 @@ -2292,7 +2418,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 320, "y": 240, "w": 40, "h": 30 @@ -2313,7 +2439,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 360, "y": 240, "w": 40, "h": 30 @@ -2334,7 +2460,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 400, "y": 240, "w": 40, "h": 30 @@ -2355,7 +2481,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 440, "y": 240, "w": 40, "h": 30 @@ -2376,7 +2502,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 480, "y": 240, "w": 40, "h": 30 @@ -2397,8 +2523,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 240, + "x": 0, + "y": 270, "w": 40, "h": 30 } @@ -2418,8 +2544,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 240, + "x": 40, + "y": 270, "w": 40, "h": 30 } @@ -2439,8 +2565,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 240, + "x": 80, + "y": 270, "w": 40, "h": 30 } @@ -2460,8 +2586,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 240, + "x": 120, + "y": 270, "w": 40, "h": 30 } @@ -2481,8 +2607,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 240, + "x": 160, + "y": 270, "w": 40, "h": 30 } @@ -2502,8 +2628,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 240, + "x": 200, + "y": 270, "w": 40, "h": 30 } @@ -2523,7 +2649,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 240, "y": 270, "w": 40, "h": 30 @@ -2544,7 +2670,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 280, "y": 270, "w": 40, "h": 30 @@ -2565,7 +2691,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 320, "y": 270, "w": 40, "h": 30 @@ -2586,7 +2712,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 360, "y": 270, "w": 40, "h": 30 @@ -2607,7 +2733,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 400, "y": 270, "w": 40, "h": 30 @@ -2628,7 +2754,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 440, "y": 270, "w": 40, "h": 30 @@ -2649,7 +2775,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 480, "y": 270, "w": 40, "h": 30 @@ -2670,8 +2796,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 270, + "x": 0, + "y": 300, "w": 40, "h": 30 } @@ -2691,8 +2817,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 270, + "x": 40, + "y": 300, "w": 40, "h": 30 } @@ -2712,8 +2838,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 270, + "x": 80, + "y": 300, "w": 40, "h": 30 } @@ -2733,8 +2859,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 270, + "x": 120, + "y": 300, "w": 40, "h": 30 } @@ -2754,8 +2880,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 270, + "x": 160, + "y": 300, "w": 40, "h": 30 } @@ -2775,8 +2901,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 270, + "x": 200, + "y": 300, "w": 40, "h": 30 } @@ -2796,7 +2922,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 240, "y": 300, "w": 40, "h": 30 @@ -2817,7 +2943,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 280, "y": 300, "w": 40, "h": 30 @@ -2838,7 +2964,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 320, "y": 300, "w": 40, "h": 30 @@ -2859,7 +2985,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 360, "y": 300, "w": 40, "h": 30 @@ -2880,7 +3006,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 400, "y": 300, "w": 40, "h": 30 @@ -2901,7 +3027,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 440, "y": 300, "w": 40, "h": 30 @@ -2922,7 +3048,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 480, "y": 300, "w": 40, "h": 30 @@ -2943,8 +3069,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 300, + "x": 0, + "y": 330, "w": 40, "h": 30 } @@ -2964,8 +3090,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 300, + "x": 40, + "y": 330, "w": 40, "h": 30 } @@ -2985,8 +3111,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 300, + "x": 80, + "y": 330, "w": 40, "h": 30 } @@ -3006,8 +3132,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 300, + "x": 120, + "y": 330, "w": 40, "h": 30 } @@ -3027,8 +3153,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 300, + "x": 160, + "y": 330, "w": 40, "h": 30 } @@ -3048,8 +3174,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 300, + "x": 200, + "y": 330, "w": 40, "h": 30 } @@ -3069,7 +3195,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 240, "y": 330, "w": 40, "h": 30 @@ -3090,7 +3216,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 280, "y": 330, "w": 40, "h": 30 @@ -3111,7 +3237,91 @@ "h": 30 }, "frame": { - "x": 80, + "x": 320, + "y": 330, + "w": 40, + "h": 30 + } + }, + { + "filename": "204_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 330, + "w": 40, + "h": 30 + } + }, + { + "filename": "204_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 330, + "w": 40, + "h": 30 + } + }, + { + "filename": "205_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 330, + "w": 40, + "h": 30 + } + }, + { + "filename": "205_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, "y": 330, "w": 40, "h": 30 @@ -3132,8 +3342,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 330, + "x": 0, + "y": 360, "w": 40, "h": 30 } @@ -3153,8 +3363,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 330, + "x": 40, + "y": 360, "w": 40, "h": 30 } @@ -3174,8 +3384,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 330, + "x": 80, + "y": 360, "w": 40, "h": 30 } @@ -3195,8 +3405,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 330, + "x": 120, + "y": 360, "w": 40, "h": 30 } @@ -3216,8 +3426,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 330, + "x": 160, + "y": 360, "w": 40, "h": 30 } @@ -3237,8 +3447,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 330, + "x": 200, + "y": 360, "w": 40, "h": 30 } @@ -3258,8 +3468,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 330, + "x": 240, + "y": 360, "w": 40, "h": 30 } @@ -3279,8 +3489,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 330, + "x": 280, + "y": 360, "w": 40, "h": 30 } @@ -3300,8 +3510,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 330, + "x": 320, + "y": 360, "w": 40, "h": 30 } @@ -3321,8 +3531,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 330, + "x": 360, + "y": 360, "w": 40, "h": 30 } @@ -3342,7 +3552,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 360, "w": 40, "h": 30 @@ -3363,7 +3573,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 360, "w": 40, "h": 30 @@ -3384,7 +3594,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 360, "w": 40, "h": 30 @@ -3405,8 +3615,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 360, + "x": 0, + "y": 390, "w": 40, "h": 30 } @@ -3426,8 +3636,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 360, + "x": 40, + "y": 390, "w": 40, "h": 30 } @@ -3447,8 +3657,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 360, + "x": 80, + "y": 390, "w": 40, "h": 30 } @@ -3468,8 +3678,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 360, + "x": 120, + "y": 390, "w": 40, "h": 30 } @@ -3489,8 +3699,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 360, + "x": 160, + "y": 390, "w": 40, "h": 30 } @@ -3510,8 +3720,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 360, + "x": 200, + "y": 390, "w": 40, "h": 30 } @@ -3531,8 +3741,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 360, + "x": 240, + "y": 390, "w": 40, "h": 30 } @@ -3552,8 +3762,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 360, + "x": 280, + "y": 390, "w": 40, "h": 30 } @@ -3573,8 +3783,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 360, + "x": 320, + "y": 390, "w": 40, "h": 30 } @@ -3594,8 +3804,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 360, + "x": 360, + "y": 390, "w": 40, "h": 30 } @@ -3615,7 +3825,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 390, "w": 40, "h": 30 @@ -3636,7 +3846,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 390, "w": 40, "h": 30 @@ -3657,7 +3867,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 390, "w": 40, "h": 30 @@ -3678,8 +3888,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 390, + "x": 0, + "y": 420, "w": 40, "h": 30 } @@ -3699,8 +3909,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 390, + "x": 40, + "y": 420, "w": 40, "h": 30 } @@ -3720,8 +3930,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 390, + "x": 80, + "y": 420, "w": 40, "h": 30 } @@ -3741,8 +3951,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 390, + "x": 120, + "y": 420, "w": 40, "h": 30 } @@ -3762,8 +3972,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 390, + "x": 160, + "y": 420, "w": 40, "h": 30 } @@ -3783,8 +3993,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 390, + "x": 200, + "y": 420, "w": 40, "h": 30 } @@ -3804,8 +4014,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 390, + "x": 240, + "y": 420, "w": 40, "h": 30 } @@ -3825,8 +4035,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 390, + "x": 280, + "y": 420, "w": 40, "h": 30 } @@ -3846,8 +4056,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 390, + "x": 320, + "y": 420, "w": 40, "h": 30 } @@ -3867,8 +4077,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 390, + "x": 360, + "y": 420, "w": 40, "h": 30 } @@ -3888,7 +4098,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 420, "w": 40, "h": 30 @@ -3909,7 +4119,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 420, "w": 40, "h": 30 @@ -3930,7 +4140,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 420, "w": 40, "h": 30 @@ -3951,8 +4161,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 420, + "x": 0, + "y": 450, "w": 40, "h": 30 } @@ -3972,8 +4182,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 420, + "x": 40, + "y": 450, "w": 40, "h": 30 } @@ -3993,8 +4203,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 420, + "x": 80, + "y": 450, "w": 40, "h": 30 } @@ -4014,8 +4224,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 420, + "x": 120, + "y": 450, "w": 40, "h": 30 } @@ -4035,8 +4245,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 420, + "x": 160, + "y": 450, "w": 40, "h": 30 } @@ -4056,8 +4266,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 420, + "x": 200, + "y": 450, "w": 40, "h": 30 } @@ -4077,8 +4287,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 420, + "x": 240, + "y": 450, "w": 40, "h": 30 } @@ -4098,8 +4308,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 420, + "x": 280, + "y": 450, "w": 40, "h": 30 } @@ -4119,8 +4329,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 420, + "x": 320, + "y": 450, "w": 40, "h": 30 } @@ -4140,8 +4350,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 420, + "x": 360, + "y": 450, "w": 40, "h": 30 } @@ -4161,7 +4371,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 450, "w": 40, "h": 30 @@ -4182,7 +4392,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 450, "w": 40, "h": 30 @@ -4203,7 +4413,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 450, "w": 40, "h": 30 @@ -4223,216 +4433,6 @@ "w": 40, "h": 30 }, - "frame": { - "x": 120, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "243_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 160, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "244_2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 200, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "244_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 240, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "245_2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 280, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "245_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 320, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "246_2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 360, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "246_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 400, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "247_2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 440, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "247_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 480, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "248-mega_2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, "frame": { "x": 0, "y": 480, @@ -4441,7 +4441,7 @@ } }, { - "filename": "248-mega_3", + "filename": "243_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4462,7 +4462,7 @@ } }, { - "filename": "248_2", + "filename": "244_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4483,7 +4483,7 @@ } }, { - "filename": "248_3", + "filename": "244_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4504,7 +4504,7 @@ } }, { - "filename": "249_2", + "filename": "245_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4525,7 +4525,7 @@ } }, { - "filename": "249_3", + "filename": "245_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4546,7 +4546,7 @@ } }, { - "filename": "250_2", + "filename": "246_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4567,7 +4567,7 @@ } }, { - "filename": "250_3", + "filename": "246_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4588,7 +4588,7 @@ } }, { - "filename": "251_2", + "filename": "247_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4609,7 +4609,7 @@ } }, { - "filename": "251_3", + "filename": "247_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4628,6 +4628,216 @@ "w": 40, "h": 30 } + }, + { + "filename": "248-mega_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 480, + "w": 40, + "h": 30 + } + }, + { + "filename": "248-mega_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 480, + "w": 40, + "h": 30 + } + }, + { + "filename": "248_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 480, + "w": 40, + "h": 30 + } + }, + { + "filename": "248_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "249_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "249_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "250_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "250_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "251_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "251_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 510, + "w": 40, + "h": 30 + } } ] } @@ -4635,6 +4845,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:cb87bf48266ab3d893dbbd24a52f875f:d37e73561b49b4fe831e3fcaee67b851:63b368599cdc6e139499267117e91cd5$" + "smartupdate": "$TexturePacker:SmartUpdate:9bbc7b4492e80aa5722cc2bf05816872:55b15740d88d2f1d62acee04668f97a7:63b368599cdc6e139499267117e91cd5$" } } diff --git a/public/images/pokemon_icons_2v.png b/public/images/pokemon_icons_2v.png index e74840b647b..fea0fb339ce 100644 Binary files a/public/images/pokemon_icons_2v.png and b/public/images/pokemon_icons_2v.png differ diff --git a/public/images/pokemon_icons_3v.json b/public/images/pokemon_icons_3v.json index 2500eebbff8..e18ce672c4e 100644 --- a/public/images/pokemon_icons_3v.json +++ b/public/images/pokemon_icons_3v.json @@ -4,8 +4,8 @@ "image": "pokemon_icons_3v.png", "format": "RGBA8888", "size": { - "w": 520, - "h": 520 + "w": 560, + "h": 560 }, "scale": 1, "frames": [ @@ -297,8 +297,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 30, + "x": 520, + "y": 0, "w": 40, "h": 30 } @@ -318,7 +318,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 0, "y": 30, "w": 40, "h": 30 @@ -339,7 +339,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 40, "y": 30, "w": 40, "h": 30 @@ -360,7 +360,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 80, "y": 30, "w": 40, "h": 30 @@ -381,7 +381,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 120, "y": 30, "w": 40, "h": 30 @@ -402,7 +402,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 160, "y": 30, "w": 40, "h": 30 @@ -423,7 +423,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 200, "y": 30, "w": 40, "h": 30 @@ -444,7 +444,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 240, "y": 30, "w": 40, "h": 30 @@ -465,7 +465,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 280, "y": 30, "w": 40, "h": 30 @@ -486,7 +486,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 320, "y": 30, "w": 40, "h": 30 @@ -507,7 +507,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 360, "y": 30, "w": 40, "h": 30 @@ -528,7 +528,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 400, "y": 30, "w": 40, "h": 30 @@ -549,7 +549,7 @@ "h": 30 }, "frame": { - "x": 480, + "x": 440, "y": 30, "w": 40, "h": 30 @@ -570,8 +570,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 60, + "x": 480, + "y": 30, "w": 40, "h": 30 } @@ -591,8 +591,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 60, + "x": 520, + "y": 30, "w": 40, "h": 30 } @@ -612,7 +612,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 0, "y": 60, "w": 40, "h": 30 @@ -633,7 +633,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 40, "y": 60, "w": 40, "h": 30 @@ -654,7 +654,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 80, "y": 60, "w": 40, "h": 30 @@ -675,7 +675,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 120, "y": 60, "w": 40, "h": 30 @@ -696,7 +696,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 160, "y": 60, "w": 40, "h": 30 @@ -717,7 +717,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 200, "y": 60, "w": 40, "h": 30 @@ -738,7 +738,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 240, "y": 60, "w": 40, "h": 30 @@ -759,7 +759,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 280, "y": 60, "w": 40, "h": 30 @@ -780,7 +780,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 320, "y": 60, "w": 40, "h": 30 @@ -801,7 +801,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 360, "y": 60, "w": 40, "h": 30 @@ -822,7 +822,7 @@ "h": 30 }, "frame": { - "x": 480, + "x": 400, "y": 60, "w": 40, "h": 30 @@ -843,8 +843,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 90, + "x": 440, + "y": 60, "w": 40, "h": 30 } @@ -864,8 +864,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 90, + "x": 480, + "y": 60, "w": 40, "h": 30 } @@ -885,8 +885,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 90, + "x": 520, + "y": 60, "w": 40, "h": 30 } @@ -906,7 +906,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 0, "y": 90, "w": 40, "h": 30 @@ -927,7 +927,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 40, "y": 90, "w": 40, "h": 30 @@ -948,7 +948,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 80, "y": 90, "w": 40, "h": 30 @@ -969,7 +969,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 120, "y": 90, "w": 40, "h": 30 @@ -990,7 +990,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 160, "y": 90, "w": 40, "h": 30 @@ -1011,7 +1011,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 200, "y": 90, "w": 40, "h": 30 @@ -1032,7 +1032,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 240, "y": 90, "w": 40, "h": 30 @@ -1053,7 +1053,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 280, "y": 90, "w": 40, "h": 30 @@ -1074,7 +1074,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 320, "y": 90, "w": 40, "h": 30 @@ -1095,7 +1095,7 @@ "h": 30 }, "frame": { - "x": 480, + "x": 360, "y": 90, "w": 40, "h": 30 @@ -1116,8 +1116,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 120, + "x": 400, + "y": 90, "w": 40, "h": 30 } @@ -1137,8 +1137,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 120, + "x": 440, + "y": 90, "w": 40, "h": 30 } @@ -1158,7 +1158,49 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, + "y": 90, + "w": 40, + "h": 30 + } + }, + { + "filename": "299_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 90, + "w": 40, + "h": 30 + } + }, + { + "filename": "299_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, "y": 120, "w": 40, "h": 30 @@ -1179,7 +1221,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 40, "y": 120, "w": 40, "h": 30 @@ -1200,7 +1242,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 80, "y": 120, "w": 40, "h": 30 @@ -1221,7 +1263,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 120, "y": 120, "w": 40, "h": 30 @@ -1242,7 +1284,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 160, "y": 120, "w": 40, "h": 30 @@ -1263,7 +1305,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 200, "y": 120, "w": 40, "h": 30 @@ -1284,7 +1326,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 240, "y": 120, "w": 40, "h": 30 @@ -1305,7 +1347,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 280, "y": 120, "w": 40, "h": 30 @@ -1326,7 +1368,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 320, "y": 120, "w": 40, "h": 30 @@ -1347,7 +1389,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 360, "y": 120, "w": 40, "h": 30 @@ -1368,7 +1410,7 @@ "h": 30 }, "frame": { - "x": 480, + "x": 400, "y": 120, "w": 40, "h": 30 @@ -1389,8 +1431,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 150, + "x": 440, + "y": 120, "w": 40, "h": 30 } @@ -1410,8 +1452,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 150, + "x": 480, + "y": 120, "w": 40, "h": 30 } @@ -1431,8 +1473,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 150, + "x": 520, + "y": 120, "w": 40, "h": 30 } @@ -1452,7 +1494,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 0, "y": 150, "w": 40, "h": 30 @@ -1473,7 +1515,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 40, "y": 150, "w": 40, "h": 30 @@ -1494,7 +1536,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 80, "y": 150, "w": 40, "h": 30 @@ -1515,7 +1557,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 120, "y": 150, "w": 40, "h": 30 @@ -1536,7 +1578,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 160, "y": 150, "w": 40, "h": 30 @@ -1557,7 +1599,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 200, "y": 150, "w": 40, "h": 30 @@ -1578,7 +1620,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 240, "y": 150, "w": 40, "h": 30 @@ -1599,7 +1641,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 280, "y": 150, "w": 40, "h": 30 @@ -1620,7 +1662,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 320, "y": 150, "w": 40, "h": 30 @@ -1641,7 +1683,7 @@ "h": 30 }, "frame": { - "x": 480, + "x": 360, "y": 150, "w": 40, "h": 30 @@ -1662,8 +1704,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 180, + "x": 400, + "y": 150, "w": 40, "h": 30 } @@ -1683,8 +1725,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 180, + "x": 440, + "y": 150, "w": 40, "h": 30 } @@ -1704,8 +1746,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 180, + "x": 480, + "y": 150, "w": 40, "h": 30 } @@ -1725,8 +1767,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 180, + "x": 520, + "y": 150, "w": 40, "h": 30 } @@ -1746,7 +1788,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 0, "y": 180, "w": 40, "h": 30 @@ -1767,7 +1809,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 40, "y": 180, "w": 40, "h": 30 @@ -1788,7 +1830,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 80, "y": 180, "w": 40, "h": 30 @@ -1809,7 +1851,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 120, "y": 180, "w": 40, "h": 30 @@ -1830,7 +1872,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 160, "y": 180, "w": 40, "h": 30 @@ -1851,7 +1893,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 200, "y": 180, "w": 40, "h": 30 @@ -1872,7 +1914,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 240, "y": 180, "w": 40, "h": 30 @@ -1893,7 +1935,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 280, "y": 180, "w": 40, "h": 30 @@ -1914,7 +1956,7 @@ "h": 30 }, "frame": { - "x": 480, + "x": 320, "y": 180, "w": 40, "h": 30 @@ -1935,8 +1977,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 210, + "x": 360, + "y": 180, "w": 40, "h": 30 } @@ -1956,8 +1998,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 210, + "x": 400, + "y": 180, "w": 40, "h": 30 } @@ -1977,8 +2019,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 210, + "x": 440, + "y": 180, "w": 40, "h": 30 } @@ -1998,8 +2040,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 210, + "x": 480, + "y": 180, "w": 40, "h": 30 } @@ -2019,8 +2061,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 210, + "x": 520, + "y": 180, "w": 40, "h": 30 } @@ -2040,7 +2082,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 0, "y": 210, "w": 40, "h": 30 @@ -2061,7 +2103,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 40, "y": 210, "w": 40, "h": 30 @@ -2082,7 +2124,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 80, "y": 210, "w": 40, "h": 30 @@ -2103,7 +2145,91 @@ "h": 30 }, "frame": { - "x": 320, + "x": 120, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "313_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "313_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "314_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "314_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, "y": 210, "w": 40, "h": 30 @@ -2124,7 +2250,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 320, "y": 210, "w": 40, "h": 30 @@ -2145,7 +2271,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 360, "y": 210, "w": 40, "h": 30 @@ -2166,7 +2292,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 400, "y": 210, "w": 40, "h": 30 @@ -2187,7 +2313,7 @@ "h": 30 }, "frame": { - "x": 480, + "x": 440, "y": 210, "w": 40, "h": 30 @@ -2208,8 +2334,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 240, + "x": 480, + "y": 210, "w": 40, "h": 30 } @@ -2228,6 +2354,48 @@ "w": 40, "h": 30 }, + "frame": { + "x": 520, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "325_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "325_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, "frame": { "x": 40, "y": 240, @@ -2235,6 +2403,48 @@ "h": 30 } }, + { + "filename": "326_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "326_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 240, + "w": 40, + "h": 30 + } + }, { "filename": "327_2", "rotated": false, @@ -2250,7 +2460,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 240, "w": 40, "h": 30 @@ -2271,7 +2481,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 240, "w": 40, "h": 30 @@ -2292,7 +2502,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 240, "w": 40, "h": 30 @@ -2313,7 +2523,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 240, "w": 40, "h": 30 @@ -2334,7 +2544,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 240, "w": 40, "h": 30 @@ -2355,7 +2565,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 240, "w": 40, "h": 30 @@ -2376,7 +2586,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 240, "w": 40, "h": 30 @@ -2396,48 +2606,6 @@ "w": 40, "h": 30 }, - "frame": { - "x": 360, - "y": 240, - "w": 40, - "h": 30 - } - }, - { - "filename": "333_2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 400, - "y": 240, - "w": 40, - "h": 30 - } - }, - { - "filename": "333_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, "frame": { "x": 440, "y": 240, @@ -2446,7 +2614,7 @@ } }, { - "filename": "334-mega_2", + "filename": "331_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -2467,7 +2635,28 @@ } }, { - "filename": "334-mega_3", + "filename": "331_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "332_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -2487,6 +2676,111 @@ "h": 30 } }, + { + "filename": "332_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "333_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "333_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "334-mega_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "334-mega_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 270, + "w": 40, + "h": 30 + } + }, { "filename": "334_2", "rotated": false, @@ -2502,7 +2796,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 240, "y": 270, "w": 40, "h": 30 @@ -2523,7 +2817,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 280, "y": 270, "w": 40, "h": 30 @@ -2544,7 +2838,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 320, "y": 270, "w": 40, "h": 30 @@ -2565,7 +2859,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 360, "y": 270, "w": 40, "h": 30 @@ -2586,7 +2880,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 400, "y": 270, "w": 40, "h": 30 @@ -2607,7 +2901,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 440, "y": 270, "w": 40, "h": 30 @@ -2628,7 +2922,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 480, "y": 270, "w": 40, "h": 30 @@ -2649,7 +2943,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 520, "y": 270, "w": 40, "h": 30 @@ -2670,8 +2964,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 270, + "x": 0, + "y": 300, "w": 40, "h": 30 } @@ -2691,8 +2985,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 270, + "x": 40, + "y": 300, "w": 40, "h": 30 } @@ -2712,8 +3006,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 270, + "x": 80, + "y": 300, "w": 40, "h": 30 } @@ -2733,8 +3027,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 270, + "x": 120, + "y": 300, "w": 40, "h": 30 } @@ -2754,7 +3048,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 300, "w": 40, "h": 30 @@ -2775,7 +3069,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 300, "w": 40, "h": 30 @@ -2796,7 +3090,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 300, "w": 40, "h": 30 @@ -2817,7 +3111,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 300, "w": 40, "h": 30 @@ -2838,7 +3132,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 300, "w": 40, "h": 30 @@ -2859,7 +3153,91 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "345_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "345_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "346_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "346_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, "y": 300, "w": 40, "h": 30 @@ -2880,8 +3258,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 300, + "x": 0, + "y": 330, "w": 40, "h": 30 } @@ -2901,8 +3279,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 300, + "x": 40, + "y": 330, "w": 40, "h": 30 } @@ -2922,8 +3300,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 300, + "x": 80, + "y": 330, "w": 40, "h": 30 } @@ -2943,8 +3321,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 300, + "x": 120, + "y": 330, "w": 40, "h": 30 } @@ -2964,8 +3342,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 300, + "x": 160, + "y": 330, "w": 40, "h": 30 } @@ -2985,8 +3363,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 300, + "x": 200, + "y": 330, "w": 40, "h": 30 } @@ -3006,8 +3384,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 300, + "x": 240, + "y": 330, "w": 40, "h": 30 } @@ -3027,7 +3405,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 280, "y": 330, "w": 40, "h": 30 @@ -3048,7 +3426,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 320, "y": 330, "w": 40, "h": 30 @@ -3069,7 +3447,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 360, "y": 330, "w": 40, "h": 30 @@ -3090,7 +3468,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 400, "y": 330, "w": 40, "h": 30 @@ -3111,7 +3489,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 440, "y": 330, "w": 40, "h": 30 @@ -3132,7 +3510,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 480, "y": 330, "w": 40, "h": 30 @@ -3153,7 +3531,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 520, "y": 330, "w": 40, "h": 30 @@ -3174,8 +3552,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 330, + "x": 0, + "y": 360, "w": 40, "h": 30 } @@ -3195,8 +3573,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 330, + "x": 40, + "y": 360, "w": 40, "h": 30 } @@ -3216,8 +3594,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 330, + "x": 80, + "y": 360, "w": 40, "h": 30 } @@ -3237,8 +3615,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 330, + "x": 120, + "y": 360, "w": 40, "h": 30 } @@ -3258,8 +3636,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 330, + "x": 160, + "y": 360, "w": 40, "h": 30 } @@ -3279,8 +3657,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 330, + "x": 200, + "y": 360, "w": 40, "h": 30 } @@ -3300,7 +3678,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 240, "y": 360, "w": 40, "h": 30 @@ -3321,7 +3699,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 280, "y": 360, "w": 40, "h": 30 @@ -3342,7 +3720,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 320, "y": 360, "w": 40, "h": 30 @@ -3363,7 +3741,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 360, "y": 360, "w": 40, "h": 30 @@ -3384,7 +3762,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 400, "y": 360, "w": 40, "h": 30 @@ -3405,7 +3783,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 440, "y": 360, "w": 40, "h": 30 @@ -3426,7 +3804,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 480, "y": 360, "w": 40, "h": 30 @@ -3447,7 +3825,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 520, "y": 360, "w": 40, "h": 30 @@ -3468,8 +3846,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 360, + "x": 0, + "y": 390, "w": 40, "h": 30 } @@ -3489,8 +3867,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 360, + "x": 40, + "y": 390, "w": 40, "h": 30 } @@ -3510,8 +3888,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 360, + "x": 80, + "y": 390, "w": 40, "h": 30 } @@ -3531,8 +3909,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 360, + "x": 120, + "y": 390, "w": 40, "h": 30 } @@ -3552,8 +3930,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 360, + "x": 160, + "y": 390, "w": 40, "h": 30 } @@ -3573,7 +3951,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 200, "y": 390, "w": 40, "h": 30 @@ -3594,7 +3972,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 240, "y": 390, "w": 40, "h": 30 @@ -3615,7 +3993,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 280, "y": 390, "w": 40, "h": 30 @@ -3636,7 +4014,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 320, "y": 390, "w": 40, "h": 30 @@ -3657,7 +4035,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 360, "y": 390, "w": 40, "h": 30 @@ -3678,7 +4056,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 400, "y": 390, "w": 40, "h": 30 @@ -3699,7 +4077,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 440, "y": 390, "w": 40, "h": 30 @@ -3720,7 +4098,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 480, "y": 390, "w": 40, "h": 30 @@ -3741,7 +4119,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 520, "y": 390, "w": 40, "h": 30 @@ -3762,8 +4140,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 390, + "x": 0, + "y": 420, "w": 40, "h": 30 } @@ -3783,8 +4161,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 390, + "x": 40, + "y": 420, "w": 40, "h": 30 } @@ -3804,8 +4182,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 390, + "x": 80, + "y": 420, "w": 40, "h": 30 } @@ -3825,8 +4203,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 390, + "x": 120, + "y": 420, "w": 40, "h": 30 } @@ -3846,7 +4224,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 420, "w": 40, "h": 30 @@ -3867,7 +4245,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 420, "w": 40, "h": 30 @@ -3888,7 +4266,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 420, "w": 40, "h": 30 @@ -3909,7 +4287,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 420, "w": 40, "h": 30 @@ -3930,7 +4308,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 420, "w": 40, "h": 30 @@ -3951,7 +4329,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 420, "w": 40, "h": 30 @@ -3972,7 +4350,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 420, "w": 40, "h": 30 @@ -3993,7 +4371,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 440, "y": 420, "w": 40, "h": 30 @@ -4014,7 +4392,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 480, "y": 420, "w": 40, "h": 30 @@ -4035,7 +4413,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 520, "y": 420, "w": 40, "h": 30 @@ -4056,8 +4434,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 420, + "x": 0, + "y": 450, "w": 40, "h": 30 } @@ -4077,8 +4455,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 420, + "x": 40, + "y": 450, "w": 40, "h": 30 } @@ -4098,8 +4476,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 420, + "x": 80, + "y": 450, "w": 40, "h": 30 } @@ -4119,7 +4497,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 120, "y": 450, "w": 40, "h": 30 @@ -4140,7 +4518,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 160, "y": 450, "w": 40, "h": 30 @@ -4161,7 +4539,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 200, "y": 450, "w": 40, "h": 30 @@ -4182,7 +4560,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 240, "y": 450, "w": 40, "h": 30 @@ -4203,7 +4581,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 280, "y": 450, "w": 40, "h": 30 @@ -4224,7 +4602,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 320, "y": 450, "w": 40, "h": 30 @@ -4245,7 +4623,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 360, "y": 450, "w": 40, "h": 30 @@ -4266,7 +4644,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 400, "y": 450, "w": 40, "h": 30 @@ -4287,7 +4665,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 440, "y": 450, "w": 40, "h": 30 @@ -4308,7 +4686,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 480, "y": 450, "w": 40, "h": 30 @@ -4329,7 +4707,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 520, "y": 450, "w": 40, "h": 30 @@ -4349,48 +4727,6 @@ "w": 40, "h": 30 }, - "frame": { - "x": 440, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "382-primal_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 480, - "y": 450, - "w": 40, - "h": 30 - } - }, - { - "filename": "382_2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, "frame": { "x": 0, "y": 480, @@ -4399,7 +4735,7 @@ } }, { - "filename": "382_3", + "filename": "382-primal_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4420,7 +4756,7 @@ } }, { - "filename": "383-primal_2", + "filename": "382_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4441,7 +4777,7 @@ } }, { - "filename": "383-primal_3", + "filename": "382_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4462,7 +4798,7 @@ } }, { - "filename": "383_2", + "filename": "383-primal_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4483,7 +4819,7 @@ } }, { - "filename": "383_3", + "filename": "383-primal_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4504,7 +4840,7 @@ } }, { - "filename": "384-mega_2", + "filename": "383_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4525,7 +4861,7 @@ } }, { - "filename": "384-mega_3", + "filename": "383_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4546,7 +4882,7 @@ } }, { - "filename": "384_2", + "filename": "384-mega_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4567,7 +4903,7 @@ } }, { - "filename": "384_3", + "filename": "384-mega_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4588,7 +4924,7 @@ } }, { - "filename": "385_1", + "filename": "384_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4609,7 +4945,7 @@ } }, { - "filename": "385_2", + "filename": "384_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4630,7 +4966,7 @@ } }, { - "filename": "385_3", + "filename": "385_1", "rotated": false, "trimmed": false, "sourceSize": { @@ -4649,6 +4985,48 @@ "w": 40, "h": 30 } + }, + { + "filename": "385_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 480, + "w": 40, + "h": 30 + } + }, + { + "filename": "385_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 510, + "w": 40, + "h": 30 + } } ] } @@ -4656,6 +5034,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:673055e796ec5f9913fd1dd04284765c:1804ddee68059c3372bf99289c91dd89:039b026190bf1878996b3e03190bcdf3$" + "smartupdate": "$TexturePacker:SmartUpdate:205dbeed0e74aff154166e4664b6771c:8bafe4b4084b51e4e837c213db97e8a4:039b026190bf1878996b3e03190bcdf3$" } } diff --git a/public/images/pokemon_icons_3v.png b/public/images/pokemon_icons_3v.png index 6b699b3bfa9..b151e36e72c 100644 Binary files a/public/images/pokemon_icons_3v.png and b/public/images/pokemon_icons_3v.png differ diff --git a/public/images/pokemon_icons_4v.json b/public/images/pokemon_icons_4v.json index 2f171915e01..ffc36e945c4 100644 --- a/public/images/pokemon_icons_4v.json +++ b/public/images/pokemon_icons_4v.json @@ -4,8 +4,8 @@ "image": "pokemon_icons_4v.png", "format": "RGBA8888", "size": { - "w": 520, - "h": 520 + "w": 540, + "h": 540 }, "scale": 1, "frames": [ @@ -388,7 +388,7 @@ } }, { - "filename": "399_2", + "filename": "396_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -408,6 +408,132 @@ "h": 30 } }, + { + "filename": "396_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "397_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "397_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "398_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "398_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "399_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 30, + "w": 40, + "h": 30 + } + }, { "filename": "399_3", "rotated": false, @@ -423,7 +549,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 480, "y": 30, "w": 40, "h": 30 @@ -444,8 +570,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 30, + "x": 0, + "y": 60, "w": 40, "h": 30 } @@ -465,8 +591,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 30, + "x": 40, + "y": 60, "w": 40, "h": 30 } @@ -486,8 +612,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 30, + "x": 80, + "y": 60, "w": 40, "h": 30 } @@ -507,8 +633,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 30, + "x": 120, + "y": 60, "w": 40, "h": 30 } @@ -528,8 +654,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 30, + "x": 160, + "y": 60, "w": 40, "h": 30 } @@ -549,8 +675,134 @@ "h": 30 }, "frame": { - "x": 480, - "y": 30, + "x": 200, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "403_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "403_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "404_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "404_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "405_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "405_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 60, "w": 40, "h": 30 } @@ -570,7 +822,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 480, "y": 60, "w": 40, "h": 30 @@ -591,8 +843,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 60, + "x": 0, + "y": 90, "w": 40, "h": 30 } @@ -612,8 +864,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 60, + "x": 40, + "y": 90, "w": 40, "h": 30 } @@ -633,8 +885,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 60, + "x": 80, + "y": 90, "w": 40, "h": 30 } @@ -654,8 +906,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 60, + "x": 120, + "y": 90, "w": 40, "h": 30 } @@ -675,8 +927,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 60, + "x": 160, + "y": 90, "w": 40, "h": 30 } @@ -696,8 +948,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 60, + "x": 200, + "y": 90, "w": 40, "h": 30 } @@ -717,8 +969,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 60, + "x": 240, + "y": 90, "w": 40, "h": 30 } @@ -738,8 +990,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 60, + "x": 280, + "y": 90, "w": 40, "h": 30 } @@ -759,8 +1011,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 60, + "x": 320, + "y": 90, "w": 40, "h": 30 } @@ -780,8 +1032,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 60, + "x": 360, + "y": 90, "w": 40, "h": 30 } @@ -801,8 +1053,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 60, + "x": 400, + "y": 90, "w": 40, "h": 30 } @@ -822,8 +1074,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 60, + "x": 440, + "y": 90, "w": 40, "h": 30 } @@ -843,7 +1095,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 480, "y": 90, "w": 40, "h": 30 @@ -864,8 +1116,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 90, + "x": 0, + "y": 120, "w": 40, "h": 30 } @@ -885,8 +1137,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 90, + "x": 40, + "y": 120, "w": 40, "h": 30 } @@ -906,8 +1158,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 90, + "x": 80, + "y": 120, "w": 40, "h": 30 } @@ -927,8 +1179,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 90, + "x": 120, + "y": 120, "w": 40, "h": 30 } @@ -948,8 +1200,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 90, + "x": 160, + "y": 120, "w": 40, "h": 30 } @@ -969,8 +1221,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 90, + "x": 200, + "y": 120, "w": 40, "h": 30 } @@ -990,8 +1242,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 90, + "x": 240, + "y": 120, "w": 40, "h": 30 } @@ -1011,8 +1263,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 90, + "x": 280, + "y": 120, "w": 40, "h": 30 } @@ -1032,8 +1284,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 90, + "x": 320, + "y": 120, "w": 40, "h": 30 } @@ -1052,9 +1304,51 @@ "w": 40, "h": 30 }, + "frame": { + "x": 360, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "417_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, "frame": { "x": 400, - "y": 90, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "417_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 120, "w": 40, "h": 30 } @@ -1074,8 +1368,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 90, + "x": 480, + "y": 120, "w": 40, "h": 30 } @@ -1095,8 +1389,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 90, + "x": 0, + "y": 150, "w": 40, "h": 30 } @@ -1116,8 +1410,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 120, + "x": 40, + "y": 150, "w": 40, "h": 30 } @@ -1137,8 +1431,134 @@ "h": 30 }, "frame": { - "x": 40, - "y": 120, + "x": 80, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "420_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "420_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "421-overcast_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "421-overcast_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "421-sunshine_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "421-sunshine_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 150, "w": 40, "h": 30 } @@ -1158,8 +1578,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 120, + "x": 360, + "y": 150, "w": 40, "h": 30 } @@ -1179,8 +1599,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 120, + "x": 400, + "y": 150, "w": 40, "h": 30 } @@ -1200,8 +1620,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 120, + "x": 440, + "y": 150, "w": 40, "h": 30 } @@ -1221,8 +1641,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 120, + "x": 480, + "y": 150, "w": 40, "h": 30 } @@ -1242,8 +1662,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 120, + "x": 0, + "y": 180, "w": 40, "h": 30 } @@ -1263,8 +1683,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 120, + "x": 40, + "y": 180, "w": 40, "h": 30 } @@ -1284,8 +1704,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 120, + "x": 80, + "y": 180, "w": 40, "h": 30 } @@ -1305,8 +1725,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 120, + "x": 120, + "y": 180, "w": 40, "h": 30 } @@ -1326,8 +1746,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 120, + "x": 160, + "y": 180, "w": 40, "h": 30 } @@ -1347,8 +1767,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 120, + "x": 200, + "y": 180, "w": 40, "h": 30 } @@ -1368,8 +1788,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 120, + "x": 240, + "y": 180, "w": 40, "h": 30 } @@ -1389,8 +1809,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 150, + "x": 280, + "y": 180, "w": 40, "h": 30 } @@ -1410,8 +1830,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 150, + "x": 320, + "y": 180, "w": 40, "h": 30 } @@ -1431,8 +1851,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 150, + "x": 360, + "y": 180, "w": 40, "h": 30 } @@ -1452,8 +1872,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 150, + "x": 400, + "y": 180, "w": 40, "h": 30 } @@ -1473,8 +1893,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 150, + "x": 440, + "y": 180, "w": 40, "h": 30 } @@ -1494,8 +1914,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 150, + "x": 480, + "y": 180, "w": 40, "h": 30 } @@ -1515,8 +1935,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 150, + "x": 0, + "y": 210, "w": 40, "h": 30 } @@ -1536,8 +1956,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 150, + "x": 40, + "y": 210, "w": 40, "h": 30 } @@ -1557,8 +1977,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 150, + "x": 80, + "y": 210, "w": 40, "h": 30 } @@ -1578,8 +1998,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 150, + "x": 120, + "y": 210, "w": 40, "h": 30 } @@ -1599,8 +2019,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 150, + "x": 160, + "y": 210, "w": 40, "h": 30 } @@ -1620,8 +2040,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 150, + "x": 200, + "y": 210, "w": 40, "h": 30 } @@ -1641,8 +2061,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 150, + "x": 240, + "y": 210, "w": 40, "h": 30 } @@ -1662,8 +2082,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 180, + "x": 280, + "y": 210, "w": 40, "h": 30 } @@ -1683,8 +2103,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 180, + "x": 320, + "y": 210, "w": 40, "h": 30 } @@ -1704,8 +2124,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 180, + "x": 360, + "y": 210, "w": 40, "h": 30 } @@ -1725,8 +2145,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 180, + "x": 400, + "y": 210, "w": 40, "h": 30 } @@ -1746,8 +2166,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 180, + "x": 440, + "y": 210, "w": 40, "h": 30 } @@ -1767,8 +2187,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 180, + "x": 480, + "y": 210, "w": 40, "h": 30 } @@ -1788,8 +2208,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 180, + "x": 0, + "y": 240, "w": 40, "h": 30 } @@ -1809,8 +2229,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 180, + "x": 40, + "y": 240, "w": 40, "h": 30 } @@ -1830,8 +2250,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 180, + "x": 80, + "y": 240, "w": 40, "h": 30 } @@ -1851,8 +2271,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 180, + "x": 120, + "y": 240, "w": 40, "h": 30 } @@ -1872,8 +2292,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 180, + "x": 160, + "y": 240, "w": 40, "h": 30 } @@ -1893,8 +2313,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 180, + "x": 200, + "y": 240, "w": 40, "h": 30 } @@ -1914,8 +2334,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 180, + "x": 240, + "y": 240, "w": 40, "h": 30 } @@ -1935,8 +2355,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 210, + "x": 280, + "y": 240, "w": 40, "h": 30 } @@ -1956,8 +2376,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 210, + "x": 320, + "y": 240, "w": 40, "h": 30 } @@ -1977,8 +2397,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 210, + "x": 360, + "y": 240, "w": 40, "h": 30 } @@ -1998,8 +2418,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 210, + "x": 400, + "y": 240, "w": 40, "h": 30 } @@ -2019,8 +2439,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 210, + "x": 440, + "y": 240, "w": 40, "h": 30 } @@ -2040,8 +2460,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 210, + "x": 480, + "y": 240, "w": 40, "h": 30 } @@ -2061,8 +2481,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 210, + "x": 0, + "y": 270, "w": 40, "h": 30 } @@ -2082,8 +2502,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 210, + "x": 40, + "y": 270, "w": 40, "h": 30 } @@ -2103,8 +2523,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 210, + "x": 80, + "y": 270, "w": 40, "h": 30 } @@ -2124,8 +2544,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 210, + "x": 120, + "y": 270, "w": 40, "h": 30 } @@ -2145,8 +2565,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 210, + "x": 160, + "y": 270, "w": 40, "h": 30 } @@ -2166,8 +2586,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 210, + "x": 200, + "y": 270, "w": 40, "h": 30 } @@ -2187,8 +2607,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 210, + "x": 240, + "y": 270, "w": 40, "h": 30 } @@ -2208,8 +2628,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 240, + "x": 280, + "y": 270, "w": 40, "h": 30 } @@ -2229,8 +2649,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 240, + "x": 320, + "y": 270, "w": 40, "h": 30 } @@ -2250,8 +2670,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 240, + "x": 360, + "y": 270, "w": 40, "h": 30 } @@ -2271,8 +2691,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 240, + "x": 400, + "y": 270, "w": 40, "h": 30 } @@ -2292,8 +2712,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 240, + "x": 440, + "y": 270, "w": 40, "h": 30 } @@ -2313,8 +2733,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 240, + "x": 480, + "y": 270, "w": 40, "h": 30 } @@ -2334,8 +2754,50 @@ "h": 30 }, "frame": { - "x": 240, - "y": 240, + "x": 0, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "446_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 300, + "w": 40, + "h": 30 + } + }, + { + "filename": "446_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 300, "w": 40, "h": 30 } @@ -2355,8 +2817,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 240, + "x": 120, + "y": 300, "w": 40, "h": 30 } @@ -2376,8 +2838,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 240, + "x": 160, + "y": 300, "w": 40, "h": 30 } @@ -2397,8 +2859,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 240, + "x": 200, + "y": 300, "w": 40, "h": 30 } @@ -2418,8 +2880,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 240, + "x": 240, + "y": 300, "w": 40, "h": 30 } @@ -2439,8 +2901,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 240, + "x": 280, + "y": 300, "w": 40, "h": 30 } @@ -2460,8 +2922,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 240, + "x": 320, + "y": 300, "w": 40, "h": 30 } @@ -2481,8 +2943,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 270, + "x": 360, + "y": 300, "w": 40, "h": 30 } @@ -2502,8 +2964,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 270, + "x": 400, + "y": 300, "w": 40, "h": 30 } @@ -2523,8 +2985,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 270, + "x": 440, + "y": 300, "w": 40, "h": 30 } @@ -2544,8 +3006,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 270, + "x": 480, + "y": 300, "w": 40, "h": 30 } @@ -2565,8 +3027,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 270, + "x": 0, + "y": 330, "w": 40, "h": 30 } @@ -2586,8 +3048,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 270, + "x": 40, + "y": 330, "w": 40, "h": 30 } @@ -2607,8 +3069,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 270, + "x": 80, + "y": 330, "w": 40, "h": 30 } @@ -2628,8 +3090,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 270, + "x": 120, + "y": 330, "w": 40, "h": 30 } @@ -2649,8 +3111,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 270, + "x": 160, + "y": 330, "w": 40, "h": 30 } @@ -2670,8 +3132,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 270, + "x": 200, + "y": 330, "w": 40, "h": 30 } @@ -2691,8 +3153,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 270, + "x": 240, + "y": 330, "w": 40, "h": 30 } @@ -2712,8 +3174,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 270, + "x": 280, + "y": 330, "w": 40, "h": 30 } @@ -2733,8 +3195,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 270, + "x": 320, + "y": 330, "w": 40, "h": 30 } @@ -2754,8 +3216,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 300, + "x": 360, + "y": 330, "w": 40, "h": 30 } @@ -2775,8 +3237,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 300, + "x": 400, + "y": 330, "w": 40, "h": 30 } @@ -2796,8 +3258,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 300, + "x": 440, + "y": 330, "w": 40, "h": 30 } @@ -2817,8 +3279,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 300, + "x": 480, + "y": 330, "w": 40, "h": 30 } @@ -2838,8 +3300,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 300, + "x": 0, + "y": 360, "w": 40, "h": 30 } @@ -2859,8 +3321,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 300, + "x": 40, + "y": 360, "w": 40, "h": 30 } @@ -2880,8 +3342,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 300, + "x": 80, + "y": 360, "w": 40, "h": 30 } @@ -2901,8 +3363,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 300, + "x": 120, + "y": 360, "w": 40, "h": 30 } @@ -2922,8 +3384,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 300, + "x": 160, + "y": 360, "w": 40, "h": 30 } @@ -2943,8 +3405,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 300, + "x": 200, + "y": 360, "w": 40, "h": 30 } @@ -2964,8 +3426,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 300, + "x": 240, + "y": 360, "w": 40, "h": 30 } @@ -2985,8 +3447,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 300, + "x": 280, + "y": 360, "w": 40, "h": 30 } @@ -3006,8 +3468,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 300, + "x": 320, + "y": 360, "w": 40, "h": 30 } @@ -3027,8 +3489,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 330, + "x": 360, + "y": 360, "w": 40, "h": 30 } @@ -3048,8 +3510,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 330, + "x": 400, + "y": 360, "w": 40, "h": 30 } @@ -3069,8 +3531,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 330, + "x": 440, + "y": 360, "w": 40, "h": 30 } @@ -3090,8 +3552,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 330, + "x": 480, + "y": 360, "w": 40, "h": 30 } @@ -3111,8 +3573,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 330, + "x": 0, + "y": 390, "w": 40, "h": 30 } @@ -3132,8 +3594,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 330, + "x": 40, + "y": 390, "w": 40, "h": 30 } @@ -3153,8 +3615,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 330, + "x": 80, + "y": 390, "w": 40, "h": 30 } @@ -3174,8 +3636,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 330, + "x": 120, + "y": 390, "w": 40, "h": 30 } @@ -3195,8 +3657,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 330, + "x": 160, + "y": 390, "w": 40, "h": 30 } @@ -3216,8 +3678,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 330, + "x": 200, + "y": 390, "w": 40, "h": 30 } @@ -3237,8 +3699,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 330, + "x": 240, + "y": 390, "w": 40, "h": 30 } @@ -3258,8 +3720,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 330, + "x": 280, + "y": 390, "w": 40, "h": 30 } @@ -3279,8 +3741,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 330, + "x": 320, + "y": 390, "w": 40, "h": 30 } @@ -3300,8 +3762,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 360, + "x": 360, + "y": 390, "w": 40, "h": 30 } @@ -3321,8 +3783,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 360, + "x": 400, + "y": 390, "w": 40, "h": 30 } @@ -3342,8 +3804,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 360, + "x": 440, + "y": 390, "w": 40, "h": 30 } @@ -3363,8 +3825,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 360, + "x": 480, + "y": 390, "w": 40, "h": 30 } @@ -3384,8 +3846,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 360, + "x": 0, + "y": 420, "w": 40, "h": 30 } @@ -3405,8 +3867,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 360, + "x": 40, + "y": 420, "w": 40, "h": 30 } @@ -3426,8 +3888,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 360, + "x": 80, + "y": 420, "w": 40, "h": 30 } @@ -3447,8 +3909,50 @@ "h": 30 }, "frame": { - "x": 280, - "y": 360, + "x": 120, + "y": 420, + "w": 40, + "h": 30 + } + }, + { + "filename": "476_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 420, + "w": 40, + "h": 30 + } + }, + { + "filename": "476_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 420, "w": 40, "h": 30 } @@ -3468,8 +3972,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 360, + "x": 240, + "y": 420, "w": 40, "h": 30 } @@ -3489,8 +3993,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 360, + "x": 280, + "y": 420, "w": 40, "h": 30 } @@ -3510,8 +4014,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 360, + "x": 320, + "y": 420, "w": 40, "h": 30 } @@ -3531,8 +4035,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 360, + "x": 360, + "y": 420, "w": 40, "h": 30 } @@ -3552,8 +4056,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 360, + "x": 400, + "y": 420, "w": 40, "h": 30 } @@ -3573,8 +4077,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 390, + "x": 440, + "y": 420, "w": 40, "h": 30 } @@ -3594,8 +4098,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 390, + "x": 480, + "y": 420, "w": 40, "h": 30 } @@ -3615,8 +4119,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 390, + "x": 0, + "y": 450, "w": 40, "h": 30 } @@ -3636,8 +4140,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 390, + "x": 40, + "y": 450, "w": 40, "h": 30 } @@ -3657,8 +4161,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 390, + "x": 80, + "y": 450, "w": 40, "h": 30 } @@ -3678,8 +4182,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 390, + "x": 120, + "y": 450, "w": 40, "h": 30 } @@ -3699,8 +4203,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 390, + "x": 160, + "y": 450, "w": 40, "h": 30 } @@ -3720,8 +4224,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 390, + "x": 200, + "y": 450, "w": 40, "h": 30 } @@ -3741,8 +4245,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 390, + "x": 240, + "y": 450, "w": 40, "h": 30 } @@ -3762,8 +4266,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 390, + "x": 280, + "y": 450, "w": 40, "h": 30 } @@ -3783,8 +4287,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 390, + "x": 320, + "y": 450, "w": 40, "h": 30 } @@ -3804,8 +4308,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 390, + "x": 360, + "y": 450, "w": 40, "h": 30 } @@ -3825,8 +4329,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 390, + "x": 400, + "y": 450, "w": 40, "h": 30 } @@ -3846,8 +4350,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 420, + "x": 440, + "y": 450, "w": 40, "h": 30 } @@ -3867,8 +4371,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 420, + "x": 480, + "y": 450, "w": 40, "h": 30 } @@ -3888,8 +4392,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 420, + "x": 0, + "y": 480, "w": 40, "h": 30 } @@ -3909,8 +4413,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 420, + "x": 40, + "y": 480, "w": 40, "h": 30 } @@ -3930,8 +4434,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 420, + "x": 80, + "y": 480, "w": 40, "h": 30 } @@ -3951,8 +4455,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 420, + "x": 120, + "y": 480, "w": 40, "h": 30 } @@ -3972,8 +4476,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 420, + "x": 160, + "y": 480, "w": 40, "h": 30 } @@ -3993,8 +4497,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 420, + "x": 200, + "y": 480, "w": 40, "h": 30 } @@ -4014,8 +4518,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 420, + "x": 240, + "y": 480, "w": 40, "h": 30 } @@ -4035,8 +4539,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 420, + "x": 280, + "y": 480, "w": 40, "h": 30 } @@ -4056,8 +4560,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 420, + "x": 320, + "y": 480, "w": 40, "h": 30 } @@ -4077,8 +4581,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 420, + "x": 360, + "y": 480, "w": 40, "h": 30 } @@ -4098,8 +4602,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 420, + "x": 400, + "y": 480, "w": 40, "h": 30 } @@ -4119,8 +4623,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 450, + "x": 440, + "y": 480, "w": 40, "h": 30 } @@ -4140,8 +4644,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 450, + "x": 480, + "y": 480, "w": 40, "h": 30 } @@ -4161,8 +4665,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 450, + "x": 0, + "y": 510, "w": 40, "h": 30 } @@ -4182,8 +4686,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 450, + "x": 40, + "y": 510, "w": 40, "h": 30 } @@ -4203,8 +4707,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 450, + "x": 80, + "y": 510, "w": 40, "h": 30 } @@ -4224,8 +4728,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 450, + "x": 120, + "y": 510, "w": 40, "h": 30 } @@ -4245,8 +4749,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 450, + "x": 160, + "y": 510, "w": 40, "h": 30 } @@ -4266,8 +4770,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 450, + "x": 200, + "y": 510, "w": 40, "h": 30 } @@ -4287,8 +4791,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 450, + "x": 240, + "y": 510, "w": 40, "h": 30 } @@ -4308,8 +4812,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 450, + "x": 280, + "y": 510, "w": 40, "h": 30 } @@ -4329,8 +4833,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 450, + "x": 320, + "y": 510, "w": 40, "h": 30 } @@ -4350,8 +4854,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 450, + "x": 360, + "y": 510, "w": 40, "h": 30 } @@ -4371,8 +4875,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 450, + "x": 400, + "y": 510, "w": 40, "h": 30 } @@ -4392,8 +4896,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 480, + "x": 440, + "y": 510, "w": 40, "h": 30 } @@ -4404,6 +4908,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2288ca6bd49f36a5ca5b49f1bcaab17a:e83f40529aad7883718910695eafd075:ebc3f8ec5b2480b298192d752b6e57dc$" + "smartupdate": "$TexturePacker:SmartUpdate:00a4e5499c11f3abdf9f56423bbf4561:6f365ccd1246c9b5ae27e0e440695926:ebc3f8ec5b2480b298192d752b6e57dc$" } } diff --git a/public/images/pokemon_icons_4v.png b/public/images/pokemon_icons_4v.png index 7cfab80312a..972bff8b777 100644 Binary files a/public/images/pokemon_icons_4v.png and b/public/images/pokemon_icons_4v.png differ diff --git a/public/images/pokemon_icons_5v.json b/public/images/pokemon_icons_5v.json index 7da5a765c0c..d793ed1b650 100644 --- a/public/images/pokemon_icons_5v.json +++ b/public/images/pokemon_icons_5v.json @@ -4,8 +4,8 @@ "image": "pokemon_icons_5v.png", "format": "RGBA8888", "size": { - "w": 520, - "h": 520 + "w": 570, + "h": 570 }, "scale": 1, "frames": [ @@ -178,7 +178,7 @@ } }, { - "filename": "501_2", + "filename": "498_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -198,6 +198,132 @@ "h": 30 } }, + { + "filename": "498_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 0, + "w": 40, + "h": 30 + } + }, + { + "filename": "499_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 0, + "w": 40, + "h": 30 + } + }, + { + "filename": "499_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 0, + "w": 40, + "h": 30 + } + }, + { + "filename": "500_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 0, + "w": 40, + "h": 30 + } + }, + { + "filename": "500_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 0, + "w": 40, + "h": 30 + } + }, + { + "filename": "501_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 30, + "w": 40, + "h": 30 + } + }, { "filename": "501_3", "rotated": false, @@ -213,8 +339,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 0, + "x": 40, + "y": 30, "w": 40, "h": 30 } @@ -234,8 +360,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 0, + "x": 80, + "y": 30, "w": 40, "h": 30 } @@ -255,8 +381,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 0, + "x": 120, + "y": 30, "w": 40, "h": 30 } @@ -276,8 +402,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 0, + "x": 160, + "y": 30, "w": 40, "h": 30 } @@ -297,12 +423,264 @@ "h": 30 }, "frame": { - "x": 0, + "x": 200, "y": 30, "w": 40, "h": 30 } }, + { + "filename": "511_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "511_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "512_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "512_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "513_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "513_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "514_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "514_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "515_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "515_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "516_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "516_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 60, + "w": 40, + "h": 30 + } + }, { "filename": "517_2", "rotated": false, @@ -318,8 +696,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 30, + "x": 160, + "y": 60, "w": 40, "h": 30 } @@ -339,8 +717,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 30, + "x": 200, + "y": 60, "w": 40, "h": 30 } @@ -360,8 +738,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 30, + "x": 240, + "y": 60, "w": 40, "h": 30 } @@ -381,8 +759,92 @@ "h": 30 }, "frame": { - "x": 160, - "y": 30, + "x": 280, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "522_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "522_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "523_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "523_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 60, "w": 40, "h": 30 } @@ -402,8 +864,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 30, + "x": 480, + "y": 60, "w": 40, "h": 30 } @@ -423,8 +885,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 30, + "x": 520, + "y": 60, "w": 40, "h": 30 } @@ -444,8 +906,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 30, + "x": 0, + "y": 90, "w": 40, "h": 30 } @@ -465,8 +927,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 30, + "x": 40, + "y": 90, "w": 40, "h": 30 } @@ -486,8 +948,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 30, + "x": 80, + "y": 90, "w": 40, "h": 30 } @@ -507,8 +969,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 30, + "x": 120, + "y": 90, "w": 40, "h": 30 } @@ -528,8 +990,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 30, + "x": 160, + "y": 90, "w": 40, "h": 30 } @@ -549,8 +1011,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 30, + "x": 200, + "y": 90, "w": 40, "h": 30 } @@ -570,8 +1032,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 60, + "x": 240, + "y": 90, "w": 40, "h": 30 } @@ -591,8 +1053,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 60, + "x": 280, + "y": 90, "w": 40, "h": 30 } @@ -612,8 +1074,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 60, + "x": 320, + "y": 90, "w": 40, "h": 30 } @@ -633,8 +1095,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 60, + "x": 360, + "y": 90, "w": 40, "h": 30 } @@ -654,8 +1116,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 60, + "x": 400, + "y": 90, "w": 40, "h": 30 } @@ -675,8 +1137,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 60, + "x": 440, + "y": 90, "w": 40, "h": 30 } @@ -696,8 +1158,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 60, + "x": 480, + "y": 90, "w": 40, "h": 30 } @@ -717,8 +1179,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 60, + "x": 520, + "y": 90, "w": 40, "h": 30 } @@ -738,8 +1200,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 60, + "x": 0, + "y": 120, "w": 40, "h": 30 } @@ -759,8 +1221,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 60, + "x": 40, + "y": 120, "w": 40, "h": 30 } @@ -780,8 +1242,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 60, + "x": 80, + "y": 120, "w": 40, "h": 30 } @@ -801,8 +1263,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 60, + "x": 120, + "y": 120, "w": 40, "h": 30 } @@ -822,8 +1284,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 60, + "x": 160, + "y": 120, "w": 40, "h": 30 } @@ -843,8 +1305,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 90, + "x": 200, + "y": 120, "w": 40, "h": 30 } @@ -864,8 +1326,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 90, + "x": 240, + "y": 120, "w": 40, "h": 30 } @@ -885,8 +1347,134 @@ "h": 30 }, "frame": { - "x": 80, - "y": 90, + "x": 280, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "535_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "535_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "536_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "536_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "537_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 120, + "w": 40, + "h": 30 + } + }, + { + "filename": "537_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 520, + "y": 120, "w": 40, "h": 30 } @@ -906,8 +1494,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 90, + "x": 0, + "y": 150, "w": 40, "h": 30 } @@ -927,8 +1515,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 90, + "x": 40, + "y": 150, "w": 40, "h": 30 } @@ -948,8 +1536,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 90, + "x": 80, + "y": 150, "w": 40, "h": 30 } @@ -969,8 +1557,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 90, + "x": 120, + "y": 150, "w": 40, "h": 30 } @@ -990,8 +1578,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 90, + "x": 160, + "y": 150, "w": 40, "h": 30 } @@ -1011,8 +1599,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 90, + "x": 200, + "y": 150, "w": 40, "h": 30 } @@ -1032,8 +1620,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 90, + "x": 240, + "y": 150, "w": 40, "h": 30 } @@ -1053,8 +1641,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 90, + "x": 280, + "y": 150, "w": 40, "h": 30 } @@ -1074,8 +1662,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 90, + "x": 320, + "y": 150, "w": 40, "h": 30 } @@ -1095,8 +1683,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 90, + "x": 360, + "y": 150, "w": 40, "h": 30 } @@ -1116,8 +1704,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 120, + "x": 400, + "y": 150, "w": 40, "h": 30 } @@ -1137,8 +1725,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 120, + "x": 440, + "y": 150, "w": 40, "h": 30 } @@ -1158,8 +1746,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 120, + "x": 480, + "y": 150, "w": 40, "h": 30 } @@ -1179,8 +1767,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 120, + "x": 520, + "y": 150, "w": 40, "h": 30 } @@ -1200,8 +1788,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 120, + "x": 0, + "y": 180, "w": 40, "h": 30 } @@ -1221,8 +1809,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 120, + "x": 40, + "y": 180, "w": 40, "h": 30 } @@ -1242,8 +1830,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 120, + "x": 80, + "y": 180, "w": 40, "h": 30 } @@ -1263,8 +1851,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 120, + "x": 120, + "y": 180, "w": 40, "h": 30 } @@ -1284,8 +1872,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 120, + "x": 160, + "y": 180, "w": 40, "h": 30 } @@ -1305,8 +1893,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 120, + "x": 200, + "y": 180, "w": 40, "h": 30 } @@ -1326,8 +1914,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 120, + "x": 240, + "y": 180, "w": 40, "h": 30 } @@ -1347,8 +1935,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 120, + "x": 280, + "y": 180, "w": 40, "h": 30 } @@ -1368,8 +1956,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 120, + "x": 320, + "y": 180, "w": 40, "h": 30 } @@ -1389,8 +1977,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 150, + "x": 360, + "y": 180, "w": 40, "h": 30 } @@ -1410,8 +1998,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 150, + "x": 400, + "y": 180, "w": 40, "h": 30 } @@ -1431,8 +2019,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 150, + "x": 440, + "y": 180, "w": 40, "h": 30 } @@ -1452,8 +2040,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 150, + "x": 480, + "y": 180, "w": 40, "h": 30 } @@ -1473,8 +2061,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 150, + "x": 520, + "y": 180, "w": 40, "h": 30 } @@ -1494,8 +2082,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 150, + "x": 0, + "y": 210, "w": 40, "h": 30 } @@ -1515,8 +2103,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 150, + "x": 40, + "y": 210, "w": 40, "h": 30 } @@ -1535,9 +2123,135 @@ "w": 40, "h": 30 }, + "frame": { + "x": 80, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "554_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "554_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "555-zen_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "555-zen_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "555_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, "frame": { "x": 280, - "y": 150, + "y": 210, + "w": 40, + "h": 30 + } + }, + { + "filename": "555_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 210, "w": 40, "h": 30 } @@ -1557,8 +2271,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 150, + "x": 360, + "y": 210, "w": 40, "h": 30 } @@ -1578,8 +2292,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 150, + "x": 400, + "y": 210, "w": 40, "h": 30 } @@ -1599,8 +2313,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 150, + "x": 440, + "y": 210, "w": 40, "h": 30 } @@ -1620,8 +2334,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 150, + "x": 480, + "y": 210, "w": 40, "h": 30 } @@ -1641,8 +2355,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 150, + "x": 520, + "y": 210, "w": 40, "h": 30 } @@ -1663,7 +2377,7 @@ }, "frame": { "x": 0, - "y": 180, + "y": 240, "w": 40, "h": 30 } @@ -1684,7 +2398,7 @@ }, "frame": { "x": 40, - "y": 180, + "y": 240, "w": 40, "h": 30 } @@ -1705,7 +2419,7 @@ }, "frame": { "x": 80, - "y": 180, + "y": 240, "w": 40, "h": 30 } @@ -1726,7 +2440,7 @@ }, "frame": { "x": 120, - "y": 180, + "y": 240, "w": 40, "h": 30 } @@ -1747,7 +2461,7 @@ }, "frame": { "x": 160, - "y": 180, + "y": 240, "w": 40, "h": 30 } @@ -1768,7 +2482,7 @@ }, "frame": { "x": 200, - "y": 180, + "y": 240, "w": 40, "h": 30 } @@ -1789,7 +2503,91 @@ }, "frame": { "x": 240, - "y": 180, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "566_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "566_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "567_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "567_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 240, "w": 40, "h": 30 } @@ -1809,8 +2607,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 180, + "x": 440, + "y": 240, "w": 40, "h": 30 } @@ -1830,8 +2628,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 180, + "x": 480, + "y": 240, "w": 40, "h": 30 } @@ -1851,8 +2649,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 180, + "x": 520, + "y": 240, "w": 40, "h": 30 } @@ -1872,8 +2670,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 180, + "x": 0, + "y": 270, "w": 40, "h": 30 } @@ -1893,8 +2691,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 180, + "x": 40, + "y": 270, "w": 40, "h": 30 } @@ -1914,8 +2712,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 180, + "x": 80, + "y": 270, "w": 40, "h": 30 } @@ -1935,8 +2733,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 210, + "x": 120, + "y": 270, "w": 40, "h": 30 } @@ -1956,8 +2754,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 210, + "x": 160, + "y": 270, "w": 40, "h": 30 } @@ -1977,8 +2775,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 210, + "x": 200, + "y": 270, "w": 40, "h": 30 } @@ -1998,8 +2796,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 210, + "x": 240, + "y": 270, "w": 40, "h": 30 } @@ -2019,8 +2817,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 210, + "x": 280, + "y": 270, "w": 40, "h": 30 } @@ -2040,8 +2838,50 @@ "h": 30 }, "frame": { - "x": 200, - "y": 210, + "x": 320, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "573_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "573_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 270, "w": 40, "h": 30 } @@ -2061,8 +2901,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 210, + "x": 440, + "y": 270, "w": 40, "h": 30 } @@ -2082,8 +2922,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 210, + "x": 480, + "y": 270, "w": 40, "h": 30 } @@ -2103,8 +2943,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 210, + "x": 520, + "y": 270, "w": 40, "h": 30 } @@ -2124,8 +2964,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 210, + "x": 0, + "y": 300, "w": 40, "h": 30 } @@ -2145,8 +2985,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 210, + "x": 40, + "y": 300, "w": 40, "h": 30 } @@ -2166,8 +3006,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 210, + "x": 80, + "y": 300, "w": 40, "h": 30 } @@ -2187,8 +3027,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 210, + "x": 120, + "y": 300, "w": 40, "h": 30 } @@ -2208,8 +3048,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 240, + "x": 160, + "y": 300, "w": 40, "h": 30 } @@ -2229,8 +3069,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 240, + "x": 200, + "y": 300, "w": 40, "h": 30 } @@ -2250,8 +3090,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 240, + "x": 240, + "y": 300, "w": 40, "h": 30 } @@ -2271,8 +3111,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 240, + "x": 280, + "y": 300, "w": 40, "h": 30 } @@ -2292,8 +3132,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 240, + "x": 320, + "y": 300, "w": 40, "h": 30 } @@ -2313,8 +3153,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 240, + "x": 360, + "y": 300, "w": 40, "h": 30 } @@ -2334,8 +3174,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 240, + "x": 400, + "y": 300, "w": 40, "h": 30 } @@ -2355,8 +3195,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 240, + "x": 440, + "y": 300, "w": 40, "h": 30 } @@ -2376,8 +3216,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 240, + "x": 480, + "y": 300, "w": 40, "h": 30 } @@ -2397,8 +3237,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 240, + "x": 520, + "y": 300, "w": 40, "h": 30 } @@ -2418,8 +3258,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 240, + "x": 0, + "y": 330, "w": 40, "h": 30 } @@ -2439,8 +3279,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 240, + "x": 40, + "y": 330, "w": 40, "h": 30 } @@ -2460,8 +3300,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 240, + "x": 80, + "y": 330, "w": 40, "h": 30 } @@ -2481,8 +3321,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 270, + "x": 120, + "y": 330, "w": 40, "h": 30 } @@ -2502,8 +3342,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 270, + "x": 160, + "y": 330, "w": 40, "h": 30 } @@ -2523,8 +3363,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 270, + "x": 200, + "y": 330, "w": 40, "h": 30 } @@ -2544,8 +3384,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 270, + "x": 240, + "y": 330, "w": 40, "h": 30 } @@ -2565,8 +3405,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 270, + "x": 280, + "y": 330, "w": 40, "h": 30 } @@ -2586,8 +3426,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 270, + "x": 320, + "y": 330, "w": 40, "h": 30 } @@ -2607,8 +3447,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 270, + "x": 360, + "y": 330, "w": 40, "h": 30 } @@ -2628,8 +3468,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 270, + "x": 400, + "y": 330, "w": 40, "h": 30 } @@ -2649,8 +3489,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 270, + "x": 440, + "y": 330, "w": 40, "h": 30 } @@ -2670,8 +3510,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 270, + "x": 480, + "y": 330, "w": 40, "h": 30 } @@ -2691,8 +3531,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 270, + "x": 520, + "y": 330, "w": 40, "h": 30 } @@ -2712,8 +3552,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 270, + "x": 0, + "y": 360, "w": 40, "h": 30 } @@ -2733,8 +3573,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 270, + "x": 40, + "y": 360, "w": 40, "h": 30 } @@ -2754,8 +3594,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 300, + "x": 80, + "y": 360, "w": 40, "h": 30 } @@ -2775,8 +3615,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 300, + "x": 120, + "y": 360, "w": 40, "h": 30 } @@ -2796,8 +3636,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 300, + "x": 160, + "y": 360, "w": 40, "h": 30 } @@ -2817,8 +3657,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 300, + "x": 200, + "y": 360, "w": 40, "h": 30 } @@ -2838,8 +3678,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 300, + "x": 240, + "y": 360, "w": 40, "h": 30 } @@ -2859,8 +3699,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 300, + "x": 280, + "y": 360, "w": 40, "h": 30 } @@ -2880,8 +3720,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 300, + "x": 320, + "y": 360, "w": 40, "h": 30 } @@ -2901,8 +3741,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 300, + "x": 360, + "y": 360, "w": 40, "h": 30 } @@ -2922,8 +3762,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 300, + "x": 400, + "y": 360, "w": 40, "h": 30 } @@ -2943,8 +3783,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 300, + "x": 440, + "y": 360, "w": 40, "h": 30 } @@ -2964,8 +3804,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 300, + "x": 480, + "y": 360, "w": 40, "h": 30 } @@ -2985,8 +3825,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 300, + "x": 520, + "y": 360, "w": 40, "h": 30 } @@ -3006,8 +3846,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 300, + "x": 0, + "y": 390, "w": 40, "h": 30 } @@ -3027,8 +3867,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 330, + "x": 40, + "y": 390, "w": 40, "h": 30 } @@ -3048,8 +3888,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 330, + "x": 80, + "y": 390, "w": 40, "h": 30 } @@ -3069,8 +3909,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 330, + "x": 120, + "y": 390, "w": 40, "h": 30 } @@ -3090,8 +3930,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 330, + "x": 160, + "y": 390, "w": 40, "h": 30 } @@ -3111,8 +3951,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 330, + "x": 200, + "y": 390, "w": 40, "h": 30 } @@ -3132,8 +3972,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 330, + "x": 240, + "y": 390, "w": 40, "h": 30 } @@ -3153,8 +3993,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 330, + "x": 280, + "y": 390, "w": 40, "h": 30 } @@ -3174,8 +4014,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 330, + "x": 320, + "y": 390, "w": 40, "h": 30 } @@ -3195,8 +4035,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 330, + "x": 360, + "y": 390, "w": 40, "h": 30 } @@ -3216,8 +4056,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 330, + "x": 400, + "y": 390, "w": 40, "h": 30 } @@ -3237,8 +4077,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 330, + "x": 440, + "y": 390, "w": 40, "h": 30 } @@ -3258,8 +4098,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 330, + "x": 480, + "y": 390, "w": 40, "h": 30 } @@ -3279,8 +4119,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 330, + "x": 520, + "y": 390, "w": 40, "h": 30 } @@ -3301,7 +4141,7 @@ }, "frame": { "x": 0, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3322,7 +4162,7 @@ }, "frame": { "x": 40, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3343,7 +4183,7 @@ }, "frame": { "x": 80, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3364,7 +4204,7 @@ }, "frame": { "x": 120, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3385,7 +4225,7 @@ }, "frame": { "x": 160, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3406,7 +4246,7 @@ }, "frame": { "x": 200, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3427,7 +4267,7 @@ }, "frame": { "x": 240, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3448,7 +4288,7 @@ }, "frame": { "x": 280, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3469,7 +4309,7 @@ }, "frame": { "x": 320, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3490,7 +4330,7 @@ }, "frame": { "x": 360, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3511,7 +4351,7 @@ }, "frame": { "x": 400, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3532,7 +4372,7 @@ }, "frame": { "x": 440, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3553,7 +4393,7 @@ }, "frame": { "x": 480, - "y": 360, + "y": 420, "w": 40, "h": 30 } @@ -3573,8 +4413,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 390, + "x": 520, + "y": 420, "w": 40, "h": 30 } @@ -3594,8 +4434,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 390, + "x": 0, + "y": 450, "w": 40, "h": 30 } @@ -3615,8 +4455,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 390, + "x": 40, + "y": 450, "w": 40, "h": 30 } @@ -3636,8 +4476,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 390, + "x": 80, + "y": 450, "w": 40, "h": 30 } @@ -3657,8 +4497,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 390, + "x": 120, + "y": 450, "w": 40, "h": 30 } @@ -3678,8 +4518,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 390, + "x": 160, + "y": 450, "w": 40, "h": 30 } @@ -3699,8 +4539,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 390, + "x": 200, + "y": 450, "w": 40, "h": 30 } @@ -3720,8 +4560,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 390, + "x": 240, + "y": 450, "w": 40, "h": 30 } @@ -3741,8 +4581,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 390, + "x": 280, + "y": 450, "w": 40, "h": 30 } @@ -3762,8 +4602,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 390, + "x": 320, + "y": 450, "w": 40, "h": 30 } @@ -3782,9 +4622,51 @@ "w": 40, "h": 30 }, + "frame": { + "x": 360, + "y": 450, + "w": 40, + "h": 30 + } + }, + { + "filename": "626_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, "frame": { "x": 400, - "y": 390, + "y": 450, + "w": 40, + "h": 30 + } + }, + { + "filename": "626_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 440, + "y": 450, "w": 40, "h": 30 } @@ -3804,8 +4686,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 390, + "x": 480, + "y": 450, "w": 40, "h": 30 } @@ -3825,8 +4707,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 390, + "x": 520, + "y": 450, "w": 40, "h": 30 } @@ -3847,7 +4729,7 @@ }, "frame": { "x": 0, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -3868,7 +4750,7 @@ }, "frame": { "x": 40, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -3889,7 +4771,7 @@ }, "frame": { "x": 80, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -3910,7 +4792,7 @@ }, "frame": { "x": 120, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -3931,7 +4813,7 @@ }, "frame": { "x": 160, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -3952,7 +4834,7 @@ }, "frame": { "x": 200, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -3973,7 +4855,7 @@ }, "frame": { "x": 240, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -3994,7 +4876,7 @@ }, "frame": { "x": 280, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -4015,7 +4897,7 @@ }, "frame": { "x": 320, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -4036,7 +4918,7 @@ }, "frame": { "x": 360, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -4057,7 +4939,7 @@ }, "frame": { "x": 400, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -4078,7 +4960,7 @@ }, "frame": { "x": 440, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -4099,7 +4981,7 @@ }, "frame": { "x": 480, - "y": 420, + "y": 480, "w": 40, "h": 30 } @@ -4119,14 +5001,35 @@ "h": 30 }, "frame": { - "x": 0, - "y": 450, + "x": 520, + "y": 480, "w": 40, "h": 30 } }, { - "filename": "641-incarnate_1", + "filename": "643_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "643_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4141,13 +5044,13 @@ }, "frame": { "x": 40, - "y": 450, + "y": 510, "w": 40, "h": 30 } }, { - "filename": "641-therian_1", + "filename": "644_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4162,13 +5065,13 @@ }, "frame": { "x": 80, - "y": 450, + "y": 510, "w": 40, "h": 30 } }, { - "filename": "642-incarnate_1", + "filename": "644_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4183,13 +5086,13 @@ }, "frame": { "x": 120, - "y": 450, + "y": 510, "w": 40, "h": 30 } }, { - "filename": "642-therian_1", + "filename": "646-black_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4204,13 +5107,13 @@ }, "frame": { "x": 160, - "y": 450, + "y": 510, "w": 40, "h": 30 } }, { - "filename": "645-incarnate_1", + "filename": "646-black_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4225,13 +5128,13 @@ }, "frame": { "x": 200, - "y": 450, + "y": 510, "w": 40, "h": 30 } }, { - "filename": "645-therian_1", + "filename": "646-white_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4246,7 +5149,70 @@ }, "frame": { "x": 240, - "y": 450, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "646-white_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "646_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 510, + "w": 40, + "h": 30 + } + }, + { + "filename": "646_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 510, "w": 40, "h": 30 } @@ -4266,8 +5232,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 450, + "x": 400, + "y": 510, "w": 40, "h": 30 } @@ -4287,8 +5253,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 450, + "x": 440, + "y": 510, "w": 40, "h": 30 } @@ -4308,8 +5274,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 450, + "x": 480, + "y": 510, "w": 40, "h": 30 } @@ -4329,8 +5295,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 450, + "x": 520, + "y": 510, "w": 40, "h": 30 } @@ -4350,8 +5316,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 450, + "x": 0, + "y": 540, "w": 40, "h": 30 } @@ -4371,8 +5337,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 450, + "x": 40, + "y": 540, "w": 40, "h": 30 } @@ -4392,8 +5358,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 480, + "x": 80, + "y": 540, "w": 40, "h": 30 } @@ -4413,8 +5379,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 480, + "x": 120, + "y": 540, "w": 40, "h": 30 } @@ -4434,8 +5400,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 480, + "x": 160, + "y": 540, "w": 40, "h": 30 } @@ -4455,8 +5421,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 480, + "x": 200, + "y": 540, "w": 40, "h": 30 } @@ -4476,8 +5442,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 480, + "x": 240, + "y": 540, "w": 40, "h": 30 } @@ -4497,8 +5463,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 480, + "x": 280, + "y": 540, "w": 40, "h": 30 } @@ -4518,8 +5484,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 480, + "x": 320, + "y": 540, "w": 40, "h": 30 } @@ -4539,8 +5505,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 480, + "x": 360, + "y": 540, "w": 40, "h": 30 } @@ -4560,8 +5526,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 480, + "x": 400, + "y": 540, "w": 40, "h": 30 } @@ -4581,8 +5547,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 480, + "x": 440, + "y": 540, "w": 40, "h": 30 } @@ -4602,8 +5568,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 480, + "x": 480, + "y": 540, "w": 40, "h": 30 } @@ -4623,8 +5589,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 480, + "x": 520, + "y": 540, "w": 40, "h": 30 } @@ -4635,6 +5601,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:b615ea9a62bec26b97d0171030d11a55:35fd8571f91311ef2e9944578f979466:f1931bc28ee7f32dba7543723757cf2a$" + "smartupdate": "$TexturePacker:SmartUpdate:d7ba1fabe0180573c58dd3fb1ea6e279:cbff8ace700a0111c2ee3279d01d11e4:f1931bc28ee7f32dba7543723757cf2a$" } } diff --git a/public/images/pokemon_icons_5v.png b/public/images/pokemon_icons_5v.png index 9dd1b278ac1..ba23de2e3f5 100644 Binary files a/public/images/pokemon_icons_5v.png and b/public/images/pokemon_icons_5v.png differ diff --git a/public/images/pokemon_icons_6v.json b/public/images/pokemon_icons_6v.json index 8061ed9152b..8626eddcc1c 100644 --- a/public/images/pokemon_icons_6v.json +++ b/public/images/pokemon_icons_6v.json @@ -2824,7 +2824,7 @@ } }, { - "filename": "696_2", + "filename": "692_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -2844,6 +2844,90 @@ "h": 30 } }, + { + "filename": "692_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 330, + "w": 40, + "h": 30 + } + }, + { + "filename": "693_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 330, + "w": 40, + "h": 30 + } + }, + { + "filename": "693_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 330, + "w": 40, + "h": 30 + } + }, + { + "filename": "696_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 330, + "w": 40, + "h": 30 + } + }, { "filename": "696_3", "rotated": false, @@ -2859,7 +2943,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 330, "w": 40, "h": 30 @@ -2880,7 +2964,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 330, "w": 40, "h": 30 @@ -2901,7 +2985,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 330, "w": 40, "h": 30 @@ -2922,7 +3006,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 330, "w": 40, "h": 30 @@ -2943,7 +3027,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 440, "y": 330, "w": 40, "h": 30 @@ -2964,8 +3048,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 330, + "x": 0, + "y": 360, "w": 40, "h": 30 } @@ -2985,8 +3069,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 330, + "x": 40, + "y": 360, "w": 40, "h": 30 } @@ -3006,8 +3090,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 330, + "x": 80, + "y": 360, "w": 40, "h": 30 } @@ -3027,8 +3111,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 330, + "x": 120, + "y": 360, "w": 40, "h": 30 } @@ -3048,7 +3132,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 360, "w": 40, "h": 30 @@ -3069,7 +3153,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 360, "w": 40, "h": 30 @@ -3090,7 +3174,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 360, "w": 40, "h": 30 @@ -3111,7 +3195,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 360, "w": 40, "h": 30 @@ -3132,7 +3216,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 360, "w": 40, "h": 30 @@ -3153,7 +3237,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 360, "w": 40, "h": 30 @@ -3174,7 +3258,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 360, "w": 40, "h": 30 @@ -3195,7 +3279,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 440, "y": 360, "w": 40, "h": 30 @@ -3216,8 +3300,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 360, + "x": 0, + "y": 390, "w": 40, "h": 30 } @@ -3237,8 +3321,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 360, + "x": 40, + "y": 390, "w": 40, "h": 30 } @@ -3258,8 +3342,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 360, + "x": 80, + "y": 390, "w": 40, "h": 30 } @@ -3279,8 +3363,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 360, + "x": 120, + "y": 390, "w": 40, "h": 30 } @@ -3300,7 +3384,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 390, "w": 40, "h": 30 @@ -3321,7 +3405,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 390, "w": 40, "h": 30 @@ -3342,7 +3426,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 390, "w": 40, "h": 30 @@ -3363,7 +3447,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 390, "w": 40, "h": 30 @@ -3384,7 +3468,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 390, "w": 40, "h": 30 @@ -3405,7 +3489,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 390, "w": 40, "h": 30 @@ -3426,7 +3510,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 390, "w": 40, "h": 30 @@ -3447,7 +3531,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 440, "y": 390, "w": 40, "h": 30 @@ -3468,8 +3552,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 390, + "x": 0, + "y": 420, "w": 40, "h": 30 } @@ -3489,8 +3573,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 390, + "x": 40, + "y": 420, "w": 40, "h": 30 } @@ -3510,8 +3594,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 390, + "x": 80, + "y": 420, "w": 40, "h": 30 } @@ -3531,8 +3615,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 390, + "x": 120, + "y": 420, "w": 40, "h": 30 } @@ -3552,7 +3636,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 420, "w": 40, "h": 30 @@ -3573,7 +3657,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 420, "w": 40, "h": 30 @@ -3594,7 +3678,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 420, "w": 40, "h": 30 @@ -3615,7 +3699,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 420, "w": 40, "h": 30 @@ -3636,7 +3720,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 420, "w": 40, "h": 30 @@ -3657,7 +3741,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 420, "w": 40, "h": 30 @@ -3678,7 +3762,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 420, "w": 40, "h": 30 @@ -3699,7 +3783,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 440, "y": 420, "w": 40, "h": 30 @@ -3719,90 +3803,6 @@ "w": 40, "h": 30 }, - "frame": { - "x": 320, - "y": 420, - "w": 40, - "h": 30 - } - }, - { - "filename": "720-unbound_1", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 360, - "y": 420, - "w": 40, - "h": 30 - } - }, - { - "filename": "720-unbound_2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 400, - "y": 420, - "w": 40, - "h": 30 - } - }, - { - "filename": "720-unbound_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, - "frame": { - "x": 440, - "y": 420, - "w": 40, - "h": 30 - } - }, - { - "filename": "720_1", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, "frame": { "x": 0, "y": 450, @@ -3811,7 +3811,7 @@ } }, { - "filename": "720_2", + "filename": "720-unbound_1", "rotated": false, "trimmed": false, "sourceSize": { @@ -3832,7 +3832,7 @@ } }, { - "filename": "720_3", + "filename": "720-unbound_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3853,7 +3853,7 @@ } }, { - "filename": "2670_2", + "filename": "720-unbound_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3874,7 +3874,7 @@ } }, { - "filename": "2670_3", + "filename": "720_1", "rotated": false, "trimmed": false, "sourceSize": { @@ -3893,6 +3893,90 @@ "w": 40, "h": 30 } + }, + { + "filename": "720_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 450, + "w": 40, + "h": 30 + } + }, + { + "filename": "720_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 450, + "w": 40, + "h": 30 + } + }, + { + "filename": "2670_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 450, + "w": 40, + "h": 30 + } + }, + { + "filename": "2670_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 450, + "w": 40, + "h": 30 + } } ] } @@ -3900,6 +3984,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:41960148e7a74c451d8ed1c46adc4e09:5dc2b45aa8a432e966da6c4070905be6:8a74f769af240f74b0e67390bbb36c14$" + "smartupdate": "$TexturePacker:SmartUpdate:5779627583192c7b11ac7da6a39690da:ad2bf1b939fe025e3f14c49511ccf058:8a74f769af240f74b0e67390bbb36c14$" } } diff --git a/public/images/pokemon_icons_6v.png b/public/images/pokemon_icons_6v.png index 29d00876b50..d8bd10eaa71 100644 Binary files a/public/images/pokemon_icons_6v.png and b/public/images/pokemon_icons_6v.png differ diff --git a/public/images/pokemon_icons_7v.json b/public/images/pokemon_icons_7v.json index 30e12ce3bb4..6a353fffe94 100644 --- a/public/images/pokemon_icons_7v.json +++ b/public/images/pokemon_icons_7v.json @@ -4,8 +4,8 @@ "image": "pokemon_icons_7v.png", "format": "RGBA8888", "size": { - "w": 440, - "h": 440 + "w": 450, + "h": 450 }, "scale": 1, "frames": [ @@ -304,7 +304,7 @@ } }, { - "filename": "747_2", + "filename": "746-school_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -324,6 +324,90 @@ "h": 30 } }, + { + "filename": "746-school_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "746_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "746_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "747_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 30, + "w": 40, + "h": 30 + } + }, { "filename": "747_3", "rotated": false, @@ -339,7 +423,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 30, "w": 40, "h": 30 @@ -360,7 +444,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 30, "w": 40, "h": 30 @@ -381,7 +465,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 30, "w": 40, "h": 30 @@ -402,8 +486,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 30, + "x": 0, + "y": 60, "w": 40, "h": 30 } @@ -423,8 +507,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 30, + "x": 40, + "y": 60, "w": 40, "h": 30 } @@ -444,8 +528,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 30, + "x": 80, + "y": 60, "w": 40, "h": 30 } @@ -465,8 +549,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 30, + "x": 120, + "y": 60, "w": 40, "h": 30 } @@ -486,7 +570,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 60, "w": 40, "h": 30 @@ -507,7 +591,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 60, "w": 40, "h": 30 @@ -528,7 +612,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 60, "w": 40, "h": 30 @@ -549,7 +633,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 60, "w": 40, "h": 30 @@ -570,7 +654,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 60, "w": 40, "h": 30 @@ -591,7 +675,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 60, "w": 40, "h": 30 @@ -612,7 +696,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 60, "w": 40, "h": 30 @@ -633,8 +717,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 60, + "x": 0, + "y": 90, "w": 40, "h": 30 } @@ -654,8 +738,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 60, + "x": 40, + "y": 90, "w": 40, "h": 30 } @@ -675,8 +759,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 60, + "x": 80, + "y": 90, "w": 40, "h": 30 } @@ -696,8 +780,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 60, + "x": 120, + "y": 90, "w": 40, "h": 30 } @@ -717,7 +801,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 90, "w": 40, "h": 30 @@ -738,7 +822,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 90, "w": 40, "h": 30 @@ -759,7 +843,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 90, "w": 40, "h": 30 @@ -780,7 +864,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 90, "w": 40, "h": 30 @@ -801,7 +885,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 90, "w": 40, "h": 30 @@ -822,7 +906,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 90, "w": 40, "h": 30 @@ -843,7 +927,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 90, "w": 40, "h": 30 @@ -864,8 +948,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 90, + "x": 0, + "y": 120, "w": 40, "h": 30 } @@ -885,8 +969,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 90, + "x": 40, + "y": 120, "w": 40, "h": 30 } @@ -906,8 +990,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 90, + "x": 80, + "y": 120, "w": 40, "h": 30 } @@ -927,8 +1011,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 90, + "x": 120, + "y": 120, "w": 40, "h": 30 } @@ -948,7 +1032,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 120, "w": 40, "h": 30 @@ -969,7 +1053,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 120, "w": 40, "h": 30 @@ -990,7 +1074,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 120, "w": 40, "h": 30 @@ -1011,7 +1095,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 120, "w": 40, "h": 30 @@ -1032,7 +1116,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 120, "w": 40, "h": 30 @@ -1053,7 +1137,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 120, "w": 40, "h": 30 @@ -1074,7 +1158,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 120, "w": 40, "h": 30 @@ -1095,8 +1179,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 120, + "x": 0, + "y": 150, "w": 40, "h": 30 } @@ -1116,8 +1200,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 120, + "x": 40, + "y": 150, "w": 40, "h": 30 } @@ -1137,8 +1221,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 120, + "x": 80, + "y": 150, "w": 40, "h": 30 } @@ -1158,8 +1242,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 120, + "x": 120, + "y": 150, "w": 40, "h": 30 } @@ -1179,7 +1263,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 150, "w": 40, "h": 30 @@ -1200,7 +1284,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 150, "w": 40, "h": 30 @@ -1221,7 +1305,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 150, "w": 40, "h": 30 @@ -1242,7 +1326,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 150, "w": 40, "h": 30 @@ -1263,7 +1347,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 150, "w": 40, "h": 30 @@ -1284,7 +1368,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 150, "w": 40, "h": 30 @@ -1305,7 +1389,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 150, "w": 40, "h": 30 @@ -1326,8 +1410,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 150, + "x": 0, + "y": 180, "w": 40, "h": 30 } @@ -1347,8 +1431,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 150, + "x": 40, + "y": 180, "w": 40, "h": 30 } @@ -1368,8 +1452,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 150, + "x": 80, + "y": 180, "w": 40, "h": 30 } @@ -1389,8 +1473,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 150, + "x": 120, + "y": 180, "w": 40, "h": 30 } @@ -1410,7 +1494,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 180, "w": 40, "h": 30 @@ -1431,7 +1515,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 180, "w": 40, "h": 30 @@ -1452,7 +1536,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 180, "w": 40, "h": 30 @@ -1473,7 +1557,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 180, "w": 40, "h": 30 @@ -1494,7 +1578,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 180, "w": 40, "h": 30 @@ -1515,7 +1599,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 180, "w": 40, "h": 30 @@ -1536,7 +1620,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 180, "w": 40, "h": 30 @@ -1557,8 +1641,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 180, + "x": 0, + "y": 210, "w": 40, "h": 30 } @@ -1578,8 +1662,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 180, + "x": 40, + "y": 210, "w": 40, "h": 30 } @@ -1599,8 +1683,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 180, + "x": 80, + "y": 210, "w": 40, "h": 30 } @@ -1620,8 +1704,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 180, + "x": 120, + "y": 210, "w": 40, "h": 30 } @@ -1641,7 +1725,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 210, "w": 40, "h": 30 @@ -1662,7 +1746,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 210, "w": 40, "h": 30 @@ -1683,7 +1767,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 210, "w": 40, "h": 30 @@ -1704,7 +1788,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 210, "w": 40, "h": 30 @@ -1725,7 +1809,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 210, "w": 40, "h": 30 @@ -1746,7 +1830,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 210, "w": 40, "h": 30 @@ -1767,7 +1851,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 210, "w": 40, "h": 30 @@ -1788,8 +1872,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 210, + "x": 0, + "y": 240, "w": 40, "h": 30 } @@ -1809,8 +1893,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 210, + "x": 40, + "y": 240, "w": 40, "h": 30 } @@ -1830,8 +1914,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 210, + "x": 80, + "y": 240, "w": 40, "h": 30 } @@ -1851,8 +1935,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 210, + "x": 120, + "y": 240, "w": 40, "h": 30 } @@ -1872,7 +1956,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 240, "w": 40, "h": 30 @@ -1893,12 +1977,180 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 240, "w": 40, "h": 30 } }, + { + "filename": "780_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "780_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "782_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 320, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "782_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 360, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "783_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 400, + "y": 240, + "w": 40, + "h": 30 + } + }, + { + "filename": "783_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "784_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 270, + "w": 40, + "h": 30 + } + }, + { + "filename": "784_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 270, + "w": 40, + "h": 30 + } + }, { "filename": "789_1", "rotated": false, @@ -1914,8 +2166,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 240, + "x": 120, + "y": 270, "w": 40, "h": 30 } @@ -1935,8 +2187,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 240, + "x": 160, + "y": 270, "w": 40, "h": 30 } @@ -1956,8 +2208,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 240, + "x": 200, + "y": 270, "w": 40, "h": 30 } @@ -1977,8 +2229,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 240, + "x": 240, + "y": 270, "w": 40, "h": 30 } @@ -1998,8 +2250,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 240, + "x": 280, + "y": 270, "w": 40, "h": 30 } @@ -2019,8 +2271,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 240, + "x": 320, + "y": 270, "w": 40, "h": 30 } @@ -2040,8 +2292,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 240, + "x": 360, + "y": 270, "w": 40, "h": 30 } @@ -2061,8 +2313,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 240, + "x": 400, + "y": 270, "w": 40, "h": 30 } @@ -2082,8 +2334,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 240, + "x": 0, + "y": 300, "w": 40, "h": 30 } @@ -2103,8 +2355,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 270, + "x": 40, + "y": 300, "w": 40, "h": 30 } @@ -2124,8 +2376,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 270, + "x": 80, + "y": 300, "w": 40, "h": 30 } @@ -2145,8 +2397,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 270, + "x": 120, + "y": 300, "w": 40, "h": 30 } @@ -2166,8 +2418,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 270, + "x": 160, + "y": 300, "w": 40, "h": 30 } @@ -2187,8 +2439,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 270, + "x": 200, + "y": 300, "w": 40, "h": 30 } @@ -2208,8 +2460,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 270, + "x": 240, + "y": 300, "w": 40, "h": 30 } @@ -2229,8 +2481,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 270, + "x": 280, + "y": 300, "w": 40, "h": 30 } @@ -2250,8 +2502,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 270, + "x": 320, + "y": 300, "w": 40, "h": 30 } @@ -2271,8 +2523,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 270, + "x": 360, + "y": 300, "w": 40, "h": 30 } @@ -2292,8 +2544,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 270, + "x": 400, + "y": 300, "w": 40, "h": 30 } @@ -2313,8 +2565,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 270, + "x": 0, + "y": 330, "w": 40, "h": 30 } @@ -2334,8 +2586,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 300, + "x": 40, + "y": 330, "w": 40, "h": 30 } @@ -2355,8 +2607,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 300, + "x": 80, + "y": 330, "w": 40, "h": 30 } @@ -2376,8 +2628,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 300, + "x": 120, + "y": 330, "w": 40, "h": 30 } @@ -2397,8 +2649,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 300, + "x": 160, + "y": 330, "w": 40, "h": 30 } @@ -2418,8 +2670,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 300, + "x": 200, + "y": 330, "w": 40, "h": 30 } @@ -2439,8 +2691,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 300, + "x": 240, + "y": 330, "w": 40, "h": 30 } @@ -2460,8 +2712,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 300, + "x": 280, + "y": 330, "w": 40, "h": 30 } @@ -2481,8 +2733,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 300, + "x": 320, + "y": 330, "w": 40, "h": 30 } @@ -2502,8 +2754,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 300, + "x": 360, + "y": 330, "w": 40, "h": 30 } @@ -2523,8 +2775,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 300, + "x": 400, + "y": 330, "w": 40, "h": 30 } @@ -2544,8 +2796,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 300, + "x": 0, + "y": 360, "w": 40, "h": 30 } @@ -2565,8 +2817,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 330, + "x": 40, + "y": 360, "w": 40, "h": 30 } @@ -2586,8 +2838,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 330, + "x": 80, + "y": 360, "w": 40, "h": 30 } @@ -2607,8 +2859,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 330, + "x": 120, + "y": 360, "w": 40, "h": 30 } @@ -2628,8 +2880,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 330, + "x": 160, + "y": 360, "w": 40, "h": 30 } @@ -2649,8 +2901,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 330, + "x": 200, + "y": 360, "w": 40, "h": 30 } @@ -2670,8 +2922,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 330, + "x": 240, + "y": 360, "w": 40, "h": 30 } @@ -2691,8 +2943,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 330, + "x": 280, + "y": 360, "w": 40, "h": 30 } @@ -2712,8 +2964,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 330, + "x": 320, + "y": 360, "w": 40, "h": 30 } @@ -2733,8 +2985,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 330, + "x": 360, + "y": 360, "w": 40, "h": 30 } @@ -2754,8 +3006,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 330, + "x": 400, + "y": 360, "w": 40, "h": 30 } @@ -2775,8 +3027,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 330, + "x": 0, + "y": 390, "w": 40, "h": 30 } @@ -2796,8 +3048,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 360, + "x": 40, + "y": 390, "w": 40, "h": 30 } @@ -2817,8 +3069,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 360, + "x": 80, + "y": 390, "w": 40, "h": 30 } @@ -2838,8 +3090,92 @@ "h": 30 }, "frame": { - "x": 80, - "y": 360, + "x": 120, + "y": 390, + "w": 40, + "h": 30 + } + }, + { + "filename": "2037_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 390, + "w": 40, + "h": 30 + } + }, + { + "filename": "2037_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 390, + "w": 40, + "h": 30 + } + }, + { + "filename": "2038_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 240, + "y": 390, + "w": 40, + "h": 30 + } + }, + { + "filename": "2038_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 280, + "y": 390, "w": 40, "h": 30 } @@ -2859,8 +3195,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 360, + "x": 320, + "y": 390, "w": 40, "h": 30 } @@ -2880,8 +3216,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 360, + "x": 360, + "y": 390, "w": 40, "h": 30 } @@ -2901,8 +3237,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 360, + "x": 400, + "y": 390, "w": 40, "h": 30 } @@ -2922,8 +3258,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 360, + "x": 0, + "y": 420, "w": 40, "h": 30 } @@ -2943,8 +3279,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 360, + "x": 40, + "y": 420, "w": 40, "h": 30 } @@ -2964,8 +3300,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 360, + "x": 80, + "y": 420, "w": 40, "h": 30 } @@ -2976,6 +3312,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:914c9869d6dab145bbbe443bdc3f932c:80b9ecf9647b68af17c07b88e1a1856e:d5975df27e1e94206a68aa1fd3c2c8d0$" + "smartupdate": "$TexturePacker:SmartUpdate:0780b00fda53c3fbd0b6e554e89a6818:b96a0f88bd707a9967af73e7bdf13031:d5975df27e1e94206a68aa1fd3c2c8d0$" } } diff --git a/public/images/pokemon_icons_7v.png b/public/images/pokemon_icons_7v.png index 1f7d6e5f826..12c81de925c 100644 Binary files a/public/images/pokemon_icons_7v.png and b/public/images/pokemon_icons_7v.png differ diff --git a/public/images/pokemon_icons_8v.json b/public/images/pokemon_icons_8v.json index a33f88e9d9b..4b1877878a5 100644 --- a/public/images/pokemon_icons_8v.json +++ b/public/images/pokemon_icons_8v.json @@ -4,8 +4,8 @@ "image": "pokemon_icons_8v.png", "format": "RGBA8888", "size": { - "w": 510, - "h": 510 + "w": 520, + "h": 520 }, "scale": 1, "frames": [ @@ -276,8 +276,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 30, + "x": 480, + "y": 0, "w": 40, "h": 30 } @@ -297,7 +297,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 0, "y": 30, "w": 40, "h": 30 @@ -318,7 +318,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 40, "y": 30, "w": 40, "h": 30 @@ -339,7 +339,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 80, "y": 30, "w": 40, "h": 30 @@ -360,7 +360,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 120, "y": 30, "w": 40, "h": 30 @@ -381,7 +381,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 160, "y": 30, "w": 40, "h": 30 @@ -402,7 +402,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 200, "y": 30, "w": 40, "h": 30 @@ -423,7 +423,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 240, "y": 30, "w": 40, "h": 30 @@ -444,7 +444,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 280, "y": 30, "w": 40, "h": 30 @@ -465,7 +465,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 320, "y": 30, "w": 40, "h": 30 @@ -486,7 +486,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 360, "y": 30, "w": 40, "h": 30 @@ -506,6 +506,27 @@ "w": 40, "h": 30 }, + "frame": { + "x": 400, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "840_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, "frame": { "x": 440, "y": 30, @@ -513,6 +534,195 @@ "h": 30 } }, + { + "filename": "840_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 30, + "w": 40, + "h": 30 + } + }, + { + "filename": "841-gigantamax_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "842-gigantamax_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 0, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "841-gigantamax_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "842-gigantamax_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "841_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "841_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "842_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 60, + "w": 40, + "h": 30 + } + }, + { + "filename": "842_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 60, + "w": 40, + "h": 30 + } + }, { "filename": "850_2", "rotated": false, @@ -528,7 +738,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 240, "y": 60, "w": 40, "h": 30 @@ -549,7 +759,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 280, "y": 60, "w": 40, "h": 30 @@ -570,7 +780,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 320, "y": 60, "w": 40, "h": 30 @@ -591,7 +801,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 360, "y": 60, "w": 40, "h": 30 @@ -612,7 +822,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 400, "y": 60, "w": 40, "h": 30 @@ -633,7 +843,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 440, "y": 60, "w": 40, "h": 30 @@ -654,7 +864,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 480, "y": 60, "w": 40, "h": 30 @@ -675,8 +885,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 60, + "x": 0, + "y": 90, "w": 40, "h": 30 } @@ -696,8 +906,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 60, + "x": 40, + "y": 90, "w": 40, "h": 30 } @@ -717,8 +927,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 60, + "x": 80, + "y": 90, "w": 40, "h": 30 } @@ -738,8 +948,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 60, + "x": 120, + "y": 90, "w": 40, "h": 30 } @@ -759,8 +969,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 60, + "x": 160, + "y": 90, "w": 40, "h": 30 } @@ -780,7 +990,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 200, "y": 90, "w": 40, "h": 30 @@ -801,7 +1011,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 240, "y": 90, "w": 40, "h": 30 @@ -822,7 +1032,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 280, "y": 90, "w": 40, "h": 30 @@ -843,7 +1053,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 320, "y": 90, "w": 40, "h": 30 @@ -864,7 +1074,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 360, "y": 90, "w": 40, "h": 30 @@ -885,7 +1095,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 400, "y": 90, "w": 40, "h": 30 @@ -906,7 +1116,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 440, "y": 90, "w": 40, "h": 30 @@ -927,7 +1137,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 480, "y": 90, "w": 40, "h": 30 @@ -948,8 +1158,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 90, + "x": 0, + "y": 120, "w": 40, "h": 30 } @@ -969,8 +1179,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 90, + "x": 40, + "y": 120, "w": 40, "h": 30 } @@ -990,8 +1200,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 90, + "x": 80, + "y": 120, "w": 40, "h": 30 } @@ -1011,8 +1221,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 90, + "x": 120, + "y": 120, "w": 40, "h": 30 } @@ -1032,7 +1242,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 120, "w": 40, "h": 30 @@ -1053,7 +1263,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 120, "w": 40, "h": 30 @@ -1074,7 +1284,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 120, "w": 40, "h": 30 @@ -1095,7 +1305,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 120, "w": 40, "h": 30 @@ -1116,7 +1326,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 120, "w": 40, "h": 30 @@ -1137,7 +1347,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 120, "w": 40, "h": 30 @@ -1158,7 +1368,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 120, "w": 40, "h": 30 @@ -1179,7 +1389,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 440, "y": 120, "w": 40, "h": 30 @@ -1200,7 +1410,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 480, "y": 120, "w": 40, "h": 30 @@ -1221,8 +1431,50 @@ "h": 30 }, "frame": { - "x": 360, - "y": 120, + "x": 0, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "871_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 40, + "y": 150, + "w": 40, + "h": 30 + } + }, + { + "filename": "871_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 150, "w": 40, "h": 30 } @@ -1242,8 +1494,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 120, + "x": 120, + "y": 150, "w": 40, "h": 30 } @@ -1263,8 +1515,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 120, + "x": 160, + "y": 150, "w": 40, "h": 30 } @@ -1284,7 +1536,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 200, "y": 150, "w": 40, "h": 30 @@ -1305,7 +1557,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 240, "y": 150, "w": 40, "h": 30 @@ -1326,7 +1578,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 280, "y": 150, "w": 40, "h": 30 @@ -1347,7 +1599,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 320, "y": 150, "w": 40, "h": 30 @@ -1368,7 +1620,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 360, "y": 150, "w": 40, "h": 30 @@ -1389,7 +1641,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 400, "y": 150, "w": 40, "h": 30 @@ -1410,7 +1662,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 440, "y": 150, "w": 40, "h": 30 @@ -1431,7 +1683,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 480, "y": 150, "w": 40, "h": 30 @@ -1452,8 +1704,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 150, + "x": 0, + "y": 180, "w": 40, "h": 30 } @@ -1473,8 +1725,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 150, + "x": 40, + "y": 180, "w": 40, "h": 30 } @@ -1494,8 +1746,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 150, + "x": 80, + "y": 180, "w": 40, "h": 30 } @@ -1515,8 +1767,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 150, + "x": 120, + "y": 180, "w": 40, "h": 30 } @@ -1536,7 +1788,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 160, "y": 180, "w": 40, "h": 30 @@ -1557,7 +1809,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 200, "y": 180, "w": 40, "h": 30 @@ -1578,7 +1830,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 240, "y": 180, "w": 40, "h": 30 @@ -1599,7 +1851,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 280, "y": 180, "w": 40, "h": 30 @@ -1620,7 +1872,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 320, "y": 180, "w": 40, "h": 30 @@ -1641,7 +1893,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 360, "y": 180, "w": 40, "h": 30 @@ -1662,7 +1914,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 400, "y": 180, "w": 40, "h": 30 @@ -1683,7 +1935,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 440, "y": 180, "w": 40, "h": 30 @@ -1704,7 +1956,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 480, "y": 180, "w": 40, "h": 30 @@ -1725,8 +1977,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 180, + "x": 0, + "y": 210, "w": 40, "h": 30 } @@ -1746,8 +1998,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 180, + "x": 40, + "y": 210, "w": 40, "h": 30 } @@ -1767,8 +2019,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 180, + "x": 80, + "y": 210, "w": 40, "h": 30 } @@ -1788,7 +2040,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 120, "y": 210, "w": 40, "h": 30 @@ -1809,7 +2061,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 160, "y": 210, "w": 40, "h": 30 @@ -1830,7 +2082,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 200, "y": 210, "w": 40, "h": 30 @@ -1851,7 +2103,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 240, "y": 210, "w": 40, "h": 30 @@ -1872,7 +2124,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 280, "y": 210, "w": 40, "h": 30 @@ -1893,7 +2145,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 320, "y": 210, "w": 40, "h": 30 @@ -1914,7 +2166,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 360, "y": 210, "w": 40, "h": 30 @@ -1935,7 +2187,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 400, "y": 210, "w": 40, "h": 30 @@ -1956,7 +2208,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 440, "y": 210, "w": 40, "h": 30 @@ -1977,7 +2229,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 480, "y": 210, "w": 40, "h": 30 @@ -1998,8 +2250,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 210, + "x": 0, + "y": 240, "w": 40, "h": 30 } @@ -2019,8 +2271,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 210, + "x": 40, + "y": 240, "w": 40, "h": 30 } @@ -2040,7 +2292,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 240, "w": 40, "h": 30 @@ -2061,7 +2313,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 240, "w": 40, "h": 30 @@ -2082,7 +2334,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 240, "w": 40, "h": 30 @@ -2103,7 +2355,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 240, "w": 40, "h": 30 @@ -2124,7 +2376,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 240, "w": 40, "h": 30 @@ -2145,7 +2397,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 240, "w": 40, "h": 30 @@ -2166,7 +2418,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 240, "w": 40, "h": 30 @@ -2187,7 +2439,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 240, "w": 40, "h": 30 @@ -2208,7 +2460,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 240, "w": 40, "h": 30 @@ -2229,7 +2481,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 240, "w": 40, "h": 30 @@ -2250,7 +2502,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 240, "w": 40, "h": 30 @@ -2270,27 +2522,6 @@ "w": 40, "h": 30 }, - "frame": { - "x": 440, - "y": 240, - "w": 40, - "h": 30 - } - }, - { - "filename": "891_2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, "frame": { "x": 0, "y": 270, @@ -2299,7 +2530,7 @@ } }, { - "filename": "891_3", + "filename": "891_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -2320,7 +2551,7 @@ } }, { - "filename": "892-gigantamax-rapid_1", + "filename": "891_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -2341,7 +2572,7 @@ } }, { - "filename": "892-gigantamax-rapid_2", + "filename": "892-gigantamax-rapid_1", "rotated": false, "trimmed": false, "sourceSize": { @@ -2362,7 +2593,7 @@ } }, { - "filename": "892-gigantamax-rapid_3", + "filename": "892-gigantamax-rapid_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -2383,7 +2614,7 @@ } }, { - "filename": "892-gigantamax-single_1", + "filename": "892-gigantamax-rapid_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -2404,7 +2635,7 @@ } }, { - "filename": "892-gigantamax-single_2", + "filename": "892-gigantamax-single_1", "rotated": false, "trimmed": false, "sourceSize": { @@ -2425,7 +2656,7 @@ } }, { - "filename": "892-gigantamax-single_3", + "filename": "892-gigantamax-single_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -2446,7 +2677,7 @@ } }, { - "filename": "892-rapid-strike_1", + "filename": "892-gigantamax-single_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -2467,7 +2698,7 @@ } }, { - "filename": "892-rapid-strike_2", + "filename": "892-rapid-strike_1", "rotated": false, "trimmed": false, "sourceSize": { @@ -2488,7 +2719,7 @@ } }, { - "filename": "892-rapid-strike_3", + "filename": "892-rapid-strike_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -2509,7 +2740,7 @@ } }, { - "filename": "892_1", + "filename": "892-rapid-strike_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -2529,6 +2760,27 @@ "h": 30 } }, + { + "filename": "892_1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 480, + "y": 270, + "w": 40, + "h": 30 + } + }, { "filename": "892_2", "rotated": false, @@ -2796,8 +3048,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 330, + "x": 480, + "y": 300, "w": 40, "h": 30 } @@ -2817,7 +3069,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 0, "y": 330, "w": 40, "h": 30 @@ -2838,7 +3090,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 40, "y": 330, "w": 40, "h": 30 @@ -2859,7 +3111,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 80, "y": 330, "w": 40, "h": 30 @@ -2880,7 +3132,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 120, "y": 330, "w": 40, "h": 30 @@ -2901,7 +3153,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 160, "y": 330, "w": 40, "h": 30 @@ -2922,7 +3174,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 200, "y": 330, "w": 40, "h": 30 @@ -2943,7 +3195,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 240, "y": 330, "w": 40, "h": 30 @@ -2964,7 +3216,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 280, "y": 330, "w": 40, "h": 30 @@ -2985,7 +3237,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 320, "y": 330, "w": 40, "h": 30 @@ -3006,7 +3258,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 360, "y": 330, "w": 40, "h": 30 @@ -3027,7 +3279,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 400, "y": 330, "w": 40, "h": 30 @@ -3048,8 +3300,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 360, + "x": 440, + "y": 330, "w": 40, "h": 30 } @@ -3069,8 +3321,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 360, + "x": 480, + "y": 330, "w": 40, "h": 30 } @@ -3090,7 +3342,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 0, "y": 360, "w": 40, "h": 30 @@ -3111,7 +3363,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 40, "y": 360, "w": 40, "h": 30 @@ -3132,7 +3384,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 80, "y": 360, "w": 40, "h": 30 @@ -3153,7 +3405,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 120, "y": 360, "w": 40, "h": 30 @@ -3174,7 +3426,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 160, "y": 360, "w": 40, "h": 30 @@ -3195,7 +3447,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 200, "y": 360, "w": 40, "h": 30 @@ -3216,7 +3468,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 240, "y": 360, "w": 40, "h": 30 @@ -3237,7 +3489,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 280, "y": 360, "w": 40, "h": 30 @@ -3258,7 +3510,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 320, "y": 360, "w": 40, "h": 30 @@ -3279,7 +3531,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 360, "y": 360, "w": 40, "h": 30 @@ -3300,8 +3552,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 390, + "x": 400, + "y": 360, "w": 40, "h": 30 } @@ -3321,8 +3573,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 390, + "x": 440, + "y": 360, "w": 40, "h": 30 } @@ -3342,8 +3594,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 390, + "x": 480, + "y": 360, "w": 40, "h": 30 } @@ -3363,7 +3615,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 0, "y": 390, "w": 40, "h": 30 @@ -3384,7 +3636,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 40, "y": 390, "w": 40, "h": 30 @@ -3405,7 +3657,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 80, "y": 390, "w": 40, "h": 30 @@ -3426,7 +3678,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 120, "y": 390, "w": 40, "h": 30 @@ -3447,7 +3699,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 160, "y": 390, "w": 40, "h": 30 @@ -3468,7 +3720,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 200, "y": 390, "w": 40, "h": 30 @@ -3489,7 +3741,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 240, "y": 390, "w": 40, "h": 30 @@ -3510,7 +3762,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 280, "y": 390, "w": 40, "h": 30 @@ -3531,7 +3783,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 320, "y": 390, "w": 40, "h": 30 @@ -3552,8 +3804,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 420, + "x": 360, + "y": 390, "w": 40, "h": 30 } @@ -3573,8 +3825,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 420, + "x": 400, + "y": 390, "w": 40, "h": 30 } @@ -3594,8 +3846,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 420, + "x": 440, + "y": 390, "w": 40, "h": 30 } @@ -3615,8 +3867,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 420, + "x": 480, + "y": 390, "w": 40, "h": 30 } @@ -3636,7 +3888,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 0, "y": 420, "w": 40, "h": 30 @@ -3657,7 +3909,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 40, "y": 420, "w": 40, "h": 30 @@ -3678,7 +3930,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 80, "y": 420, "w": 40, "h": 30 @@ -3699,7 +3951,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 120, "y": 420, "w": 40, "h": 30 @@ -3720,7 +3972,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 160, "y": 420, "w": 40, "h": 30 @@ -3741,7 +3993,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 200, "y": 420, "w": 40, "h": 30 @@ -3762,7 +4014,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 240, "y": 420, "w": 40, "h": 30 @@ -3783,7 +4035,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 280, "y": 420, "w": 40, "h": 30 @@ -3804,8 +4056,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 450, + "x": 320, + "y": 420, "w": 40, "h": 30 } @@ -3825,8 +4077,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 450, + "x": 360, + "y": 420, "w": 40, "h": 30 } @@ -3846,8 +4098,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 450, + "x": 400, + "y": 420, "w": 40, "h": 30 } @@ -3867,8 +4119,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 450, + "x": 440, + "y": 420, "w": 40, "h": 30 } @@ -3888,8 +4140,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 450, + "x": 480, + "y": 420, "w": 40, "h": 30 } @@ -3909,7 +4161,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 0, "y": 450, "w": 40, "h": 30 @@ -3930,7 +4182,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 40, "y": 450, "w": 40, "h": 30 @@ -3951,7 +4203,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 80, "y": 450, "w": 40, "h": 30 @@ -3972,7 +4224,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 120, "y": 450, "w": 40, "h": 30 @@ -3993,7 +4245,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 160, "y": 450, "w": 40, "h": 30 @@ -4014,7 +4266,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 200, "y": 450, "w": 40, "h": 30 @@ -4035,7 +4287,7 @@ "h": 30 }, "frame": { - "x": 440, + "x": 240, "y": 450, "w": 40, "h": 30 @@ -4056,8 +4308,8 @@ "h": 30 }, "frame": { - "x": 0, - "y": 480, + "x": 280, + "y": 450, "w": 40, "h": 30 } @@ -4077,8 +4329,8 @@ "h": 30 }, "frame": { - "x": 40, - "y": 480, + "x": 320, + "y": 450, "w": 40, "h": 30 } @@ -4098,8 +4350,8 @@ "h": 30 }, "frame": { - "x": 80, - "y": 480, + "x": 360, + "y": 450, "w": 40, "h": 30 } @@ -4110,6 +4362,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:c6192164d1b1971f54a6c5864e11748d:46b3adcf2a25bfb824db3d24cd1c96a9:ec5f05e7f30cd98f74db0c2326109fd3$" + "smartupdate": "$TexturePacker:SmartUpdate:8408a38565cd946fb1dcfa1e942bfa70:5d4e77c515d77c2e94d454fb7c52d9fc:ec5f05e7f30cd98f74db0c2326109fd3$" } } diff --git a/public/images/pokemon_icons_8v.png b/public/images/pokemon_icons_8v.png index 2af86ac656f..4017b0945d6 100644 Binary files a/public/images/pokemon_icons_8v.png and b/public/images/pokemon_icons_8v.png differ diff --git a/public/images/pokemon_icons_9v.json b/public/images/pokemon_icons_9v.json index 6c8b93208e3..4b7a7ba4572 100644 --- a/public/images/pokemon_icons_9v.json +++ b/public/images/pokemon_icons_9v.json @@ -3013,7 +3013,7 @@ } }, { - "filename": "1012-counterfeit_2", + "filename": "1011_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3034,7 +3034,7 @@ } }, { - "filename": "1012-counterfeit_3", + "filename": "1011_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3055,7 +3055,7 @@ } }, { - "filename": "1013-unremarkable_2", + "filename": "1012-counterfeit_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3076,7 +3076,7 @@ } }, { - "filename": "1013-unremarkable_3", + "filename": "1012-counterfeit_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3097,7 +3097,7 @@ } }, { - "filename": "1018_2", + "filename": "1013-unremarkable_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3118,7 +3118,7 @@ } }, { - "filename": "1018_3", + "filename": "1013-unremarkable_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3139,7 +3139,7 @@ } }, { - "filename": "1022_2", + "filename": "1018_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3160,7 +3160,7 @@ } }, { - "filename": "1022_3", + "filename": "1018_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3181,7 +3181,7 @@ } }, { - "filename": "1023_2", + "filename": "1019_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3202,7 +3202,7 @@ } }, { - "filename": "1023_3", + "filename": "1019_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3223,7 +3223,7 @@ } }, { - "filename": "8901_1", + "filename": "1022_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3244,7 +3244,7 @@ } }, { - "filename": "8901_2", + "filename": "1022_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3265,7 +3265,7 @@ } }, { - "filename": "8901_3", + "filename": "1023_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3284,6 +3284,90 @@ "w": 40, "h": 30 } + }, + { + "filename": "1023_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 80, + "y": 420, + "w": 40, + "h": 30 + } + }, + { + "filename": "8901_1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 120, + "y": 420, + "w": 40, + "h": 30 + } + }, + { + "filename": "8901_2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 160, + "y": 420, + "w": 40, + "h": 30 + } + }, + { + "filename": "8901_3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 40, + "h": 30 + }, + "frame": { + "x": 200, + "y": 420, + "w": 40, + "h": 30 + } } ] } @@ -3291,6 +3375,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:c13ec323095f727665fa953e64e98300:e7531bea9b5e1bef44def5b357c81630:3ec5c0bc286c296cfb7fa30a8b06f3da$" + "smartupdate": "$TexturePacker:SmartUpdate:a78ab8261d4cd63caee19962a0e01d8a:cb77bcbd2cc296577c3f2ba84b4c50f2:3ec5c0bc286c296cfb7fa30a8b06f3da$" } } diff --git a/public/images/pokemon_icons_9v.png b/public/images/pokemon_icons_9v.png index f71b6c5ada5..3636c3059d8 100644 Binary files a/public/images/pokemon_icons_9v.png and b/public/images/pokemon_icons_9v.png differ diff --git a/public/locales b/public/locales index e98f0eb9c20..a7036a07875 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit e98f0eb9c2022bc78b53f0444424c636498e725a +Subproject commit a7036a07875615674ea898d0fe3b182a1080af38 diff --git a/scripts/find_sprite_variant_mismatches.py b/scripts/find_sprite_variant_mismatches.py index 483695fdb66..b26058c2de3 100644 --- a/scripts/find_sprite_variant_mismatches.py +++ b/scripts/find_sprite_variant_mismatches.py @@ -22,6 +22,9 @@ from typing import Literal as L MASTERLIST_PATH = os.path.join( os.path.dirname(os.path.dirname(__file__)), "public", "images", "pokemon", "variant", "_masterlist.json" ) +EXP_MASTERLIST_PATH = os.path.join( + os.path.dirname(os.path.dirname(__file__)), "public", "images", "pokemon", "variant", "_exp_masterlist.json" +) DEFAULT_OUTPUT_PATH = "sprite-mismatches.csv" @@ -93,6 +96,7 @@ if __name__ == "__main__": help=f"The path to a file to save the output file. If not specified, will write to {DEFAULT_OUTPUT_PATH}.", ) p.add_argument("--masterlist", default=MASTERLIST_PATH, help=f"The path to the masterlist file to validate. Defaults to {MASTERLIST_PATH}.") + p.add_argument("--exp-masterlist", default=EXP_MASTERLIST_PATH, help=f"The path to the exp masterlist file to validate against. Defaults to {EXP_MASTERLIST_PATH}.") args = p.parse_args() mismatches = make_mismatch_sprite_list(args.masterlist) write_mismatch_csv(args.output, mismatches) diff --git a/src/@types/SessionSaveMigrator.ts b/src/@types/SessionSaveMigrator.ts new file mode 100644 index 00000000000..c4b0ad8dda4 --- /dev/null +++ b/src/@types/SessionSaveMigrator.ts @@ -0,0 +1,6 @@ +import type { SessionSaveData } from "#app/system/game-data"; + +export interface SessionSaveMigrator { + version: string; + migrate: (data: SessionSaveData) => void; +} diff --git a/src/@types/SettingsSaveMigrator.ts b/src/@types/SettingsSaveMigrator.ts new file mode 100644 index 00000000000..aae3df7cc60 --- /dev/null +++ b/src/@types/SettingsSaveMigrator.ts @@ -0,0 +1,5 @@ +export interface SettingsSaveMigrator { + version: string; + // biome-ignore lint/complexity/noBannedTypes: TODO - refactor settings + migrate: (data: Object) => void; +} diff --git a/src/@types/SystemSaveMigrator.ts b/src/@types/SystemSaveMigrator.ts new file mode 100644 index 00000000000..a22b5f6c93d --- /dev/null +++ b/src/@types/SystemSaveMigrator.ts @@ -0,0 +1,6 @@ +import type { SystemSaveData } from "#app/system/game-data"; + +export interface SystemSaveMigrator { + version: string; + migrate: (data: SystemSaveData) => void; +} diff --git a/src/@types/ability-types.ts b/src/@types/ability-types.ts new file mode 100644 index 00000000000..5d21aaaa844 --- /dev/null +++ b/src/@types/ability-types.ts @@ -0,0 +1,11 @@ +import type { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr"; +import type Move from "#app/data/moves/move"; +import type Pokemon from "#app/field/pokemon"; +import type { BattleStat } from "#enums/stat"; + +export type AbAttrApplyFunc = (attr: TAttr, passive: boolean) => void; +export type AbAttrSuccessFunc = (attr: TAttr, passive: boolean) => boolean; +export type AbAttrCondition = (pokemon: Pokemon) => boolean; +export type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean; +export type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean; +export type PokemonStatStageChangeCondition = (target: Pokemon, statsChanged: BattleStat[], stages: number) => boolean; diff --git a/src/account.ts b/src/account.ts index 96ce32714bb..3416fa6ed5e 100644 --- a/src/account.ts +++ b/src/account.ts @@ -1,11 +1,11 @@ import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import type { UserInfo } from "#app/@types/UserInfo"; -import { bypassLogin } from "./battle-scene"; -import * as Utils from "./utils"; +import { bypassLogin } from "./global-vars/bypass-login"; +import { randomString } from "#app/utils/common"; export let loggedInUser: UserInfo | null = null; // This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting -export const clientSessionId = Utils.randomString(32); +export const clientSessionId = randomString(32); export function initLoggedInUser(): void { loggedInUser = { diff --git a/src/battle-scene.ts b/src/battle-scene.ts index a759cbb84c2..db036847994 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -5,9 +5,20 @@ import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import type { PokemonSpeciesFilter } from "#app/data/pokemon-species"; import type PokemonSpecies from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; -import type { Constructor } from "#app/utils"; -import { isNullOrUndefined, randSeedInt } from "#app/utils"; -import * as Utils from "#app/utils"; +import { + fixedInt, + getIvsFromId, + randSeedInt, + getEnumValues, + randomString, + NumberHolder, + shiftCharCodes, + formatMoney, + isNullOrUndefined, + BooleanHolder, + type Constructor, +} from "#app/utils/common"; +import { deepMergeSpriteData } from "#app/utils/data"; import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier"; import { ConsumableModifier, @@ -56,7 +67,6 @@ import { } from "#app/modifier/modifier-type"; import AbilityBar from "#app/ui/ability-bar"; import { - allAbilities, applyAbAttrs, applyPostBattleInitAbAttrs, applyPostItemLostAbAttrs, @@ -64,9 +74,11 @@ import { DoubleBattleChanceAbAttr, PostBattleInitAbAttr, PostItemLostAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; +import { allAbilities } from "./data/data-lists"; import type { FixedBattleConfig } from "#app/battle"; -import Battle, { BattleType } from "#app/battle"; +import Battle from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import type { GameMode } from "#app/game-mode"; import { GameModes, getGameMode } from "#app/game-mode"; import FieldSpritePipeline from "#app/pipelines/field-sprite"; @@ -106,8 +118,8 @@ import PokemonInfoContainer from "#app/ui/pokemon-info-container"; import { biomeDepths, getBiomeName } from "#app/data/balance/biomes"; import { SceneBase } from "#app/scene-base"; import CandyBar from "#app/ui/candy-bar"; -import type { Variant, VariantSet } from "#app/data/variant"; -import { variantColorCache, variantData } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; +import { variantData, clearVariantData } from "#app/sprites/variant"; import type { Localizable } from "#app/interfaces/locales"; import Overrides from "#app/overrides"; import { InputsController } from "#app/inputs-controller"; @@ -139,7 +151,6 @@ import { NextEncounterPhase } from "#app/phases/next-encounter-phase"; import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; import { ReturnPhase } from "#app/phases/return-phase"; -import { SelectBiomePhase } from "#app/phases/select-biome-phase"; import { ShowTrainerPhase } from "#app/phases/show-trainer-phase"; import { SummonPhase } from "#app/phases/summon-phase"; import { SwitchPhase } from "#app/phases/switch-phase"; @@ -170,9 +181,11 @@ import { StatusEffect } from "#enums/status-effect"; import { initGlobalScene } from "#app/global-scene"; import { ShowAbilityPhase } from "#app/phases/show-ability-phase"; import { HideAbilityPhase } from "#app/phases/hide-ability-phase"; +import { expSpriteKeys } from "./sprites/sprite-keys"; +import { hasExpSprite } from "./sprites/sprite-utils"; import { timedEventManager } from "./global-event-manager"; - -export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; +import { starterColors } from "./global-vars/starter-colors"; +import { startingWave } from "./starting-wave"; const DEBUG_RNG = false; @@ -180,15 +193,6 @@ const OPP_IVS_OVERRIDE_VALIDATED: number[] = ( Array.isArray(Overrides.OPP_IVS_OVERRIDE) ? Overrides.OPP_IVS_OVERRIDE : new Array(6).fill(Overrides.OPP_IVS_OVERRIDE) ).map(iv => (Number.isNaN(iv) || iv === null || iv > 31 ? -1 : iv)); -export const startingWave = Overrides.STARTING_WAVE_OVERRIDE || 1; - -const expSpriteKeys: string[] = []; - -export let starterColors: StarterColors; -interface StarterColors { - [key: string]: [string, string]; -} - export interface PokeballCounts { [pb: string]: number; } @@ -409,7 +413,7 @@ export default class BattleScene extends SceneBase { } const variant = atlasPath.includes("variant/") || /_[0-3]$/.test(atlasPath); if (experimental) { - experimental = this.hasExpSprite(key); + experimental = hasExpSprite(key); } if (variant) { atlasPath = atlasPath.replace("variant/", ""); @@ -421,35 +425,6 @@ export default class BattleScene extends SceneBase { ); } - /** - * Load the variant assets for the given sprite and stores them in {@linkcode variantColorCache} - */ - public async loadPokemonVariantAssets(spriteKey: string, fileRoot: string, variant?: Variant): Promise { - const useExpSprite = this.experimentalSprites && this.hasExpSprite(spriteKey); - if (useExpSprite) { - fileRoot = `exp/${fileRoot}`; - } - let variantConfig = variantData; - fileRoot.split("/").map(p => (variantConfig ? (variantConfig = variantConfig[p]) : null)); - const variantSet = variantConfig as VariantSet; - - return new Promise(resolve => { - if (variantSet && variant !== undefined && variantSet[variant] === 1) { - if (variantColorCache.hasOwnProperty(spriteKey)) { - return resolve(); - } - this.cachedFetch(`./images/pokemon/variant/${fileRoot}.json`) - .then(res => res.json()) - .then(c => { - variantColorCache[spriteKey] = c; - resolve(); - }); - } else { - resolve(); - } - }); - } - async preload() { if (DEBUG_RNG) { const originalRealInRange = Phaser.Math.RND.realInRange; @@ -762,7 +737,7 @@ export default class BattleScene extends SceneBase { } this.playTimeTimer = this.time.addEvent({ - delay: Utils.fixedInt(1000), + delay: fixedInt(1000), repeat: -1, callback: () => { if (this.gameData) { @@ -783,53 +758,36 @@ export default class BattleScene extends SceneBase { } async initExpSprites(): Promise { - if (expSpriteKeys.length) { + if (expSpriteKeys.size > 0) { return; } this.cachedFetch("./exp-sprites.json") .then(res => res.json()) .then(keys => { if (Array.isArray(keys)) { - expSpriteKeys.push(...keys); + for (const key of keys) { + expSpriteKeys.add(key); + } } Promise.resolve(); }); } + /** + * Initialize the variant data. + * If experimental sprites are enabled, their entries are replaced via this method. + */ async initVariantData(): Promise { - for (const key of Object.keys(variantData)) { - delete variantData[key]; + clearVariantData(); + const otherVariantData = await this.cachedFetch("./images/pokemon/variant/_masterlist.json").then(r => r.json()); + for (const k of Object.keys(otherVariantData)) { + variantData[k] = otherVariantData[k]; } - await this.cachedFetch("./images/pokemon/variant/_masterlist.json") - .then(res => res.json()) - .then(v => { - for (const k of Object.keys(v)) { - variantData[k] = v[k]; - } - if (this.experimentalSprites) { - const expVariantData = variantData["exp"]; - const traverseVariantData = (keys: string[]) => { - let variantTree = variantData; - let expTree = expVariantData; - keys.map((k: string, i: number) => { - if (i < keys.length - 1) { - variantTree = variantTree[k]; - expTree = expTree[k]; - } else if (variantTree.hasOwnProperty(k) && expTree.hasOwnProperty(k)) { - if (["back", "female"].includes(k)) { - traverseVariantData(keys.concat(k)); - } else { - variantTree[k] = expTree[k]; - } - } - }); - }; - for (const ek of Object.keys(expVariantData)) { - traverseVariantData([ek]); - } - } - Promise.resolve(); - }); + if (!this.experimentalSprites) { + return; + } + const expVariantData = await this.cachedFetch("./images/pokemon/variant/_exp_masterlist.json").then(r => r.json()); + deepMergeSpriteData(variantData, expVariantData); } cachedFetch(url: string, init?: RequestInit): Promise { @@ -843,48 +801,15 @@ export default class BattleScene extends SceneBase { return fetch(url, init); } - initStarterColors(): Promise { - return new Promise(resolve => { - if (starterColors) { - return resolve(); - } - - this.cachedFetch("./starter-colors.json") - .then(res => res.json()) - .then(sc => { - starterColors = {}; - for (const key of Object.keys(sc)) { - starterColors[key] = sc[key]; - } - - resolve(); - }); - }); - } - - hasExpSprite(key: string): boolean { - const keyMatch = /^pkmn__?(back__)?(shiny__)?(female__)?(\d+)(\-.*?)?(?:_[1-3])?$/g.exec(key); - if (!keyMatch) { - return false; + async initStarterColors(): Promise { + if (Object.keys(starterColors).length > 0) { + // already initialized + return; } - - let k = keyMatch[4]!; - if (keyMatch[2]) { - k += "s"; + const sc = await this.cachedFetch("./starter-colors.json").then(res => res.json()); + for (const key of Object.keys(sc)) { + starterColors[key] = sc[key]; } - if (keyMatch[1]) { - k += "b"; - } - if (keyMatch[3]) { - k += "f"; - } - if (keyMatch[5]) { - k += keyMatch[5]; - } - if (!expSpriteKeys.includes(k)) { - return false; - } - return true; } public getPlayerParty(): PlayerPokemon[] { @@ -910,6 +835,7 @@ export default class BattleScene extends SceneBase { return this.getPlayerField().find(p => p.isActive() && (includeSwitching || p.switchOutStatus === false)); } + // TODO: Add `undefined` to return type /** * Returns an array of PlayerPokemon of length 1 or 2 depending on if in a double battle or not. * Does not actually check if the pokemon are on the field or not. @@ -925,9 +851,9 @@ export default class BattleScene extends SceneBase { } /** - * @returns The first {@linkcode EnemyPokemon} that is {@linkcode getEnemyField on the field} - * and {@linkcode EnemyPokemon.isActive is active} - * (aka {@linkcode EnemyPokemon.isAllowedInBattle is allowed in battle}), + * @returns The first {@linkcode EnemyPokemon} that is {@linkcode getEnemyField | on the field} + * and {@linkcode EnemyPokemon.isActive | is active} + * (aka {@linkcode EnemyPokemon.isAllowedInBattle | is allowed in battle}), * or `undefined` if there are no valid pokemon * @param includeSwitching Whether a pokemon that is currently switching out is valid, default `true` */ @@ -948,8 +874,8 @@ export default class BattleScene extends SceneBase { /** * Returns an array of Pokemon on both sides of the battle - player first, then enemy. * Does not actually check if the pokemon are on the field or not, and always has length 4 regardless of battle type. - * @param activeOnly Whether to consider only active pokemon - * @returns array of {@linkcode Pokemon} + * @param activeOnly - Whether to consider only active pokemon; default `false` + * @returns An array of {@linkcode Pokemon}, as described above. */ public getField(activeOnly = false): Pokemon[] { const ret = new Array(4).fill(null); @@ -1067,7 +993,7 @@ export default class BattleScene extends SceneBase { } if (boss && !dataSource) { - const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967296)); + const secondaryIvs = getIvsFromId(randSeedInt(4294967296)); for (let s = 0; s < pokemon.ivs.length; s++) { pokemon.ivs[s] = Math.round( @@ -1140,7 +1066,7 @@ export default class BattleScene extends SceneBase { container.add(icon); - if (pokemon.isFusion()) { + if (pokemon.isFusion(true)) { const fusionIcon = this.add.sprite(0, 0, pokemon.getFusionIconAtlasKey(ignoreOverride)); fusionIcon.setName("sprite-fusion-icon"); fusionIcon.setOrigin(0.5, 0); @@ -1226,7 +1152,7 @@ export default class BattleScene extends SceneBase { * Generates a random number using the current battle's seed * * This calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts` - * which calls {@linkcode Utils.randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts` + * which calls {@linkcode randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts` * * @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min} * @param min The minimum integer to pick, default `0` @@ -1251,7 +1177,7 @@ export default class BattleScene extends SceneBase { this.lockModifierTiers = false; this.pokeballCounts = Object.fromEntries( - Utils.getEnumValues(PokeballType) + getEnumValues(PokeballType) .filter(p => p <= PokeballType.MASTER_BALL) .map(t => [t, 0]), ); @@ -1283,7 +1209,7 @@ export default class BattleScene extends SceneBase { // Reset RNG after end of game or save & quit. // This needs to happen after clearing this.currentBattle or the seed will be affected by the last wave played - this.setSeed(Overrides.SEED_OVERRIDE || Utils.randomString(24)); + this.setSeed(Overrides.SEED_OVERRIDE || randomString(24)); console.log("Seed:", this.seed); this.resetSeed(); @@ -1324,7 +1250,7 @@ export default class BattleScene extends SceneBase { ...allSpecies, ...allMoves, ...allAbilities, - ...Utils.getEnumValues(ModifierPoolType) + ...getEnumValues(ModifierPoolType) .map(mpt => getModifierPoolForType(mpt)) .flatMap(mp => Object.values(mp) @@ -1364,7 +1290,7 @@ export default class BattleScene extends SceneBase { } getDoubleBattleChance(newWaveIndex: number, playerField: PlayerPokemon[]) { - const doubleChance = new Utils.NumberHolder(newWaveIndex % 10 === 0 ? 32 : 8); + const doubleChance = new NumberHolder(newWaveIndex % 10 === 0 ? 32 : 8); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); for (const p of playerField) { applyAbAttrs(DoubleBattleChanceAbAttr, p, null, false, doubleChance); @@ -1372,14 +1298,23 @@ export default class BattleScene extends SceneBase { return Math.max(doubleChance.value, 1); } - // TODO: ...this never actually returns `null`, right? + isNewBiome(currentBattle = this.currentBattle) { + const isWaveIndexMultipleOfTen = !(currentBattle.waveIndex % 10); + const isEndlessOrDaily = this.gameMode.hasShortBiomes || this.gameMode.isDaily; + const isEndlessFifthWave = this.gameMode.hasShortBiomes && currentBattle.waveIndex % 5 === 0; + const isWaveIndexMultipleOfFiftyMinusOne = currentBattle.waveIndex % 50 === 49; + const isNewBiome = + isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne); + return isNewBiome; + } + newBattle( waveIndex?: number, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounterType?: MysteryEncounterType, - ): Battle | null { + ): Battle { const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave; const newWaveIndex = waveIndex || (this.currentBattle?.waveIndex || _startingWave - 1) + 1; let newDouble: boolean | undefined; @@ -1406,22 +1341,27 @@ export default class BattleScene extends SceneBase { } else { if ( !this.gameMode.hasTrainers || + Overrides.BATTLE_TYPE_OVERRIDE === BattleType.WILD || (Overrides.DISABLE_STANDARD_TRAINERS_OVERRIDE && isNullOrUndefined(trainerData)) ) { newBattleType = BattleType.WILD; - } else if (battleType === undefined) { - newBattleType = this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD; } else { - newBattleType = battleType; + newBattleType = + Overrides.BATTLE_TYPE_OVERRIDE ?? + battleType ?? + (this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD); } if (newBattleType === BattleType.TRAINER) { - const trainerType = this.arena.randomTrainerType(newWaveIndex); + const trainerType = + Overrides.RANDOM_TRAINER_OVERRIDE?.trainerType ?? this.arena.randomTrainerType(newWaveIndex); let doubleTrainer = false; if (trainerConfigs[trainerType].doubleOnly) { doubleTrainer = true; } else if (trainerConfigs[trainerType].hasDouble) { - doubleTrainer = !Utils.randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField)); + doubleTrainer = + Overrides.RANDOM_TRAINER_OVERRIDE?.alwaysDouble || + !randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField)); // Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance if ( trainerConfigs[trainerType].trainerTypeDouble && @@ -1432,7 +1372,7 @@ export default class BattleScene extends SceneBase { } const variant = doubleTrainer ? TrainerVariant.DOUBLE - : Utils.randSeedInt(2) + : randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT; newTrainer = trainerData !== undefined ? trainerData.toTrainer() : new Trainer(trainerType, variant); @@ -1441,7 +1381,10 @@ export default class BattleScene extends SceneBase { // Check for mystery encounter // Can only occur in place of a standard (non-boss) wild battle, waves 10-180 - if (this.isWaveMysteryEncounter(newBattleType, newWaveIndex) || newBattleType === BattleType.MYSTERY_ENCOUNTER) { + if ( + !Overrides.BATTLE_TYPE_OVERRIDE && + (this.isWaveMysteryEncounter(newBattleType, newWaveIndex) || newBattleType === BattleType.MYSTERY_ENCOUNTER) + ) { newBattleType = BattleType.MYSTERY_ENCOUNTER; // Reset to base spawn weight this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT; @@ -1450,7 +1393,7 @@ export default class BattleScene extends SceneBase { if (double === undefined && newWaveIndex > 1) { if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) { - newDouble = !Utils.randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField)); + newDouble = !randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField)); } else if (newBattleType === BattleType.TRAINER) { newDouble = newTrainer?.variant === TrainerVariant.DOUBLE; } @@ -1463,10 +1406,10 @@ export default class BattleScene extends SceneBase { newDouble = false; } - if (!isNullOrUndefined(Overrides.BATTLE_TYPE_OVERRIDE)) { + if (!isNullOrUndefined(Overrides.BATTLE_STYLE_OVERRIDE)) { let doubleOverrideForWave: "single" | "double" | null = null; - switch (Overrides.BATTLE_TYPE_OVERRIDE) { + switch (Overrides.BATTLE_STYLE_OVERRIDE) { case "double": doubleOverrideForWave = "double"; break; @@ -1486,7 +1429,7 @@ export default class BattleScene extends SceneBase { } /** * Override battles into single only if not fighting with trainers. - * @see {@link https://github.com/pagefaultgames/pokerogue/issues/1948 | GitHub Issue #1948} + * @see {@link https://github.com/pagefaultgames/pokerogue/issues/1948 GitHub Issue #1948} */ if (newBattleType !== BattleType.TRAINER && doubleOverrideForWave === "single") { newDouble = false; @@ -1526,15 +1469,8 @@ export default class BattleScene extends SceneBase { this.currentBattle.mysteryEncounterType = mysteryEncounterType; } - //this.pushPhase(new TrainerMessageTestPhase(this, TrainerType.RIVAL, TrainerType.RIVAL_2, TrainerType.RIVAL_3, TrainerType.RIVAL_4, TrainerType.RIVAL_5, TrainerType.RIVAL_6)); - if (!waveIndex && lastBattle) { - const isWaveIndexMultipleOfTen = !(lastBattle.waveIndex % 10); - const isEndlessOrDaily = this.gameMode.hasShortBiomes || this.gameMode.isDaily; - const isEndlessFifthWave = this.gameMode.hasShortBiomes && lastBattle.waveIndex % 5 === 0; - const isWaveIndexMultipleOfFiftyMinusOne = lastBattle.waveIndex % 50 === 49; - const isNewBiome = - isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne); + const isNewBiome = this.isNewBiome(lastBattle); const resetArenaState = isNewBiome || [BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) || @@ -1560,7 +1496,7 @@ export default class BattleScene extends SceneBase { }); for (const pokemon of this.getPlayerParty()) { - pokemon.resetBattleData(); + pokemon.resetBattleAndWaveData(); pokemon.resetTera(); applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon); if ( @@ -1583,7 +1519,6 @@ export default class BattleScene extends SceneBase { if (!this.gameMode.hasRandomBiomes && !isNewBiome) { this.pushPhase(new NextEncounterPhase()); } else { - this.pushPhase(new SelectBiomePhase()); this.pushPhase(new NewBiomeEncounterPhase()); const newMaxExpLevel = this.getMaxExpLevel(); @@ -1640,7 +1575,7 @@ export default class BattleScene extends SceneBase { scale: scale, x: (defaultWidth - scaledWidth) / 2, y: defaultHeight - scaledHeight, - duration: !instant ? Utils.fixedInt(Math.abs(this.field.scale - scale) * 200) : 0, + duration: !instant ? fixedInt(Math.abs(this.field.scale - scale) * 200) : 0, ease: "Sine.easeInOut", onComplete: () => resolve(), }); @@ -1737,12 +1672,12 @@ export default class BattleScene extends SceneBase { case Species.SQUAWKABILLY: case Species.TATSUGIRI: case Species.PALDEA_TAUROS: - return Utils.randSeedInt(species.forms.length); + return randSeedInt(species.forms.length); case Species.PIKACHU: if (this.currentBattle?.battleType === BattleType.TRAINER && this.currentBattle?.waveIndex < 30) { return 0; // Ban Cosplay and Partner Pika from Trainers before wave 30 } - return Utils.randSeedInt(8); + return randSeedInt(8); case Species.EEVEE: if ( this.currentBattle?.battleType === BattleType.TRAINER && @@ -1751,22 +1686,22 @@ export default class BattleScene extends SceneBase { ) { return 0; // No Partner Eevee for Wave 12 Preschoolers } - return Utils.randSeedInt(2); + return randSeedInt(2); case Species.FROAKIE: case Species.FROGADIER: case Species.GRENINJA: if (this.currentBattle?.battleType === BattleType.TRAINER && !isEggPhase) { return 0; // Don't give trainers Battle Bond Greninja, Froakie or Frogadier } - return Utils.randSeedInt(2); + return randSeedInt(2); case Species.URSHIFU: - return Utils.randSeedInt(2); + return randSeedInt(2); case Species.ZYGARDE: - return Utils.randSeedInt(4); + return randSeedInt(4); case Species.MINIOR: - return Utils.randSeedInt(7); + return randSeedInt(7); case Species.ALCREMIE: - return Utils.randSeedInt(9); + return randSeedInt(9); case Species.MEOWSTIC: case Species.INDEEDEE: case Species.BASCULEGION: @@ -1797,7 +1732,7 @@ export default class BattleScene extends SceneBase { if (this.gameMode.hasMysteryEncounters && !isEggPhase) { return 1; // Wandering form } - return Utils.randSeedInt(species.forms.length); + return randSeedInt(species.forms.length); } if (ignoreArena) { @@ -1806,7 +1741,7 @@ export default class BattleScene extends SceneBase { case Species.WORMADAM: case Species.ROTOM: case Species.LYCANROC: - return Utils.randSeedInt(species.forms.length); + return randSeedInt(species.forms.length); } return 0; } @@ -1818,7 +1753,7 @@ export default class BattleScene extends SceneBase { let ret = false; this.executeWithSeedOffset( () => { - ret = !Utils.randSeedInt(2); + ret = !randSeedInt(2); }, 0, this.seed.toString(), @@ -1830,7 +1765,7 @@ export default class BattleScene extends SceneBase { let ret = 0; this.executeWithSeedOffset( () => { - ret = Utils.randSeedInt(8) * 5; + ret = randSeedInt(8) * 5; }, 0, this.seed.toString(), @@ -1859,7 +1794,7 @@ export default class BattleScene extends SceneBase { isBoss = waveIndex % 10 === 0 || (this.gameMode.hasRandomBosses && - Utils.randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30)); + randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30)); }, waveIndex << 2); } if (!isBoss) { @@ -1886,7 +1821,7 @@ export default class BattleScene extends SceneBase { const infectedIndexes: number[] = []; const spread = (index: number, spreadTo: number) => { const partyMember = party[index + spreadTo]; - if (!partyMember.pokerus && !Utils.randSeedInt(10)) { + if (!partyMember.pokerus && !randSeedInt(10)) { partyMember.pokerus = true; infectedIndexes.push(index + spreadTo); } @@ -1912,7 +1847,7 @@ export default class BattleScene extends SceneBase { resetSeed(waveIndex?: number): void { const wave = waveIndex || this.currentBattle?.waveIndex || 0; - this.waveSeed = Utils.shiftCharCodes(this.seed, wave); + this.waveSeed = shiftCharCodes(this.seed, wave); Phaser.Math.RND.sow([this.waveSeed]); console.log("Wave Seed:", this.waveSeed, wave); this.rngCounter = 0; @@ -1931,7 +1866,7 @@ export default class BattleScene extends SceneBase { const tempRngOffset = this.rngOffset; const tempRngSeedOverride = this.rngSeedOverride; const state = Phaser.Math.RND.state(); - Phaser.Math.RND.sow([Utils.shiftCharCodes(seedOverride || this.seed, offset)]); + Phaser.Math.RND.sow([shiftCharCodes(seedOverride || this.seed, offset)]); this.rngCounter = 0; this.rngOffset = offset; this.rngSeedOverride = seedOverride || ""; @@ -2076,7 +2011,7 @@ export default class BattleScene extends SceneBase { if (this.money === undefined) { return; } - const formattedMoney = Utils.formatMoney(this.moneyFormat, this.money); + const formattedMoney = formatMoney(this.moneyFormat, this.money); this.moneyText.setText(i18next.t("battleScene:moneyOwned", { formattedMoney })); this.fieldUI.moveAbove(this.moneyText, this.luckText); if (forceVisible) { @@ -2233,12 +2168,12 @@ export default class BattleScene extends SceneBase { ), ] : allSpecies.filter(s => s.isCatchable()); - return filteredSpecies[Utils.randSeedInt(filteredSpecies.length)]; + return filteredSpecies[randSeedInt(filteredSpecies.length)]; } generateRandomBiome(waveIndex: number): Biome { const relWave = waveIndex % 250; - const biomes = Utils.getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END); + const biomes = getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END); const maxDepth = biomeDepths[Biome.END][0] - 2; const depthWeights = new Array(maxDepth + 1) .fill(null) @@ -2250,7 +2185,7 @@ export default class BattleScene extends SceneBase { biomeThresholds.push(totalWeight); } - const randInt = Utils.randSeedInt(totalWeight); + const randInt = randSeedInt(totalWeight); for (let i = 0; i < biomes.length; i++) { if (randInt < biomeThresholds[i]) { @@ -2258,7 +2193,7 @@ export default class BattleScene extends SceneBase { } } - return biomes[Utils.randSeedInt(biomes.length)]; + return biomes[randSeedInt(biomes.length)]; } isBgmPlaying(): boolean { @@ -2443,7 +2378,7 @@ export default class BattleScene extends SceneBase { this.bgmResumeTimer.destroy(); } if (resumeBgm) { - this.bgmResumeTimer = this.time.delayedCall(pauseDuration || Utils.fixedInt(sound.totalDuration * 1000), () => { + this.bgmResumeTimer = this.time.delayedCall(pauseDuration || fixedInt(sound.totalDuration * 1000), () => { this.resumeBgm(); this.bgmResumeTimer = null; }); @@ -3036,7 +2971,7 @@ export default class BattleScene extends SceneBase { const args: unknown[] = []; if (modifier instanceof PokemonHpRestoreModifier) { if (!(modifier as PokemonHpRestoreModifier).fainted) { - const hpRestoreMultiplier = new Utils.NumberHolder(1); + const hpRestoreMultiplier = new NumberHolder(1); this.applyModifiers(HealingBoosterModifier, true, hpRestoreMultiplier); args.push(hpRestoreMultiplier.value); } else { @@ -3044,7 +2979,7 @@ export default class BattleScene extends SceneBase { } } else if (modifier instanceof FusePokemonModifier) { args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon); - } else if (modifier instanceof RememberMoveModifier && !Utils.isNullOrUndefined(cost)) { + } else if (modifier instanceof RememberMoveModifier && !isNullOrUndefined(cost)) { args.push(cost); } @@ -3113,7 +3048,7 @@ export default class BattleScene extends SceneBase { itemLost = true, ): boolean { const source = itemModifier.pokemonId ? itemModifier.getPokemon() : null; - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); if (source && source.isPlayer() !== target.isPlayer()) { applyAbAttrs(BlockItemTheftAbAttr, source, cancelled); @@ -3182,7 +3117,7 @@ export default class BattleScene extends SceneBase { canTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferQuantity = 1): boolean { const mod = itemModifier.clone() as PokemonHeldItemModifier; const source = mod.pokemonId ? mod.getPokemon() : null; - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); if (source && source.isPlayer() !== target.isPlayer()) { applyAbAttrs(BlockItemTheftAbAttr, source, cancelled); @@ -3276,7 +3211,7 @@ export default class BattleScene extends SceneBase { } let count = 0; for (let c = 0; c < chances; c++) { - if (!Utils.randSeedInt(this.gameMode.getEnemyModifierChance(isBoss))) { + if (!randSeedInt(this.gameMode.getEnemyModifierChance(isBoss))) { count++; } } @@ -3329,6 +3264,7 @@ export default class BattleScene extends SceneBase { [this.modifierBar, this.enemyModifierBar].map(m => m.setVisible(visible)); } + // TODO: Document this updateModifiers(player = true, instant?: boolean): void { const modifiers = player ? this.modifiers : (this.enemyModifiers as PersistentModifier[]); for (let m = 0; m < modifiers.length; m++) { @@ -3381,8 +3317,8 @@ export default class BattleScene extends SceneBase { * gets removed. This function does NOT apply in-battle effects, such as Unburden. * If in-battle effects are needed, use {@linkcode Pokemon.loseHeldItem} instead. * @param modifier The item to be removed. - * @param enemy If `true`, remove an item owned by the enemy. If `false`, remove an item owned by the player. Default is `false`. - * @returns `true` if the item exists and was successfully removed, `false` otherwise. + * @param enemy `true` to remove an item owned by the enemy rather than the player; default `false`. + * @returns `true` if the item exists and was successfully removed, `false` otherwise */ removeModifier(modifier: PersistentModifier, enemy = false): boolean { const modifiers = !enemy ? this.modifiers : this.enemyModifiers; @@ -3452,7 +3388,7 @@ export default class BattleScene extends SceneBase { if (mods.length < 1) { return mods; } - const rand = Utils.randSeedInt(mods.length); + const rand = randSeedInt(mods.length); return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))]; }; modifiers = shuffleModifiers(modifiers); @@ -3678,7 +3614,7 @@ export default class BattleScene extends SceneBase { */ initFinalBossPhaseTwo(pokemon: Pokemon): void { if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) { - this.fadeOutBgm(Utils.fixedInt(2000), false); + this.fadeOutBgm(fixedInt(2000), false); this.ui.showDialogue( battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, pokemon.species.name, @@ -3781,7 +3717,7 @@ export default class BattleScene extends SceneBase { if (Overrides.XP_MULTIPLIER_OVERRIDE !== null) { expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE; } - const pokemonExp = new Utils.NumberHolder(expValue * expMultiplier); + const pokemonExp = new NumberHolder(expValue * expMultiplier); this.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp); partyMemberExp.push(Math.floor(pokemonExp.value)); } @@ -3930,7 +3866,7 @@ export default class BattleScene extends SceneBase { while (i < this.mysteryEncounterSaveData.queuedEncounters.length && !!encounter) { const candidate = this.mysteryEncounterSaveData.queuedEncounters[i]; const forcedChance = candidate.spawnPercent; - if (Utils.randSeedInt(100) < forcedChance) { + if (randSeedInt(100) < forcedChance) { encounter = allMysteryEncounters[candidate.type]; } @@ -3963,7 +3899,7 @@ export default class BattleScene extends SceneBase { } const totalWeight = tierWeights.reduce((a, b) => a + b); - const tierValue = Utils.randSeedInt(totalWeight); + const tierValue = randSeedInt(totalWeight); const commonThreshold = totalWeight - tierWeights[0]; const greatThreshold = totalWeight - tierWeights[0] - tierWeights[1]; const ultraThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2]; @@ -4055,7 +3991,7 @@ export default class BattleScene extends SceneBase { console.log("No Mystery Encounters found, falling back to Mysterious Challengers."); return allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHALLENGERS]; } - encounter = availableEncounters[Utils.randSeedInt(availableEncounters.length)]; + encounter = availableEncounters[randSeedInt(availableEncounters.length)]; // New encounter object to not dirty flags encounter = new MysteryEncounter(encounter); encounter.populateDialogueTokensFromRequirements(); diff --git a/src/battle.ts b/src/battle.ts index 367c52568dc..07e520d6bc0 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -1,6 +1,14 @@ import { globalScene } from "#app/global-scene"; import type { Command } from "./ui/command-ui-handler"; -import * as Utils from "./utils"; +import { + randomString, + getEnumValues, + NumberHolder, + randSeedInt, + shiftCharCodes, + randSeedItem, + randInt, +} from "#app/utils/common"; import Trainer, { TrainerVariant } from "./field/trainer"; import type { GameMode } from "./game-mode"; import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; @@ -22,36 +30,8 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import type { CustomModifierSettings } from "#app/modifier/modifier-type"; import { ModifierTier } from "#app/modifier/modifier-tier"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; - -export enum ClassicFixedBossWaves { - TOWN_YOUNGSTER = 5, - RIVAL_1 = 8, - RIVAL_2 = 25, - EVIL_GRUNT_1 = 35, - RIVAL_3 = 55, - EVIL_GRUNT_2 = 62, - EVIL_GRUNT_3 = 64, - EVIL_ADMIN_1 = 66, - RIVAL_4 = 95, - EVIL_GRUNT_4 = 112, - EVIL_ADMIN_2 = 114, - EVIL_BOSS_1 = 115, - RIVAL_5 = 145, - EVIL_BOSS_2 = 165, - ELITE_FOUR_1 = 182, - ELITE_FOUR_2 = 184, - ELITE_FOUR_3 = 186, - ELITE_FOUR_4 = 188, - CHAMPION = 190, - RIVAL_6 = 195, -} - -export enum BattleType { - WILD, - TRAINER, - CLEAR, - MYSTERY_ENCOUNTER, -} +import { BattleType } from "#enums/battle-type"; +import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves"; export enum BattlerIndex { ATTACKER = -1, @@ -99,7 +79,7 @@ export default class Battle { public postBattleLoot: PokemonHeldItemModifier[] = []; public escapeAttempts = 0; public lastMove: Moves; - public battleSeed: string = Utils.randomString(16, true); + public battleSeed: string = randomString(16, true); private battleSeedState: string | null = null; public moneyScattered = 0; /** Primarily for double battles, keeps track of last enemy and player pokemon that triggered its ability or used a move */ @@ -181,8 +161,8 @@ export default class Battle { incrementTurn(): void { this.turn++; - this.turnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [bt, null])); - this.preTurnCommands = Object.fromEntries(Utils.getEnumValues(BattlerIndex).map(bt => [bt, null])); + this.turnCommands = Object.fromEntries(getEnumValues(BattlerIndex).map(bt => [bt, null])); + this.preTurnCommands = Object.fromEntries(getEnumValues(BattlerIndex).map(bt => [bt, null])); this.battleSeedState = null; } @@ -211,7 +191,7 @@ export default class Battle { } pickUpScatteredMoney(): void { - const moneyAmount = new Utils.NumberHolder(globalScene.currentBattle.moneyScattered); + const moneyAmount = new NumberHolder(globalScene.currentBattle.moneyScattered); globalScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); if (globalScene.arena.getTag(ArenaTagType.HAPPY_HOUR)) { @@ -448,7 +428,7 @@ export default class Battle { } /** - * Generates a random number using the current battle's seed. Calls {@linkcode Utils.randSeedInt} + * Generates a random number using the current battle's seed. Calls {@linkcode randSeedInt} * @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min} * @param min The minimum integer to pick, default `0` * @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1) @@ -463,12 +443,12 @@ export default class Battle { if (this.battleSeedState) { Phaser.Math.RND.state(this.battleSeedState); } else { - Phaser.Math.RND.sow([Utils.shiftCharCodes(this.battleSeed, this.turn << 6)]); + Phaser.Math.RND.sow([shiftCharCodes(this.battleSeed, this.turn << 6)]); console.log("Battle Seed:", this.battleSeed); } globalScene.rngCounter = this.rngCounter++; globalScene.rngSeedOverride = this.battleSeed; - const ret = Utils.randSeedInt(range, min); + const ret = randSeedInt(range, min); this.battleSeedState = Phaser.Math.RND.state(); Phaser.Math.RND.state(state); globalScene.rngCounter = tempRngCounter; @@ -554,19 +534,19 @@ export function getRandomTrainerFunc( seedOffset = 0, ): GetTrainerFunc { return () => { - const rand = Utils.randSeedInt(trainerPool.length); + const rand = randSeedInt(trainerPool.length); const trainerTypes: TrainerType[] = []; globalScene.executeWithSeedOffset(() => { for (const trainerPoolEntry of trainerPool) { - const trainerType = Array.isArray(trainerPoolEntry) ? Utils.randSeedItem(trainerPoolEntry) : trainerPoolEntry; + const trainerType = Array.isArray(trainerPoolEntry) ? randSeedItem(trainerPoolEntry) : trainerPoolEntry; trainerTypes.push(trainerType); } }, seedOffset); let trainerGender = TrainerVariant.DEFAULT; if (randomGender) { - trainerGender = Utils.randInt(2) === 0 ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT; + trainerGender = randInt(2) === 0 ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT; } /* 1/3 chance for evil team grunts to be double battles */ @@ -585,7 +565,7 @@ export function getRandomTrainerFunc( const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]); if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) { - return new Trainer(trainerTypes[rand], Utils.randInt(3) === 0 ? TrainerVariant.DOUBLE : trainerGender); + return new Trainer(trainerTypes[rand], randInt(3) === 0 ? TrainerVariant.DOUBLE : trainerGender); } return new Trainer(trainerTypes[rand], trainerGender); @@ -608,7 +588,7 @@ export const classicFixedBattles: FixedBattleConfigs = { [ClassicFixedBossWaves.TOWN_YOUNGSTER]: new FixedBattleConfig() .setBattleType(BattleType.TRAINER) .setGetTrainerFunc( - () => new Trainer(TrainerType.YOUNGSTER, Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT), + () => new Trainer(TrainerType.YOUNGSTER, randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT), ), [ClassicFixedBossWaves.RIVAL_1]: new FixedBattleConfig() .setBattleType(BattleType.TRAINER) diff --git a/src/configs/inputs/cfg_keyboard_qwerty.ts b/src/configs/inputs/cfg_keyboard_qwerty.ts index 2ad04ab418d..4f0353971e0 100644 --- a/src/configs/inputs/cfg_keyboard_qwerty.ts +++ b/src/configs/inputs/cfg_keyboard_qwerty.ts @@ -31,6 +31,7 @@ const cfg_keyboard_qwerty = { KEY_X: Phaser.Input.Keyboard.KeyCodes.X, KEY_Y: Phaser.Input.Keyboard.KeyCodes.Y, KEY_Z: Phaser.Input.Keyboard.KeyCodes.Z, + KEY_0: Phaser.Input.Keyboard.KeyCodes.ZERO, KEY_1: Phaser.Input.Keyboard.KeyCodes.ONE, KEY_2: Phaser.Input.Keyboard.KeyCodes.TWO, @@ -41,11 +42,7 @@ const cfg_keyboard_qwerty = { KEY_7: Phaser.Input.Keyboard.KeyCodes.SEVEN, KEY_8: Phaser.Input.Keyboard.KeyCodes.EIGHT, KEY_9: Phaser.Input.Keyboard.KeyCodes.NINE, - KEY_CTRL: Phaser.Input.Keyboard.KeyCodes.CTRL, - KEY_DEL: Phaser.Input.Keyboard.KeyCodes.DELETE, - KEY_END: Phaser.Input.Keyboard.KeyCodes.END, - KEY_ENTER: Phaser.Input.Keyboard.KeyCodes.ENTER, - KEY_ESC: Phaser.Input.Keyboard.KeyCodes.ESC, + KEY_F1: Phaser.Input.Keyboard.KeyCodes.F1, KEY_F2: Phaser.Input.Keyboard.KeyCodes.F2, KEY_F3: Phaser.Input.Keyboard.KeyCodes.F3, @@ -58,24 +55,41 @@ const cfg_keyboard_qwerty = { KEY_F10: Phaser.Input.Keyboard.KeyCodes.F10, KEY_F11: Phaser.Input.Keyboard.KeyCodes.F11, KEY_F12: Phaser.Input.Keyboard.KeyCodes.F12, - KEY_HOME: Phaser.Input.Keyboard.KeyCodes.HOME, - KEY_INSERT: Phaser.Input.Keyboard.KeyCodes.INSERT, + KEY_PAGE_DOWN: Phaser.Input.Keyboard.KeyCodes.PAGE_DOWN, KEY_PAGE_UP: Phaser.Input.Keyboard.KeyCodes.PAGE_UP, + + KEY_CTRL: Phaser.Input.Keyboard.KeyCodes.CTRL, + KEY_DEL: Phaser.Input.Keyboard.KeyCodes.DELETE, + KEY_END: Phaser.Input.Keyboard.KeyCodes.END, + KEY_ENTER: Phaser.Input.Keyboard.KeyCodes.ENTER, + KEY_ESC: Phaser.Input.Keyboard.KeyCodes.ESC, + KEY_HOME: Phaser.Input.Keyboard.KeyCodes.HOME, + KEY_INSERT: Phaser.Input.Keyboard.KeyCodes.INSERT, + KEY_PLUS: Phaser.Input.Keyboard.KeyCodes.NUMPAD_ADD, // Assuming numpad plus KEY_MINUS: Phaser.Input.Keyboard.KeyCodes.NUMPAD_SUBTRACT, // Assuming numpad minus KEY_QUOTATION: Phaser.Input.Keyboard.KeyCodes.QUOTES, KEY_SHIFT: Phaser.Input.Keyboard.KeyCodes.SHIFT, + KEY_SPACE: Phaser.Input.Keyboard.KeyCodes.SPACE, KEY_TAB: Phaser.Input.Keyboard.KeyCodes.TAB, KEY_TILDE: Phaser.Input.Keyboard.KeyCodes.BACKTICK, + KEY_ARROW_UP: Phaser.Input.Keyboard.KeyCodes.UP, KEY_ARROW_DOWN: Phaser.Input.Keyboard.KeyCodes.DOWN, KEY_ARROW_LEFT: Phaser.Input.Keyboard.KeyCodes.LEFT, KEY_ARROW_RIGHT: Phaser.Input.Keyboard.KeyCodes.RIGHT, + KEY_LEFT_BRACKET: Phaser.Input.Keyboard.KeyCodes.OPEN_BRACKET, KEY_RIGHT_BRACKET: Phaser.Input.Keyboard.KeyCodes.CLOSED_BRACKET, + KEY_SEMICOLON: Phaser.Input.Keyboard.KeyCodes.SEMICOLON, + KEY_COMMA: Phaser.Input.Keyboard.KeyCodes.COMMA, + KEY_PERIOD: Phaser.Input.Keyboard.KeyCodes.PERIOD, + KEY_BACK_SLASH: Phaser.Input.Keyboard.KeyCodes.BACK_SLASH, + KEY_FORWARD_SLASH: Phaser.Input.Keyboard.KeyCodes.FORWARD_SLASH, + KEY_BACKSPACE: Phaser.Input.Keyboard.KeyCodes.BACKSPACE, KEY_ALT: Phaser.Input.Keyboard.KeyCodes.ALT, }, @@ -160,6 +174,10 @@ const cfg_keyboard_qwerty = { KEY_RIGHT_BRACKET: "RIGHT_BRACKET.png", KEY_SEMICOLON: "SEMICOLON.png", + KEY_COMMA: "COMMA.png", + KEY_PERIOD: "PERIOD.png", + KEY_BACK_SLASH: "BACK_SLASH.png", + KEY_FORWARD_SLASH: "FORWARD_SLASH.png", KEY_BACKSPACE: "BACK.png", KEY_ALT: "ALT.png", diff --git a/src/constants.ts b/src/constants.ts index 927575c0a28..d3594c389b6 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -9,3 +9,11 @@ export const SESSION_ID_COOKIE_NAME: string = "pokerogue_sessionId"; /** Max value for an integer attribute in {@linkcode SystemSaveData} */ export const MAX_INT_ATTR_VALUE = 0x80000000; + +/** The min and max waves for mystery encounters to spawn in classic mode */ +export const CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180] as const; +/** The min and max waves for mystery encounters to spawn in challenge mode */ +export const CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180] as const; + +/** The raw percentage power boost for type boost items*/ +export const TYPE_BOOST_ITEM_BOOST_PERCENT = 20; diff --git a/src/data/abilities/ab-attrs/ab-attr.ts b/src/data/abilities/ab-attrs/ab-attr.ts new file mode 100644 index 00000000000..24fbb6dc338 --- /dev/null +++ b/src/data/abilities/ab-attrs/ab-attr.ts @@ -0,0 +1,58 @@ +import type { AbAttrCondition } from "#app/@types/ability-types"; +import type Pokemon from "#app/field/pokemon"; +import type { BooleanHolder } from "#app/utils/common"; + +export abstract class AbAttr { + public showAbility: boolean; + private extraCondition: AbAttrCondition; + + /** + * @param showAbility - Whether to show this ability as a flyout during battle; default `true`. + * Should be kept in parity with mainline where possible. + */ + constructor(showAbility = true) { + this.showAbility = showAbility; + } + + /** + * Applies ability effects without checking conditions + * @param _pokemon - The pokemon to apply this ability to + * @param _passive - Whether or not the ability is a passive + * @param _simulated - Whether the call is simulated + * @param _args - Extra args passed to the function. Handled by child classes. + * @see {@linkcode canApply} + */ + apply( + _pokemon: Pokemon, + _passive: boolean, + _simulated: boolean, + _cancelled: BooleanHolder | null, + _args: any[], + ): void {} + + getTriggerMessage(_pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null { + return null; + } + + getCondition(): AbAttrCondition | null { + return this.extraCondition || null; + } + + addCondition(condition: AbAttrCondition): AbAttr { + this.extraCondition = condition; + return this; + } + + /** + * Returns a boolean describing whether the ability can be applied under current conditions + * @param _pokemon - The pokemon to apply this ability to + * @param _passive - Whether or not the ability is a passive + * @param _simulated - Whether the call is simulated + * @param _args - Extra args passed to the function. Handled by child classes. + * @returns `true` if the ability can be applied, `false` otherwise + * @see {@linkcode apply} + */ + canApply(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean { + return true; + } +} diff --git a/src/data/abilities/ability-class.ts b/src/data/abilities/ability-class.ts new file mode 100644 index 00000000000..387c5fb328b --- /dev/null +++ b/src/data/abilities/ability-class.ts @@ -0,0 +1,137 @@ +import { Abilities } from "#enums/abilities"; +import type { AbAttrCondition } from "#app/@types/ability-types"; +import type { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr"; +import i18next from "i18next"; +import type { Localizable } from "#app/interfaces/locales"; +import type { Constructor } from "#app/utils/common"; + +export class Ability implements Localizable { + public id: Abilities; + + private nameAppend: string; + public name: string; + public description: string; + public generation: number; + public isBypassFaint: boolean; + public isIgnorable: boolean; + public isSuppressable = true; + public isCopiable = true; + public isReplaceable = true; + public attrs: AbAttr[]; + public conditions: AbAttrCondition[]; + + constructor(id: Abilities, generation: number) { + this.id = id; + + this.nameAppend = ""; + this.generation = generation; + this.attrs = []; + this.conditions = []; + + this.isSuppressable = true; + this.isCopiable = true; + this.isReplaceable = true; + + this.localize(); + } + + public get isSwappable(): boolean { + return this.isCopiable && this.isReplaceable; + } + localize(): void { + const i18nKey = Abilities[this.id] + .split("_") + .filter(f => f) + .map((f, i) => (i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase())) + .join("") as string; + + this.name = this.id ? `${i18next.t(`ability:${i18nKey}.name`) as string}${this.nameAppend}` : ""; + this.description = this.id ? (i18next.t(`ability:${i18nKey}.description`) as string) : ""; + } + + /** + * Get all ability attributes that match `attrType` + * @param attrType any attribute that extends {@linkcode AbAttr} + * @returns Array of attributes that match `attrType`, Empty Array if none match. + */ + getAttrs(attrType: Constructor): T[] { + return this.attrs.filter((a): a is T => a instanceof attrType); + } + + /** + * Check if an ability has an attribute that matches `attrType` + * @param attrType any attribute that extends {@linkcode AbAttr} + * @returns true if the ability has attribute `attrType` + */ + hasAttr(attrType: Constructor): boolean { + return this.attrs.some(attr => attr instanceof attrType); + } + + attr>(AttrType: T, ...args: ConstructorParameters): Ability { + const attr = new AttrType(...args); + this.attrs.push(attr); + + return this; + } + + conditionalAttr>( + condition: AbAttrCondition, + AttrType: T, + ...args: ConstructorParameters + ): Ability { + const attr = new AttrType(...args); + attr.addCondition(condition); + this.attrs.push(attr); + + return this; + } + + bypassFaint(): Ability { + this.isBypassFaint = true; + return this; + } + + ignorable(): Ability { + this.isIgnorable = true; + return this; + } + + unsuppressable(): Ability { + this.isSuppressable = false; + return this; + } + + uncopiable(): Ability { + this.isCopiable = false; + return this; + } + + unreplaceable(): Ability { + this.isReplaceable = false; + return this; + } + + condition(condition: AbAttrCondition): Ability { + this.conditions.push(condition); + + return this; + } + + partial(): this { + this.nameAppend += " (P)"; + return this; + } + + unimplemented(): this { + this.nameAppend += " (N)"; + return this; + } + + /** + * Internal flag used for developers to document edge cases. When using this, please be sure to document the edge case. + * @returns the ability + */ + edgeCase(): this { + return this; + } +} diff --git a/src/data/ability.ts b/src/data/abilities/ability.ts similarity index 86% rename from src/data/ability.ts rename to src/data/abilities/ability.ts index eea24c791b0..705de6f242d 100644 --- a/src/data/ability.ts +++ b/src/data/abilities/ability.ts @@ -1,240 +1,94 @@ -import type { EnemyPokemon, PokemonMove } from "../field/pokemon"; -import type Pokemon from "../field/pokemon"; -import { HitResult, MoveResult, PlayerPokemon } from "../field/pokemon"; -import { PokemonType } from "#enums/pokemon-type"; -import type { Constructor } from "#app/utils"; -import * as Utils from "../utils"; -import { getPokemonNameWithAffix } from "../messages"; -import type { Weather } from "#app/data/weather"; -import type { BattlerTag } from "./battler-tags"; -import { BattlerTagLapseType, GroundedTag } from "./battler-tags"; +import { HitResult, MoveResult, PlayerPokemon } from "#app/field/pokemon"; +import { BooleanHolder, NumberHolder, toDmgValue, isNullOrUndefined, randSeedItem, randSeedInt, type Constructor } from "#app/utils/common"; +import { getPokemonNameWithAffix } from "#app/messages"; +import { BattlerTagLapseType, GroundedTag } from "#app/data/battler-tags"; import { getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "#app/data/status-effect"; -import { Gender } from "./gender"; -import type Move from "./moves/move"; -import { AttackMove, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./moves/move"; -import { MoveFlags } from "#enums/MoveFlags"; -import { MoveTarget } from "#enums/MoveTarget"; -import { MoveCategory } from "#enums/MoveCategory"; -import type { ArenaTrapTag, SuppressAbilitiesTag } from "./arena-tag"; -import { ArenaTagSide } from "./arena-tag"; -import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "../modifier/modifier"; -import { TerrainType } from "./terrain"; -import { SpeciesFormChangeAbilityTrigger, SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger } from "./pokemon-forms"; +import { Gender } from "#app/data/gender"; +import { + AttackMove, + FlinchAttr, + OneHitKOAttr, + HitHealAttr, + allMoves, + StatusMove, + SelfStatusMove, + VariablePowerAttr, + applyMoveAttrs, + RandomMovesetMoveAttr, + RandomMoveAttr, + NaturePowerAttr, + CopyMoveAttr, + NeutralDamageAgainstFlyingTypeMultiplierAttr, + FixedDamageAttr, +} from "#app/data/moves/move"; +import { ArenaTagSide } from "#app/data/arena-tag"; +import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; +import { TerrainType } from "#app/data/terrain"; +import { SpeciesFormChangeAbilityTrigger, SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger } from "#app/data/pokemon-forms"; import i18next from "i18next"; -import type { Localizable } from "#app/interfaces/locales"; -import { Command } from "../ui/command-ui-handler"; +import { Command } from "#app/ui/command-ui-handler"; import { BerryModifierType } from "#app/modifier/modifier-type"; -import { getPokeballName } from "./pokeball"; -import type { BattlerIndex } from "#app/battle"; -import { BattleType } from "#app/battle"; -import { Abilities } from "#enums/abilities"; -import { ArenaTagType } from "#enums/arena-tag-type"; -import { BattlerTagType } from "#enums/battler-tag-type"; -import { Moves } from "#enums/moves"; -import { Species } from "#enums/species"; -import { Stat, type BattleStat, type EffectiveStat, BATTLE_STATS, EFFECTIVE_STATS, getStatKey } from "#app/enums/stat"; +import { getPokeballName } from "#app/data/pokeball"; +import { BattleType } from "#enums/battle-type"; import { MovePhase } from "#app/phases/move-phase"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { globalScene } from "#app/global-scene"; -import { SwitchType } from "#app/enums/switch-type"; import { SwitchPhase } from "#app/phases/switch-phase"; import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { NewBattlePhase } from "#app/phases/new-battle-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; +import { PokemonTransformPhase } from "#app/phases/pokemon-transform-phase"; +import { allAbilities } from "#app/data/data-lists"; +import { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr"; +import { Ability } from "#app/data/abilities/ability-class"; +import { TrainerVariant } from "#app/field/trainer"; + +// Enum imports +import { Stat, type BattleStat , BATTLE_STATS, EFFECTIVE_STATS, getStatKey, type EffectiveStat } from "#enums/stat"; +import { PokemonType } from "#enums/pokemon-type"; import { PokemonAnimType } from "#enums/pokemon-anim-type"; import { StatusEffect } from "#enums/status-effect"; import { WeatherType } from "#enums/weather-type"; -import { PokemonTransformPhase } from "#app/phases/pokemon-transform-phase"; +import { Abilities } from "#enums/abilities"; +import { ArenaTagType } from "#enums/arena-tag-type"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { SwitchType } from "#enums/switch-type"; +import { MoveFlags } from "#enums/MoveFlags"; +import { MoveTarget } from "#enums/MoveTarget"; +import { MoveCategory } from "#enums/MoveCategory"; +import type { BerryType } from "#enums/berry-type"; +import { CommonAnimPhase } from "#app/phases/common-anim-phase"; +import { CommonAnim } from "../battle-anims"; +import { getBerryEffectFunc } from "../berry"; +import { BerryUsedEvent } from "#app/events/battle-scene"; -export class Ability implements Localizable { - public id: Abilities; - private nameAppend: string; - public name: string; - public description: string; - public generation: number; - public isBypassFaint: boolean; - public isIgnorable: boolean; - public isSuppressable = true; - public isCopiable = true; - public isReplaceable = true; - public attrs: AbAttr[]; - public conditions: AbAttrCondition[]; - - constructor(id: Abilities, generation: number) { - this.id = id; - - this.nameAppend = ""; - this.generation = generation; - this.attrs = []; - this.conditions = []; - - this.isSuppressable = true; - this.isCopiable = true; - this.isReplaceable = true; - - this.localize(); - } - - public get isSwappable(): boolean { - return this.isCopiable && this.isReplaceable; - } - localize(): void { - const i18nKey = Abilities[this.id].split("_").filter(f => f).map((f, i) => i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()).join("") as string; - - this.name = this.id ? `${i18next.t(`ability:${i18nKey}.name`) as string}${this.nameAppend}` : ""; - this.description = this.id ? i18next.t(`ability:${i18nKey}.description`) as string : ""; - } - - /** - * Get all ability attributes that match `attrType` - * @param attrType any attribute that extends {@linkcode AbAttr} - * @returns Array of attributes that match `attrType`, Empty Array if none match. - */ - getAttrs(attrType: Constructor ): T[] { - return this.attrs.filter((a): a is T => a instanceof attrType); - } - - /** - * Check if an ability has an attribute that matches `attrType` - * @param attrType any attribute that extends {@linkcode AbAttr} - * @returns true if the ability has attribute `attrType` - */ - hasAttr(attrType: Constructor): boolean { - return this.attrs.some((attr) => attr instanceof attrType); - } - - attr>(AttrType: T, ...args: ConstructorParameters): Ability { - const attr = new AttrType(...args); - this.attrs.push(attr); - - return this; - } - - conditionalAttr>(condition: AbAttrCondition, AttrType: T, ...args: ConstructorParameters): Ability { - const attr = new AttrType(...args); - attr.addCondition(condition); - this.attrs.push(attr); - - return this; - } - - bypassFaint(): Ability { - this.isBypassFaint = true; - return this; - } - - ignorable(): Ability { - this.isIgnorable = true; - return this; - } - - unsuppressable(): Ability { - this.isSuppressable = false; - return this; - } - - uncopiable(): Ability { - this.isCopiable = false; - return this; - } - - unreplaceable(): Ability { - this.isReplaceable = false; - return this; - } - - condition(condition: AbAttrCondition): Ability { - this.conditions.push(condition); - - return this; - } - - partial(): this { - this.nameAppend += " (P)"; - return this; - } - - unimplemented(): this { - this.nameAppend += " (N)"; - return this; - } - - /** - * Internal flag used for developers to document edge cases. When using this, please be sure to document the edge case. - * @returns the ability - */ - edgeCase(): this { - return this; - } -} - -type AbAttrApplyFunc = (attr: TAttr, passive: boolean) => void; -type AbAttrSuccessFunc = (attr: TAttr, passive: boolean) => boolean; -type AbAttrCondition = (pokemon: Pokemon) => boolean; - -// TODO: Can this be improved? -type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean; -type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean; -type PokemonStatStageChangeCondition = (target: Pokemon, statsChanged: BattleStat[], stages: number) => boolean; - -export abstract class AbAttr { - public showAbility: boolean; - private extraCondition: AbAttrCondition; - - constructor(showAbility = true) { - this.showAbility = showAbility; - } - - /** - * Applies ability effects without checking conditions - * @param pokemon - The pokemon to apply this ability to - * @param passive - Whether or not the ability is a passive - * @param simulated - Whether the call is simulated - * @param args - Extra args passed to the function. Handled by child classes. - * @see {@linkcode canApply} - */ - apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder | null, args: any[]): void {} - - getTriggerMessage(_pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null { - return null; - } - - getCondition(): AbAttrCondition | null { - return this.extraCondition || null; - } - - addCondition(condition: AbAttrCondition): AbAttr { - this.extraCondition = condition; - return this; - } - - /** - * Returns a boolean describing whether the ability can be applied under current conditions - * @param pokemon - The pokemon to apply this ability to - * @param passive - Whether or not the ability is a passive - * @param simulated - Whether the call is simulated - * @param args - Extra args passed to the function. Handled by child classes. - * @returns `true` if the ability can be applied, `false` otherwise - * @see {@linkcode apply} - */ - canApply(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - return true; - } -} +// Type imports +import type { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; +import type Pokemon from "#app/field/pokemon"; +import type { Weather } from "#app/data/weather"; +import type { BattlerTag } from "#app/data/battler-tags"; +import type { AbAttrCondition, PokemonDefendCondition, PokemonStatStageChangeCondition, PokemonAttackCondition, AbAttrApplyFunc, AbAttrSuccessFunc } from "#app/@types/ability-types"; +import type { BattlerIndex } from "#app/battle"; +import type Move from "#app/data/moves/move"; +import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag"; +import { SelectBiomePhase } from "#app/phases/select-biome-phase"; +import { noAbilityTypeOverrideMoves } from "../moves/invalid-moves"; export class BlockRecoilDamageAttr extends AbAttr { constructor() { super(false); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } - getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) { + getTriggerMessage(pokemon: Pokemon, abilityName: string, ..._args: any[]) { return i18next.t("abilityTriggers:blockRecoilDamage", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName: abilityName }); } } @@ -251,10 +105,10 @@ export class DoubleBattleChanceAbAttr extends AbAttr { /** * Increases the chance of a double battle occurring - * @param args [0] {@linkcode Utils.NumberHolder} for double battle chance + * @param args [0] {@linkcode NumberHolder} for double battle chance */ - override apply(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: Utils.BooleanHolder, args: any[]): void { - const doubleBattleChance = args[0] as Utils.NumberHolder; + override apply(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder, args: any[]): void { + const doubleBattleChance = args[0] as NumberHolder; // This is divided because the chance is generated as a number from 0 to doubleBattleChance.value using Utils.randSeedInt // A double battle will initiate if the generated number is 0 doubleBattleChance.value = doubleBattleChance.value / 4; @@ -299,7 +153,7 @@ export class PostTeraFormChangeStatChangeAbAttr extends AbAttr { this.stages = stages; } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder | null, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder | null, args: any[]): void { const statStageChangePhases: StatStageChangePhase[] = []; if (!simulated) { @@ -331,7 +185,7 @@ export class ClearWeatherAbAttr extends AbAttr { return globalScene.arena.canSetWeather(WeatherType.NONE); } - public override apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + public override apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: BooleanHolder, args: any[]): void { if (!simulated) { globalScene.arena.trySetWeather(WeatherType.NONE, pokemon); } @@ -357,7 +211,7 @@ export class ClearTerrainAbAttr extends AbAttr { return globalScene.arena.canSetTerrain(TerrainType.NONE); } - public override apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + public override apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: BooleanHolder, args: any[]): void { if (!simulated) { globalScene.arena.trySetTerrain(TerrainType.NONE, true, pokemon); } @@ -373,7 +227,7 @@ export class PreDefendAbAttr extends AbAttr { simulated: boolean, attacker: Pokemon, move: Move | null, - cancelled: Utils.BooleanHolder | null, + cancelled: BooleanHolder | null, args: any[]): boolean { return true; } @@ -384,19 +238,19 @@ export class PreDefendAbAttr extends AbAttr { simulated: boolean, attacker: Pokemon, move: Move | null, - cancelled: Utils.BooleanHolder | null, + cancelled: BooleanHolder | null, args: any[], ): void {} } export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr { - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move | null, cancelled: BooleanHolder | null, args: any[]): boolean { return pokemon.isFullHp() && pokemon.getMaxHp() > 1 //Checks if pokemon has wonder_guard (which forces 1hp) - && (args[0] as Utils.NumberHolder).value >= pokemon.hp; //Damage >= hp + && (args[0] as NumberHolder).value >= pokemon.hp; //Damage >= hp } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { if (!simulated) { pokemon.addTag(BattlerTagType.STURDY, 1); } @@ -404,7 +258,7 @@ export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr { } export class BlockItemTheftAbAttr extends AbAttr { - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } @@ -422,11 +276,11 @@ export class StabBoostAbAttr extends AbAttr { } override canApply(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - return (args[0] as Utils.NumberHolder).value > 1; + return (args[0] as NumberHolder).value > 1; } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value += 0.5; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value += 0.5; } } @@ -441,12 +295,12 @@ export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr { this.damageMultiplier = damageMultiplier; } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return this.condition(pokemon, attacker, move); } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value = Utils.toDmgValue((args[0] as Utils.NumberHolder).value * this.damageMultiplier); + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value = toDmgValue((args[0] as NumberHolder).value * this.damageMultiplier); } } @@ -465,11 +319,11 @@ export class AlliedFieldDamageReductionAbAttr extends PreDefendAbAttr { /** * Handles the damage reduction * @param args - * - `[0]` {@linkcode Utils.NumberHolder} - The damage being dealt + * - `[0]` {@linkcode NumberHolder} - The damage being dealt */ - override applyPreDefend(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _attacker: Pokemon, _move: Move, _cancelled: Utils.BooleanHolder, args: any[]): void { - const damage = args[0] as Utils.NumberHolder; - damage.value = Utils.toDmgValue(damage.value * this.damageMultiplier); + override applyPreDefend(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _attacker: Pokemon, _move: Move, _cancelled: BooleanHolder, args: any[]): void { + const damage = args[0] as NumberHolder; + damage.value = toDmgValue(damage.value * this.damageMultiplier); } } @@ -496,7 +350,7 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr { this.condition = condition ?? null; } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return ![ MoveTarget.BOTH_SIDES, MoveTarget.ENEMY_SIDE, MoveTarget.USER_SIDE ].includes(move.moveTarget) && attacker !== pokemon && attacker.getMoveType(move) === this.immuneType; } @@ -506,12 +360,12 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr { * @param passive - Whether the ability is passive. * @param attacker {@linkcode Pokemon} The attacking Pokemon. * @param move {@linkcode Move} The attacking move. - * @param cancelled {@linkcode Utils.BooleanHolder} - A holder for a boolean value indicating if the move was cancelled. - * @param args [0] {@linkcode Utils.NumberHolder} gets set to 0 if move is immuned by an ability. + * @param cancelled {@linkcode BooleanHolder} - A holder for a boolean value indicating if the move was cancelled. + * @param args [0] {@linkcode NumberHolder} gets set to 0 if move is immuned by an ability. * @param args [1] - Whether the move is simulated. */ - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value = 0; + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value = 0; } getImmuneType(): PokemonType | null { @@ -528,7 +382,7 @@ export class AttackTypeImmunityAbAttr extends TypeImmunityAbAttr { super(immuneType, condition); } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return move.category !== MoveCategory.STATUS && !move.hasAttr(NeutralDamageAgainstFlyingTypeMultiplierAttr) && super.canApplyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); } @@ -538,7 +392,7 @@ export class AttackTypeImmunityAbAttr extends TypeImmunityAbAttr { * Type immunity abilities that do not give additional benefits (HP recovery, stat boosts, etc) are not immune to status moves of the type * Example: Levitate */ - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { // this is a hacky way to fix the Levitate/Thousand Arrows interaction, but it works for now... super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); } @@ -549,16 +403,16 @@ export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr { super(immuneType); } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return super.canApplyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); if (!pokemon.isFullHp() && !simulated) { const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; globalScene.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(), - Utils.toDmgValue(pokemon.getMaxHp() / 4), i18next.t("abilityTriggers:typeImmunityHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + toDmgValue(pokemon.getMaxHp() / 4), i18next.t("abilityTriggers:typeImmunityHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); cancelled.value = true; // Suppresses "No Effect" message } } @@ -575,11 +429,11 @@ class TypeImmunityStatStageChangeAbAttr extends TypeImmunityAbAttr { this.stages = stages; } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return super.canApplyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); cancelled.value = true; // Suppresses "No Effect" message if (!simulated) { @@ -599,11 +453,11 @@ class TypeImmunityAddBattlerTagAbAttr extends TypeImmunityAbAttr { this.turnCount = turnCount; } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return super.canApplyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); cancelled.value = true; // Suppresses "No Effect" message if (!simulated) { @@ -617,16 +471,16 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { super(null, condition); } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { const modifierValue = args.length > 0 - ? (args[0] as Utils.NumberHolder).value + ? (args[0] as NumberHolder).value : pokemon.getAttackTypeEffectiveness(attacker.getMoveType(move), attacker, undefined, undefined, move); return move instanceof AttackMove && modifierValue < 2; } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; // Suppresses "No Effect" message - (args[0] as Utils.NumberHolder).value = 0; + (args[0] as NumberHolder).value = 0; } getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { @@ -644,9 +498,9 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { */ export class FullHpResistTypeAbAttr extends PreDefendAbAttr { - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move | null, cancelled: BooleanHolder | null, args: any[]): boolean { const typeMultiplier = args[0]; - return (typeMultiplier && typeMultiplier instanceof Utils.NumberHolder) && !(move && move.hasAttr(FixedDamageAttr)) && pokemon.isFullHp() && typeMultiplier.value > 0.5; + return (typeMultiplier && typeMultiplier instanceof NumberHolder) && !(move && move.hasAttr(FixedDamageAttr)) && pokemon.isFullHp() && typeMultiplier.value > 0.5; } /** @@ -665,7 +519,7 @@ export class FullHpResistTypeAbAttr extends PreDefendAbAttr { simulated: boolean, attacker: Pokemon, move: Move | null, - cancelled: Utils.BooleanHolder | null, + cancelled: BooleanHolder | null, args: any[]): void { const typeMultiplier = args[0]; typeMultiplier.value = 0.5; @@ -704,11 +558,11 @@ export class PostDefendAbAttr extends AbAttr { export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr { - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return !(move.moveTarget === MoveTarget.USER || move.moveTarget === MoveTarget.NEAR_ALLY) && move.getPriority(attacker) > 0 && !move.isMultiTarget(); } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -743,11 +597,11 @@ export class MoveImmunityAbAttr extends PreDefendAbAttr { this.immuneCondition = immuneCondition; } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return this.immuneCondition(pokemon, attacker, move); } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } @@ -768,13 +622,13 @@ export class WonderSkinAbAttr extends PreDefendAbAttr { super(false); } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { - const moveAccuracy = args[0] as Utils.NumberHolder; + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { + const moveAccuracy = args[0] as NumberHolder; return move.category === MoveCategory.STATUS && moveAccuracy.value >= 50; } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { - const moveAccuracy = args[0] as Utils.NumberHolder; + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { + const moveAccuracy = args[0] as NumberHolder; moveAccuracy.value = 50; } } @@ -789,11 +643,11 @@ export class MoveImmunityStatStageChangeAbAttr extends MoveImmunityAbAttr { this.stages = stages; } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return !simulated && super.canApplyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); } - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages)); } @@ -805,8 +659,8 @@ export class MoveImmunityStatStageChangeAbAttr extends MoveImmunityAbAttr { */ export class ReverseDrainAbAttr extends PostDefendAbAttr { - override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return move.hasAttr(HitHealAttr) && !move.hitsSubstitute(attacker, pokemon); + override canApplyPostDefend(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _attacker: Pokemon, move: Move, _hitResult: HitResult | null, args: any[]): boolean { + return move.hasAttr(HitHealAttr); } /** @@ -845,7 +699,7 @@ export class PostDefendStatStageChangeAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return this.condition(pokemon, attacker, move) && !move.hitsSubstitute(attacker, pokemon); + return this.condition(pokemon, attacker, move); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { @@ -855,7 +709,7 @@ export class PostDefendStatStageChangeAbAttr extends PostDefendAbAttr { if (this.allOthers) { const ally = pokemon.getAlly(); - const otherPokemon = !Utils.isNullOrUndefined(ally) ? pokemon.getOpponents().concat([ ally ]) : pokemon.getOpponents(); + const otherPokemon = !isNullOrUndefined(ally) ? pokemon.getOpponents().concat([ ally ]) : pokemon.getOpponents(); for (const other of otherPokemon) { globalScene.unshiftPhase(new StatStageChangePhase((other).getBattlerIndex(), false, [ this.stat ], this.stages)); } @@ -886,7 +740,7 @@ export class PostDefendHpGatedStatStageChangeAbAttr extends PostDefendAbAttr { const hpGateFlat: number = Math.ceil(pokemon.getMaxHp() * this.hpGate); const lastAttackReceived = pokemon.turnData.attacksReceived[pokemon.turnData.attacksReceived.length - 1]; const damageReceived = lastAttackReceived?.damage || 0; - return this.condition(pokemon, attacker, move) && (pokemon.hp <= hpGateFlat && (pokemon.hp + damageReceived) > hpGateFlat) && !move.hitsSubstitute(attacker, pokemon); + return this.condition(pokemon, attacker, move) && (pokemon.hp <= hpGateFlat && (pokemon.hp + damageReceived) > hpGateFlat); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { @@ -909,7 +763,7 @@ export class PostDefendApplyArenaTrapTagAbAttr extends PostDefendAbAttr { override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { const tag = globalScene.arena.getTag(this.tagType) as ArenaTrapTag; - return (this.condition(pokemon, attacker, move) && !move.hitsSubstitute(attacker, pokemon)) + return (this.condition(pokemon, attacker, move)) && (!globalScene.arena.getTag(this.tagType) || tag.layers < tag.maxLayers); } @@ -931,7 +785,7 @@ export class PostDefendApplyBattlerTagAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return this.condition(pokemon, attacker, move) && !move.hitsSubstitute(attacker, pokemon); + return this.condition(pokemon, attacker, move); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { @@ -948,7 +802,7 @@ export class PostDefendTypeChangeAbAttr extends PostDefendAbAttr { override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { this.type = attacker.getMoveType(move); const pokemonTypes = pokemon.getTypes(true); - return hitResult < HitResult.NO_EFFECT && !move.hitsSubstitute(attacker, pokemon) && (simulated || pokemonTypes.length !== 1 || pokemonTypes[0] !== this.type); + return hitResult < HitResult.NO_EFFECT && (simulated || pokemonTypes.length !== 1 || pokemonTypes[0] !== this.type); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, _args: any[]): void { @@ -975,7 +829,7 @@ export class PostDefendTerrainChangeAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { - return hitResult < HitResult.NO_EFFECT && !move.hitsSubstitute(attacker, pokemon) && globalScene.arena.canSetTerrain(this.terrainType); + return hitResult < HitResult.NO_EFFECT && globalScene.arena.canSetTerrain(this.terrainType); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, _args: any[]): void { @@ -998,8 +852,8 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr { override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; - return move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.status - && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance) && !move.hitsSubstitute(attacker, pokemon) + return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && !attacker.status + && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance) && attacker.canSetStatus(effect, true, false, pokemon); } @@ -1038,8 +892,8 @@ export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance - && !move.hitsSubstitute(attacker, pokemon) && attacker.canAddTag(this.tagType); + return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && pokemon.randSeedInt(100) < this.chance + && attacker.canAddTag(this.tagType); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { @@ -1060,10 +914,6 @@ export class PostDefendCritStatStageChangeAbAttr extends PostDefendAbAttr { this.stages = stages; } - override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return !move.hitsSubstitute(attacker, pokemon); - } - override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { if (!simulated) { globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages)); @@ -1085,13 +935,13 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return !simulated && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) - && !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !move.hitsSubstitute(attacker, pokemon); + return !simulated && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) + && !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { - attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), { result: HitResult.INDIRECT }); - attacker.turnData.damageTaken += Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)); + attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), { result: HitResult.INDIRECT }); + attacker.turnData.damageTaken += toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)); } override getTriggerMessage(pokemon: Pokemon, abilityName: string, ..._args: any[]): string { @@ -1118,8 +968,7 @@ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !move.hitsSubstitute(attacker, pokemon)) - && !attacker.getTag(BattlerTagType.PERISH_SONG); + return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && !attacker.getTag(BattlerTagType.PERISH_SONG); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { @@ -1146,7 +995,7 @@ export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return (!(this.condition && !this.condition(pokemon, attacker, move) || move.hitsSubstitute(attacker, pokemon)) + return (!(this.condition && !this.condition(pokemon, attacker, move)) && !globalScene.arena.weather?.isImmutable() && globalScene.arena.canSetWeather(this.weatherType)); } @@ -1163,8 +1012,8 @@ export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) - && attacker.getAbility().isSwappable && !move.hitsSubstitute(attacker, pokemon); + return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) + && attacker.getAbility().isSwappable; } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, args: any[]): void { @@ -1189,11 +1038,11 @@ export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && attacker.getAbility().isSuppressable - && !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr) && !move.hitsSubstitute(attacker, pokemon); + return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && attacker.getAbility().isSuppressable + && !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr); } - override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { + override applyPostDefend(_pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { if (!simulated) { attacker.setTempAbility(allAbilities[this.ability]); } @@ -1219,8 +1068,8 @@ export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr { } override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { - return attacker.getTag(BattlerTagType.DISABLED) === null && !move.hitsSubstitute(attacker, pokemon) - && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance); + return attacker.getTag(BattlerTagType.DISABLED) === null + && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { @@ -1292,16 +1141,16 @@ export class MoveEffectChanceMultiplierAbAttr extends AbAttr { override canApply(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const exceptMoves = [ Moves.ORDER_UP, Moves.ELECTRO_SHOT ]; - return !((args[0] as Utils.NumberHolder).value <= 0 || exceptMoves.includes((args[1] as Move).id)); + return !((args[0] as NumberHolder).value <= 0 || exceptMoves.includes((args[1] as Move).id)); } /** - * @param args [0]: {@linkcode Utils.NumberHolder} Move additional effect chance. Has to be higher than or equal to 0. + * @param args [0]: {@linkcode NumberHolder} Move additional effect chance. Has to be higher than or equal to 0. * [1]: {@linkcode Moves } Move used by the ability user. */ - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value *= this.chanceMultiplier; - (args[0] as Utils.NumberHolder).value = Math.min((args[0] as Utils.NumberHolder).value, 100); + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value *= this.chanceMultiplier; + (args[0] as NumberHolder).value = Math.min((args[0] as NumberHolder).value, 100); } } @@ -1315,15 +1164,15 @@ export class IgnoreMoveEffectsAbAttr extends PreDefendAbAttr { super(showAbility); } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { - return (args[0] as Utils.NumberHolder).value > 0; + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move | null, cancelled: BooleanHolder | null, args: any[]): boolean { + return (args[0] as NumberHolder).value > 0; } /** - * @param args [0]: {@linkcode Utils.NumberHolder} Move additional effect chance. + * @param args [0]: {@linkcode NumberHolder} Move additional effect chance. */ - override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value = 0; + override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value = 0; } } @@ -1338,7 +1187,7 @@ export class FieldPreventExplosiveMovesAbAttr extends AbAttr { pokemon: Pokemon, passive: boolean, simulated: boolean, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[], ): void { cancelled.value = true; @@ -1350,7 +1199,7 @@ export class FieldPreventExplosiveMovesAbAttr extends AbAttr { * If this ability cannot stack, a BooleanHolder can be used to prevent this from stacking. * @see {@link applyFieldStatMultiplierAbAttrs} * @see {@link applyFieldStat} - * @see {@link Utils.BooleanHolder} + * @see {@link BooleanHolder} */ export class FieldMultiplyStatAbAttr extends AbAttr { private stat: Stat; @@ -1365,7 +1214,7 @@ export class FieldMultiplyStatAbAttr extends AbAttr { this.canStack = canStack; } - canApplyFieldStat(pokemon: Pokemon, passive: boolean, simulated: boolean, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, args: any[]): boolean { + canApplyFieldStat(pokemon: Pokemon, passive: boolean, simulated: boolean, stat: Stat, statValue: NumberHolder, checkedPokemon: Pokemon, hasApplied: BooleanHolder, args: any[]): boolean { return this.canStack || !hasApplied.value && this.stat === stat && checkedPokemon.getAbilityAttrs(FieldMultiplyStatAbAttr).every(attr => (attr as FieldMultiplyStatAbAttr).stat !== stat); } @@ -1375,12 +1224,12 @@ export class FieldMultiplyStatAbAttr extends AbAttr { * @param pokemon {@linkcode Pokemon} the Pokemon using this ability * @param passive {@linkcode boolean} unused * @param stat {@linkcode Stat} the type of the checked stat - * @param statValue {@linkcode Utils.NumberHolder} the value of the checked stat + * @param statValue {@linkcode NumberHolder} the value of the checked stat * @param checkedPokemon {@linkcode Pokemon} the Pokemon this ability is targeting - * @param hasApplied {@linkcode Utils.BooleanHolder} whether or not another multiplier has been applied to this stat + * @param hasApplied {@linkcode BooleanHolder} whether or not another multiplier has been applied to this stat * @param args {any[]} unused */ - applyFieldStat(pokemon: Pokemon, passive: boolean, simulated: boolean, stat: Stat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, hasApplied: Utils.BooleanHolder, args: any[]): void { + applyFieldStat(pokemon: Pokemon, passive: boolean, simulated: boolean, stat: Stat, statValue: NumberHolder, checkedPokemon: Pokemon, hasApplied: BooleanHolder, args: any[]): void { statValue.value *= this.multiplier; hasApplied.value = true; } @@ -1396,16 +1245,43 @@ export class MoveTypeChangeAbAttr extends PreAttackAbAttr { super(false); } - override canApplyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon | null, move: Move, args: any[]): boolean { - return (this.condition && this.condition(pokemon, defender, move)) ?? false; + /** + * Determine if the move type change attribute can be applied + * + * Can be applied if: + * - The ability's condition is met, e.g. pixilate only boosts normal moves, + * - The move is not forbidden from having its type changed by an ability, e.g. {@linkcode Moves.MULTI_ATTACK} + * - The user is not terastallized and using tera blast + * - The user is not a terastallized terapagos with tera stellar using tera starstorm + * @param pokemon - The pokemon that has the move type changing ability and is using the attacking move + * @param _passive - Unused + * @param _simulated - Unused + * @param _defender - The pokemon being attacked (unused) + * @param move - The move being used + * @param _args - args[0] holds the type that the move is changed to, args[1] holds the multiplier + * @returns whether the move type change attribute can be applied + */ + override canApplyPreAttack(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _defender: Pokemon | null, move: Move, _args: [NumberHolder?, NumberHolder?, ...any]): boolean { + return (!this.condition || this.condition(pokemon, _defender, move)) && + !noAbilityTypeOverrideMoves.has(move.id) && + (!pokemon.isTerastallized || + (move.id !== Moves.TERA_BLAST && + (move.id !== Moves.TERA_STARSTORM || pokemon.getTeraType() !== PokemonType.STELLAR || !pokemon.hasSpecies(Species.TERAPAGOS)))); } - // TODO: Decouple this into two attributes (type change / power boost) - override applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): void { - if (args[0] && args[0] instanceof Utils.NumberHolder) { + /** + * @param pokemon - The pokemon that has the move type changing ability and is using the attacking move + * @param passive - Unused + * @param simulated - Unused + * @param defender - The pokemon being attacked (unused) + * @param move - The move being used + * @param args - args[0] holds the type that the move is changed to, args[1] holds the multiplier + */ + override applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: [NumberHolder?, NumberHolder?, ...any]): void { + if (args[0] && args[0] instanceof NumberHolder) { args[0].value = this.newType; } - if (args[1] && args[1] instanceof Utils.NumberHolder) { + if (args[1] && args[1] instanceof NumberHolder) { args[1].value *= this.powerMultiplier; } } @@ -1483,12 +1359,12 @@ export class AddSecondStrikeAbAttr extends PreAttackAbAttr { * @param defender n/a * @param move the {@linkcode Move} used by the ability source * @param args Additional arguments: - * - `[0]` the number of strikes this move currently has ({@linkcode Utils.NumberHolder}) - * - `[1]` the damage multiplier for the current strike ({@linkcode Utils.NumberHolder}) + * - `[0]` the number of strikes this move currently has ({@linkcode NumberHolder}) + * - `[1]` the damage multiplier for the current strike ({@linkcode NumberHolder}) */ override applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): void { - const hitCount = args[0] as Utils.NumberHolder; - const multiplier = args[1] as Utils.NumberHolder; + const hitCount = args[0] as NumberHolder; + const multiplier = args[1] as NumberHolder; if (hitCount?.value) { hitCount.value += 1; } @@ -1528,8 +1404,8 @@ export class DamageBoostAbAttr extends PreAttackAbAttr { * @param args Utils.NumberHolder as damage */ override applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): void { - const power = args[0] as Utils.NumberHolder; - power.value = Utils.toDmgValue(power.value * this.damageMultiplier); + const power = args[0] as NumberHolder; + power.value = toDmgValue(power.value * this.damageMultiplier); } } @@ -1548,7 +1424,7 @@ export class MovePowerBoostAbAttr extends VariableMovePowerAbAttr { } override applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): void { - (args[0] as Utils.NumberHolder).value *= this.powerMultiplier; + (args[0] as NumberHolder).value *= this.powerMultiplier; } } @@ -1591,7 +1467,7 @@ export class VariableMovePowerBoostAbAttr extends VariableMovePowerAbAttr { override applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): void { const multiplier = this.mult(pokemon, defender, move); - (args[0] as Utils.NumberHolder).value *= multiplier; + (args[0] as NumberHolder).value *= multiplier; } } @@ -1620,7 +1496,7 @@ export class FieldMovePowerBoostAbAttr extends AbAttr { applyPreAttack(pokemon: Pokemon | null, passive: boolean | null, simulated: boolean, defender: Pokemon | null, move: Move, args: any[]): void { if (this.condition(pokemon, defender, move)) { - (args[0] as Utils.NumberHolder).value *= this.powerMultiplier; + (args[0] as NumberHolder).value *= this.powerMultiplier; } } } @@ -1683,7 +1559,7 @@ export class StatMultiplierAbAttr extends AbAttr { _passive: boolean, simulated: boolean, stat: BattleStat, - statValue: Utils.NumberHolder, + statValue: NumberHolder, args: any[]): boolean { const move = (args[0] as Move); return stat === this.stat && (!this.condition || this.condition(pokemon, null, move)); @@ -1694,7 +1570,7 @@ export class StatMultiplierAbAttr extends AbAttr { _passive: boolean, simulated: boolean, stat: BattleStat, - statValue: Utils.NumberHolder, + statValue: NumberHolder, args: any[]): void { statValue.value *= this.multiplier; } @@ -1767,13 +1643,13 @@ export class AllyStatMultiplierAbAttr extends AbAttr { * @param passive - unused * @param _simulated - Whether the ability is being simulated (unused) * @param _stat - The type of the checked {@linkcode Stat} (unused) - * @param statValue - {@linkcode Utils.NumberHolder} containing the value of the checked stat + * @param statValue - {@linkcode NumberHolder} containing the value of the checked stat * @param _checkedPokemon - The {@linkcode Pokemon} this ability is targeting (unused) * @param _ignoreAbility - Whether the ability should be ignored if possible * @param _args - unused * @returns `true` if this changed the checked stat, `false` otherwise. */ - applyAllyStat(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _stat: BattleStat, statValue: Utils.NumberHolder, _checkedPokemon: Pokemon, _ignoreAbility: boolean, _args: any[]) { + applyAllyStat(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _stat: BattleStat, statValue: NumberHolder, _checkedPokemon: Pokemon, _ignoreAbility: boolean, _args: any[]) { statValue.value *= this.multiplier; } @@ -1783,13 +1659,13 @@ export class AllyStatMultiplierAbAttr extends AbAttr { * @param passive - unused * @param simulated - Whether the ability is being simulated (unused) * @param stat - The type of the checked {@linkcode Stat} - * @param statValue - {@linkcode Utils.NumberHolder} containing the value of the checked stat + * @param statValue - {@linkcode NumberHolder} containing the value of the checked stat * @param checkedPokemon - The {@linkcode Pokemon} this ability is targeting (unused) * @param ignoreAbility - Whether the ability should be ignored if possible * @param args - unused * @returns `true` if this can apply to the checked stat, `false` otherwise. */ - canApplyAllyStat(pokemon: Pokemon, _passive: boolean, simulated: boolean, stat: BattleStat, statValue: Utils.NumberHolder, checkedPokemon: Pokemon, ignoreAbility: boolean, args: any[]): boolean { + canApplyAllyStat(pokemon: Pokemon, _passive: boolean, simulated: boolean, stat: BattleStat, statValue: NumberHolder, checkedPokemon: Pokemon, ignoreAbility: boolean, args: any[]): boolean { return stat === this.stat && !(ignoreAbility && this.ignorable); } } @@ -1923,9 +1799,8 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr { override canApplyPostAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { if ( super.canApplyPostAttack(pokemon, passive, simulated, attacker, move, hitResult, args) - && !(pokemon !== attacker && move.hitsSubstitute(attacker, pokemon)) && (simulated || !attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker - && (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) + && (!this.contactRequired || move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) ) { const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; return simulated || attacker.canSetStatus(effect, true, false, pokemon); @@ -1964,7 +1839,7 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr { /**Battler tags inflicted by abilities post attacking are also considered additional effects.*/ return super.canApplyPostAttack(pokemon, passive, simulated, attacker, move, hitResult, args) && !attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && - (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && + (!this.contactRequired || move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})) && pokemon.randSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status; } @@ -1990,8 +1865,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { if ( !simulated && hitResult < HitResult.NO_EFFECT && - (!this.condition || this.condition(pokemon, attacker, move)) && - !move.hitsSubstitute(attacker, pokemon) + (!this.condition || this.condition(pokemon, attacker, move)) ) { const heldItems = this.getTargetHeldItems(attacker).filter((i) => i.isTransferable); if (heldItems.length) { @@ -2221,8 +2095,8 @@ export class IgnoreOpponentStatStagesAbAttr extends AbAttr { * @param _cancelled n/a * @param args A BooleanHolder that represents whether or not to ignore a stat's stat changes */ - override apply(_pokemon: Pokemon, _passive: boolean, simulated: boolean, _cancelled: Utils.BooleanHolder, args: any[]): void { - (args[1] as Utils.BooleanHolder).value = true; + override apply(_pokemon: Pokemon, _passive: boolean, simulated: boolean, _cancelled: BooleanHolder, args: any[]): void { + (args[1] as BooleanHolder).value = true; } } @@ -2231,7 +2105,7 @@ export class IntimidateImmunityAbAttr extends AbAttr { super(false); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } @@ -2255,7 +2129,7 @@ export class PostIntimidateStatStageChangeAbAttr extends AbAttr { this.overwrites = !!overwrites; } - override apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: BooleanHolder, args: any[]): void { if (!simulated) { globalScene.pushPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), false, this.stats, this.stages)); } @@ -2296,6 +2170,11 @@ export class PostSummonAbAttr extends AbAttr { applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {} } +/** + * Base class for ability attributes which remove an effect on summon + */ +export class PostSummonRemoveEffectAbAttr extends PostSummonAbAttr {} + /** * Removes specified arena tags when a Pokemon is summoned. */ @@ -2406,6 +2285,31 @@ export class PostSummonAddBattlerTagAbAttr extends PostSummonAbAttr { } } +/** + * Removes Specific battler tags when a Pokemon is summoned + * + * This should realistically only ever activate on gain rather than on summon + */ +export class PostSummonRemoveBattlerTagAbAttr extends PostSummonRemoveEffectAbAttr { + private immuneTags: BattlerTagType[]; + + /** + * @param immuneTags - The {@linkcode BattlerTagType | battler tags} the Pokémon is immune to. + */ + constructor(...immuneTags: BattlerTagType[]) { + super(); + this.immuneTags = immuneTags; + } + + public override canApplyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + return this.immuneTags.some(tagType => !!pokemon.getTag(tagType)); + } + + public override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { + this.immuneTags.forEach(tagType => pokemon.removeTag(tagType)); + } +} + export class PostSummonStatStageChangeAbAttr extends PostSummonAbAttr { private stats: BattleStat[]; private stages: number; @@ -2432,7 +2336,7 @@ export class PostSummonStatStageChangeAbAttr extends PostSummonAbAttr { globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages)); } else { for (const opponent of pokemon.getOpponents()) { - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); if (this.intimidate) { applyAbAttrs(IntimidateImmunityAbAttr, opponent, cancelled, simulated); applyAbAttrs(PostIntimidateStatStageChangeAbAttr, opponent, cancelled, simulated); @@ -2466,9 +2370,9 @@ export class PostSummonAllyHealAbAttr extends PostSummonAbAttr { override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { const target = pokemon.getAlly(); - if (!simulated && !Utils.isNullOrUndefined(target)) { + if (!simulated && !isNullOrUndefined(target)) { globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(), - Utils.toDmgValue(pokemon.getMaxHp() / this.healRatio), i18next.t("abilityTriggers:postSummonAllyHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(target), pokemonName: pokemon.name }), true, !this.showAnim)); + toDmgValue(pokemon.getMaxHp() / this.healRatio), i18next.t("abilityTriggers:postSummonAllyHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(target), pokemonName: pokemon.name }), true, !this.showAnim)); } } } @@ -2492,7 +2396,7 @@ export class PostSummonClearAllyStatStagesAbAttr extends PostSummonAbAttr { override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { const target = pokemon.getAlly(); - if (!simulated && !Utils.isNullOrUndefined(target)) { + if (!simulated && !isNullOrUndefined(target)) { for (const s of BATTLE_STATS) { target.setStatStage(s, 0); } @@ -2593,6 +2497,43 @@ export class PostSummonTerrainChangeAbAttr extends PostSummonAbAttr { } } +/** + * Heals a status effect if the Pokemon is afflicted with it upon switch in (or gain) + */ +export class PostSummonHealStatusAbAttr extends PostSummonRemoveEffectAbAttr { + private immuneEffects: StatusEffect[]; + private statusHealed: StatusEffect; + + /** + * @param immuneEffects - The {@linkcode StatusEffect}s the Pokémon is immune to. + */ + constructor(...immuneEffects: StatusEffect[]) { + super(); + this.immuneEffects = immuneEffects; + } + + public override canApplyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { + const status = pokemon.status?.effect; + return !isNullOrUndefined(status) && (this.immuneEffects.length < 1 || this.immuneEffects.includes(status)) + } + + public override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { + const status = pokemon.status?.effect; + if (!isNullOrUndefined(status)) { + this.statusHealed = status; + pokemon.resetStatus(false); + pokemon.updateInfo(); + } + } + + public override getTriggerMessage(_pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null { + if (this.statusHealed) { + return getStatusEffectHealText(this.statusHealed, getPokemonNameWithAffix(_pokemon)); + } + return null; + } +} + export class PostSummonFormChangeAbAttr extends PostSummonAbAttr { private formFunc: (p: Pokemon) => number; @@ -2626,7 +2567,7 @@ export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr { let target: Pokemon; if (targets.length > 1) { - globalScene.executeWithSeedOffset(() => target = Utils.randSeedItem(targets), globalScene.currentBattle.waveIndex); + globalScene.executeWithSeedOffset(() => target = randSeedItem(targets), globalScene.currentBattle.waveIndex); } else { target = targets[0]; } @@ -2713,7 +2654,7 @@ export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr { } const ally = pokemon.getAlly(); - if (Utils.isNullOrUndefined(ally) || ally.getStatStages().every(s => s === 0)) { + if (isNullOrUndefined(ally) || ally.getStatStages().every(s => s === 0)) { return false; } @@ -2722,7 +2663,7 @@ export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr { override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { const ally = pokemon.getAlly(); - if (!simulated && !Utils.isNullOrUndefined(ally)) { + if (!simulated && !isNullOrUndefined(ally)) { for (const s of BATTLE_STATS) { pokemon.setStatStage(s, ally.getStatStage(s)); } @@ -2739,7 +2680,7 @@ export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr { } /** - * Used by Imposter + * Attribute used by {@linkcode Abilities.IMPOSTER} to transform into a random opposing pokemon on entry. */ export class PostSummonTransformAbAttr extends PostSummonAbAttr { constructor() { @@ -2747,7 +2688,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { } private getTarget(targets: Pokemon[]): Pokemon { - let target: Pokemon; + let target: Pokemon = targets[0]; if (targets.length > 1) { globalScene.executeWithSeedOffset(() => { // in a double battle, if one of the opposing pokemon is fused the other one will be chosen @@ -2759,11 +2700,12 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { target = targets[0]; return; } - target = Utils.randSeedItem(targets); + target = randSeedItem(targets); }, globalScene.currentBattle.waveIndex); } else { target = targets[0]; } + target = target!; return target; @@ -2771,6 +2713,12 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { override canApplyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const targets = pokemon.getOpponents(); + const target = this.getTarget(targets); + + if (target.summonData.illusion) { + return false; + } + if (simulated || !targets.length) { return simulated; } @@ -2868,7 +2816,7 @@ export class CommanderAbAttr extends AbAttr { // TODO: Should this work with X + Dondozo fusions? const ally = pokemon.getAlly(); - return globalScene.currentBattle?.double && !Utils.isNullOrUndefined(ally) && ally.species.speciesId === Species.DONDOZO + return globalScene.currentBattle?.double && !isNullOrUndefined(ally) && ally.species.speciesId === Species.DONDOZO && !(ally.isFainted() || ally.getTag(BattlerTagType.COMMANDED)); } @@ -2904,7 +2852,7 @@ export class PreSwitchOutResetStatusAbAttr extends PreSwitchOutAbAttr { } override canApplyPreSwitchOut(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - return !Utils.isNullOrUndefined(pokemon.status); + return !isNullOrUndefined(pokemon.status); } override applyPreSwitchOut(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { @@ -2986,7 +2934,7 @@ export class PreSwitchOutHealAbAttr extends PreSwitchOutAbAttr { override applyPreSwitchOut(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { if (!simulated) { - const healAmount = Utils.toDmgValue(pokemon.getMaxHp() * 0.33); + const healAmount = toDmgValue(pokemon.getMaxHp() * 0.33); pokemon.heal(healAmount); pokemon.updateInfo(); } @@ -3100,7 +3048,7 @@ export class PreStatStageChangeAbAttr extends AbAttr { passive: boolean, simulated: boolean, stat: BattleStat, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[]): boolean { return true; } @@ -3110,7 +3058,7 @@ export class PreStatStageChangeAbAttr extends AbAttr { passive: boolean, simulated: boolean, stat: BattleStat, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[], ): void {} } @@ -3129,10 +3077,10 @@ export class ReflectStatStageChangeAbAttr extends PreStatStageChangeAbAttr { * @param _passive N/A * @param simulated `true` if the ability is being simulated by the AI * @param stat the {@linkcode BattleStat} being affected - * @param cancelled The {@linkcode Utils.BooleanHolder} that will be set to true due to reflection + * @param cancelled The {@linkcode BooleanHolder} that will be set to true due to reflection * @param args */ - override applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, simulated: boolean, stat: BattleStat, cancelled: BooleanHolder, args: any[]): void { const attacker: Pokemon = args[0]; const stages = args[1]; this.reflectedStat = stat; @@ -3164,8 +3112,8 @@ export class ProtectStatAbAttr extends PreStatStageChangeAbAttr { this.protectedStat = protectedStat; } - override canApplyPreStatStageChange(pokemon: Pokemon | null, passive: boolean, simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean { - return Utils.isNullOrUndefined(this.protectedStat) || stat === this.protectedStat; + override canApplyPreStatStageChange(pokemon: Pokemon | null, passive: boolean, simulated: boolean, stat: BattleStat, cancelled: BooleanHolder, args: any[]): boolean { + return isNullOrUndefined(this.protectedStat) || stat === this.protectedStat; } /** @@ -3174,10 +3122,10 @@ export class ProtectStatAbAttr extends PreStatStageChangeAbAttr { * @param _passive * @param simulated * @param stat the {@linkcode BattleStat} being affected - * @param cancelled The {@linkcode Utils.BooleanHolder} that will be set to true if the stat is protected + * @param cancelled The {@linkcode BooleanHolder} that will be set to true if the stat is protected * @param _args */ - override applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, _args: any[]): void { + override applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, stat: BattleStat, cancelled: BooleanHolder, _args: any[]): void { cancelled.value = true; } @@ -3236,7 +3184,7 @@ export class PreSetStatusAbAttr extends AbAttr { passive: boolean, simulated: boolean, effect: StatusEffect | undefined, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[]): boolean { return true; } @@ -3246,7 +3194,7 @@ export class PreSetStatusAbAttr extends AbAttr { passive: boolean, simulated: boolean, effect: StatusEffect | undefined, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[], ): void {} } @@ -3256,6 +3204,7 @@ export class PreSetStatusAbAttr extends AbAttr { */ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr { protected immuneEffects: StatusEffect[]; + private lastEffect: StatusEffect; /** * @param immuneEffects - The status effects to which the Pokémon is immune. @@ -3266,7 +3215,7 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr { this.immuneEffects = immuneEffects; } - override canApplyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean { + override canApplyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect, cancelled: BooleanHolder, args: any[]): boolean { return effect !== StatusEffect.FAINT && this.immuneEffects.length < 1 || this.immuneEffects.includes(effect); } @@ -3279,8 +3228,9 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr { * @param cancelled - A holder for a boolean value indicating if the status application was cancelled. * @param args - n/a */ - override applyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; + this.lastEffect = effect; } getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { @@ -3288,7 +3238,7 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr { i18next.t("abilityTriggers:statusEffectImmunityWithName", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName, - statusEffectName: getStatusEffectDescriptor(args[0] as StatusEffect) + statusEffectName: getStatusEffectDescriptor(this.lastEffect) }) : i18next.t("abilityTriggers:statusEffectImmunity", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), @@ -3334,7 +3284,7 @@ export class ConditionalUserFieldStatusEffectImmunityAbAttr extends UserFieldSta * @param args `Args[0]` is the target of the status effect, `Args[1]` is the source. * @returns Whether the ability can be applied to cancel the status effect. */ - override canApplyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: [Pokemon, Pokemon | null, ...any]): boolean { + override canApplyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect, cancelled: BooleanHolder, args: [Pokemon, Pokemon | null, ...any]): boolean { return (!cancelled.value && effect !== StatusEffect.FAINT && this.immuneEffects.length < 1 || this.immuneEffects.includes(effect)) && this.condition(args[0], args[1]); } @@ -3347,13 +3297,13 @@ export class ConditionalUserFieldStatusEffectImmunityAbAttr extends UserFieldSta /** * Conditionally provides immunity to stat drop effects to the user's field. - * + * * Used by {@linkcode Abilities.FLOWER_VEIL | Flower Veil}. */ export class ConditionalUserFieldProtectStatAbAttr extends PreStatStageChangeAbAttr { /** {@linkcode BattleStat} to protect or `undefined` if **all** {@linkcode BattleStat} are protected */ protected protectedStat?: BattleStat; - + /** If the method evaluates to true, the stat will be protected. */ protected condition: (target: Pokemon) => boolean; @@ -3370,14 +3320,14 @@ export class ConditionalUserFieldProtectStatAbAttr extends PreStatStageChangeAbA * @param stat The stat being affected * @param cancelled Holds whether the stat change was already prevented. * @param args Args[0] is the target pokemon of the stat change. - * @returns + * @returns */ - override canApplyPreStatStageChange(pokemon: Pokemon, passive: boolean, simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: [Pokemon, ...any]): boolean { + override canApplyPreStatStageChange(pokemon: Pokemon, passive: boolean, simulated: boolean, stat: BattleStat, cancelled: BooleanHolder, args: [Pokemon, ...any]): boolean { const target = args[0]; if (!target) { return false; } - return !cancelled.value && (Utils.isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) && this.condition(target); + return !cancelled.value && (isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) && this.condition(target); } /** @@ -3389,7 +3339,7 @@ export class ConditionalUserFieldProtectStatAbAttr extends PreStatStageChangeAbA * @param cancelled Will be set to true if the stat change is prevented * @param _args unused */ - override applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _stat: BattleStat, cancelled: Utils.BooleanHolder, _args: any[]): void { + override applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _stat: BattleStat, cancelled: BooleanHolder, _args: any[]): void { cancelled.value = true; } } @@ -3401,7 +3351,7 @@ export class PreApplyBattlerTagAbAttr extends AbAttr { passive: boolean, simulated: boolean, tag: BattlerTag, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[], ): boolean { return true; @@ -3412,7 +3362,7 @@ export class PreApplyBattlerTagAbAttr extends AbAttr { passive: boolean, simulated: boolean, tag: BattlerTag, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[], ): void {} } @@ -3430,13 +3380,13 @@ export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr { this.immuneTagTypes = Array.isArray(immuneTagTypes) ? immuneTagTypes : [ immuneTagTypes ]; } - override canApplyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean { + override canApplyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: BooleanHolder, args: any[]): boolean { this.battlerTag = tag; return !cancelled.value && this.immuneTagTypes.includes(tag.tagType); } - override applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } @@ -3474,7 +3424,7 @@ export class ConditionalUserFieldBattlerTagImmunityAbAttr extends UserFieldBattl * @param args Args[0] is the target that the tag is attempting to be applied to * @returns Whether the ability can be used to cancel the battler tag */ - override canApplyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: [Pokemon, ...any]): boolean { + override canApplyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: BooleanHolder, args: [Pokemon, ...any]): boolean { return super.canApplyPreApplyBattlerTag(pokemon, passive, simulated, tag, cancelled, args) && this.condition(args[0]); } @@ -3490,8 +3440,12 @@ export class BlockCritAbAttr extends AbAttr { super(false); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.BooleanHolder).value = true; + /** + * Apply the block crit ability by setting the value in the provided boolean holder to false + * @param args - [0] is a boolean holder representing whether the attack can crit + */ + override apply(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder, args: [BooleanHolder, ...any]): void { + (args[0]).value = false; } } @@ -3499,8 +3453,18 @@ export class BonusCritAbAttr extends AbAttr { constructor() { super(false); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.BooleanHolder).value = true; + + /** + * Apply the bonus crit ability by increasing the value in the provided number holder by 1 + * + * @param pokemon The pokemon with the BonusCrit ability (unused) + * @param passive Unused + * @param simulated Unused + * @param cancelled Unused + * @param args Args[0] is a number holder containing the crit stage. + */ + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: [NumberHolder, ...any]): void { + (args[0] as NumberHolder).value += 1; } } @@ -3514,12 +3478,12 @@ export class MultCritAbAttr extends AbAttr { } override canApply(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - const critMult = args[0] as Utils.NumberHolder; + const critMult = args[0] as NumberHolder; return critMult.value > 1; } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - const critMult = args[0] as Utils.NumberHolder; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + const critMult = args[0] as NumberHolder; critMult.value *= this.multAmount; } } @@ -3546,12 +3510,12 @@ export class ConditionalCritAbAttr extends AbAttr { /** * @param pokemon {@linkcode Pokemon} user. - * @param args [0] {@linkcode Utils.BooleanHolder} If true critical hit is guaranteed. + * @param args [0] {@linkcode BooleanHolder} If true critical hit is guaranteed. * [1] {@linkcode Pokemon} Target. * [2] {@linkcode Move} used by ability user. */ - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.BooleanHolder).value = true; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[0] as BooleanHolder).value = true; } } @@ -3560,7 +3524,7 @@ export class BlockNonDirectDamageAbAttr extends AbAttr { super(false); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -3590,16 +3554,16 @@ export class BlockStatusDamageAbAttr extends AbAttr { /** * @param {Pokemon} pokemon The pokemon with the ability * @param {boolean} passive N/A - * @param {Utils.BooleanHolder} cancelled Whether to cancel the status damage + * @param {BooleanHolder} cancelled Whether to cancel the status damage * @param {any[]} args N/A */ - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } export class BlockOneHitKOAbAttr extends AbAttr { - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -3628,8 +3592,8 @@ export class ChangeMovePriorityAbAttr extends AbAttr { return this.moveFunc(pokemon, args[0] as Move); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[1] as Utils.NumberHolder).value += this.changeAmount; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[1] as NumberHolder).value += this.changeAmount; } } @@ -3641,17 +3605,17 @@ export class PreWeatherEffectAbAttr extends AbAttr { passive: Boolean, simulated: boolean, weather: Weather | null, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[]): boolean { return true; } - + applyPreWeatherEffect( pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather | null, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[], ): void {} } @@ -3667,11 +3631,11 @@ export class BlockWeatherDamageAttr extends PreWeatherDamageAbAttr { this.weatherTypes = weatherTypes; } - override canApplyPreWeatherEffect(pokemon: Pokemon, passive: Boolean, simulated: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { + override canApplyPreWeatherEffect(pokemon: Pokemon, passive: Boolean, simulated: boolean, weather: Weather, cancelled: BooleanHolder, args: any[]): boolean { return !this.weatherTypes.length || this.weatherTypes.indexOf(weather?.weatherType) > -1; } - override applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -3685,11 +3649,11 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr { this.affectsImmutable = !!affectsImmutable; } - override canApplyPreWeatherEffect(pokemon: Pokemon, passive: Boolean, simulated: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { + override canApplyPreWeatherEffect(pokemon: Pokemon, passive: Boolean, simulated: boolean, weather: Weather, cancelled: BooleanHolder, args: any[]): boolean { return this.affectsImmutable || weather.isImmutable(); } - override applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -3698,14 +3662,10 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr { * Condition function to applied to abilities related to Sheer Force. * Checks if last move used against target was affected by a Sheer Force user and: * Disables: Color Change, Pickpocket, Berserk, Anger Shell - * @returns {AbAttrCondition} If false disables the ability which the condition is applied to. + * @returns An {@linkcode AbAttrCondition} to disable the ability under the proper conditions. */ function getSheerForceHitDisableAbCondition(): AbAttrCondition { return (pokemon: Pokemon) => { - if (!pokemon.turnData) { - return true; - } - const lastReceivedAttack = pokemon.turnData.attacksReceived[0]; if (!lastReceivedAttack) { return true; @@ -3716,7 +3676,7 @@ function getSheerForceHitDisableAbCondition(): AbAttrCondition { return true; } - /**if the last move chance is greater than or equal to cero, and the last attacker's ability is sheer force*/ + /** `true` if the last move's chance is above 0 and the last attacker's ability is sheer force */ const SheerForceAffected = allMoves[lastReceivedAttack.move].chance >= 0 && lastAttacker.hasAbility(Abilities.SHEER_FORCE); return !SheerForceAffected; @@ -3786,7 +3746,7 @@ function getAnticipationCondition(): AbAttrCondition { */ function getOncePerBattleCondition(ability: Abilities): AbAttrCondition { return (pokemon: Pokemon) => { - return !pokemon.battleData?.abilitiesApplied.includes(ability); + return !pokemon.waveData.abilitiesApplied.has(ability); }; } @@ -3966,7 +3926,7 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr { const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; if (!simulated) { globalScene.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(), - Utils.toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)), i18next.t("abilityTriggers:postWeatherLapseHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)), i18next.t("abilityTriggers:postWeatherLapseHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); } } } @@ -3988,7 +3948,7 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr { if (!simulated) { const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; globalScene.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName })); - pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / (16 / this.damageFactor)), { result: HitResult.INDIRECT }); + pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / (16 / this.damageFactor)), { result: HitResult.INDIRECT }); } } } @@ -4056,7 +4016,7 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr { } override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - return !Utils.isNullOrUndefined(pokemon.status) && this.effects.includes(pokemon.status.effect) && !pokemon.isFullHp(); + return !isNullOrUndefined(pokemon.status) && this.effects.includes(pokemon.status.effect) && !pokemon.isFullHp(); } /** @@ -4068,14 +4028,14 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr { if (!simulated) { const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; globalScene.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(), - Utils.toDmgValue(pokemon.getMaxHp() / 8), i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }), true)); + toDmgValue(pokemon.getMaxHp() / 8), i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }), true)); } } } /** * After the turn ends, resets the status of either the ability holder or their ally - * @param {boolean} allyTarget Whether to target ally, defaults to false (self-target) + * @param allyTarget Whether to target ally, defaults to false (self-target) */ export class PostTurnResetStatusAbAttr extends PostTurnAbAttr { private allyTarget: boolean; @@ -4092,7 +4052,9 @@ export class PostTurnResetStatusAbAttr extends PostTurnAbAttr { } else { this.target = pokemon; } - return !Utils.isNullOrUndefined(this.target?.status); + + const effect = this.target?.status?.effect; + return !!effect && effect !== StatusEffect.FAINT; } override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { @@ -4105,79 +4067,153 @@ export class PostTurnResetStatusAbAttr extends PostTurnAbAttr { } /** - * After the turn ends, try to create an extra item + * Attribute to try and restore eaten berries after the turn ends. + * Used by {@linkcode Abilities.HARVEST}. */ -export class PostTurnLootAbAttr extends PostTurnAbAttr { +export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr { /** - * @param itemType - The type of item to create - * @param procChance - Chance to create an item - * @see {@linkcode applyPostTurn()} + * Array containing all {@linkcode BerryType | BerryTypes} that are under cap and able to be restored. + * Stored inside the class for a minor performance boost + */ + private berriesUnderCap: BerryType[] + + /** + * @param procChance - function providing chance to restore an item + * @see {@linkcode createEatenBerry()} */ constructor( - /** Extend itemType to add more options */ - private itemType: "EATEN_BERRIES" | "HELD_BERRIES", private procChance: (pokemon: Pokemon) => number ) { super(); } - override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - // Clamp procChance to [0, 1]. Skip if didn't proc (less than pass) - const pass = Phaser.Math.RND.realInRange(0, 1); - return !(Math.max(Math.min(this.procChance(pokemon), 1), 0) < pass) && this.itemType === "EATEN_BERRIES" && !!pokemon.battleData.berriesEaten; - } + override canApplyPostTurn(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean { + // Ensure we have at least 1 recoverable berry (at least 1 berry in berriesEaten is not capped) + const cappedBerries = new Set( + globalScene.getModifiers(BerryModifier, pokemon.isPlayer()).filter( + bm => bm.pokemonId === pokemon.id && bm.getCountUnderMax() < 1 + ).map(bm => bm.berryType) + ); - override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { - this.createEatenBerry(pokemon, simulated); - } + this.berriesUnderCap = pokemon.battleData.berriesEaten.filter( + bt => !cappedBerries.has(bt) + ); - /** - * Create a new berry chosen randomly from the berries the pokemon ate this battle - * @param pokemon The pokemon with this ability - * @param simulated whether the associated ability call is simulated - * @returns whether a new berry was created - */ - createEatenBerry(pokemon: Pokemon, simulated: boolean): boolean { - const berriesEaten = pokemon.battleData.berriesEaten; - - if (!berriesEaten.length) { + if (!this.berriesUnderCap.length) { return false; } - if (simulated) { - return true; + // Clamp procChance to [0, 1]. Skip if didn't proc (less than pass) + const pass = Phaser.Math.RND.realInRange(0, 1); + return Phaser.Math.Clamp(this.procChance(pokemon), 0, 1) >= pass; + } + + override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { + if (!simulated) { + this.createEatenBerry(pokemon); } + } - const randomIdx = Utils.randSeedInt(berriesEaten.length); - const chosenBerryType = berriesEaten[randomIdx]; + /** + * Create a new berry chosen randomly from all berries the pokemon ate this battle + * @param pokemon - The {@linkcode Pokemon} with this ability + * @returns `true` if a new berry was created + */ + createEatenBerry(pokemon: Pokemon): boolean { + // Pick a random available berry to yoink + const randomIdx = randSeedInt(this.berriesUnderCap.length); + const chosenBerryType = this.berriesUnderCap[randomIdx]; + pokemon.battleData.berriesEaten.splice(randomIdx, 1); // Remove berry from memory const chosenBerry = new BerryModifierType(chosenBerryType); - berriesEaten.splice(randomIdx); // Remove berry from memory + // Add the randomly chosen berry or update the existing one const berryModifier = globalScene.findModifier( - (m) => m instanceof BerryModifier && m.berryType === chosenBerryType, + (m) => m instanceof BerryModifier && m.berryType === chosenBerryType && m.pokemonId == pokemon.id, pokemon.isPlayer() ) as BerryModifier | undefined; - if (!berryModifier) { + if (berryModifier) { + berryModifier.stackCount++ + } else { const newBerry = new BerryModifier(chosenBerry, pokemon.id, chosenBerryType, 1); if (pokemon.isPlayer()) { globalScene.addModifier(newBerry); } else { globalScene.addEnemyModifier(newBerry); } - } else if (berryModifier.stackCount < berryModifier.getMaxHeldItemCount(pokemon)) { - berryModifier.stackCount++; } - globalScene.queueMessage(i18next.t("abilityTriggers:postTurnLootCreateEatenBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: chosenBerry.name })); globalScene.updateModifiers(pokemon.isPlayer()); - + globalScene.queueMessage(i18next.t("abilityTriggers:postTurnLootCreateEatenBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: chosenBerry.name })); return true; } } /** - * Attribute used for {@linkcode Abilities.MOODY} + * Attribute to track and re-trigger last turn's berries at the end of the `BerryPhase`. + * Used by {@linkcode Abilities.CUD_CHEW}. +*/ +export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr { + /** + * @returns `true` if the pokemon ate anything last turn + */ + override canApply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean { + // force ability popup for ability triggers on normal turns. + // Still not used if ability doesn't proc + this.showAbility = true; + return !!pokemon.summonData.berriesEatenLast.length; + } + + /** + * Cause this {@linkcode Pokemon} to regurgitate and eat all berries inside its `berriesEatenLast` array. + * Triggers a berry use animation, but does *not* count for other berry or item-related abilities. + * @param pokemon - The {@linkcode Pokemon} having a bad tummy ache + * @param _passive - N/A + * @param _simulated - N/A + * @param _cancelled - N/A + * @param _args - N/A + */ + override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder | null, _args: any[]): void { + globalScene.unshiftPhase( + new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM), + ); + + // Re-apply effects of all berries previously scarfed. + // This doesn't count as "eating" a berry (for unnerve/stuff cheeks/unburden) as no item is consumed. + for (const berryType of pokemon.summonData.berriesEatenLast) { + getBerryEffectFunc(berryType)(pokemon); + const bMod = new BerryModifier(new BerryModifierType(berryType), pokemon.id, berryType, 1); + globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(bMod)); // trigger message + } + + // uncomment to make cheek pouch work with cud chew + // applyAbAttrs(HealFromBerryUseAbAttr, pokemon, new BooleanHolder(false)); + } + + /** + * @returns always `true` as we always want to move berries into summon data + */ + override canApplyPostTurn(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean { + this.showAbility = false; // don't show popup for turn end berry moving (should ideally be hidden) + return true; + } + + /** + * Move this {@linkcode Pokemon}'s `berriesEaten` array from `PokemonTurnData` + * into `PokemonSummonData` on turn end. + * Both arrays are cleared on switch. + * @param pokemon - The {@linkcode Pokemon} having a nice snack + * @param _passive - N/A + * @param _simulated - N/A + * @param _args - N/A + */ + override applyPostTurn(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): void { + pokemon.summonData.berriesEatenLast = pokemon.turnData.berriesEaten; + } +} + +/** + * Attribute used for {@linkcode Abilities.MOODY} to randomly raise and lower stats at turn end. */ export class MoodyAbAttr extends PostTurnAbAttr { constructor() { @@ -4236,7 +4272,7 @@ export class PostTurnHealAbAttr extends PostTurnAbAttr { if (!simulated) { const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; globalScene.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(), - Utils.toDmgValue(pokemon.getMaxHp() / 16), i18next.t("abilityTriggers:postTurnHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); + toDmgValue(pokemon.getMaxHp() / 16), i18next.t("abilityTriggers:postTurnHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true)); } } } @@ -4271,7 +4307,7 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr { } /** * Deals damage to all sleeping opponents equal to 1/8 of their max hp (min 1) - * @param pokemon Pokemon that has this ability + * @param pokemon {@linkcode Pokemon} with this ability * @param passive N/A * @param simulated `true` if applying in a simulated call. * @param args N/A @@ -4280,7 +4316,7 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr { for (const opp of pokemon.getOpponents()) { if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !opp.switchOutStatus) { if (!simulated) { - opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), { result: HitResult.INDIRECT }); + opp.damageAndUpdate(toDmgValue(opp.getMaxHp() / 8), { result: HitResult.INDIRECT }); globalScene.queueMessage(i18next.t("abilityTriggers:badDreams", { pokemonName: getPokemonNameWithAffix(opp) })); } } @@ -4299,7 +4335,7 @@ export class FetchBallAbAttr extends PostTurnAbAttr { } override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - return !simulated && !Utils.isNullOrUndefined(globalScene.currentBattle.lastUsedPokeball) && !!pokemon.isPlayer; + return !simulated && !isNullOrUndefined(globalScene.currentBattle.lastUsedPokeball) && !!pokemon.isPlayer; } /** @@ -4331,7 +4367,7 @@ export class PostBiomeChangeWeatherChangeAbAttr extends PostBiomeChangeAbAttr { return ((globalScene.arena.weather?.isImmutable() ?? false) && globalScene.arena.canSetWeather(this.weatherType)); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { if (!simulated) { globalScene.arena.trySetWeather(this.weatherType, pokemon); } @@ -4351,7 +4387,7 @@ export class PostBiomeChangeTerrainChangeAbAttr extends PostBiomeChangeAbAttr { return globalScene.arena.canSetTerrain(this.terrainType); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { if (!simulated) { globalScene.arena.trySetTerrain(this.terrainType, false, pokemon); } @@ -4453,7 +4489,7 @@ export class PostItemLostAbAttr extends AbAttr { } /** - * Applies a Battler Tag to the Pokemon after it loses or consumes item + * Applies a Battler Tag to the Pokemon after it loses or consumes an item * @extends PostItemLostAbAttr */ export class PostItemLostApplyBattlerTagAbAttr extends PostItemLostAbAttr { @@ -4486,8 +4522,8 @@ export class StatStageChangeMultiplierAbAttr extends AbAttr { this.multiplier = multiplier; } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value *= this.multiplier; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value *= this.multiplier; } } @@ -4496,7 +4532,7 @@ export class StatStageChangeCopyAbAttr extends AbAttr { pokemon: Pokemon, passive: boolean, simulated: boolean, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, args: any[], ): void { if (!simulated) { @@ -4510,7 +4546,7 @@ export class BypassBurnDamageReductionAbAttr extends AbAttr { super(false); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -4529,21 +4565,32 @@ export class ReduceBurnDamageAbAttr extends AbAttr { * @param pokemon N/A * @param passive N/A * @param cancelled N/A - * @param args `[0]` {@linkcode Utils.NumberHolder} The damage value being modified + * @param args `[0]` {@linkcode NumberHolder} The damage value being modified */ - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value = Utils.toDmgValue((args[0] as Utils.NumberHolder).value * this.multiplier); + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value = toDmgValue((args[0] as NumberHolder).value * this.multiplier); } } export class DoubleBerryEffectAbAttr extends AbAttr { - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value *= 2; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value *= 2; } } +/** + * Attribute to prevent opposing berry use while on the field. + * Used by {@linkcode Abilities.UNNERVE}, {@linkcode Abilities.AS_ONE_GLASTRIER} and {@linkcode Abilities.AS_ONE_SPECTRIER} + */ export class PreventBerryUseAbAttr extends AbAttr { - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + /** + * Prevent use of opposing berries. + * @param _pokemon - Unused + * @param _passive - Unused + * @param _simulated - Unused + * @param cancelled - {@linkcode BooleanHolder} containing whether to block berry use + */ + override apply(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, cancelled: BooleanHolder): void { cancelled.value = true; } } @@ -4564,24 +4611,26 @@ export class HealFromBerryUseAbAttr extends AbAttr { this.healPercent = Math.max(Math.min(healPercent, 1), 0); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, ...args: [Utils.BooleanHolder, any[]]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, ...args: [BooleanHolder, any[]]): void { + if (simulated) { + return; + } + const { name: abilityName } = passive ? pokemon.getPassiveAbility() : pokemon.getAbility(); - if (!simulated) { - globalScene.unshiftPhase( - new PokemonHealPhase( - pokemon.getBattlerIndex(), - Utils.toDmgValue(pokemon.getMaxHp() * this.healPercent), - i18next.t("abilityTriggers:healFromBerryUse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), - true + globalScene.unshiftPhase( + new PokemonHealPhase( + pokemon.getBattlerIndex(), + toDmgValue(pokemon.getMaxHp() * this.healPercent), + i18next.t("abilityTriggers:healFromBerryUse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), + true ) ); - } } } export class RunSuccessAbAttr extends AbAttr { - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value = 256; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value = 256; } } @@ -4605,9 +4654,10 @@ export class CheckTrappedAbAttr extends AbAttr { pokemon: Pokemon, passive: boolean, simulated: boolean, - trapped: Utils.BooleanHolder, + trapped: BooleanHolder, otherPokemon: Pokemon, - args: any[]): boolean { + args: any[], + ): boolean { return true; } @@ -4615,7 +4665,7 @@ export class CheckTrappedAbAttr extends AbAttr { pokemon: Pokemon, passive: boolean, simulated: boolean, - trapped: Utils.BooleanHolder, + trapped: BooleanHolder, otherPokemon: Pokemon, args: any[], ): void {} @@ -4628,7 +4678,7 @@ export class CheckTrappedAbAttr extends AbAttr { * @see {@linkcode applyCheckTrapped} */ export class ArenaTrapAbAttr extends CheckTrappedAbAttr { - override canApplyCheckTrapped(pokemon: Pokemon, passive: boolean, simulated: boolean, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, args: any[]): boolean { + override canApplyCheckTrapped(pokemon: Pokemon, passive: boolean, simulated: boolean, trapped: BooleanHolder, otherPokemon: Pokemon, args: any[]): boolean { return this.arenaTrapCondition(pokemon, otherPokemon) && !(otherPokemon.getTypes(true).includes(PokemonType.GHOST) || (otherPokemon.getTypes(true).includes(PokemonType.STELLAR) && otherPokemon.getTypes().includes(PokemonType.GHOST))) && !otherPokemon.hasAbility(Abilities.RUN_AWAY); @@ -4642,11 +4692,11 @@ export class ArenaTrapAbAttr extends CheckTrappedAbAttr { * If the user has Arena Trap and the enemy is not grounded, it is not trapped. * @param pokemon The {@link Pokemon} with this {@link AbAttr} * @param passive N/A - * @param trapped {@link Utils.BooleanHolder} indicating whether the other Pokemon is trapped or not + * @param trapped {@link BooleanHolder} indicating whether the other Pokemon is trapped or not * @param otherPokemon The {@link Pokemon} that is affected by an Arena Trap ability * @param args N/A */ - override applyCheckTrapped(pokemon: Pokemon, passive: boolean, simulated: boolean, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, args: any[]): void { + override applyCheckTrapped(pokemon: Pokemon, passive: boolean, simulated: boolean, trapped: BooleanHolder, otherPokemon: Pokemon, args: any[]): void { trapped.value = true; } @@ -4660,14 +4710,14 @@ export class MaxMultiHitAbAttr extends AbAttr { super(false); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value = 0; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value = 0; } } export class PostBattleAbAttr extends AbAttr { - constructor() { - super(true); + constructor(showAbility: boolean = true) { + super(showAbility); } canApplyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { @@ -4683,7 +4733,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr { override canApplyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const postBattleLoot = globalScene.currentBattle.postBattleLoot; if (!simulated && postBattleLoot.length && args[0]) { - this.randItem = Utils.randSeedItem(postBattleLoot); + this.randItem = randSeedItem(postBattleLoot); return globalScene.canTransferHeldItemModifier(this.randItem, pokemon, 1); } return false; @@ -4695,7 +4745,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr { override applyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { const postBattleLoot = globalScene.currentBattle.postBattleLoot; if (!this.randItem) { - this.randItem = Utils.randSeedItem(postBattleLoot); + this.randItem = randSeedItem(postBattleLoot); } if (globalScene.tryTransferHeldItemModifier(this.randItem, pokemon, true, 1, true, undefined, false)) { @@ -4751,8 +4801,8 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr { } override canApplyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean { - const diedToDirectDamage = move !== undefined && attacker !== undefined && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon); - const cancelled = new Utils.BooleanHolder(false); + const diedToDirectDamage = move !== undefined && attacker !== undefined && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}); + const cancelled = new BooleanHolder(false); globalScene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated)); if (!diedToDirectDamage || cancelled.value || attacker!.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { return false; @@ -4763,8 +4813,8 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr { override applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): void { if (!simulated) { - attacker!.damageAndUpdate(Utils.toDmgValue(attacker!.getMaxHp() * (1 / this.damageRatio)), { result: HitResult.INDIRECT }); - attacker!.turnData.damageTaken += Utils.toDmgValue(attacker!.getMaxHp() * (1 / this.damageRatio)); + attacker!.damageAndUpdate(toDmgValue(attacker!.getMaxHp() * (1 / this.damageRatio)), { result: HitResult.INDIRECT }); + attacker!.turnData.damageTaken += toDmgValue(attacker!.getMaxHp() * (1 / this.damageRatio)); } } @@ -4810,13 +4860,13 @@ export class RedirectMoveAbAttr extends AbAttr { if (!this.canRedirect(args[0] as Moves, args[2] as Pokemon)) { return false; } - const target = args[1] as Utils.NumberHolder; + const target = args[1] as NumberHolder; const newTarget = pokemon.getBattlerIndex(); return target.value !== newTarget; } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - const target = args[1] as Utils.NumberHolder; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + const target = args[1] as NumberHolder; const newTarget = pokemon.getBattlerIndex(); target.value = newTarget; } @@ -4857,7 +4907,7 @@ export class ReduceStatusEffectDurationAbAttr extends AbAttr { } override canApply(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - return args[1] instanceof Utils.NumberHolder && args[0] === this.statusEffect; + return args[1] instanceof NumberHolder && args[0] === this.statusEffect; } /** @@ -4866,7 +4916,7 @@ export class ReduceStatusEffectDurationAbAttr extends AbAttr { * - `[0]` - The {@linkcode StatusEffect} of the Pokemon * - `[1]` - The number of turns remaining until the status is healed */ - override apply(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder, args: any[]): void { args[1].value -= 1; } } @@ -4890,7 +4940,7 @@ export class FlinchStatStageChangeAbAttr extends FlinchEffectAbAttr { this.stages = stages; } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { if (!simulated) { globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages)); } @@ -4900,7 +4950,7 @@ export class FlinchStatStageChangeAbAttr extends FlinchEffectAbAttr { export class IncreasePpAbAttr extends AbAttr { } export class ForceSwitchOutImmunityAbAttr extends AbAttr { - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -4915,7 +4965,7 @@ export class ReduceBerryUseThresholdAbAttr extends AbAttr { return args[0].value < hpRatio; } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { args[0].value *= 2; } } @@ -4933,8 +4983,8 @@ export class WeightMultiplierAbAttr extends AbAttr { this.multiplier = multiplier; } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - (args[0] as Utils.NumberHolder).value *= this.multiplier; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + (args[0] as NumberHolder).value *= this.multiplier; } } @@ -4943,7 +4993,7 @@ export class SyncEncounterNatureAbAttr extends AbAttr { super(false); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { (args[0] as Pokemon).setNature(pokemon.getNature()); } } @@ -4961,7 +5011,7 @@ export class MoveAbilityBypassAbAttr extends AbAttr { return this.moveIgnoreFunc(pokemon, (args[0] as Move)); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -4981,7 +5031,7 @@ export class InfiltratorAbAttr extends AbAttr { } override canApply(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - return args[0] instanceof Utils.BooleanHolder; + return args[0] instanceof BooleanHolder; } /** @@ -4990,7 +5040,7 @@ export class InfiltratorAbAttr extends AbAttr { * @param passive n/a * @param simulated n/a * @param cancelled n/a - * @param args `[0]` a {@linkcode Utils.BooleanHolder | BooleanHolder} containing the flag + * @param args `[0]` a {@linkcode BooleanHolder | BooleanHolder} containing the flag */ override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: null, args: any[]): void { const bypassed = args[0]; @@ -5031,7 +5081,7 @@ export class IgnoreTypeImmunityAbAttr extends AbAttr { return this.defenderType === (args[1] as PokemonType) && this.allowedMoveTypes.includes(args[0] as PokemonType); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -5054,7 +5104,7 @@ export class IgnoreTypeStatusEffectImmunityAbAttr extends AbAttr { return this.statusEffect.includes(args[0] as StatusEffect) && this.defenderType.includes(args[1] as PokemonType); } - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { cancelled.value = true; } } @@ -5130,6 +5180,8 @@ export class PostSummonStatStageChangeOnArenaAbAttr extends PostSummonStatStageC /** * Takes no damage from the first hit of a damaging move. * This is used in the Disguise and Ice Face abilities. + * + * Does not apply to a user's substitute * @extends ReceivedMoveDamageMultiplierAbAttr */ export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr { @@ -5147,7 +5199,7 @@ export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr { this.triggerMessageFunc = triggerMessageFunc; } - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder | null, args: any[]): boolean { + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder | null, args: any[]): boolean { return this.condition(pokemon, attacker, move) && !move.hitsSubstitute(attacker, pokemon); } @@ -5162,9 +5214,9 @@ export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr { * @param _cancelled n/a * @param args Additional arguments. */ - override applyPreDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _cancelled: Utils.BooleanHolder, args: any[]): void { + override applyPreDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _cancelled: BooleanHolder, args: any[]): void { if (!simulated) { - (args[0] as Utils.NumberHolder).value = this.multiplier; + (args[0] as NumberHolder).value = this.multiplier; pokemon.removeTag(this.tagType); if (this.recoilDamageFunc) { pokemon.damageAndUpdate(this.recoilDamageFunc(pokemon), { result: HitResult.INDIRECT, ignoreSegments: true, ignoreFaintPhase: true }); @@ -5184,6 +5236,98 @@ export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr { } } +/** + * Base class for defining {@linkcode Ability} attributes before summon + * (should use {@linkcode PostSummonAbAttr} for most ability) + * @see {@linkcode applyPreSummon()} + */ +export class PreSummonAbAttr extends AbAttr { + applyPreSummon(pokemon: Pokemon, passive: boolean, args: any[]): void {} + + canApplyPreSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + return true; + } +} + +export class IllusionPreSummonAbAttr extends PreSummonAbAttr { + /** + * Apply a new illusion when summoning Zoroark if the illusion is available + * + * @param pokemon - The Pokémon with the Illusion ability. + * @param passive - N/A + * @param args - N/A + * @returns Whether the illusion was applied. + */ + override applyPreSummon(pokemon: Pokemon, passive: boolean, args: any[]): void { + const party: Pokemon[] = (pokemon.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty()).filter(p => p.isAllowedInBattle()); + const lastPokemon: Pokemon = party.filter(p => p !==pokemon).at(-1) || pokemon; + pokemon.setIllusion(lastPokemon); + } + + override canApplyPreSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + if (pokemon.hasTrainer()) { + const party: Pokemon[] = (pokemon.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty()).filter(p => p.isAllowedInBattle()); + const lastPokemon: Pokemon = party.filter(p => p !==pokemon).at(-1) || pokemon; + const speciesId = lastPokemon.species.speciesId; + + // If the last conscious Pokémon in the party is a Terastallized Ogerpon or Terapagos, Illusion will not activate. + // Illusion will also not activate if the Pokémon with Illusion is Terastallized and the last Pokémon in the party is Ogerpon or Terapagos. + if ( + lastPokemon === pokemon || + ((speciesId === Species.OGERPON || speciesId === Species.TERAPAGOS) && (lastPokemon.isTerastallized || pokemon.isTerastallized)) + ) { + return false; + } + } + return !pokemon.summonData.illusionBroken; + } +} + +export class IllusionBreakAbAttr extends AbAttr { + override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder | null, _args: any[]): void { + pokemon.breakIllusion(); + pokemon.summonData.illusionBroken = true; + } +} + +export class PostDefendIllusionBreakAbAttr extends PostDefendAbAttr { + /** + * Destroy the illusion upon taking damage + * + * @param pokemon - The Pokémon with the Illusion ability. + * @param passive - unused + * @param attacker - The attacking Pokémon. + * @param move - The move being used. + * @param hitResult - The type of hitResult the pokemon got + * @param args - unused + * @returns - Whether the illusion was destroyed. + */ + override applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): void { + pokemon.breakIllusion(); + pokemon.summonData.illusionBroken = true; + } + + override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { + const breakIllusion: HitResult[] = [ HitResult.EFFECTIVE, HitResult.SUPER_EFFECTIVE, HitResult.NOT_VERY_EFFECTIVE, HitResult.ONE_HIT_KO ]; + return breakIllusion.includes(hitResult) && !!pokemon.summonData.illusion + } +} + +export class IllusionPostBattleAbAttr extends PostBattleAbAttr { + /** + * Break the illusion once the battle ends + * + * @param pokemon - The Pokémon with the Illusion ability. + * @param passive - Unused + * @param args - Unused + * @returns - Whether the illusion was applied. + */ + override applyPostBattle(pokemon: Pokemon, passive: boolean, simulated:boolean, args: any[]): void { + pokemon.breakIllusion() + } +} + + /** * If a Pokémon with this Ability selects a damaging move, it has a 30% chance of going first in its priority bracket. If the Ability activates, this is announced at the start of the turn (after move selection). * @@ -5201,7 +5345,7 @@ export class BypassSpeedChanceAbAttr extends AbAttr { } override canApply(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - const bypassSpeed = args[0] as Utils.BooleanHolder; + const bypassSpeed = args[0] as BooleanHolder; const turnCommand = globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()]; const isCommandFight = turnCommand?.command === Command.FIGHT; const move = turnCommand?.move?.move ? allMoves[turnCommand.move.move] : null; @@ -5213,11 +5357,11 @@ export class BypassSpeedChanceAbAttr extends AbAttr { * bypass move order in their priority bracket when pokemon choose damaging move * @param {Pokemon} pokemon {@linkcode Pokemon} the Pokemon applying this ability * @param {boolean} passive N/A - * @param {Utils.BooleanHolder} cancelled N/A - * @param {any[]} args [0] {@linkcode Utils.BooleanHolder} set to true when the ability activated + * @param {BooleanHolder} cancelled N/A + * @param {any[]} args [0] {@linkcode BooleanHolder} set to true when the ability activated */ - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - const bypassSpeed = args[0] as Utils.BooleanHolder; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + const bypassSpeed = args[0] as BooleanHolder; bypassSpeed.value = true; } @@ -5252,9 +5396,9 @@ export class PreventBypassSpeedChanceAbAttr extends AbAttr { * @argument {boolean} bypassSpeed - determines if a Pokemon is able to bypass speed at the moment * @argument {boolean} canCheckHeldItems - determines if a Pokemon has access to Quick Claw's effects or not */ - override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): void { - const bypassSpeed = args[0] as Utils.BooleanHolder; - const canCheckHeldItems = args[1] as Utils.BooleanHolder; + override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void { + const bypassSpeed = args[0] as BooleanHolder; + const canCheckHeldItems = args[1] as BooleanHolder; bypassSpeed.value = false; canCheckHeldItems.value = false; } @@ -5273,7 +5417,7 @@ export class TerrainEventTypeChangeAbAttr extends PostSummonAbAttr { return !pokemon.isTerastallized; } - override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: Utils.BooleanHolder, _args: any[]): void { + override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder, _args: any[]): void { const currentTerrain = globalScene.arena.getTerrainType(); const typeChange: PokemonType[] = this.determineTypeChange(pokemon, currentTerrain); if (typeChange.length !== 0) { @@ -5324,7 +5468,7 @@ export class TerrainEventTypeChangeAbAttr extends PostSummonAbAttr { * Checks if the Pokemon should change types if summoned into an active terrain */ override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { - this.apply(pokemon, passive, simulated, new Utils.BooleanHolder(false), []); + this.apply(pokemon, passive, simulated, new BooleanHolder(false), []); } override getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) { @@ -5386,11 +5530,8 @@ function applySingleAbAttrs( globalScene.queueAbilityDisplay(pokemon, passive, false); } - if (pokemon.summonData && !pokemon.summonData.abilitiesApplied.includes(ability.id)) { - pokemon.summonData.abilitiesApplied.push(ability.id); - } - if (pokemon.battleData && !simulated && !pokemon.battleData.abilitiesApplied.includes(ability.id)) { - pokemon.battleData.abilitiesApplied.push(ability.id); + if (!simulated) { + pokemon.waveData.abilitiesApplied.add(ability.id); } globalScene.clearPhaseQueueSplice(); @@ -5451,7 +5592,7 @@ class ForceSwitchOutHelper { if (switchOutTarget.hp > 0) { switchOutTarget.leaveField(false); globalScene.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500); - if (globalScene.currentBattle.double && !Utils.isNullOrUndefined(allyPokemon)) { + if (globalScene.currentBattle.double && !isNullOrUndefined(allyPokemon)) { globalScene.redirectPokemonMoves(switchOutTarget, allyPokemon); } } @@ -5461,6 +5602,11 @@ class ForceSwitchOutHelper { if (switchOutTarget.hp) { globalScene.pushPhase(new BattleEndPhase(false)); + + if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { + globalScene.pushPhase(new SelectBiomePhase()); + } + globalScene.pushPhase(new NewBattlePhase()); } } @@ -5480,7 +5626,7 @@ class ForceSwitchOutHelper { const player = switchOutTarget instanceof PlayerPokemon; if (player) { - const blockedByAbility = new Utils.BooleanHolder(false); + const blockedByAbility = new BooleanHolder(false); applyAbAttrs(ForceSwitchOutImmunityAbAttr, opponent, blockedByAbility); return !blockedByAbility.value; } @@ -5497,8 +5643,8 @@ class ForceSwitchOutHelper { const party = player ? globalScene.getPlayerParty() : globalScene.getEnemyParty(); return (!player && globalScene.currentBattle.battleType === BattleType.WILD) - || party.filter(p => p.isAllowedInBattle() - && (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > globalScene.currentBattle.getBattlerCount(); + || party.filter(p => p.isAllowedInBattle() && !p.isOnField() + && (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > 0; } /** @@ -5508,7 +5654,7 @@ class ForceSwitchOutHelper { * @returns The failure message, or `null` if no failure. */ public getFailedText(target: Pokemon): string | null { - const blockedByAbility = new Utils.BooleanHolder(false); + const blockedByAbility = new BooleanHolder(false); applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, blockedByAbility); return blockedByAbility.value ? i18next.t("moveTriggers:cannotBeSwitchedOut", { pokemonName: getPokemonNameWithAffix(target) }) : null; } @@ -5527,7 +5673,7 @@ class ForceSwitchOutHelper { function calculateShellBellRecovery(pokemon: Pokemon): number { const shellBellModifier = pokemon.getHeldItems().find(m => m instanceof HitHealModifier); if (shellBellModifier) { - return Utils.toDmgValue(pokemon.turnData.totalDamageDealt / 8) * shellBellModifier.stackCount; + return toDmgValue(pokemon.turnData.totalDamageDealt / 8) * shellBellModifier.stackCount; } return 0; } @@ -5576,6 +5722,7 @@ export class PostDamageForceSwitchAbAttr extends PostDamageAbAttr { this.hpRatio = hpRatio; } + // TODO: Refactor to use more early returns public override canApplyPostDamage( pokemon: Pokemon, damage: number, @@ -5603,6 +5750,7 @@ export class PostDamageForceSwitchAbAttr extends PostDamageAbAttr { if (fordbiddenDefendingMoves.includes(enemyLastMoveUsed.move) || enemyLastMoveUsed.move === Moves.SKY_DROP && enemyLastMoveUsed.result === MoveResult.OTHER) { return false; // Will not activate if the Pokémon's HP falls below half by a move affected by Sheer Force. + // TODO: Make this use the sheer force disable condition } else if (allMoves[enemyLastMoveUsed.move].chance >= 0 && source.hasAbility(Abilities.SHEER_FORCE)) { return false; // Activate only after the last hit of multistrike moves @@ -5667,7 +5815,7 @@ function applyAbAttrsInternal( export function applyAbAttrs( attrType: Constructor, pokemon: Pokemon, - cancelled: Utils.BooleanHolder | null, + cancelled: BooleanHolder | null, simulated = false, ...args: any[] ): void { @@ -5702,7 +5850,7 @@ export function applyPreDefendAbAttrs( pokemon: Pokemon, attacker: Pokemon, move: Move | null, - cancelled: Utils.BooleanHolder | null, + cancelled: BooleanHolder | null, simulated = false, ...args: any[] ): void { @@ -5757,7 +5905,7 @@ export function applyStatMultiplierAbAttrs( attrType: Constructor, pokemon: Pokemon, stat: BattleStat, - statValue: Utils.NumberHolder, + statValue: NumberHolder, simulated = false, ...args: any[] ): void { @@ -5775,13 +5923,13 @@ export function applyStatMultiplierAbAttrs( * @param attrType - {@linkcode AllyStatMultiplierAbAttr} should always be AllyStatMultiplierAbAttr for the time being * @param pokemon - The {@linkcode Pokemon} with the ability * @param stat - The type of the checked {@linkcode Stat} - * @param statValue - {@linkcode Utils.NumberHolder} containing the value of the checked stat + * @param statValue - {@linkcode NumberHolder} containing the value of the checked stat * @param checkedPokemon - The {@linkcode Pokemon} with the checked stat * @param ignoreAbility - Whether or not the ability should be ignored by the pokemon or its move. * @param args - unused */ export function applyAllyStatMultiplierAbAttrs(attrType: Constructor, - pokemon: Pokemon, stat: BattleStat, statValue: Utils.NumberHolder, simulated: boolean = false, checkedPokemon: Pokemon, ignoreAbility: boolean, ...args: any[] + pokemon: Pokemon, stat: BattleStat, statValue: NumberHolder, simulated: boolean = false, checkedPokemon: Pokemon, ignoreAbility: boolean, ...args: any[] ): void { return applyAbAttrsInternal( attrType, @@ -5834,18 +5982,18 @@ export function applyPostDamageAbAttrs( * @param attrType {@linkcode FieldMultiplyStatAbAttr} should always be FieldMultiplyBattleStatAbAttr for the time being * @param pokemon {@linkcode Pokemon} the Pokemon applying this ability * @param stat {@linkcode Stat} the type of the checked stat - * @param statValue {@linkcode Utils.NumberHolder} the value of the checked stat + * @param statValue {@linkcode NumberHolder} the value of the checked stat * @param checkedPokemon {@linkcode Pokemon} the Pokemon with the checked stat - * @param hasApplied {@linkcode Utils.BooleanHolder} whether or not a FieldMultiplyBattleStatAbAttr has already affected this stat + * @param hasApplied {@linkcode BooleanHolder} whether or not a FieldMultiplyBattleStatAbAttr has already affected this stat * @param args unused */ export function applyFieldStatMultiplierAbAttrs( attrType: Constructor, pokemon: Pokemon, stat: Stat, - statValue: Utils.NumberHolder, + statValue: NumberHolder, checkedPokemon: Pokemon, - hasApplied: Utils.BooleanHolder, + hasApplied: BooleanHolder, simulated = false, ...args: any[] ): void { @@ -5942,6 +6090,20 @@ export function applyPostSummonAbAttrs( ); } +export function applyPreSummonAbAttrs( + attrType: Constructor, + pokemon: Pokemon, + ...args: any[] +): void { + applyAbAttrsInternal( + attrType, + pokemon, + (attr, passive) => attr.applyPreSummon(pokemon, passive, args), + (attr, passive) => attr.canApplyPreSummon(pokemon, passive, args), + args + ); +} + export function applyPreSwitchOutAbAttrs( attrType: Constructor, pokemon: Pokemon, @@ -5979,7 +6141,7 @@ export function applyPreStatStageChangeAbAttrs, pokemon: Pokemon | null, stat: BattleStat, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, simulated = false, ...args: any[] ): void { @@ -6015,7 +6177,7 @@ export function applyPreSetStatusAbAttrs( attrType: Constructor, pokemon: Pokemon, effect: StatusEffect | undefined, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, simulated = false, ...args: any[] ): void { @@ -6033,7 +6195,7 @@ export function applyPreApplyBattlerTagAbAttrs( attrType: Constructor, pokemon: Pokemon, tag: BattlerTag, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, simulated = false, ...args: any[] ): void { @@ -6051,7 +6213,7 @@ export function applyPreWeatherEffectAbAttrs( attrType: Constructor, pokemon: Pokemon, weather: Weather | null, - cancelled: Utils.BooleanHolder, + cancelled: BooleanHolder, simulated = false, ...args: any[] ): void { @@ -6135,7 +6297,7 @@ export function applyPostTerrainChangeAbAttrs( export function applyCheckTrappedAbAttrs( attrType: Constructor, pokemon: Pokemon, - trapped: Utils.BooleanHolder, + trapped: BooleanHolder, otherPokemon: Pokemon, messages: string[], simulated = false, @@ -6224,7 +6386,7 @@ export function applyOnGainAbAttrs( } /** - * Clears primal weather/neutralizing gas during the turn if {@linkcode pokemon}'s ability corresponds to one + * Applies ability attributes which activate when the ability is lost or suppressed (i.e. primal weather) */ export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, simulated = false, ...args: any[]): void { applySingleAbAttrs( @@ -6236,21 +6398,29 @@ export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, simulated args, true, simulated); + + applySingleAbAttrs( + pokemon, + passive, + IllusionBreakAbAttr, + (attr, passive) => attr.apply(pokemon, passive, simulated, null, args), + (attr, passive) => attr.canApply(pokemon, passive, simulated, args), + args, + true, + simulated + ) } /** * Sets the ability of a Pokémon as revealed. - * * @param pokemon - The Pokémon whose ability is being revealed. */ function setAbilityRevealed(pokemon: Pokemon): void { - if (pokemon.battleData) { - pokemon.battleData.abilityRevealed = true; - } + pokemon.waveData.abilityRevealed = true; } /** - * Returns the Pokemon with weather-based forms + * Returns all Pokemon on field with weather-based forms */ function getPokemonWithWeatherBasedForms() { return globalScene.getField(true).filter(p => @@ -6259,10 +6429,9 @@ function getPokemonWithWeatherBasedForms() { ); } -export const allAbilities = [ new Ability(Abilities.NONE, 3) ]; - export function initAbilities() { allAbilities.push( + new Ability(Abilities.NONE, 3), new Ability(Abilities.STENCH, 3) .attr(PostAttackApplyBattlerTagAbAttr, false, (user, target, move) => !move.hasAttr(FlinchAttr) && !move.hitsSubstitute(user, target) ? 10 : 0, BattlerTagType.FLINCHED), new Ability(Abilities.DRIZZLE, 3) @@ -6282,6 +6451,7 @@ export function initAbilities() { .ignorable(), new Ability(Abilities.LIMBER, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.PARALYSIS) + .attr(PostSummonHealStatusAbAttr, StatusEffect.PARALYSIS) .ignorable(), new Ability(Abilities.SAND_VEIL, 3) .attr(StatMultiplierAbAttr, Stat.EVA, 1.2) @@ -6299,6 +6469,7 @@ export function initAbilities() { .ignorable(), new Ability(Abilities.OBLIVIOUS, 3) .attr(BattlerTagImmunityAbAttr, [ BattlerTagType.INFATUATED, BattlerTagType.TAUNT ]) + .attr(PostSummonRemoveBattlerTagAbAttr, BattlerTagType.INFATUATED, BattlerTagType.TAUNT) .attr(IntimidateImmunityAbAttr) .ignorable(), new Ability(Abilities.CLOUD_NINE, 3) @@ -6311,6 +6482,7 @@ export function initAbilities() { .attr(StatMultiplierAbAttr, Stat.ACC, 1.3), new Ability(Abilities.INSOMNIA, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.SLEEP) + .attr(PostSummonHealStatusAbAttr, StatusEffect.SLEEP) .attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY) .ignorable(), new Ability(Abilities.COLOR_CHANGE, 3) @@ -6318,6 +6490,7 @@ export function initAbilities() { .condition(getSheerForceHitDisableAbCondition()), new Ability(Abilities.IMMUNITY, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) + .attr(PostSummonHealStatusAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) .ignorable(), new Ability(Abilities.FLASH_FIRE, 3) .attr(TypeImmunityAddBattlerTagAbAttr, PokemonType.FIRE, BattlerTagType.FIRE_BOOST, 1) @@ -6327,6 +6500,7 @@ export function initAbilities() { .ignorable(), new Ability(Abilities.OWN_TEMPO, 3) .attr(BattlerTagImmunityAbAttr, BattlerTagType.CONFUSED) + .attr(PostSummonRemoveBattlerTagAbAttr, BattlerTagType.CONFUSED) .attr(IntimidateImmunityAbAttr) .ignorable(), new Ability(Abilities.SUCTION_CUPS, 3) @@ -6392,9 +6566,11 @@ export function initAbilities() { .ignorable(), new Ability(Abilities.MAGMA_ARMOR, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.FREEZE) + .attr(PostSummonHealStatusAbAttr, StatusEffect.FREEZE) .ignorable(), new Ability(Abilities.WATER_VEIL, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.BURN) + .attr(PostSummonHealStatusAbAttr, StatusEffect.BURN) .ignorable(), new Ability(Abilities.MAGNET_PULL, 3) .attr(ArenaTrapAbAttr, (user, target) => { @@ -6456,7 +6632,7 @@ export function initAbilities() { .bypassFaint() .ignorable(), new Ability(Abilities.SHED_SKIN, 3) - .conditionalAttr(pokemon => !Utils.randSeedInt(3), PostTurnResetStatusAbAttr), + .conditionalAttr(pokemon => !randSeedInt(3), PostTurnResetStatusAbAttr), new Ability(Abilities.GUTS, 3) .attr(BypassBurnDamageReductionAbAttr) .conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), StatMultiplierAbAttr, Stat.ATK, 1.5), @@ -6488,6 +6664,7 @@ export function initAbilities() { .attr(DoubleBattleChanceAbAttr), new Ability(Abilities.VITAL_SPIRIT, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.SLEEP) + .attr(PostSummonHealStatusAbAttr, StatusEffect.SLEEP) .attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY) .ignorable(), new Ability(Abilities.WHITE_SMOKE, 3) @@ -6563,9 +6740,7 @@ export function initAbilities() { .conditionalAttr(pokemon => pokemon.status ? pokemon.status.effect === StatusEffect.PARALYSIS : false, StatMultiplierAbAttr, Stat.SPD, 2) .conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(Abilities.COMATOSE), StatMultiplierAbAttr, Stat.SPD, 1.5), new Ability(Abilities.NORMALIZE, 4) - .attr(MoveTypeChangeAbAttr, PokemonType.NORMAL, 1.2, (user, target, move) => { - return ![ Moves.MULTI_ATTACK, Moves.REVELATION_DANCE, Moves.TERRAIN_PULSE, Moves.HIDDEN_POWER, Moves.WEATHER_BALL, Moves.NATURAL_GIFT, Moves.JUDGMENT, Moves.TECHNO_BLAST ].includes(move.id); - }), + .attr(MoveTypeChangeAbAttr, PokemonType.NORMAL, 1.2), new Ability(Abilities.SNIPER, 4) .attr(MultCritAbAttr, 1.5), new Ability(Abilities.MAGIC_GUARD, 4) @@ -6577,7 +6752,7 @@ export function initAbilities() { .attr(ChangeMovePriorityAbAttr, (pokemon, move: Move) => true, -0.2), new Ability(Abilities.TECHNICIAN, 4) .attr(MovePowerBoostAbAttr, (user, target, move) => { - const power = new Utils.NumberHolder(move.power); + const power = new NumberHolder(move.power); applyMoveAttrs(VariablePowerAttr, user, target, move, power); return power.value <= 60; }, 1.5), @@ -6651,11 +6826,11 @@ export function initAbilities() { new Ability(Abilities.BAD_DREAMS, 4) .attr(PostTurnHurtIfSleepingAbAttr), new Ability(Abilities.PICKPOCKET, 5) - .attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT)) + .attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user, target})) .condition(getSheerForceHitDisableAbCondition()), new Ability(Abilities.SHEER_FORCE, 5) - .attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 5461 / 4096) - .attr(MoveEffectChanceMultiplierAbAttr, 0), // Should disable life orb, eject button, red card, kee/maranga berry if they get implemented + .attr(MovePowerBoostAbAttr, (user, target, move) => move.chance >= 1, 1.3) + .attr(MoveEffectChanceMultiplierAbAttr, 0), // This attribute does not seem to function - Should disable life orb, eject button, red card, kee/maranga berry if they get implemented new Ability(Abilities.CONTRARY, 5) .attr(StatStageChangeMultiplierAbAttr, -1) .ignorable(), @@ -6671,7 +6846,7 @@ export function initAbilities() { .attr(PostDefendMoveDisableAbAttr, 30) .bypassFaint(), new Ability(Abilities.HEALER, 5) - .conditionalAttr(pokemon => !Utils.isNullOrUndefined(pokemon.getAlly()) && Utils.randSeedInt(10) < 3, PostTurnResetStatusAbAttr, true), + .conditionalAttr(pokemon => !isNullOrUndefined(pokemon.getAlly()) && randSeedInt(10) < 3, PostTurnResetStatusAbAttr, true), new Ability(Abilities.FRIEND_GUARD, 5) .attr(AlliedFieldDamageReductionAbAttr, 0.75) .ignorable(), @@ -6693,8 +6868,7 @@ export function initAbilities() { .attr(MovePowerBoostAbAttr, (user, target, move) => move.category === MoveCategory.SPECIAL && user?.status?.effect === StatusEffect.BURN, 1.5), new Ability(Abilities.HARVEST, 5) .attr( - PostTurnLootAbAttr, - "EATEN_BERRIES", + PostTurnRestoreBerryAbAttr, /** Rate is doubled when under sun {@link https://dex.pokemonshowdown.com/abilities/harvest} */ (pokemon) => 0.5 * (getWeatherCondition(WeatherType.SUNNY, WeatherType.HARSH_SUN)(pokemon) ? 2 : 1) ) @@ -6725,11 +6899,20 @@ export function initAbilities() { new Ability(Abilities.ANALYTIC, 5) .attr(MovePowerBoostAbAttr, (user, target, move) => { const movePhase = globalScene.findPhase((phase) => phase instanceof MovePhase && phase.pokemon.id !== user?.id); - return Utils.isNullOrUndefined(movePhase); + return isNullOrUndefined(movePhase); }, 1.3), new Ability(Abilities.ILLUSION, 5) + // The Pokemon generate an illusion if it's available + .attr(IllusionPreSummonAbAttr, false) + .attr(IllusionBreakAbAttr) + // The Pokemon loses its illusion when damaged by a move + .attr(PostDefendIllusionBreakAbAttr, true) + // Disable Illusion in fusions + .attr(NoFusionAbilityAbAttr) + // Illusion is available again after a battle + .conditionalAttr((pokemon) => pokemon.isAllowedInBattle(), IllusionPostBattleAbAttr, false) .uncopiable() - .unimplemented(), + .bypassFaint(), new Ability(Abilities.IMPOSTER, 5) .attr(PostSummonTransformAbAttr) .uncopiable(), @@ -6809,7 +6992,7 @@ export function initAbilities() { .attr(HealFromBerryUseAbAttr, 1 / 3), new Ability(Abilities.PROTEAN, 6) .attr(PokemonTypeChangeAbAttr), - //.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.PROTEAN)), //Gen 9 Implementation + //.condition((p) => !p.summonData.abilitiesApplied.includes(Abilities.PROTEAN)), //Gen 9 Implementation new Ability(Abilities.FUR_COAT, 6) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, 0.5) .ignorable(), @@ -6823,9 +7006,10 @@ export function initAbilities() { new Ability(Abilities.STRONG_JAW, 6) .attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.BITING_MOVE), 1.5), new Ability(Abilities.REFRIGERATE, 6) - .attr(MoveTypeChangeAbAttr, PokemonType.ICE, 1.2, (user, target, move) => move.type === PokemonType.NORMAL && !move.hasAttr(VariableMoveTypeAttr)), + .attr(MoveTypeChangeAbAttr, PokemonType.ICE, 1.2, (user, target, move) => move.type === PokemonType.NORMAL), new Ability(Abilities.SWEET_VEIL, 6) .attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.SLEEP) + .attr(PostSummonUserFieldRemoveStatusEffectAbAttr, StatusEffect.SLEEP) .attr(UserFieldBattlerTagImmunityAbAttr, BattlerTagType.DROWSY) .ignorable() .partial(), // Mold Breaker ally should not be affected by Sweet Veil @@ -6846,11 +7030,11 @@ export function initAbilities() { new Ability(Abilities.TOUGH_CLAWS, 6) .attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 1.3), new Ability(Abilities.PIXILATE, 6) - .attr(MoveTypeChangeAbAttr, PokemonType.FAIRY, 1.2, (user, target, move) => move.type === PokemonType.NORMAL && !move.hasAttr(VariableMoveTypeAttr)), + .attr(MoveTypeChangeAbAttr, PokemonType.FAIRY, 1.2, (user, target, move) => move.type === PokemonType.NORMAL), new Ability(Abilities.GOOEY, 6) .attr(PostDefendStatStageChangeAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), Stat.SPD, -1, false), new Ability(Abilities.AERILATE, 6) - .attr(MoveTypeChangeAbAttr, PokemonType.FLYING, 1.2, (user, target, move) => move.type === PokemonType.NORMAL && !move.hasAttr(VariableMoveTypeAttr)), + .attr(MoveTypeChangeAbAttr, PokemonType.FLYING, 1.2, (user, target, move) => move.type === PokemonType.NORMAL), new Ability(Abilities.PARENTAL_BOND, 6) .attr(AddSecondStrikeAbAttr, 0.25), new Ability(Abilities.DARK_AURA, 6) @@ -6910,6 +7094,7 @@ export function initAbilities() { .attr(ReceivedTypeDamageMultiplierAbAttr, PokemonType.FIRE, 0.5) .attr(MoveTypePowerBoostAbAttr, PokemonType.WATER, 2) .attr(StatusEffectImmunityAbAttr, StatusEffect.BURN) + .attr(PostSummonHealStatusAbAttr, StatusEffect.BURN) .ignorable(), new Ability(Abilities.STEELWORKER, 7) .attr(MoveTypePowerBoostAbAttr, PokemonType.STEEL), @@ -6926,7 +7111,7 @@ export function initAbilities() { new Ability(Abilities.TRIAGE, 7) .attr(ChangeMovePriorityAbAttr, (pokemon, move) => move.hasFlag(MoveFlags.TRIAGE_MOVE), 3), new Ability(Abilities.GALVANIZE, 7) - .attr(MoveTypeChangeAbAttr, PokemonType.ELECTRIC, 1.2, (user, target, move) => move.type === PokemonType.NORMAL && !move.hasAttr(VariableMoveTypeAttr)), + .attr(MoveTypeChangeAbAttr, PokemonType.ELECTRIC, 1.2, (_user, _target, move) => move.type === PokemonType.NORMAL), new Ability(Abilities.SURGE_SURFER, 7) .conditionalAttr(getTerrainCondition(TerrainType.ELECTRIC), StatMultiplierAbAttr, Stat.SPD, 2), new Ability(Abilities.SCHOOLING, 7) @@ -6946,7 +7131,7 @@ export function initAbilities() { .attr(FormBlockDamageAbAttr, (target, user, move) => !!target.getTag(BattlerTagType.DISGUISE) && target.getMoveEffectiveness(user, move) > 0, 0, BattlerTagType.DISGUISE, (pokemon, abilityName) => i18next.t("abilityTriggers:disguiseAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: abilityName }), - (pokemon) => Utils.toDmgValue(pokemon.getMaxHp() / 8)) + (pokemon) => toDmgValue(pokemon.getMaxHp() / 8)) .attr(PostBattleInitFormChangeAbAttr, () => 0) .uncopiable() .unreplaceable() @@ -6993,7 +7178,7 @@ export function initAbilities() { new Ability(Abilities.BATTERY, 7) .attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL ], 1.3), new Ability(Abilities.FLUFFY, 7) - .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), 0.5) + .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user, target}), 0.5) .attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => user.getMoveType(move) === PokemonType.FIRE, 2) .ignorable(), new Ability(Abilities.DAZZLING, 7) @@ -7002,7 +7187,7 @@ export function initAbilities() { new Ability(Abilities.SOUL_HEART, 7) .attr(PostKnockOutStatStageChangeAbAttr, Stat.SPATK, 1), new Ability(Abilities.TANGLING_HAIR, 7) - .attr(PostDefendStatStageChangeAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT), Stat.SPD, -1, false), + .attr(PostDefendStatStageChangeAbAttr, (target, user, move) => move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user, target}), Stat.SPD, -1, false), new Ability(Abilities.RECEIVER, 7) .attr(CopyFaintedAllyAbilityAbAttr) .uncopiable(), @@ -7053,7 +7238,7 @@ export function initAbilities() { .attr(PostSummonStatStageChangeAbAttr, [ Stat.DEF ], 1, true), new Ability(Abilities.LIBERO, 8) .attr(PokemonTypeChangeAbAttr), - //.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.LIBERO)), //Gen 9 Implementation + //.condition((p) => !p.summonData.abilitiesApplied.includes(Abilities.LIBERO)), //Gen 9 Implementation new Ability(Abilities.BALL_FETCH, 8) .attr(FetchBallAbAttr) .condition(getOncePerBattleCondition(Abilities.BALL_FETCH)), @@ -7158,7 +7343,7 @@ export function initAbilities() { new Ability(Abilities.CURIOUS_MEDICINE, 8) .attr(PostSummonClearAllyStatStagesAbAttr), new Ability(Abilities.TRANSISTOR, 8) - .attr(MoveTypePowerBoostAbAttr, PokemonType.ELECTRIC), + .attr(MoveTypePowerBoostAbAttr, PokemonType.ELECTRIC, 1.3), new Ability(Abilities.DRAGONS_MAW, 8) .attr(MoveTypePowerBoostAbAttr, PokemonType.DRAGON), new Ability(Abilities.CHILLING_NEIGH, 8) @@ -7188,6 +7373,7 @@ export function initAbilities() { new Ability(Abilities.THERMAL_EXCHANGE, 9) .attr(PostDefendStatStageChangeAbAttr, (target, user, move) => user.getMoveType(move) === PokemonType.FIRE && move.category !== MoveCategory.STATUS, Stat.ATK, 1) .attr(StatusEffectImmunityAbAttr, StatusEffect.BURN) + .attr(PostSummonHealStatusAbAttr, StatusEffect.BURN) .ignorable(), new Ability(Abilities.ANGER_SHELL, 9) .attr(PostDefendHpGatedStatStageChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ Stat.ATK, Stat.SPATK, Stat.SPD ], 1) @@ -7267,7 +7453,7 @@ export function initAbilities() { new Ability(Abilities.OPPORTUNIST, 9) .attr(StatStageChangeCopyAbAttr), new Ability(Abilities.CUD_CHEW, 9) - .unimplemented(), + .attr(RepeatBerryNextTurnAbAttr), new Ability(Abilities.SHARPNESS, 9) .attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.SLICING_MOVE), 1.5), new Ability(Abilities.SUPREME_OVERLORD, 9) diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 871f622f70a..19c94a8a045 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -1,13 +1,13 @@ import { globalScene } from "#app/global-scene"; import type { Arena } from "#app/field/arena"; import { PokemonType } from "#enums/pokemon-type"; -import { BooleanHolder, NumberHolder, toDmgValue } from "#app/utils"; +import { BooleanHolder, NumberHolder, toDmgValue } from "#app/utils/common"; import { allMoves } from "#app/data/moves/move"; import { MoveTarget } from "#enums/MoveTarget"; import { MoveCategory } from "#enums/MoveCategory"; import { getPokemonNameWithAffix } from "#app/messages"; import type Pokemon from "#app/field/pokemon"; -import { HitResult, PokemonMove } from "#app/field/pokemon"; +import { HitResult } from "#app/field/pokemon"; import { StatusEffect } from "#enums/status-effect"; import type { BattlerIndex } from "#app/battle"; import { @@ -18,7 +18,7 @@ import { applyAbAttrs, applyOnGainAbAttrs, applyOnLoseAbAttrs, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; import { Stat } from "#enums/stat"; import { CommonAnim, CommonBattleAnim } from "#app/data/battle-anims"; import i18next from "i18next"; @@ -335,7 +335,7 @@ export class ConditionalProtectTag extends ArenaTag { * @param arena the {@linkcode Arena} containing this tag * @param simulated `true` if the tag is applied quietly; `false` otherwise. * @param isProtected a {@linkcode BooleanHolder} used to flag if the move is protected against - * @param attacker the attacking {@linkcode Pokemon} + * @param _attacker the attacking {@linkcode Pokemon} * @param defender the defending {@linkcode Pokemon} * @param moveId the {@linkcode Moves | identifier} for the move being used * @param ignoresProtectBypass a {@linkcode BooleanHolder} used to flag if a protection effect supercedes effects that ignore protection @@ -345,7 +345,7 @@ export class ConditionalProtectTag extends ArenaTag { arena: Arena, simulated: boolean, isProtected: BooleanHolder, - attacker: Pokemon, + _attacker: Pokemon, defender: Pokemon, moveId: Moves, ignoresProtectBypass: BooleanHolder, @@ -354,8 +354,6 @@ export class ConditionalProtectTag extends ArenaTag { if (!isProtected.value) { isProtected.value = true; if (!simulated) { - attacker.stopMultiHit(defender); - new CommonBattleAnim(CommonAnim.PROTECT, defender).play(); globalScene.queueMessage( i18next.t("arenaTag:conditionalProtectApply", { @@ -770,32 +768,27 @@ class SpikesTag extends ArenaTrapTag { } override activateTrap(pokemon: Pokemon, simulated: boolean): boolean { - if (pokemon.isGrounded()) { - const cancelled = new BooleanHolder(false); - applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); - - if (simulated) { - return !cancelled.value; - } - - if (!cancelled.value) { - const damageHpRatio = 1 / (10 - 2 * this.layers); - const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio); - - globalScene.queueMessage( - i18next.t("arenaTag:spikesActivateTrap", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - }), - ); - pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT }); - if (pokemon.turnData) { - pokemon.turnData.damageTaken += damage; - } - return true; - } + if (!pokemon.isGrounded()) { + return false; } - return false; + const cancelled = new BooleanHolder(false); + applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); + if (simulated || cancelled.value) { + return !cancelled.value; + } + + const damageHpRatio = 1 / (10 - 2 * this.layers); + const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio); + + globalScene.queueMessage( + i18next.t("arenaTag:spikesActivateTrap", { + pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), + }), + ); + pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT }); + pokemon.turnData.damageTaken += damage; + return true; } } @@ -899,7 +892,7 @@ export class DelayedAttackTag extends ArenaTag { if (!ret) { globalScene.unshiftPhase( - new MoveEffectPhase(this.sourceId!, [this.targetIndex], new PokemonMove(this.sourceMove!, 0, 0, true)), + new MoveEffectPhase(this.sourceId!, [this.targetIndex], allMoves[this.sourceMove!], false, true), ); // TODO: are those bangs correct? } @@ -964,31 +957,28 @@ class StealthRockTag extends ArenaTrapTag { override activateTrap(pokemon: Pokemon, simulated: boolean): boolean { const cancelled = new BooleanHolder(false); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); - if (cancelled.value) { return false; } const damageHpRatio = this.getDamageHpRatio(pokemon); + if (!damageHpRatio) { + return false; + } - if (damageHpRatio) { - if (simulated) { - return true; - } - const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio); - globalScene.queueMessage( - i18next.t("arenaTag:stealthRockActivateTrap", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - }), - ); - pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT }); - if (pokemon.turnData) { - pokemon.turnData.damageTaken += damage; - } + if (simulated) { return true; } - return false; + const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio); + globalScene.queueMessage( + i18next.t("arenaTag:stealthRockActivateTrap", { + pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), + }), + ); + pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT }); + pokemon.turnData.damageTaken += damage; + return true; } getMatchupScoreMultiplier(pokemon: Pokemon): number { diff --git a/src/data/balance/biomes.ts b/src/data/balance/biomes.ts index 3dff1722af6..968164c7902 100644 --- a/src/data/balance/biomes.ts +++ b/src/data/balance/biomes.ts @@ -1,5 +1,5 @@ import { PokemonType } from "#enums/pokemon-type"; -import * as Utils from "#app/utils"; +import { randSeedInt, getEnumValues } from "#app/utils/common"; import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import i18next from "i18next"; @@ -7710,7 +7710,7 @@ export function initBiomes() { if (biome === Biome.END) { const biomeList = Object.keys(Biome).filter(key => !Number.isNaN(Number(key))); biomeList.pop(); // Removes Biome.END from the list - const randIndex = Utils.randSeedInt(biomeList.length, 1); // Will never be Biome.TOWN + const randIndex = randSeedInt(biomeList.length, 1); // Will never be Biome.TOWN biome = Biome[biomeList[randIndex]]; } const linkedBiomes: (Biome | [ Biome, number ])[] = Array.isArray(biomeLinks[biome]) @@ -7733,15 +7733,15 @@ export function initBiomes() { traverseBiome(Biome.TOWN, 0); biomeDepths[Biome.END] = [ Object.values(biomeDepths).map(d => d[0]).reduce((max: number, value: number) => Math.max(max, value), 0) + 1, 1 ]; - for (const biome of Utils.getEnumValues(Biome)) { + for (const biome of getEnumValues(Biome)) { biomePokemonPools[biome] = {}; biomeTrainerPools[biome] = {}; - for (const tier of Utils.getEnumValues(BiomePoolTier)) { + for (const tier of getEnumValues(BiomePoolTier)) { biomePokemonPools[biome][tier] = {}; biomeTrainerPools[biome][tier] = []; - for (const tod of Utils.getEnumValues(TimeOfDay)) { + for (const tod of getEnumValues(TimeOfDay)) { biomePokemonPools[biome][tier][tod] = []; } } diff --git a/src/data/balance/egg-moves.ts b/src/data/balance/egg-moves.ts index 19038ad824c..289ac60bcc5 100644 --- a/src/data/balance/egg-moves.ts +++ b/src/data/balance/egg-moves.ts @@ -1,5 +1,5 @@ import { allMoves } from "#app/data/moves/move"; -import * as Utils from "#app/utils"; +import { getEnumKeys, getEnumValues } from "#app/utils/common"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -12,7 +12,7 @@ export const speciesEggMoves = { [Species.WEEDLE]: [ Moves.THOUSAND_ARROWS, Moves.NOXIOUS_TORQUE, Moves.ATTACK_ORDER, Moves.VICTORY_DANCE ], [Species.PIDGEY]: [ Moves.BLEAKWIND_STORM, Moves.SANDSEAR_STORM, Moves.CALM_MIND, Moves.BOOMBURST ], [Species.RATTATA]: [ Moves.HYPER_FANG, Moves.PSYCHIC_FANGS, Moves.FIRE_FANG, Moves.EXTREME_SPEED ], - [Species.SPEAROW]: [ Moves.FLOATY_FALL, Moves.HYPER_DRILL, Moves.TIDY_UP, Moves.TRIPLE_ARROWS ], + [Species.SPEAROW]: [ Moves.FLOATY_FALL, Moves.EXTREME_SPEED, Moves.KNOCK_OFF, Moves.TRIPLE_ARROWS ], [Species.EKANS]: [ Moves.NOXIOUS_TORQUE, Moves.DRAGON_DANCE, Moves.SLACK_OFF, Moves.SHED_TAIL ], [Species.SANDSHREW]: [ Moves.HIGH_HORSEPOWER, Moves.DIRE_CLAW, Moves.SHORE_UP, Moves.MIGHTY_CLEAVE ], [Species.NIDORAN_F]: [ Moves.CALM_MIND, Moves.MOONLIGHT, Moves.MALIGNANT_CHAIN, Moves.SANDSEAR_STORM ], @@ -53,7 +53,7 @@ export const speciesEggMoves = { [Species.RHYHORN]: [ Moves.SHORE_UP, Moves.ICE_HAMMER, Moves.ACCELEROCK, Moves.HEAD_SMASH ], [Species.TANGELA]: [ Moves.NATURES_MADNESS, Moves.SNAP_TRAP, Moves.PARTING_SHOT, Moves.SAPPY_SEED ], [Species.KANGASKHAN]: [ Moves.POWER_UP_PUNCH, Moves.TRAILBLAZE, Moves.COVET, Moves.SEISMIC_TOSS ], - [Species.HORSEA]: [ Moves.SNIPE_SHOT, Moves.FROST_BREATH, Moves.SLUDGE_BOMB, Moves.CLANGING_SCALES ], + [Species.HORSEA]: [ Moves.SNIPE_SHOT, Moves.TAKE_HEART, Moves.SHELL_SIDE_ARM, Moves.DRAGON_ENERGY ], [Species.GOLDEEN]: [ Moves.GLACIAL_LANCE, Moves.SUPERCELL_SLAM, Moves.DRAGON_DANCE, Moves.FISHIOUS_REND ], [Species.STARYU]: [ Moves.CALM_MIND, Moves.BOUNCY_BUBBLE, Moves.MOONBLAST, Moves.MYSTICAL_POWER ], [Species.SCYTHER]: [ Moves.MIGHTY_CLEAVE, Moves.GEAR_GRIND, Moves.STORM_THROW, Moves.BITTER_BLADE ], @@ -66,7 +66,7 @@ export const speciesEggMoves = { [Species.PORYGON]: [ Moves.THUNDERCLAP, Moves.AURA_SPHERE, Moves.FLAMETHROWER, Moves.TECHNO_BLAST ], [Species.OMANYTE]: [ Moves.FREEZE_DRY, Moves.GIGA_DRAIN, Moves.POWER_GEM, Moves.STEAM_ERUPTION ], [Species.KABUTO]: [ Moves.CEASELESS_EDGE, Moves.HIGH_HORSEPOWER, Moves.CRABHAMMER, Moves.MIGHTY_CLEAVE ], - [Species.AERODACTYL]: [ Moves.FLOATY_FALL, Moves.FLARE_BLITZ, Moves.SWORDS_DANCE, Moves.MIGHTY_CLEAVE ], + [Species.AERODACTYL]: [ Moves.FLOATY_FALL, Moves.HIGH_HORSEPOWER, Moves.STONE_AXE, Moves.SWORDS_DANCE ], [Species.ARTICUNO]: [ Moves.EARTH_POWER, Moves.CALM_MIND, Moves.AURORA_VEIL, Moves.AEROBLAST ], [Species.ZAPDOS]: [ Moves.BLEAKWIND_STORM, Moves.CALM_MIND, Moves.SANDSEAR_STORM, Moves.ELECTRO_SHOT ], [Species.MOLTRES]: [ Moves.EARTH_POWER, Moves.CALM_MIND, Moves.AEROBLAST, Moves.TORCH_SONG ], @@ -78,7 +78,7 @@ export const speciesEggMoves = { [Species.CYNDAQUIL]: [ Moves.NASTY_PLOT, Moves.EARTH_POWER, Moves.FIERY_DANCE, Moves.ELECTRO_DRIFT ], [Species.TOTODILE]: [ Moves.THUNDER_PUNCH, Moves.DRAGON_DANCE, Moves.PLAY_ROUGH, Moves.SURGING_STRIKES ], [Species.SENTRET]: [ Moves.TIDY_UP, Moves.FAKE_OUT, Moves.NUZZLE, Moves.EXTREME_SPEED ], - [Species.HOOTHOOT]: [ Moves.CALM_MIND, Moves.ESPER_WING, Moves.AEROBLAST, Moves.BOOMBURST ], + [Species.HOOTHOOT]: [ Moves.TAKE_HEART, Moves.ESPER_WING, Moves.AEROBLAST, Moves.BOOMBURST ], [Species.LEDYBA]: [ Moves.POLLEN_PUFF, Moves.MAT_BLOCK, Moves.PARTING_SHOT, Moves.SPORE ], [Species.SPINARAK]: [ Moves.PARTING_SHOT, Moves.ATTACK_ORDER, Moves.GASTRO_ACID, Moves.STRENGTH_SAP ], [Species.CHINCHOU]: [ Moves.THUNDERCLAP, Moves.BOUNCY_BUBBLE, Moves.THUNDER_CAGE, Moves.TAIL_GLOW ], @@ -166,7 +166,7 @@ export const speciesEggMoves = { [Species.SPOINK]: [ Moves.AURA_SPHERE, Moves.MILK_DRINK, Moves.EXPANDING_FORCE, Moves.TAIL_GLOW ], [Species.SPINDA]: [ Moves.SUPERPOWER, Moves.SLACK_OFF, Moves.FLEUR_CANNON, Moves.V_CREATE ], [Species.TRAPINCH]: [ Moves.FIRE_LASH, Moves.DRAGON_DARTS, Moves.THOUSAND_ARROWS, Moves.DRAGON_ENERGY ], - [Species.CACNEA]: [ Moves.EARTH_POWER, Moves.CEASELESS_EDGE, Moves.NIGHT_DAZE, Moves.SAPPY_SEED ], + [Species.CACNEA]: [ Moves.EARTH_POWER, Moves.CEASELESS_EDGE, Moves.NIGHT_DAZE, Moves.IVY_CUDGEL ], [Species.SWABLU]: [ Moves.ROOST, Moves.NASTY_PLOT, Moves.FLOATY_FALL, Moves.BOOMBURST ], [Species.ZANGOOSE]: [ Moves.FACADE, Moves.HIGH_HORSEPOWER, Moves.EXTREME_SPEED, Moves.TIDY_UP ], [Species.SEVIPER]: [ Moves.ICE_BEAM, Moves.BITTER_BLADE, Moves.SUCKER_PUNCH, Moves.NO_RETREAT ], @@ -222,7 +222,7 @@ export const speciesEggMoves = { [Species.DRIFLOON]: [ Moves.PSYCHO_SHIFT, Moves.MIND_BLOWN, Moves.CALM_MIND, Moves.OBLIVION_WING ], [Species.BUNEARY]: [ Moves.TRIPLE_AXEL, Moves.EXTREME_SPEED, Moves.THUNDEROUS_KICK, Moves.SWORDS_DANCE ], [Species.GLAMEOW]: [ Moves.PARTING_SHOT, Moves.HIGH_HORSEPOWER, Moves.SWORDS_DANCE, Moves.EXTREME_SPEED ], - [Species.CHINGLING]: [ Moves.BUZZY_BUZZ, Moves.EERIE_SPELL, Moves.TORCH_SONG, Moves.BOOMBURST ], + [Species.CHINGLING]: [ Moves.ALLURING_VOICE, Moves.EERIE_SPELL, Moves.TORCH_SONG, Moves.BOOMBURST ], [Species.STUNKY]: [ Moves.CEASELESS_EDGE, Moves.FIRE_LASH, Moves.RECOVER, Moves.DIRE_CLAW ], [Species.BRONZOR]: [ Moves.RECOVER, Moves.TACHYON_CUTTER, Moves.GLARE, Moves.LUMINA_CRASH ], [Species.BONSLY]: [ Moves.ACCELEROCK, Moves.SWORDS_DANCE, Moves.STRENGTH_SAP, Moves.SAPPY_SEED ], @@ -246,7 +246,7 @@ export const speciesEggMoves = { [Species.AZELF]: [ Moves.PSYSTRIKE, Moves.AURA_SPHERE, Moves.ICE_BEAM, Moves.TAIL_GLOW ], [Species.DIALGA]: [ Moves.CORE_ENFORCER, Moves.TAKE_HEART, Moves.RECOVER, Moves.MAKE_IT_RAIN ], [Species.PALKIA]: [ Moves.MALIGNANT_CHAIN, Moves.TAKE_HEART, Moves.RECOVER, Moves.ORIGIN_PULSE ], - [Species.HEATRAN]: [ Moves.MATCHA_GOTCHA, Moves.RECOVER, Moves.ERUPTION, Moves.TACHYON_CUTTER ], + [Species.HEATRAN]: [ Moves.ENERGY_BALL, Moves.RECOVER, Moves.ERUPTION, Moves.TACHYON_CUTTER ], [Species.REGIGIGAS]: [ Moves.SKILL_SWAP, Moves.RECOVER, Moves.EXTREME_SPEED, Moves.GIGATON_HAMMER ], [Species.GIRATINA]: [ Moves.DRAGON_DANCE, Moves.SPECTRAL_THIEF, Moves.RECOVER, Moves.COLLISION_COURSE ], [Species.CRESSELIA]: [ Moves.COSMIC_POWER, Moves.BODY_PRESS, Moves.SIZZLY_SLIDE, Moves.LUMINA_CRASH ], @@ -284,10 +284,10 @@ export const speciesEggMoves = { [Species.BASCULIN]: [ Moves.LAST_RESPECTS, Moves.CLOSE_COMBAT, Moves.SPLISHY_SPLASH, Moves.NO_RETREAT ], [Species.SANDILE]: [ Moves.DIRE_CLAW, Moves.SUCKER_PUNCH, Moves.FIRE_LASH, Moves.HEADLONG_RUSH ], [Species.DARUMAKA]: [ Moves.DRAIN_PUNCH, Moves.ZIPPY_ZAP, Moves.HEADLONG_RUSH, Moves.PYRO_BALL ], - [Species.MARACTUS]: [ Moves.EARTH_POWER, Moves.QUIVER_DANCE, Moves.FIERY_DANCE, Moves.SEED_FLARE ], + [Species.MARACTUS]: [ Moves.EARTH_POWER, Moves.SIZZLY_SLIDE, Moves.FIERY_DANCE, Moves.QUIVER_DANCE ], [Species.DWEBBLE]: [ Moves.CRABHAMMER, Moves.STONE_AXE, Moves.LEECH_LIFE, Moves.MIGHTY_CLEAVE ], [Species.SCRAGGY]: [ Moves.SUCKER_PUNCH, Moves.BULLET_PUNCH, Moves.NOXIOUS_TORQUE, Moves.VICTORY_DANCE ], - [Species.SIGILYPH]: [ Moves.MOONBLAST, Moves.CALM_MIND, Moves.ESPER_WING, Moves.OBLIVION_WING ], + [Species.SIGILYPH]: [ Moves.MOONBLAST, Moves.PSYCHO_SHIFT, Moves.ESPER_WING, Moves.OBLIVION_WING ], [Species.YAMASK]: [ Moves.STRENGTH_SAP, Moves.GLARE, Moves.AURA_SPHERE, Moves.ASTRAL_BARRAGE ], [Species.TIRTOUGA]: [ Moves.ICE_SPINNER, Moves.AQUA_STEP, Moves.SHORE_UP, Moves.MIGHTY_CLEAVE ], [Species.ARCHEN]: [ Moves.ROOST, Moves.EARTHQUAKE, Moves.FLOATY_FALL, Moves.MIGHTY_CLEAVE ], @@ -319,7 +319,7 @@ export const speciesEggMoves = { [Species.DRUDDIGON]: [ Moves.FIRE_LASH, Moves.MORNING_SUN, Moves.DRAGON_DARTS, Moves.CLANGOROUS_SOUL ], [Species.GOLETT]: [ Moves.SHIFT_GEAR, Moves.DRAIN_PUNCH, Moves.HEADLONG_RUSH, Moves.RAGE_FIST ], [Species.PAWNIARD]: [ Moves.SUCKER_PUNCH, Moves.CEASELESS_EDGE, Moves.BITTER_BLADE, Moves.LAST_RESPECTS ], - [Species.BOUFFALANT]: [ Moves.SLACK_OFF, Moves.HIGH_JUMP_KICK, Moves.HEAD_SMASH, Moves.FLARE_BLITZ ], + [Species.BOUFFALANT]: [ Moves.HORN_LEECH, Moves.HIGH_JUMP_KICK, Moves.HEAD_SMASH, Moves.FLARE_BLITZ ], [Species.RUFFLET]: [ Moves.FLOATY_FALL, Moves.AURA_SPHERE, Moves.NO_RETREAT, Moves.BOLT_BEAK ], [Species.VULLABY]: [ Moves.FOUL_PLAY, Moves.BODY_PRESS, Moves.ROOST, Moves.RUINATION ], [Species.HEATMOR]: [ Moves.EARTH_POWER, Moves.OVERHEAT, Moves.THUNDERBOLT, Moves.V_CREATE ], @@ -360,7 +360,7 @@ export const speciesEggMoves = { [Species.CLAUNCHER]: [ Moves.SHELL_SMASH, Moves.ARMOR_CANNON, Moves.ENERGY_BALL, Moves.ORIGIN_PULSE ], [Species.HELIOPTILE]: [ Moves.WEATHER_BALL, Moves.HYDRO_STEAM, Moves.EARTH_POWER, Moves.BOOMBURST ], [Species.TYRUNT]: [ Moves.DRAGON_HAMMER, Moves.FLARE_BLITZ, Moves.VOLT_TACKLE, Moves.SHIFT_GEAR ], - [Species.AMAURA]: [ Moves.RECOVER, Moves.WRING_OUT, Moves.POWER_GEM, Moves.GEOMANCY ], + [Species.AMAURA]: [ Moves.RECOVER, Moves.TERA_STARSTORM, Moves.POWER_GEM, Moves.GEOMANCY ], [Species.HAWLUCHA]: [ Moves.TRIPLE_AXEL, Moves.HIGH_HORSEPOWER, Moves.FLOATY_FALL, Moves.WICKED_BLOW ], [Species.DEDENNE]: [ Moves.BOOMBURST, Moves.FAKE_OUT, Moves.NASTY_PLOT, Moves.REVIVAL_BLESSING ], [Species.CARBINK]: [ Moves.BODY_PRESS, Moves.SHORE_UP, Moves.SPARKLY_SWIRL, Moves.DIAMOND_STORM ], @@ -436,12 +436,12 @@ export const speciesEggMoves = { [Species.ALOLA_RATTATA]: [ Moves.FALSE_SURRENDER, Moves.PSYCHIC_FANGS, Moves.COIL, Moves.EXTREME_SPEED ], [Species.ALOLA_SANDSHREW]: [ Moves.SPIKY_SHIELD, Moves.LIQUIDATION, Moves.SHIFT_GEAR, Moves.GLACIAL_LANCE ], [Species.ALOLA_VULPIX]: [ Moves.MOONBLAST, Moves.GLARE, Moves.MYSTICAL_FIRE, Moves.REVIVAL_BLESSING ], - [Species.ALOLA_DIGLETT]: [ Moves.THOUSAND_WAVES, Moves.SWORDS_DANCE, Moves.TRIPLE_DIVE, Moves.MOUNTAIN_GALE ], + [Species.ALOLA_DIGLETT]: [ Moves.THOUSAND_WAVES, Moves.SWORDS_DANCE, Moves.TRIPLE_DIVE, Moves.PYRO_BALL ], [Species.ALOLA_MEOWTH]: [ Moves.BADDY_BAD, Moves.BUZZY_BUZZ, Moves.PARTING_SHOT, Moves.MAKE_IT_RAIN ], [Species.ALOLA_GEODUDE]: [ Moves.THOUSAND_WAVES, Moves.BULK_UP, Moves.STONE_AXE, Moves.EXTREME_SPEED ], [Species.ALOLA_GRIMER]: [ Moves.SUCKER_PUNCH, Moves.BARB_BARRAGE, Moves.RECOVER, Moves.SURGING_STRIKES ], - [Species.GROOKEY]: [ Moves.HIGH_HORSEPOWER, Moves.CLANGOROUS_SOUL, Moves.GRASSY_GLIDE, Moves.SAPPY_SEED ], + [Species.GROOKEY]: [ Moves.ROCK_SLIDE, Moves.PLAY_ROUGH, Moves.GRASSY_GLIDE, Moves.CLANGOROUS_SOUL ], [Species.SCORBUNNY]: [ Moves.EXTREME_SPEED, Moves.HIGH_JUMP_KICK, Moves.TRIPLE_AXEL, Moves.BOLT_STRIKE ], [Species.SOBBLE]: [ Moves.AEROBLAST, Moves.FROST_BREATH, Moves.ENERGY_BALL, Moves.NASTY_PLOT ], [Species.SKWOVET]: [ Moves.SUCKER_PUNCH, Moves.SLACK_OFF, Moves.COIL, Moves.POPULATION_BOMB ], @@ -457,7 +457,7 @@ export const speciesEggMoves = { [Species.SILICOBRA]: [ Moves.SHORE_UP, Moves.SHED_TAIL, Moves.MOUNTAIN_GALE, Moves.THOUSAND_ARROWS ], [Species.CRAMORANT]: [ Moves.APPLE_ACID, Moves.SURF, Moves.BOLT_BEAK, Moves.OBLIVION_WING ], [Species.ARROKUDA]: [ Moves.SUPERCELL_SLAM, Moves.TRIPLE_DIVE, Moves.ICE_SPINNER, Moves.SWORDS_DANCE ], - [Species.TOXEL]: [ Moves.NASTY_PLOT, Moves.BUG_BUZZ, Moves.SPARKLING_ARIA, Moves.TORCH_SONG ], + [Species.TOXEL]: [ Moves.BUZZY_BUZZ, Moves.BUG_BUZZ, Moves.SPARKLING_ARIA, Moves.TORCH_SONG ], [Species.SIZZLIPEDE]: [ Moves.BURNING_BULWARK, Moves.ZING_ZAP, Moves.FIRST_IMPRESSION, Moves.BITTER_BLADE ], [Species.CLOBBOPUS]: [ Moves.STORM_THROW, Moves.JET_PUNCH, Moves.MACH_PUNCH, Moves.SURGING_STRIKES ], [Species.SINISTEA]: [ Moves.SPLISHY_SPLASH, Moves.MATCHA_GOTCHA, Moves.DRAINING_KISS, Moves.MOONGEIST_BEAM ], @@ -587,8 +587,8 @@ export const speciesEggMoves = { function parseEggMoves(content: string): void { let output = ""; - const speciesNames = Utils.getEnumKeys(Species); - const speciesValues = Utils.getEnumValues(Species); + const speciesNames = getEnumKeys(Species); + const speciesValues = getEnumValues(Species); const lines = content.split(/\n/g); for (const line of lines) { diff --git a/src/data/balance/passives.ts b/src/data/balance/passives.ts index 624e242944b..73310cc2116 100644 --- a/src/data/balance/passives.ts +++ b/src/data/balance/passives.ts @@ -143,7 +143,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [Species.TAUROS]: { 0: Abilities.STAMINA }, [Species.MAGIKARP]: { 0: Abilities.MULTISCALE }, [Species.GYARADOS]: { 0: Abilities.MULTISCALE, 1: Abilities.MULTISCALE }, - [Species.LAPRAS]: { 0: Abilities.LIGHTNING_ROD, 1: Abilities.FILTER }, + [Species.LAPRAS]: { 0: Abilities.FILTER, 1: Abilities.FILTER }, [Species.DITTO]: { 0: Abilities.ADAPTABILITY }, [Species.EEVEE]: { 0: Abilities.PICKUP, 1: Abilities.PICKUP, 2: Abilities.FLUFFY }, [Species.VAPOREON]: { 0: Abilities.REGENERATOR }, @@ -161,7 +161,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [Species.OMASTAR]: { 0: Abilities.STURDY }, [Species.KABUTO]: { 0: Abilities.TOUGH_CLAWS }, [Species.KABUTOPS]: { 0: Abilities.TOUGH_CLAWS }, - [Species.AERODACTYL]: { 0: Abilities.INTIMIDATE, 1: Abilities.INTIMIDATE }, + [Species.AERODACTYL]: { 0: Abilities.INTIMIDATE, 1: Abilities.ROCKY_PAYLOAD }, [Species.ARTICUNO]: { 0: Abilities.SNOW_WARNING }, [Species.ZAPDOS]: { 0: Abilities.DRIZZLE }, [Species.MOLTRES]: { 0: Abilities.DROUGHT }, @@ -506,7 +506,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [Species.SNOVER]: { 0: Abilities.SLUSH_RUSH }, [Species.ABOMASNOW]: { 0: Abilities.SLUSH_RUSH, 1: Abilities.SEED_SOWER }, [Species.ROTOM]: { 0: Abilities.HADRON_ENGINE, 1: Abilities.HADRON_ENGINE, 2: Abilities.HADRON_ENGINE, 3: Abilities.HADRON_ENGINE, 4: Abilities.HADRON_ENGINE, 5: Abilities.HADRON_ENGINE }, - [Species.UXIE]: { 0: Abilities.UNNERVE }, + [Species.UXIE]: { 0: Abilities.ILLUSION }, [Species.MESPRIT]: { 0: Abilities.MOODY }, [Species.AZELF]: { 0: Abilities.NEUROFORCE }, [Species.DIALGA]: { 0: Abilities.BERSERK, 1: Abilities.BERSERK }, @@ -600,8 +600,8 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [Species.ARCHEOPS]: { 0: Abilities.MULTISCALE }, [Species.TRUBBISH]: { 0: Abilities.NEUTRALIZING_GAS }, [Species.GARBODOR]: { 0: Abilities.NEUTRALIZING_GAS, 1: Abilities.NEUTRALIZING_GAS }, - [Species.ZORUA]: { 0: Abilities.DARK_AURA }, - [Species.ZOROARK]: { 0: Abilities.DARK_AURA }, + [Species.ZORUA]: { 0: Abilities.ADAPTABILITY }, + [Species.ZOROARK]: { 0: Abilities.ADAPTABILITY }, [Species.MINCCINO]: { 0: Abilities.FUR_COAT }, [Species.CINCCINO]: { 0: Abilities.FUR_COAT }, [Species.GOTHITA]: { 0: Abilities.UNNERVE }, @@ -729,8 +729,8 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [Species.CLAWITZER]: { 0: Abilities.PROTEAN }, [Species.HELIOPTILE]: { 0: Abilities.PROTEAN }, [Species.HELIOLISK]: { 0: Abilities.PROTEAN }, - [Species.TYRUNT]: { 0: Abilities.RECKLESS }, - [Species.TYRANTRUM]: { 0: Abilities.RECKLESS }, + [Species.TYRUNT]: { 0: Abilities.SHEER_FORCE }, + [Species.TYRANTRUM]: { 0: Abilities.SHEER_FORCE }, [Species.AMAURA]: { 0: Abilities.ICE_SCALES }, [Species.AURORUS]: { 0: Abilities.ICE_SCALES }, [Species.HAWLUCHA]: { 0: Abilities.MOXIE }, @@ -744,8 +744,8 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [Species.KLEFKI]: { 0: Abilities.LEVITATE }, [Species.PHANTUMP]: { 0: Abilities.SHADOW_TAG }, [Species.TREVENANT]: { 0: Abilities.SHADOW_TAG }, - [Species.PUMPKABOO]: { 0: Abilities.WELL_BAKED_BODY, 1: Abilities.ADAPTABILITY, 2: Abilities.PRANKSTER, 3: Abilities.SEED_SOWER }, - [Species.GOURGEIST]: { 0: Abilities.WELL_BAKED_BODY, 1: Abilities.ADAPTABILITY, 2: Abilities.PRANKSTER, 3: Abilities.SEED_SOWER }, + [Species.PUMPKABOO]: { 0: Abilities.ILLUMINATE, 1: Abilities.ADAPTABILITY, 2: Abilities.WELL_BAKED_BODY, 3: Abilities.SEED_SOWER }, + [Species.GOURGEIST]: { 0: Abilities.ILLUMINATE, 1: Abilities.ADAPTABILITY, 2: Abilities.WELL_BAKED_BODY, 3: Abilities.SEED_SOWER }, [Species.BERGMITE]: { 0: Abilities.ICE_SCALES }, [Species.AVALUGG]: { 0: Abilities.ICE_SCALES }, [Species.HISUI_AVALUGG]: { 0: Abilities.ICE_SCALES }, @@ -781,7 +781,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [Species.CRABOMINABLE]: { 0: Abilities.WATER_BUBBLE }, [Species.ORICORIO]: { 0: Abilities.ADAPTABILITY, 1: Abilities.ADAPTABILITY, 2: Abilities.ADAPTABILITY, 3: Abilities.ADAPTABILITY }, [Species.CUTIEFLY]: { 0: Abilities.PICKUP }, - [Species.RIBOMBEE]: { 0: Abilities.TINTED_LENS }, + [Species.RIBOMBEE]: { 0: Abilities.PICKUP }, [Species.ROCKRUFF]: { 0: Abilities.PICKUP, 1: Abilities.PICKUP }, [Species.LYCANROC]: { 0: Abilities.STURDY, 1: Abilities.INTIMIDATE, 2: Abilities.STAKEOUT }, [Species.WISHIWASHI]: { 0: Abilities.REGENERATOR, 1: Abilities.REGENERATOR }, @@ -932,7 +932,7 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [Species.COPPERAJAH]: { 0: Abilities.EARTH_EATER, 1: Abilities.EARTH_EATER }, [Species.DRACOZOLT]: { 0: Abilities.NO_GUARD }, [Species.ARCTOZOLT]: { 0: Abilities.WATER_ABSORB }, - [Species.DRACOVISH]: { 0: Abilities.SWIFT_SWIM }, + [Species.DRACOVISH]: { 0: Abilities.THERMAL_EXCHANGE }, [Species.ARCTOVISH]: { 0: Abilities.STRONG_JAW }, [Species.DURALUDON]: { 0: Abilities.FILTER, 1: Abilities.UNAWARE }, [Species.ARCHALUDON]: { 0: Abilities.TRANSISTOR }, @@ -981,8 +981,8 @@ export const starterPassiveAbilities: StarterPassiveAbilities = { [Species.OVERQWIL]: { 0: Abilities.MERCILESS }, [Species.HISUI_SNEASEL]: { 0: Abilities.SCRAPPY }, [Species.SNEASLER]: { 0: Abilities.SCRAPPY }, - [Species.HISUI_ZORUA]: { 0: Abilities.ADAPTABILITY }, - [Species.HISUI_ZOROARK]: { 0: Abilities.ADAPTABILITY }, + [Species.HISUI_ZORUA]: { 0: Abilities.SHADOW_SHIELD }, + [Species.HISUI_ZOROARK]: { 0: Abilities.SHADOW_SHIELD }, [Species.SPRIGATITO]: { 0: Abilities.PICKUP }, [Species.FLORAGATO]: { 0: Abilities.MAGICIAN }, diff --git a/src/data/balance/pokemon-evolutions.ts b/src/data/balance/pokemon-evolutions.ts index e49bd049cd6..64409c3c989 100644 --- a/src/data/balance/pokemon-evolutions.ts +++ b/src/data/balance/pokemon-evolutions.ts @@ -3,7 +3,7 @@ import { Gender } from "#app/data/gender"; import { PokeballType } from "#enums/pokeball"; import type Pokemon from "#app/field/pokemon"; import { PokemonType } from "#enums/pokemon-type"; -import * as Utils from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import { WeatherType } from "#enums/weather-type"; import { Nature } from "#enums/nature"; import { Biome } from "#enums/biome"; @@ -14,6 +14,7 @@ import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifi import { SpeciesFormKey } from "#enums/species-form-key"; import { speciesStarterCosts } from "./starters"; import i18next from "i18next"; +import { initI18n } from "#app/plugins/i18n"; export enum SpeciesWildEvolutionDelay { @@ -95,6 +96,9 @@ export class SpeciesFormEvolution { public description = ""; constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: number, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) { + if (!i18next.isInitialized) { + initI18n(); + } this.speciesId = speciesId; this.preFormKey = preFormKey; this.evoFormKey = evoFormKey; @@ -333,7 +337,7 @@ class DunsparceEvolutionCondition extends SpeciesEvolutionCondition { super(p => { let ret = false; if (p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0) { - globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id); + globalScene.executeWithSeedOffset(() => ret = !randSeedInt(4), p.id); } return ret; }); @@ -346,7 +350,7 @@ class TandemausEvolutionCondition extends SpeciesEvolutionCondition { constructor() { super(p => { let ret = false; - globalScene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id); + globalScene.executeWithSeedOffset(() => ret = !randSeedInt(4), p.id); return ret; }); } diff --git a/src/data/balance/pokemon-level-moves.ts b/src/data/balance/pokemon-level-moves.ts index dcbc2fb0c0d..0b0ba1b5f71 100644 --- a/src/data/balance/pokemon-level-moves.ts +++ b/src/data/balance/pokemon-level-moves.ts @@ -19383,6 +19383,44 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = { [ 100, Moves.SEED_FLARE ], ] }, + [Species.BASCULIN]: { + 1: [ + [ 1, Moves.TAIL_WHIP ], + [ 1, Moves.WATER_GUN ], + [ 4, Moves.TACKLE ], + [ 8, Moves.FLAIL ], + [ 12, Moves.AQUA_JET ], + [ 16, Moves.BITE ], + [ 20, Moves.SCARY_FACE ], + [ 24, Moves.HEADBUTT ], + [ 28, Moves.SOAK ], + [ 32, Moves.CRUNCH ], + [ 36, Moves.TAKE_DOWN ], + [ 40, Moves.FINAL_GAMBIT ], + [ 44, Moves.WAVE_CRASH ], + [ 48, Moves.THRASH ], + [ 52, Moves.DOUBLE_EDGE ], + [ 56, Moves.HEAD_SMASH ], + ], + 2: [ + [ 1, Moves.TAIL_WHIP ], + [ 1, Moves.WATER_GUN ], + [ 4, Moves.TACKLE ], + [ 8, Moves.FLAIL ], + [ 12, Moves.AQUA_JET ], + [ 16, Moves.BITE ], + [ 20, Moves.SCARY_FACE ], + [ 24, Moves.HEADBUTT ], + [ 28, Moves.SOAK ], + [ 32, Moves.CRUNCH ], + [ 36, Moves.TAKE_DOWN ], + [ 40, Moves.UPROAR ], + [ 44, Moves.WAVE_CRASH ], + [ 48, Moves.THRASH ], + [ 52, Moves.DOUBLE_EDGE ], + [ 56, Moves.HEAD_SMASH ], + ] + }, [Species.KYUREM]: { 1: [ [ 1, Moves.DRAGON_BREATH ], diff --git a/src/data/balance/signature-species.ts b/src/data/balance/signature-species.ts index a1b73af40cd..fb8f33d4435 100644 --- a/src/data/balance/signature-species.ts +++ b/src/data/balance/signature-species.ts @@ -4,159 +4,103 @@ export type SignatureSpecies = { [key in string]: (Species | Species[])[]; }; -/* +/** * The signature species for each Gym Leader, Elite Four member, and Champion. * The key is the trainer type, and the value is an array of Species or Species arrays. * This is in a separate const so it can be accessed from other places and not just the trainerConfigs + * + * @remarks + * The `Proxy` object allows us to define a handler that will intercept + * the property access and return an empty array if the property does not exist in the object. + * + * This means that accessing `signatureSpecies` will not throw an error if the property does not exist, + * but instead default to an empty array. */ -export const signatureSpecies: SignatureSpecies = { +export const signatureSpecies: SignatureSpecies = new Proxy({ // Gym Leaders- Kanto - BROCK: [Species.GEODUDE, Species.ONIX], - MISTY: [Species.STARYU, Species.PSYDUCK], - LT_SURGE: [Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ], + BROCK: [Species.ONIX, Species.GEODUDE, [Species.OMANYTE, Species.KABUTO], Species.AERODACTYL], + MISTY: [Species.STARYU, Species.PSYDUCK, Species.WOOPER, Species.LAPRAS], + LT_SURGE: [Species.PICHU, Species.VOLTORB, Species.ELEKID, Species.JOLTEON], ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP], - JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT], - SABRINA: [Species.ABRA, Species.MR_MIME, Species.ESPEON], - BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGMAR], - GIOVANNI: [Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F], + JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT, Species.KOFFING], + SABRINA: [Species.ABRA, Species.MR_MIME, Species.SMOOCHUM, Species.ESPEON], + BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGBY, Species.VULPIX], + GIOVANNI: [Species.RHYHORN, Species.MEOWTH, [Species.NIDORAN_F, Species.NIDORAN_M], Species.DIGLETT], // Tera Ground Meowth // Gym Leaders- Johto - FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.DODUO], - BUGSY: [Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR], - WHITNEY: [Species.JIGGLYPUFF, Species.MILTANK, Species.AIPOM, Species.GIRAFARIG], - MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE], - CHUCK: [Species.POLIWRATH, Species.MANKEY], - JASMINE: [Species.MAGNEMITE, Species.STEELIX], - PRYCE: [Species.SEEL, Species.SWINUB], - CLAIR: [Species.DRATINI, Species.HORSEA, Species.GYARADOS], + FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.NATU, Species.MURKROW], + BUGSY: [Species.SCYTHER, Species.SHUCKLE, Species.YANMA, [Species.PINSIR, Species.HERACROSS]], + WHITNEY: [Species.MILTANK, Species.AIPOM, Species.IGGLYBUFF, [Species.GIRAFARIG, Species.STANTLER]], + MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.DUSKULL, Species.SABLEYE], + CHUCK: [Species.POLIWRATH, Species.MANKEY, Species.TYROGUE, Species.MACHOP], + JASMINE: [Species.STEELIX, Species.MAGNEMITE, Species.PINECO, Species.SKARMORY], + PRYCE: [Species.SWINUB, Species.SEEL, Species.SHELLDER, Species.SNEASEL], + CLAIR: [Species.HORSEA, Species.DRATINI, Species.MAGIKARP, Species.DRUDDIGON], // Tera Dragon Magikarp // Gym Leaders- Hoenn - ROXANNE: [Species.GEODUDE, Species.NOSEPASS], - BRAWLY: [Species.MACHOP, Species.MAKUHITA], - WATTSON: [Species.MAGNEMITE, Species.VOLTORB, Species.ELECTRIKE], - FLANNERY: [Species.SLUGMA, Species.TORKOAL, Species.NUMEL], - NORMAN: [Species.SLAKOTH, Species.SPINDA, Species.ZIGZAGOON, Species.KECLEON], + ROXANNE: [Species.NOSEPASS, Species.GEODUDE, [Species.LILEEP, Species.ANORITH], Species.ARON], + BRAWLY: [Species.MAKUHITA, Species.MACHOP, Species.MEDITITE, Species.SHROOMISH], + WATTSON: [Species.ELECTRIKE, Species.VOLTORB, Species.MAGNEMITE, [Species.PLUSLE, Species.MINUN]], + FLANNERY: [Species.TORKOAL, Species.SLUGMA, Species.NUMEL, Species.HOUNDOUR], + NORMAN: [Species.SLAKOTH, Species.KECLEON, Species.WHISMUR, Species.ZANGOOSE], WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY], - TATE: [Species.SOLROCK, Species.NATU, Species.CHIMECHO, Species.GALLADE], - LIZA: [Species.LUNATONE, Species.SPOINK, Species.BALTOY, Species.GARDEVOIR], - JUAN: [Species.HORSEA, Species.BARBOACH, Species.SPHEAL, Species.RELICANTH], + TATE: [Species.SOLROCK, Species.NATU, Species.CHINGLING, Species.GALLADE], + LIZA: [Species.LUNATONE, Species.BALTOY, Species.SPOINK, Species.GARDEVOIR], + JUAN: [Species.HORSEA, Species.SPHEAL, Species.BARBOACH, Species.CORPHISH], // Gym Leaders- Sinnoh - ROARK: [Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE], - GARDENIA: [Species.ROSELIA, Species.TANGELA, Species.TURTWIG], - MAYLENE: [Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR], + ROARK: [Species.CRANIDOS, Species.GEODUDE, Species.NOSEPASS, Species.LARVITAR], + GARDENIA: [Species.BUDEW, Species.CHERUBI, Species.TURTWIG, Species.LEAFEON], + MAYLENE: [Species.RIOLU, Species.MEDITITE, Species.CHIMCHAR, Species.CROAGUNK], CRASHER_WAKE: [Species.BUIZEL, Species.WOOPER, Species.PIPLUP, Species.MAGIKARP], - FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.SPIRITOMB], - BYRON: [Species.SHIELDON, Species.BRONZOR, Species.AGGRON], - CANDICE: [Species.SNEASEL, Species.SNOVER, Species.SNORUNT], - VOLKNER: [Species.SHINX, Species.CHINCHOU, Species.ROTOM], + FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.DUSKULL, Species.SPIRITOMB], + BYRON: [Species.SHIELDON, Species.BRONZOR, Species.ARON, Species.SKARMORY], + CANDICE: [Species.FROSLASS, Species.SNOVER, Species.SNEASEL, Species.GLACEON], + VOLKNER: [Species.ELEKID, Species.SHINX, Species.CHINCHOU, Species.ROTOM], // Gym Leaders- Unova - CILAN: [Species.PANSAGE, Species.FOONGUS, Species.PETILIL], - CHILI: [Species.PANSEAR, Species.DARUMAKA, Species.NUMEL], - CRESS: [Species.PANPOUR, Species.TYMPOLE, Species.SLOWPOKE], - CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE], - LENORA: [Species.PATRAT, Species.DEERLING, Species.AUDINO], - ROXIE: [Species.VENIPEDE, Species.TRUBBISH, Species.SKORUPI], - BURGH: [Species.SEWADDLE, Species.SHELMET, Species.KARRABLAST], - ELESA: [Species.EMOLGA, Species.BLITZLE, Species.JOLTIK], - CLAY: [Species.DRILBUR, Species.SANDILE, Species.GOLETT], - SKYLA: [Species.DUCKLETT, Species.WOOBAT, Species.RUFFLET], - BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO], - DRAYDEN: [Species.DRUDDIGON, Species.AXEW, Species.DEINO], - MARLON: [Species.WAILMER, Species.FRILLISH, Species.TIRTOUGA], + CILAN: [Species.PANSAGE, Species.SNIVY, Species.MARACTUS, Species.FERROSEED], + CHILI: [Species.PANSEAR, Species.TEPIG, Species.HEATMOR, Species.DARUMAKA], + CRESS: [Species.PANPOUR, Species.OSHAWOTT, Species.BASCULIN, Species.TYMPOLE], + CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE, Species.BOUFFALANT], + LENORA: [Species.PATRAT, Species.DEERLING, Species.AUDINO, Species.BRAVIARY], + ROXIE: [Species.VENIPEDE, Species.KOFFING, Species.TRUBBISH, Species.TOXEL], + BURGH: [Species.SEWADDLE, Species.DWEBBLE, [Species.KARRABLAST, Species.SHELMET], Species.DURANT], + ELESA: [Species.BLITZLE, Species.EMOLGA, Species.JOLTIK, Species.TYNAMO], + CLAY: [Species.DRILBUR, Species.SANDILE, Species.TYMPOLE, Species.GOLETT], + SKYLA: [Species.DUCKLETT, Species.WOOBAT, [Species.RUFFLET, Species.VULLABY], Species.ARCHEN], + BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO, Species.GALAR_DARUMAKA], + DRAYDEN: [Species.AXEW, Species.DRUDDIGON, Species.TRAPINCH, Species.DEINO], + MARLON: [Species.FRILLISH, Species.TIRTOUGA, Species.WAILMER, Species.MANTYKE], // Gym Leaders- Kalos - VIOLA: [Species.SURSKIT, Species.SCATTERBUG], - GRANT: [Species.AMAURA, Species.TYRUNT], - KORRINA: [Species.HAWLUCHA, Species.LUCARIO, Species.MIENFOO], - RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT], - CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.EMOLGA], - VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME], - OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.SLOWKING], - WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL], + VIOLA: [Species.SCATTERBUG, Species.SURSKIT, Species.CUTIEFLY, Species.BLIPBUG], + GRANT: [Species.TYRUNT, Species.AMAURA, Species.BINACLE, Species.DWEBBLE], + KORRINA: [Species.RIOLU, Species.MIENFOO, Species.HAWLUCHA, Species.PANCHAM], + RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT, [Species.PHANTUMP, Species.PUMPKABOO]], + CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.DEDENNE, Species.ROTOM], + VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME, [Species.SPRITZEE, Species.SWIRLIX]], + OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.INKAY, Species.SLOWKING], + WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL, Species.SWINUB], // Gym Leaders- Galar - MILO: [Species.GOSSIFLEUR, Species.APPLIN, Species.BOUNSWEET], - NESSA: [Species.CHEWTLE, Species.ARROKUDA, Species.WIMPOD], - KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.TORKOAL], - BEA: [Species.GALAR_FARFETCHD, Species.MACHOP, Species.CLOBBOPUS], - ALLISTER: [Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.GASTLY], - OPAL: [Species.MILCERY, Species.TOGETIC, Species.GALAR_WEEZING], - BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR], - GORDIE: [Species.ROLYCOLY, Species.STONJOURNER, Species.BINACLE], - MELONY: [Species.SNOM, Species.GALAR_DARUMAKA, Species.GALAR_MR_MIME], - PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY], - MARNIE: [Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO], - RAIHAN: [Species.DURALUDON, Species.TURTONATOR, Species.GOOMY], + MILO: [Species.GOSSIFLEUR, Species.SEEDOT, Species.APPLIN, Species.LOTAD], + NESSA: [Species.CHEWTLE, Species.WIMPOD, Species.ARROKUDA, Species.MAREANIE], + KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.GROWLITHE, Species.TORKOAL], + BEA: [Species.MACHOP, Species.GALAR_FARFETCHD, Species.CLOBBOPUS, Species.FALINKS], + ALLISTER: [Species.GASTLY, Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.SINISTEA], + OPAL: [Species.MILCERY, Species.GALAR_WEEZING, Species.TOGEPI, Species.MAWILE], + BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR, Species.SYLVEON], + GORDIE: [Species.ROLYCOLY, [Species.SHUCKLE, Species.BINACLE], Species.STONJOURNER, Species.LARVITAR], + MELONY: [Species.LAPRAS, Species.SNOM, Species.EISCUE, [Species.GALAR_MR_MIME, Species.GALAR_DARUMAKA]], + PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.TOXEL, Species.INKAY], // Tera Dark Toxel + MARNIE: [Species.IMPIDIMP, Species.MORPEKO, Species.PURRLOIN, Species.CROAGUNK], // Tera Dark Croagunk + RAIHAN: [Species.DURALUDON, Species.TRAPINCH, Species.GOOMY, Species.TURTONATOR], // Gym Leaders- Paldea; First slot is Tera - KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA], // Tera Bug Teddiursa - BRASSIUS: [Species.SUDOWOODO, Species.BRAMBLIN, Species.SMOLIV], // Tera Grass Sudowoodo - IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL], // Tera Ghost Misdreavus + KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA, Species.RELLOR], // Tera Bug Teddiursa + BRASSIUS: [Species.BONSLY, Species.SMOLIV, Species.BRAMBLIN, Species.SUNKERN], // Tera Grass Bonsly + IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL, Species.MAGNEMITE], // Tera Ghost Misdreavus KOFU: [Species.CRABRAWLER, Species.VELUZA, Species.WIGLETT, Species.WINGULL], // Tera Water Crabrawler LARRY: [Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA], // Tera Normal Starly RYME: [Species.TOXEL, Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], // Tera Ghost Toxel TULIP: [Species.FLABEBE, Species.FLITTLE, Species.RALTS, Species.GIRAFARIG], // Tera Psychic Flabebe - GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.CUBCHOO, Species.ALOLA_VULPIX], // Tera Ice Swablu - - // Elite Four- Kanto - LORELEI: [ - Species.JYNX, - [Species.SLOWBRO, Species.GALAR_SLOWBRO], - Species.LAPRAS, - [Species.CLOYSTER, Species.ALOLA_SANDSLASH], - ], - BRUNO: [Species.MACHAMP, Species.HITMONCHAN, Species.HITMONLEE, [Species.GOLEM, Species.ALOLA_GOLEM]], - AGATHA: [Species.GENGAR, [Species.ARBOK, Species.WEEZING], Species.CROBAT, Species.ALOLA_MAROWAK], - LANCE: [Species.DRAGONITE, Species.GYARADOS, Species.AERODACTYL, Species.ALOLA_EXEGGUTOR], - // Elite Four- Johto (Bruno included) - WILL: [Species.XATU, Species.JYNX, [Species.SLOWBRO, Species.SLOWKING], Species.EXEGGUTOR], - KOGA: [[Species.MUK, Species.WEEZING], [Species.VENOMOTH, Species.ARIADOS], Species.CROBAT, Species.TENTACRUEL], - KAREN: [Species.UMBREON, Species.HONCHKROW, Species.HOUNDOOM, Species.WEAVILE], - // Elite Four- Hoenn - SIDNEY: [ - [Species.SHIFTRY, Species.CACTURNE], - [Species.SHARPEDO, Species.CRAWDAUNT], - Species.ABSOL, - Species.MIGHTYENA, - ], - PHOEBE: [Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, [Species.DRIFBLIM, Species.MISMAGIUS]], - GLACIA: [Species.GLALIE, Species.WALREIN, Species.FROSLASS, Species.ABOMASNOW], - DRAKE: [Species.ALTARIA, Species.SALAMENCE, Species.FLYGON, Species.KINGDRA], - // Elite Four- Sinnoh - AARON: [[Species.SCIZOR, Species.KLEAVOR], Species.HERACROSS, [Species.VESPIQUEN, Species.YANMEGA], Species.DRAPION], - BERTHA: [Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR], - FLINT: [ - [Species.RAPIDASH, Species.FLAREON], - Species.MAGMORTAR, - [Species.STEELIX, Species.LOPUNNY], - Species.INFERNAPE, - ], // Tera Fire Steelix or Lopunny - LUCIAN: [Species.MR_MIME, Species.GALLADE, Species.BRONZONG, [Species.ALAKAZAM, Species.ESPEON]], - // Elite Four- Unova - SHAUNTAL: [Species.COFAGRIGUS, Species.CHANDELURE, Species.GOLURK, Species.JELLICENT], - MARSHAL: [Species.CONKELDURR, Species.MIENSHAO, Species.THROH, Species.SAWK], - GRIMSLEY: [Species.LIEPARD, Species.KINGAMBIT, Species.SCRAFTY, Species.KROOKODILE], - CAITLIN: [Species.MUSHARNA, Species.GOTHITELLE, Species.SIGILYPH, Species.REUNICLUS], - // Elite Four- Kalos - MALVA: [Species.PYROAR, Species.TORKOAL, Species.CHANDELURE, Species.TALONFLAME], - SIEBOLD: [Species.CLAWITZER, Species.GYARADOS, Species.BARBARACLE, Species.STARMIE], - WIKSTROM: [Species.KLEFKI, Species.PROBOPASS, Species.SCIZOR, Species.AEGISLASH], - DRASNA: [Species.DRAGALGE, Species.DRUDDIGON, Species.ALTARIA, Species.NOIVERN], - // Elite Four- Alola - HALA: [Species.HARIYAMA, Species.BEWEAR, Species.CRABOMINABLE, [Species.POLIWRATH, Species.ANNIHILAPE]], - MOLAYNE: [Species.KLEFKI, Species.MAGNEZONE, Species.METAGROSS, Species.ALOLA_DUGTRIO], - OLIVIA: [Species.RELICANTH, Species.CARBINK, Species.ALOLA_GOLEM, Species.LYCANROC], - ACEROLA: [[Species.BANETTE, Species.DRIFBLIM], Species.MIMIKYU, Species.DHELMISE, Species.PALOSSAND], - KAHILI: [[Species.BRAVIARY, Species.MANDIBUZZ], Species.HAWLUCHA, Species.ORICORIO, Species.TOUCANNON], - // Elite Four- Galar - MARNIE_ELITE: [Species.MORPEKO, Species.LIEPARD, [Species.TOXICROAK, Species.SCRAFTY], Species.GRIMMSNARL], - NESSA_ELITE: [Species.GOLISOPOD, [Species.QUAGSIRE, Species.PELIPPER], Species.TOXAPEX, Species.DREDNAW], - BEA_ELITE: [Species.HAWLUCHA, [Species.GRAPPLOCT, Species.SIRFETCHD], Species.FALINKS, Species.MACHAMP], - ALLISTER_ELITE: [Species.DUSKNOIR, [Species.POLTEAGEIST, Species.RUNERIGUS], Species.CURSOLA, Species.GENGAR], - RAIHAN_ELITE: [Species.GOODRA, [Species.TORKOAL, Species.TURTONATOR], Species.FLYGON, Species.ARCHALUDON], - // Elite Four- Paldea - RIKA: [Species.CLODSIRE, [Species.DUGTRIO, Species.DONPHAN], Species.CAMERUPT, Species.WHISCASH], // Tera Ground Clodsire - POPPY: [Species.TINKATON, Species.BRONZONG, Species.CORVIKNIGHT, Species.COPPERAJAH], // Tera Steel Tinkaton - LARRY_ELITE: [Species.FLAMIGO, Species.STARAPTOR, [Species.ALTARIA, Species.TROPIUS], Species.ORICORIO], // Tera Flying Flamigo; random Oricorio - HASSEL: [Species.BAXCALIBUR, [Species.FLAPPLE, Species.APPLETUN], Species.DRAGALGE, Species.NOIVERN], // Tera Dragon Baxcalibur - // Elite Four- BBL - CRISPIN: [Species.BLAZIKEN, Species.MAGMORTAR, [Species.CAMERUPT, Species.TALONFLAME], Species.ROTOM], // Tera Fire Blaziken; Heat Rotom - AMARYS: [Species.METAGROSS, Species.SCIZOR, Species.EMPOLEON, Species.SKARMORY], // Tera Steel Metagross - LACEY: [Species.EXCADRILL, Species.PRIMARINA, [Species.WHIMSICOTT, Species.ALCREMIE], Species.GRANBULL], // Tera Fairy Excadrill - DRAYTON: [Species.ARCHALUDON, Species.DRAGONITE, Species.HAXORUS, Species.SCEPTILE], // Tera Dragon Archaludon -}; + GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.SNOM, Species.CUBCHOO], // Tera Ice Swablu +}, { + get(target, prop: string) { + return target[prop as keyof SignatureSpecies] ?? []; + } +}); diff --git a/src/data/balance/tms.ts b/src/data/balance/tms.ts index 788ffd4f273..69aef9b135d 100644 --- a/src/data/balance/tms.ts +++ b/src/data/balance/tms.ts @@ -5724,7 +5724,6 @@ export const tmSpecies: TmSpecies = { Species.SCOLIPEDE, Species.WHIMSICOTT, Species.LILLIGANT, - Species.BASCULIN, Species.KROOKODILE, Species.DARMANITAN, Species.CRUSTLE, @@ -6023,6 +6022,11 @@ export const tmSpecies: TmSpecies = { Species.HISUI_DECIDUEYE, Species.PALDEA_TAUROS, Species.BLOODMOON_URSALUNA, + [ + Species.BASCULIN, + "blue-striped", + "red-striped", + ] ], [Moves.LOW_KICK]: [ Species.SANDSHREW, @@ -19126,6 +19130,8 @@ export const tmSpecies: TmSpecies = { Species.KROOKODILE, Species.SCRAGGY, Species.SCRAFTY, + Species.YAMASK, + Species.COFAGRIGUS, Species.SAWSBUCK, Species.LITWICK, Species.LAMPENT, @@ -19163,6 +19169,7 @@ export const tmSpecies: TmSpecies = { Species.SINISTEA, Species.POLTEAGEIST, Species.PERRSERKER, + Species.RUNERIGUS, Species.PINCURCHIN, Species.STONJOURNER, Species.CUFANT, @@ -19228,6 +19235,7 @@ export const tmSpecies: TmSpecies = { Species.GALAR_SLOWBRO, Species.GALAR_WEEZING, Species.GALAR_SLOWKING, + Species.GALAR_YAMASK, Species.HISUI_ELECTRODE, Species.HISUI_TYPHLOSION, Species.HISUI_QWILFISH, @@ -19331,7 +19339,6 @@ export const tmSpecies: TmSpecies = { Species.CONKELDURR, Species.THROH, Species.SAWK, - Species.BASCULIN, Species.DARMANITAN, Species.SCRAFTY, Species.ESCAVALIER, @@ -19445,6 +19452,11 @@ export const tmSpecies: TmSpecies = { Species.HISUI_BRAVIARY, Species.HISUI_DECIDUEYE, Species.PALDEA_TAUROS, + [ + Species.BASCULIN, + "blue-striped", + "red-striped", + ], ], [Moves.SPITE]: [ Species.EKANS, @@ -30922,6 +30934,7 @@ export const tmSpecies: TmSpecies = { Species.MURKROW, Species.SLOWKING, Species.MISDREAVUS, + Species.UNOWN, Species.GIRAFARIG, Species.PINECO, Species.FORRETRESS, @@ -40134,6 +40147,8 @@ export const tmSpecies: TmSpecies = { Species.MEOWSTIC, Species.SPRITZEE, Species.AROMATISSE, + Species.INKAY, + Species.MALAMAR, Species.SYLVEON, Species.CARBINK, Species.PHANTUMP, @@ -49173,6 +49188,7 @@ export const tmSpecies: TmSpecies = { Species.KANGASKHAN, Species.GOLDEEN, Species.SEAKING, + Species.GYARADOS, Species.LAPRAS, Species.VAPOREON, Species.KABUTOPS, @@ -51333,7 +51349,6 @@ export const tmSpecies: TmSpecies = { Species.SCOLIPEDE, Species.WHIMSICOTT, Species.LILLIGANT, - Species.BASCULIN, Species.KROOKODILE, Species.DARMANITAN, Species.CRUSTLE, @@ -51647,6 +51662,11 @@ export const tmSpecies: TmSpecies = { Species.HISUI_DECIDUEYE, Species.PALDEA_TAUROS, Species.BLOODMOON_URSALUNA, + [ + Species.BASCULIN, + "blue-striped", + "red-striped", + ], ], [Moves.NASTY_PLOT]: [ Species.PIKACHU, @@ -52587,6 +52607,7 @@ export const tmSpecies: TmSpecies = { Species.SNORLAX, Species.MEWTWO, Species.MEW, + Species.MEGANIUM, Species.CYNDAQUIL, Species.QUILAVA, Species.TYPHLOSION, @@ -66205,7 +66226,11 @@ export const tmSpecies: TmSpecies = { Species.SQUIRTLE, Species.WARTORTLE, Species.BLASTOISE, + Species.CATERPIE, + Species.METAPOD, Species.BUTTERFREE, + Species.WEEDLE, + Species.KAKUNA, Species.BEEDRILL, Species.PIDGEY, Species.PIDGEOTTO, @@ -66451,7 +66476,10 @@ export const tmSpecies: TmSpecies = { Species.MIGHTYENA, Species.ZIGZAGOON, Species.LINOONE, + Species.WURMPLE, + Species.SILCOON, Species.BEAUTIFLY, + Species.CASCOON, Species.DUSTOX, Species.LOTAD, Species.LOMBRE, @@ -66987,6 +67015,8 @@ export const tmSpecies: TmSpecies = { Species.STAKATAKA, Species.BLACEPHALON, Species.ZERAORA, + Species.MELTAN, + Species.MELMETAL, Species.ALOLA_RATTATA, Species.ALOLA_RATICATE, Species.ALOLA_RAICHU, @@ -67020,8 +67050,19 @@ export const tmSpecies: TmSpecies = { Species.ROOKIDEE, Species.CORVISQUIRE, Species.CORVIKNIGHT, + Species.BLIPBUG, + Species.DOTTLER, + Species.ORBEETLE, + Species.NICKIT, + Species.THIEVUL, + Species.GOSSIFLEUR, + Species.ELDEGOSS, + Species.WOOLOO, + Species.DUBWOOL, Species.CHEWTLE, Species.DREDNAW, + Species.YAMPER, + Species.BOLTUND, Species.ROLYCOLY, Species.CARKOL, Species.COALOSSAL, @@ -67035,6 +67076,10 @@ export const tmSpecies: TmSpecies = { Species.BARRASKEWDA, Species.TOXEL, Species.TOXTRICITY, + Species.SIZZLIPEDE, + Species.CENTISKORCH, + Species.CLOBBOPUS, + Species.GRAPPLOCT, Species.SINISTEA, Species.POLTEAGEIST, Species.HATENNA, @@ -67043,7 +67088,14 @@ export const tmSpecies: TmSpecies = { Species.IMPIDIMP, Species.MORGREM, Species.GRIMMSNARL, + Species.OBSTAGOON, Species.PERRSERKER, + Species.CURSOLA, + Species.SIRFETCHD, + Species.MR_RIME, + Species.RUNERIGUS, + Species.MILCERY, + Species.ALCREMIE, Species.FALINKS, Species.PINCURCHIN, Species.SNOM, @@ -67054,6 +67106,11 @@ export const tmSpecies: TmSpecies = { Species.MORPEKO, Species.CUFANT, Species.COPPERAJAH, + Species.DRACOZOLT, + Species.ARCTOZOLT, + Species.DRACOVISH, + Species.ARCTOVISH, + Species.DURALUDON, Species.DREEPY, Species.DRAKLOAK, Species.DRAGAPULT, @@ -67195,13 +67252,24 @@ export const tmSpecies: TmSpecies = { Species.IRON_CROWN, Species.PECHARUNT, Species.GALAR_MEOWTH, + Species.GALAR_PONYTA, + Species.GALAR_RAPIDASH, Species.GALAR_SLOWPOKE, Species.GALAR_SLOWBRO, + Species.GALAR_FARFETCHD, Species.GALAR_WEEZING, + Species.GALAR_MR_MIME, Species.GALAR_ARTICUNO, Species.GALAR_ZAPDOS, Species.GALAR_MOLTRES, Species.GALAR_SLOWKING, + Species.GALAR_CORSOLA, + Species.GALAR_ZIGZAGOON, + Species.GALAR_LINOONE, + Species.GALAR_DARUMAKA, + Species.GALAR_DARMANITAN, + Species.GALAR_YAMASK, + Species.GALAR_STUNFISK, Species.HISUI_GROWLITHE, Species.HISUI_ARCANINE, Species.HISUI_VOLTORB, diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index 341976b388d..454bd40130c 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -2,11 +2,11 @@ import { globalScene } from "#app/global-scene"; import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, SelfStatusMove, allMoves } from "./moves/move"; import { MoveFlags } from "#enums/MoveFlags"; import type Pokemon from "../field/pokemon"; -import { type nil, getFrameMs, getEnumKeys, getEnumValues, animationFileName } from "../utils"; +import { type nil, getFrameMs, getEnumKeys, getEnumValues, animationFileName } from "../utils/common"; import type { BattlerIndex } from "../battle"; import { Moves } from "#enums/moves"; import { SubstituteTag } from "./battler-tags"; -import { isNullOrUndefined } from "../utils"; +import { isNullOrUndefined } from "../utils/common"; import Phaser from "phaser"; import { EncounterAnim } from "#enums/encounter-anims"; @@ -1132,7 +1132,6 @@ export abstract class BattleAnim { if (priority === 0) { // Place the sprite in front of the pokemon on the field. targetSprite = globalScene.getEnemyField().find(p => p) ?? globalScene.getPlayerField().find(p => p); - console.log(typeof targetSprite); moveFunc = globalScene.field.moveBelow; } else if (priority === 2 && this.bgSprite) { moveFunc = globalScene.field.moveAbove; @@ -1428,7 +1427,8 @@ export class MoveAnim extends BattleAnim { public move: Moves; constructor(move: Moves, user: Pokemon, target: BattlerIndex, playOnEmptyField = false) { - super(user, globalScene.getField()[target], playOnEmptyField); + // Set target to the user pokemon if no target is found to avoid crashes + super(user, globalScene.getField()[target] ?? user, playOnEmptyField); this.move = move; } diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 546dbb4a3db..8a512f3c16c 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1,13 +1,14 @@ import { globalScene } from "#app/global-scene"; +import Overrides from "#app/overrides"; import { - allAbilities, applyAbAttrs, BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ProtectStatAbAttr, ConditionalUserFieldProtectStatAbAttr, ReverseDrainAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; +import { allAbilities } from "./data-lists"; import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "#app/data/battle-anims"; import type Move from "#app/data/moves/move"; import { @@ -33,7 +34,7 @@ import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import i18next from "#app/plugins/i18n"; -import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils"; +import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; @@ -42,7 +43,7 @@ import { Species } from "#enums/species"; import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; import { WeatherType } from "#enums/weather-type"; -import * as Utils from "../utils"; +import { isNullOrUndefined } from "#app/utils/common"; export enum BattlerTagLapseType { FAINT, @@ -52,6 +53,7 @@ export enum BattlerTagLapseType { MOVE_EFFECT, TURN_END, HIT, + /** Tag lapses AFTER_HIT, applying its effects even if the user faints */ AFTER_HIT, CUSTOM, } @@ -90,7 +92,12 @@ export class BattlerTag { onOverlap(_pokemon: Pokemon): void {} + /** + * Tick down this {@linkcode BattlerTag}'s duration. + * @returns `true` if the tag should be kept (`turnCount` > 0`) + */ lapse(_pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean { + // TODO: Maybe flip this (return `true` if tag needs removal) return --this.turnCount > 0; } @@ -107,9 +114,9 @@ export class BattlerTag { } /** - * When given a battler tag or json representing one, load the data for it. - * This is meant to be inherited from by any battler tag with custom attributes - * @param {BattlerTag | any} source A battler tag + * Load the data for a given {@linkcode BattlerTag} or JSON representation thereof. + * Should be inherited from by any battler tag with custom attributes. + * @param source The battler tag to load */ loadTag(source: BattlerTag | any): void { this.turnCount = source.turnCount; @@ -119,7 +126,7 @@ export class BattlerTag { /** * Helper function that retrieves the source Pokemon object - * @returns The source {@linkcode Pokemon} or `null` if none is found + * @returns The source {@linkcode Pokemon}, or `null` if none is found */ public getSourcePokemon(): Pokemon | null { return this.sourceId ? globalScene.getPokemonById(this.sourceId) : null; @@ -139,8 +146,8 @@ export interface TerrainBattlerTag { * in-game. This is not to be confused with {@linkcode Moves.DISABLE}. * * Descendants can override {@linkcode isMoveRestricted} to restrict moves that - * match a condition. A restricted move gets cancelled before it is used. Players and enemies should not be allowed - * to select restricted moves. + * match a condition. A restricted move gets cancelled before it is used. + * Players and enemies should not be allowed to select restricted moves. */ export abstract class MoveRestrictionBattlerTag extends BattlerTag { constructor( @@ -302,7 +309,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag { super.onAdd(pokemon); const move = pokemon.getLastXMoves(-1).find(m => !m.virtual); - if (Utils.isNullOrUndefined(move) || move.move === Moves.STRUGGLE || move.move === Moves.NONE) { + if (isNullOrUndefined(move) || move.move === Moves.STRUGGLE || move.move === Moves.NONE) { return; } @@ -498,7 +505,13 @@ export class BeakBlastChargingTag extends BattlerTag { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { if (lapseType === BattlerTagLapseType.AFTER_HIT) { const phaseData = getMoveEffectPhaseData(pokemon); - if (phaseData?.move.hasFlag(MoveFlags.MAKES_CONTACT)) { + if ( + phaseData?.move.doesFlagEffectApply({ + flag: MoveFlags.MAKES_CONTACT, + user: phaseData.attacker, + target: pokemon, + }) + ) { phaseData.attacker.trySetStatus(StatusEffect.BURN, true, pokemon); } return true; @@ -739,31 +752,33 @@ export class ConfusedTag extends BattlerTag { } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - const ret = lapseType !== BattlerTagLapseType.CUSTOM && super.lapse(pokemon, lapseType); + const shouldLapse = lapseType !== BattlerTagLapseType.CUSTOM && super.lapse(pokemon, lapseType); - if (ret) { - globalScene.queueMessage( - i18next.t("battlerTags:confusedLapse", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - }), - ); - globalScene.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION)); - - // 1/3 chance of hitting self with a 40 base power move - if (pokemon.randSeedInt(3) === 0) { - const atk = pokemon.getEffectiveStat(Stat.ATK); - const def = pokemon.getEffectiveStat(Stat.DEF); - const damage = toDmgValue( - ((((2 * pokemon.level) / 5 + 2) * 40 * atk) / def / 50 + 2) * (pokemon.randSeedIntRange(85, 100) / 100), - ); - globalScene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself")); - pokemon.damageAndUpdate(damage, { result: HitResult.CONFUSION }); - pokemon.battleData.hitCount++; - (globalScene.getCurrentPhase() as MovePhase).cancel(); - } + if (!shouldLapse) { + return false; } - return ret; + globalScene.queueMessage( + i18next.t("battlerTags:confusedLapse", { + pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), + }), + ); + globalScene.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION)); + + // 1/3 chance of hitting self with a 40 base power move + if (pokemon.randSeedInt(3) === 0 || Overrides.CONFUSION_ACTIVATION_OVERRIDE === true) { + const atk = pokemon.getEffectiveStat(Stat.ATK); + const def = pokemon.getEffectiveStat(Stat.DEF); + const damage = toDmgValue( + ((((2 * pokemon.level) / 5 + 2) * 40 * atk) / def / 50 + 2) * (pokemon.randSeedIntRange(85, 100) / 100), + ); + // Intentionally don't increment rage fist's hitCount + globalScene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself")); + pokemon.damageAndUpdate(damage, { result: HitResult.CONFUSION }); + (globalScene.getCurrentPhase() as MovePhase).cancel(); + } + + return true; } getDescriptor(): string { @@ -1110,8 +1125,8 @@ export class FrenzyTag extends BattlerTag { } /** - * Applies the effects of the move Encore onto the target Pokemon - * Encore forces the target Pokemon to use its most-recent move for 3 turns + * Applies the effects of {@linkcode Moves.ENCORE} onto the target Pokemon. + * Encore forces the target Pokemon to use its most-recent move for 3 turns. */ export class EncoreTag extends MoveRestrictionBattlerTag { public moveId: Moves; @@ -1126,10 +1141,6 @@ export class EncoreTag extends MoveRestrictionBattlerTag { ); } - /** - * When given a battler tag or json representing one, load the data for it. - * @param {BattlerTag | any} source A battler tag - */ loadTag(source: BattlerTag | any): void { super.loadTag(source); this.moveId = source.moveId as Moves; @@ -1611,19 +1622,50 @@ export class ProtectedTag extends BattlerTag { } } -/** Base class for `BattlerTag`s that block damaging moves but not status moves */ -export class DamageProtectedTag extends ProtectedTag {} +/** Class for `BattlerTag`s that apply some effect when hit by a contact move */ +export class ContactProtectedTag extends ProtectedTag { + /** + * Function to call when a contact move hits the pokemon with this tag. + * @param _attacker - The pokemon using the contact move + * @param _user - The pokemon that is being attacked and has the tag + * @param _move - The move used by the attacker + */ + onContact(_attacker: Pokemon, _user: Pokemon) {} + + /** + * Lapse the tag and apply `onContact` if the move makes contact and + * `lapseType` is custom, respecting the move's flags and the pokemon's + * abilities, and whether the lapseType is custom. + * + * @param pokemon - The pokemon with the tag + * @param lapseType - The type of lapse to apply. If this is not {@linkcode BattlerTagLapseType.CUSTOM CUSTOM}, no effect will be applied. + * @returns Whether the tag continues to exist after the lapse. + */ + lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { + const ret = super.lapse(pokemon, lapseType); + + const moveData = getMoveEffectPhaseData(pokemon); + if ( + lapseType === BattlerTagLapseType.CUSTOM && + moveData && + moveData.move.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user: moveData.attacker, target: pokemon }) + ) { + this.onContact(moveData.attacker, pokemon); + } + + return ret; + } +} /** * `BattlerTag` class for moves that block damaging moves damage the enemy if the enemy's move makes contact * Used by {@linkcode Moves.SPIKY_SHIELD} */ -export class ContactDamageProtectedTag extends ProtectedTag { +export class ContactDamageProtectedTag extends ContactProtectedTag { private damageRatio: number; constructor(sourceMove: Moves, damageRatio: number) { super(sourceMove, BattlerTagType.SPIKY_SHIELD); - this.damageRatio = damageRatio; } @@ -1636,22 +1678,46 @@ export class ContactDamageProtectedTag extends ProtectedTag { this.damageRatio = source.damageRatio; } - lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - const ret = super.lapse(pokemon, lapseType); - - if (lapseType === BattlerTagLapseType.CUSTOM) { - const effectPhase = globalScene.getCurrentPhase(); - if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { - const attacker = effectPhase.getPokemon(); - if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { - attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), { - result: HitResult.INDIRECT, - }); - } - } + /** + * Damage the attacker by `this.damageRatio` of the target's max HP + * @param attacker - The pokemon using the contact move + * @param user - The pokemon that is being attacked and has the tag + */ + override onContact(attacker: Pokemon, user: Pokemon): void { + const cancelled = new BooleanHolder(false); + applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled); + if (!cancelled.value) { + attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), { + result: HitResult.INDIRECT, + }); } + } +} - return ret; +/** Base class for `BattlerTag`s that block damaging moves but not status moves */ +export class DamageProtectedTag extends ContactProtectedTag {} + +export class ContactSetStatusProtectedTag extends DamageProtectedTag { + /** + * @param sourceMove The move that caused the tag to be applied + * @param tagType The type of the tag + * @param statusEffect The status effect to apply to the attacker + */ + constructor( + sourceMove: Moves, + tagType: BattlerTagType, + private statusEffect: StatusEffect, + ) { + super(sourceMove, tagType); + } + + /** + * Set the status effect on the attacker + * @param attacker - The pokemon using the contact move + * @param user - The pokemon that is being attacked and has the tag + */ + override onContact(attacker: Pokemon, user: Pokemon): void { + attacker.trySetStatus(this.statusEffect, true, user); } } @@ -1674,68 +1740,19 @@ export class ContactStatStageChangeProtectedTag extends DamageProtectedTag { * When given a battler tag or json representing one, load the data for it. * @param {BattlerTag | any} source A battler tag */ - loadTag(source: BattlerTag | any): void { + override loadTag(source: BattlerTag | any): void { super.loadTag(source); this.stat = source.stat; this.levels = source.levels; } - lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - const ret = super.lapse(pokemon, lapseType); - - if (lapseType === BattlerTagLapseType.CUSTOM) { - const effectPhase = globalScene.getCurrentPhase(); - if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { - const attacker = effectPhase.getPokemon(); - globalScene.unshiftPhase(new StatStageChangePhase(attacker.getBattlerIndex(), false, [this.stat], this.levels)); - } - } - - return ret; - } -} - -export class ContactPoisonProtectedTag extends ProtectedTag { - constructor(sourceMove: Moves) { - super(sourceMove, BattlerTagType.BANEFUL_BUNKER); - } - - lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - const ret = super.lapse(pokemon, lapseType); - - if (lapseType === BattlerTagLapseType.CUSTOM) { - const effectPhase = globalScene.getCurrentPhase(); - if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { - const attacker = effectPhase.getPokemon(); - attacker.trySetStatus(StatusEffect.POISON, true, pokemon); - } - } - - return ret; - } -} - -/** - * `BattlerTag` class for moves that block damaging moves and burn the enemy if the enemy's move makes contact - * Used by {@linkcode Moves.BURNING_BULWARK} - */ -export class ContactBurnProtectedTag extends DamageProtectedTag { - constructor(sourceMove: Moves) { - super(sourceMove, BattlerTagType.BURNING_BULWARK); - } - - lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - const ret = super.lapse(pokemon, lapseType); - - if (lapseType === BattlerTagLapseType.CUSTOM) { - const effectPhase = globalScene.getCurrentPhase(); - if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { - const attacker = effectPhase.getPokemon(); - attacker.trySetStatus(StatusEffect.BURN, true); - } - } - - return ret; + /** + * Initiate the stat stage change on the attacker + * @param attacker - The pokemon using the contact move + * @param user - The pokemon that is being attacked and has the tag + */ + override onContact(attacker: Pokemon, _user: Pokemon): void { + globalScene.unshiftPhase(new StatStageChangePhase(attacker.getBattlerIndex(), false, [this.stat], this.levels)); } } @@ -2624,7 +2641,7 @@ export class GulpMissileTag extends BattlerTag { return false; } - if (moveEffectPhase.move.getMove().hitsSubstitute(attacker, pokemon)) { + if (moveEffectPhase.move.hitsSubstitute(attacker, pokemon)) { return true; } @@ -2980,7 +2997,7 @@ export class SubstituteTag extends BattlerTag { if (!attacker) { return; } - const move = moveEffectPhase.move.getMove(); + const move = moveEffectPhase.move; const firstHit = attacker.turnData.hitCount === attacker.turnData.hitsLeft; if (firstHit && move.hitsSubstitute(attacker, pokemon)) { @@ -3518,9 +3535,9 @@ export function getBattlerTag( case BattlerTagType.SILK_TRAP: return new ContactStatStageChangeProtectedTag(sourceMove, tagType, Stat.SPD, -1); case BattlerTagType.BANEFUL_BUNKER: - return new ContactPoisonProtectedTag(sourceMove); + return new ContactSetStatusProtectedTag(sourceMove, tagType, StatusEffect.POISON); case BattlerTagType.BURNING_BULWARK: - return new ContactBurnProtectedTag(sourceMove); + return new ContactSetStatusProtectedTag(sourceMove, tagType, StatusEffect.BURN); case BattlerTagType.ENDURING: return new EnduringTag(tagType, BattlerTagLapseType.TURN_END, sourceMove); case BattlerTagType.ENDURE_TOKEN: @@ -3668,7 +3685,7 @@ function getMoveEffectPhaseData(_pokemon: Pokemon): { phase: MoveEffectPhase; at return { phase: phase, attacker: phase.getPokemon(), - move: phase.move.getMove(), + move: phase.move, }; } return null; diff --git a/src/data/berry.ts b/src/data/berry.ts index 13820b1277b..ecc3e92ca64 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -2,14 +2,12 @@ import { getPokemonNameWithAffix } from "../messages"; import type Pokemon from "../field/pokemon"; import { HitResult } from "../field/pokemon"; import { getStatusEffectHealText } from "./status-effect"; -import * as Utils from "../utils"; +import { NumberHolder, toDmgValue, randSeedInt } from "#app/utils/common"; import { DoubleBerryEffectAbAttr, - PostItemLostAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs, - applyPostItemLostAbAttrs, -} from "./ability"; +} from "./abilities/ability"; import i18next from "i18next"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; @@ -43,7 +41,7 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate { case BerryType.APICOT: case BerryType.SALAC: return (pokemon: Pokemon) => { - const threshold = new Utils.NumberHolder(0.25); + const threshold = new NumberHolder(0.25); // Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth const stat: BattleStat = berryType - BerryType.ENIGMA; applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); @@ -51,116 +49,113 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate { }; case BerryType.LANSAT: return (pokemon: Pokemon) => { - const threshold = new Utils.NumberHolder(0.25); + const threshold = new NumberHolder(0.25); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST); }; case BerryType.STARF: return (pokemon: Pokemon) => { - const threshold = new Utils.NumberHolder(0.25); + const threshold = new NumberHolder(0.25); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); return pokemon.getHpRatio() < 0.25; }; case BerryType.LEPPA: return (pokemon: Pokemon) => { - const threshold = new Utils.NumberHolder(0.25); + const threshold = new NumberHolder(0.25); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); return !!pokemon.getMoveset().find(m => !m.getPpRatio()); }; } } -export type BerryEffectFunc = (pokemon: Pokemon, berryOwner?: Pokemon) => void; +export type BerryEffectFunc = (consumer: Pokemon) => void; export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { - switch (berryType) { - case BerryType.SITRUS: - case BerryType.ENIGMA: - return (pokemon: Pokemon, berryOwner?: Pokemon) => { - if (pokemon.battleData) { - pokemon.battleData.berriesEaten.push(berryType); - } - const hpHealed = new Utils.NumberHolder(Utils.toDmgValue(pokemon.getMaxHp() / 4)); - applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed); - globalScene.unshiftPhase( - new PokemonHealPhase( - pokemon.getBattlerIndex(), - hpHealed.value, - i18next.t("battle:hpHealBerry", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - berryName: getBerryName(berryType), - }), - true, - ), - ); - applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); - }; - case BerryType.LUM: - return (pokemon: Pokemon, berryOwner?: Pokemon) => { - if (pokemon.battleData) { - pokemon.battleData.berriesEaten.push(berryType); - } - if (pokemon.status) { - globalScene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon))); - } - pokemon.resetStatus(true, true); - pokemon.updateInfo(); - applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); - }; - case BerryType.LIECHI: - case BerryType.GANLON: - case BerryType.PETAYA: - case BerryType.APICOT: - case BerryType.SALAC: - return (pokemon: Pokemon, berryOwner?: Pokemon) => { - if (pokemon.battleData) { - pokemon.battleData.berriesEaten.push(berryType); - } - // Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth - const stat: BattleStat = berryType - BerryType.ENIGMA; - const statStages = new Utils.NumberHolder(1); - applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statStages); - globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [stat], statStages.value)); - applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); - }; - case BerryType.LANSAT: - return (pokemon: Pokemon, berryOwner?: Pokemon) => { - if (pokemon.battleData) { - pokemon.battleData.berriesEaten.push(berryType); - } - pokemon.addTag(BattlerTagType.CRIT_BOOST); - applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); - }; - case BerryType.STARF: - return (pokemon: Pokemon, berryOwner?: Pokemon) => { - if (pokemon.battleData) { - pokemon.battleData.berriesEaten.push(berryType); - } - const randStat = Utils.randSeedInt(Stat.SPD, Stat.ATK); - const stages = new Utils.NumberHolder(2); - applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages); - globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [randStat], stages.value)); - applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); - }; - case BerryType.LEPPA: - return (pokemon: Pokemon, berryOwner?: Pokemon) => { - if (pokemon.battleData) { - pokemon.battleData.berriesEaten.push(berryType); - } - const ppRestoreMove = pokemon.getMoveset().find(m => !m.getPpRatio()) - ? pokemon.getMoveset().find(m => !m.getPpRatio()) - : pokemon.getMoveset().find(m => m.getPpRatio() < 1); - if (ppRestoreMove !== undefined) { - ppRestoreMove!.ppUsed = Math.max(ppRestoreMove!.ppUsed - 10, 0); - globalScene.queueMessage( - i18next.t("battle:ppHealBerry", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - moveName: ppRestoreMove!.getName(), - berryName: getBerryName(berryType), - }), + return (consumer: Pokemon) => { + // Apply an effect pertaining to what berry we're using + switch (berryType) { + case BerryType.SITRUS: + case BerryType.ENIGMA: + { + const hpHealed = new NumberHolder(toDmgValue(consumer.getMaxHp() / 4)); + applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, hpHealed); + globalScene.unshiftPhase( + new PokemonHealPhase( + consumer.getBattlerIndex(), + hpHealed.value, + i18next.t("battle:hpHealBerry", { + pokemonNameWithAffix: getPokemonNameWithAffix(consumer), + berryName: getBerryName(berryType), + }), + true, + ), ); - applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner ?? pokemon, false); } - }; - } + break; + case BerryType.LUM: + { + if (consumer.status) { + globalScene.queueMessage( + getStatusEffectHealText(consumer.status.effect, getPokemonNameWithAffix(consumer)), + ); + } + consumer.resetStatus(true, true); + consumer.updateInfo(); + } + break; + case BerryType.LIECHI: + case BerryType.GANLON: + case BerryType.PETAYA: + case BerryType.APICOT: + case BerryType.SALAC: + { + // Offset BerryType such that LIECHI --> Stat.ATK = 1, GANLON --> Stat.DEF = 2, etc etc. + const stat: BattleStat = berryType - BerryType.ENIGMA; + const statStages = new NumberHolder(1); + applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, statStages); + globalScene.unshiftPhase( + new StatStageChangePhase(consumer.getBattlerIndex(), true, [stat], statStages.value), + ); + } + break; + + case BerryType.LANSAT: + { + consumer.addTag(BattlerTagType.CRIT_BOOST); + } + break; + + case BerryType.STARF: + { + const randStat = randSeedInt(Stat.SPD, Stat.ATK); + const stages = new NumberHolder(2); + applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, stages); + globalScene.unshiftPhase( + new StatStageChangePhase(consumer.getBattlerIndex(), true, [randStat], stages.value), + ); + } + break; + + case BerryType.LEPPA: + { + // Pick the first move completely out of PP, or else the first one that has any PP missing + const ppRestoreMove = + consumer.getMoveset().find(m => m.ppUsed === m.getMovePp()) ?? + consumer.getMoveset().find(m => m.ppUsed < m.getMovePp()); + if (ppRestoreMove) { + ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0); + globalScene.queueMessage( + i18next.t("battle:ppHealBerry", { + pokemonNameWithAffix: getPokemonNameWithAffix(consumer), + moveName: ppRestoreMove.getName(), + berryName: getBerryName(berryType), + }), + ); + } + } + break; + default: + console.error("Incorrect BerryType %d passed to GetBerryEffectFunc", berryType); + } + }; } diff --git a/src/data/challenge.ts b/src/data/challenge.ts index 868fc7d2e60..b4b8db2cc10 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -1,4 +1,5 @@ -import * as Utils from "#app/utils"; +import { BooleanHolder, type NumberHolder, randSeedItem } from "#app/utils/common"; +import { deepCopy } from "#app/utils/data"; import i18next from "i18next"; import type { DexAttrProps, GameData } from "#app/system/game-data"; import { defaultStarterSpecies } from "#app/system/game-data"; @@ -8,7 +9,9 @@ import { speciesStarterCosts } from "#app/data/balance/starters"; import type Pokemon from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon"; import type { FixedBattleConfig } from "#app/battle"; -import { ClassicFixedBossWaves, BattleType, getRandomTrainerFunc } from "#app/battle"; +import { getRandomTrainerFunc } from "#app/battle"; +import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves"; +import { BattleType } from "#enums/battle-type"; import Trainer, { TrainerVariant } from "#app/field/trainer"; import { PokemonType } from "#enums/pokemon-type"; import { Challenges } from "#enums/challenges"; @@ -283,30 +286,30 @@ export abstract class Challenge { /** * An apply function for STARTER_CHOICE challenges. Derived classes should alter this. * @param _pokemon {@link PokemonSpecies} The pokemon to check the validity of. - * @param _valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. + * @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon. * @returns {@link boolean} Whether this function did anything. */ - applyStarterChoice(_pokemon: PokemonSpecies, _valid: Utils.BooleanHolder, _dexAttr: DexAttrProps): boolean { + applyStarterChoice(_pokemon: PokemonSpecies, _valid: BooleanHolder, _dexAttr: DexAttrProps): boolean { return false; } /** * An apply function for STARTER_POINTS challenges. Derived classes should alter this. - * @param _points {@link Utils.NumberHolder} The amount of points you have available. + * @param _points {@link NumberHolder} The amount of points you have available. * @returns {@link boolean} Whether this function did anything. */ - applyStarterPoints(_points: Utils.NumberHolder): boolean { + applyStarterPoints(_points: NumberHolder): boolean { return false; } /** * An apply function for STARTER_COST challenges. Derived classes should alter this. * @param _species {@link Species} The pokemon to change the cost of. - * @param _cost {@link Utils.NumberHolder} The cost of the starter. + * @param _cost {@link NumberHolder} The cost of the starter. * @returns {@link boolean} Whether this function did anything. */ - applyStarterCost(_species: Species, _cost: Utils.NumberHolder): boolean { + applyStarterCost(_species: Species, _cost: NumberHolder): boolean { return false; } @@ -322,10 +325,10 @@ export abstract class Challenge { /** * An apply function for POKEMON_IN_BATTLE challenges. Derived classes should alter this. * @param _pokemon {@link Pokemon} The pokemon to check the validity of. - * @param _valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. + * @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @returns {@link boolean} Whether this function did anything. */ - applyPokemonInBattle(_pokemon: Pokemon, _valid: Utils.BooleanHolder): boolean { + applyPokemonInBattle(_pokemon: Pokemon, _valid: BooleanHolder): boolean { return false; } @@ -341,42 +344,42 @@ export abstract class Challenge { /** * An apply function for TYPE_EFFECTIVENESS challenges. Derived classes should alter this. - * @param _effectiveness {@linkcode Utils.NumberHolder} The current effectiveness of the move. + * @param _effectiveness {@linkcode NumberHolder} The current effectiveness of the move. * @returns Whether this function did anything. */ - applyTypeEffectiveness(_effectiveness: Utils.NumberHolder): boolean { + applyTypeEffectiveness(_effectiveness: NumberHolder): boolean { return false; } /** * An apply function for AI_LEVEL challenges. Derived classes should alter this. - * @param _level {@link Utils.NumberHolder} The generated level. + * @param _level {@link NumberHolder} The generated level. * @param _levelCap {@link Number} The current level cap. * @param _isTrainer {@link Boolean} Whether this is a trainer pokemon. * @param _isBoss {@link Boolean} Whether this is a non-trainer boss pokemon. * @returns {@link boolean} Whether this function did anything. */ - applyLevelChange(_level: Utils.NumberHolder, _levelCap: number, _isTrainer: boolean, _isBoss: boolean): boolean { + applyLevelChange(_level: NumberHolder, _levelCap: number, _isTrainer: boolean, _isBoss: boolean): boolean { return false; } /** * An apply function for AI_MOVE_SLOTS challenges. Derived classes should alter this. * @param pokemon {@link Pokemon} The pokemon that is being considered. - * @param moveSlots {@link Utils.NumberHolder} The amount of move slots. + * @param moveSlots {@link NumberHolder} The amount of move slots. * @returns {@link boolean} Whether this function did anything. */ - applyMoveSlot(_pokemon: Pokemon, _moveSlots: Utils.NumberHolder): boolean { + applyMoveSlot(_pokemon: Pokemon, _moveSlots: NumberHolder): boolean { return false; } /** * An apply function for PASSIVE_ACCESS challenges. Derived classes should alter this. * @param pokemon {@link Pokemon} The pokemon to change. - * @param hasPassive {@link Utils.BooleanHolder} Whether it should have its passive. + * @param hasPassive {@link BooleanHolder} Whether it should have its passive. * @returns {@link boolean} Whether this function did anything. */ - applyPassiveAccess(_pokemon: Pokemon, _hasPassive: Utils.BooleanHolder): boolean { + applyPassiveAccess(_pokemon: Pokemon, _hasPassive: BooleanHolder): boolean { return false; } @@ -393,15 +396,10 @@ export abstract class Challenge { * @param _pokemon {@link Pokemon} What pokemon would learn the move. * @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param _move {@link Moves} The move in question. - * @param _level {@link Utils.NumberHolder} The level threshold for access. + * @param _level {@link NumberHolder} The level threshold for access. * @returns {@link boolean} Whether this function did anything. */ - applyMoveAccessLevel( - _pokemon: Pokemon, - _moveSource: MoveSourceType, - _move: Moves, - _level: Utils.NumberHolder, - ): boolean { + applyMoveAccessLevel(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: Moves, _level: NumberHolder): boolean { return false; } @@ -410,10 +408,10 @@ export abstract class Challenge { * @param _pokemon {@link Pokemon} What pokemon would learn the move. * @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param _move {@link Moves} The move in question. - * @param _weight {@link Utils.NumberHolder} The base weight of the move + * @param _weight {@link NumberHolder} The base weight of the move * @returns {@link boolean} Whether this function did anything. */ - applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: Moves, _level: Utils.NumberHolder): boolean { + applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: Moves, _level: NumberHolder): boolean { return false; } @@ -438,7 +436,7 @@ export class SingleGenerationChallenge extends Challenge { super(Challenges.SINGLE_GENERATION, 9); } - applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { + applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean { if (pokemon.generation !== this.value) { valid.value = false; return true; @@ -446,7 +444,7 @@ export class SingleGenerationChallenge extends Challenge { return false; } - applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean { + applyPokemonInBattle(pokemon: Pokemon, valid: BooleanHolder): boolean { const baseGeneration = getPokemonSpecies(pokemon.species.speciesId).generation; const fusionGeneration = pokemon.isFusion() ? getPokemonSpecies(pokemon.fusionSpecies!.speciesId).generation : 0; if ( @@ -575,7 +573,7 @@ export class SingleGenerationChallenge extends Challenge { TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, - Utils.randSeedItem([TrainerType.HALA, TrainerType.MOLAYNE]), + randSeedItem([TrainerType.HALA, TrainerType.MOLAYNE]), TrainerType.MARNIE_ELITE, TrainerType.RIKA, ]; @@ -602,7 +600,7 @@ export class SingleGenerationChallenge extends Challenge { TrainerType.GRIMSLEY, TrainerType.WIKSTROM, TrainerType.ACEROLA, - Utils.randSeedItem([TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE]), + randSeedItem([TrainerType.BEA_ELITE, TrainerType.ALLISTER_ELITE]), TrainerType.LARRY_ELITE, ]; break; @@ -622,14 +620,14 @@ export class SingleGenerationChallenge extends Challenge { case ClassicFixedBossWaves.CHAMPION: trainerTypes = [ TrainerType.BLUE, - Utils.randSeedItem([TrainerType.RED, TrainerType.LANCE_CHAMPION]), - Utils.randSeedItem([TrainerType.STEVEN, TrainerType.WALLACE]), + randSeedItem([TrainerType.RED, TrainerType.LANCE_CHAMPION]), + randSeedItem([TrainerType.STEVEN, TrainerType.WALLACE]), TrainerType.CYNTHIA, - Utils.randSeedItem([TrainerType.ALDER, TrainerType.IRIS]), + randSeedItem([TrainerType.ALDER, TrainerType.IRIS]), TrainerType.DIANTHA, - Utils.randSeedItem([TrainerType.KUKUI, TrainerType.HAU]), - Utils.randSeedItem([TrainerType.LEON, TrainerType.MUSTARD]), - Utils.randSeedItem([TrainerType.GEETA, TrainerType.NEMONA]), + randSeedItem([TrainerType.KUKUI, TrainerType.HAU]), + randSeedItem([TrainerType.LEON, TrainerType.MUSTARD]), + randSeedItem([TrainerType.GEETA, TrainerType.NEMONA]), ]; break; } @@ -718,7 +716,7 @@ export class SingleTypeChallenge extends Challenge { super(Challenges.SINGLE_TYPE, 18); } - override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps): boolean { + override applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder, dexAttr: DexAttrProps): boolean { const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex); const types = [speciesForm.type1, speciesForm.type2]; if (!types.includes(this.value - 1)) { @@ -728,7 +726,7 @@ export class SingleTypeChallenge extends Challenge { return false; } - applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean { + applyPokemonInBattle(pokemon: Pokemon, valid: BooleanHolder): boolean { if ( pokemon.isPlayer() && !pokemon.isOfType(this.value - 1, false, false, true) && @@ -798,7 +796,7 @@ export class FreshStartChallenge extends Challenge { super(Challenges.FRESH_START, 1); } - applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { + applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean { if (!defaultStarterSpecies.includes(pokemon.speciesId)) { valid.value = false; return true; @@ -806,7 +804,7 @@ export class FreshStartChallenge extends Challenge { return false; } - applyStarterCost(species: Species, cost: Utils.NumberHolder): boolean { + applyStarterCost(species: Species, cost: NumberHolder): boolean { if (defaultStarterSpecies.includes(species)) { cost.value = speciesStarterCosts[species]; return true; @@ -864,7 +862,7 @@ export class InverseBattleChallenge extends Challenge { return 0; } - applyTypeEffectiveness(effectiveness: Utils.NumberHolder): boolean { + applyTypeEffectiveness(effectiveness: NumberHolder): boolean { if (effectiveness.value < 1) { effectiveness.value = 2; return true; @@ -887,7 +885,7 @@ export class FlipStatChallenge extends Challenge { } override applyFlipStat(_pokemon: Pokemon, baseStats: number[]) { - const origStats = Utils.deepCopy(baseStats); + const origStats = deepCopy(baseStats); baseStats[0] = origStats[5]; baseStats[1] = origStats[4]; baseStats[2] = origStats[3]; @@ -923,7 +921,7 @@ export class LowerStarterMaxCostChallenge extends Challenge { return (DEFAULT_PARTY_MAX_COST - overrideValue).toString(); } - applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean { + applyStarterChoice(pokemon: PokemonSpecies, valid: BooleanHolder): boolean { if (speciesStarterCosts[pokemon.speciesId] > DEFAULT_PARTY_MAX_COST - this.value) { valid.value = false; return true; @@ -957,7 +955,7 @@ export class LowerStarterPointsChallenge extends Challenge { return (DEFAULT_PARTY_MAX_COST - overrideValue).toString(); } - applyStarterPoints(points: Utils.NumberHolder): boolean { + applyStarterPoints(points: NumberHolder): boolean { points.value -= this.value; return true; } @@ -974,34 +972,34 @@ export class LowerStarterPointsChallenge extends Challenge { * Apply all challenges that modify starter choice. * @param challengeType {@link ChallengeType} ChallengeType.STARTER_CHOICE * @param pokemon {@link PokemonSpecies} The pokemon to check the validity of. - * @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. + * @param valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon. * @returns True if any challenge was successfully applied. */ export function applyChallenges( challengeType: ChallengeType.STARTER_CHOICE, pokemon: PokemonSpecies, - valid: Utils.BooleanHolder, + valid: BooleanHolder, dexAttr: DexAttrProps, ): boolean; /** * Apply all challenges that modify available total starter points. * @param challengeType {@link ChallengeType} ChallengeType.STARTER_POINTS - * @param points {@link Utils.NumberHolder} The amount of points you have available. + * @param points {@link NumberHolder} The amount of points you have available. * @returns True if any challenge was successfully applied. */ -export function applyChallenges(challengeType: ChallengeType.STARTER_POINTS, points: Utils.NumberHolder): boolean; +export function applyChallenges(challengeType: ChallengeType.STARTER_POINTS, points: NumberHolder): boolean; /** * Apply all challenges that modify the cost of a starter. * @param challengeType {@link ChallengeType} ChallengeType.STARTER_COST * @param species {@link Species} The pokemon to change the cost of. - * @param points {@link Utils.NumberHolder} The cost of the pokemon. + * @param points {@link NumberHolder} The cost of the pokemon. * @returns True if any challenge was successfully applied. */ export function applyChallenges( challengeType: ChallengeType.STARTER_COST, species: Species, - cost: Utils.NumberHolder, + cost: NumberHolder, ): boolean; /** * Apply all challenges that modify a starter after selection. @@ -1014,13 +1012,13 @@ export function applyChallenges(challengeType: ChallengeType.STARTER_MODIFY, pok * Apply all challenges that what pokemon you can have in battle. * @param challengeType {@link ChallengeType} ChallengeType.POKEMON_IN_BATTLE * @param pokemon {@link Pokemon} The pokemon to check the validity of. - * @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. + * @param valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @returns True if any challenge was successfully applied. */ export function applyChallenges( challengeType: ChallengeType.POKEMON_IN_BATTLE, pokemon: Pokemon, - valid: Utils.BooleanHolder, + valid: BooleanHolder, ): boolean; /** * Apply all challenges that modify what fixed battles there are. @@ -1037,17 +1035,14 @@ export function applyChallenges( /** * Apply all challenges that modify type effectiveness. * @param challengeType {@linkcode ChallengeType} ChallengeType.TYPE_EFFECTIVENESS - * @param effectiveness {@linkcode Utils.NumberHolder} The current effectiveness of the move. + * @param effectiveness {@linkcode NumberHolder} The current effectiveness of the move. * @returns True if any challenge was successfully applied. */ -export function applyChallenges( - challengeType: ChallengeType.TYPE_EFFECTIVENESS, - effectiveness: Utils.NumberHolder, -): boolean; +export function applyChallenges(challengeType: ChallengeType.TYPE_EFFECTIVENESS, effectiveness: NumberHolder): boolean; /** * Apply all challenges that modify what level AI are. * @param challengeType {@link ChallengeType} ChallengeType.AI_LEVEL - * @param level {@link Utils.NumberHolder} The generated level of the pokemon. + * @param level {@link NumberHolder} The generated level of the pokemon. * @param levelCap {@link Number} The maximum level cap for the current wave. * @param isTrainer {@link Boolean} Whether this is a trainer pokemon. * @param isBoss {@link Boolean} Whether this is a non-trainer boss pokemon. @@ -1055,7 +1050,7 @@ export function applyChallenges( */ export function applyChallenges( challengeType: ChallengeType.AI_LEVEL, - level: Utils.NumberHolder, + level: NumberHolder, levelCap: number, isTrainer: boolean, isBoss: boolean, @@ -1064,25 +1059,25 @@ export function applyChallenges( * Apply all challenges that modify how many move slots the AI has. * @param challengeType {@link ChallengeType} ChallengeType.AI_MOVE_SLOTS * @param pokemon {@link Pokemon} The pokemon being considered. - * @param moveSlots {@link Utils.NumberHolder} The amount of move slots. + * @param moveSlots {@link NumberHolder} The amount of move slots. * @returns True if any challenge was successfully applied. */ export function applyChallenges( challengeType: ChallengeType.AI_MOVE_SLOTS, pokemon: Pokemon, - moveSlots: Utils.NumberHolder, + moveSlots: NumberHolder, ): boolean; /** * Apply all challenges that modify whether a pokemon has its passive. * @param challengeType {@link ChallengeType} ChallengeType.PASSIVE_ACCESS * @param pokemon {@link Pokemon} The pokemon to modify. - * @param hasPassive {@link Utils.BooleanHolder} Whether it has its passive. + * @param hasPassive {@link BooleanHolder} Whether it has its passive. * @returns True if any challenge was successfully applied. */ export function applyChallenges( challengeType: ChallengeType.PASSIVE_ACCESS, pokemon: Pokemon, - hasPassive: Utils.BooleanHolder, + hasPassive: BooleanHolder, ): boolean; /** * Apply all challenges that modify the game modes settings. @@ -1096,7 +1091,7 @@ export function applyChallenges(challengeType: ChallengeType.GAME_MODE_MODIFY): * @param pokemon {@link Pokemon} What pokemon would learn the move. * @param moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param move {@link Moves} The move in question. - * @param level {@link Utils.NumberHolder} The level threshold for access. + * @param level {@link NumberHolder} The level threshold for access. * @returns True if any challenge was successfully applied. */ export function applyChallenges( @@ -1104,7 +1099,7 @@ export function applyChallenges( pokemon: Pokemon, moveSource: MoveSourceType, move: Moves, - level: Utils.NumberHolder, + level: NumberHolder, ): boolean; /** * Apply all challenges that modify what weight a pokemon gives to move generation @@ -1112,7 +1107,7 @@ export function applyChallenges( * @param pokemon {@link Pokemon} What pokemon would learn the move. * @param moveSource {@link MoveSourceType} What source the pokemon would get the move from. * @param move {@link Moves} The move in question. - * @param weight {@link Utils.NumberHolder} The weight of the move. + * @param weight {@link NumberHolder} The weight of the move. * @returns True if any challenge was successfully applied. */ export function applyChallenges( @@ -1120,7 +1115,7 @@ export function applyChallenges( pokemon: Pokemon, moveSource: MoveSourceType, move: Moves, - weight: Utils.NumberHolder, + weight: NumberHolder, ): boolean; export function applyChallenges(challengeType: ChallengeType.FLIP_STAT, pokemon: Pokemon, baseStats: number[]): boolean; @@ -1225,7 +1220,7 @@ export function initChallenges() { */ export function checkStarterValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) { if (!soft) { - const isValidForChallenge = new Utils.BooleanHolder(true); + const isValidForChallenge = new BooleanHolder(true); applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props); return isValidForChallenge.value; } @@ -1263,7 +1258,7 @@ export function checkStarterValidForChallenge(species: PokemonSpecies, props: De * @returns `true` if the species is considered valid. */ function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) { - const isValidForChallenge = new Utils.BooleanHolder(true); + const isValidForChallenge = new BooleanHolder(true); applyChallenges(ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props); if (!soft || !pokemonFormChanges.hasOwnProperty(species.speciesId)) { return isValidForChallenge.value; @@ -1282,7 +1277,7 @@ function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrPr return species.forms.some((f2, formIndex) => { if (f1.formKey === f2.formKey) { const formProps = { ...props, formIndex }; - const isFormValidForChallenge = new Utils.BooleanHolder(true); + const isFormValidForChallenge = new BooleanHolder(true); applyChallenges(ChallengeType.STARTER_CHOICE, species, isFormValidForChallenge, formProps); return isFormValidForChallenge.value; } diff --git a/src/data/custom-pokemon-data.ts b/src/data/custom-pokemon-data.ts index d95d9f77b83..20f6ea96174 100644 --- a/src/data/custom-pokemon-data.ts +++ b/src/data/custom-pokemon-data.ts @@ -1,36 +1,31 @@ import type { Abilities } from "#enums/abilities"; import type { PokemonType } from "#enums/pokemon-type"; -import { isNullOrUndefined } from "#app/utils"; import type { Nature } from "#enums/nature"; /** - * Data that can customize a Pokemon in non-standard ways from its Species - * Used by Mystery Encounters and Mints - * Also used as a counter how often a Pokemon got hit until new arena encounter + * Data that can customize a Pokemon in non-standard ways from its Species. + * Includes abilities, nature, changed types, etc. */ export class CustomPokemonData { - public spriteScale: number; + // TODO: Change the default value for all these from -1 to something a bit more sensible + /** + * The scale at which to render this Pokemon's sprite. + */ + public spriteScale = -1; public ability: Abilities | -1; public passive: Abilities | -1; public nature: Nature | -1; public types: PokemonType[]; - /** `hitsReceivedCount` aka `hitsRecCount` saves how often the pokemon got hit until a new arena encounter (used for Rage Fist) */ - public hitsRecCount: number; + /** Deprecated but needed for session save migration */ + // TODO: Remove this once pre-session migration is implemented + public hitsRecCount: number | null = null; constructor(data?: CustomPokemonData | Partial) { - if (!isNullOrUndefined(data)) { - Object.assign(this, data); - } - - this.spriteScale = this.spriteScale ?? -1; - this.ability = this.ability ?? -1; - this.passive = this.passive ?? -1; - this.nature = this.nature ?? -1; - this.types = this.types ?? []; - this.hitsRecCount = this.hitsRecCount ?? 0; - } - - resetHitReceivedCount(): void { - this.hitsRecCount = 0; + this.spriteScale = data?.spriteScale ?? -1; + this.ability = data?.ability ?? -1; + this.passive = data?.passive ?? -1; + this.nature = data?.nature ?? -1; + this.types = data?.types ?? []; + this.hitsRecCount = data?.hitsRecCount ?? null; } } diff --git a/src/data/daily-run.ts b/src/data/daily-run.ts index 22fb7db10ae..8a1632ce160 100644 --- a/src/data/daily-run.ts +++ b/src/data/daily-run.ts @@ -3,7 +3,7 @@ import type { Species } from "#enums/species"; import { globalScene } from "#app/global-scene"; import { PlayerPokemon } from "#app/field/pokemon"; import type { Starter } from "#app/ui/starter-select-ui-handler"; -import * as Utils from "#app/utils"; +import { randSeedGauss, randSeedInt, randSeedItem, getEnumValues } from "#app/utils/common"; import type { PokemonSpeciesForm } from "#app/data/pokemon-species"; import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species"; import { speciesStarterCosts } from "#app/data/balance/starters"; @@ -43,8 +43,8 @@ export function getDailyRunStarters(seed: string): Starter[] { } const starterCosts: number[] = []; - starterCosts.push(Math.min(Math.round(3.5 + Math.abs(Utils.randSeedGauss(1))), 8)); - starterCosts.push(Utils.randSeedInt(9 - starterCosts[0], 1)); + starterCosts.push(Math.min(Math.round(3.5 + Math.abs(randSeedGauss(1))), 8)); + starterCosts.push(randSeedInt(9 - starterCosts[0], 1)); starterCosts.push(10 - (starterCosts[0] + starterCosts[1])); for (let c = 0; c < starterCosts.length; c++) { @@ -52,7 +52,7 @@ export function getDailyRunStarters(seed: string): Starter[] { const costSpecies = Object.keys(speciesStarterCosts) .map(s => Number.parseInt(s) as Species) .filter(s => speciesStarterCosts[s] === cost); - const randPkmSpecies = getPokemonSpecies(Utils.randSeedItem(costSpecies)); + const randPkmSpecies = getPokemonSpecies(randSeedItem(costSpecies)); const starterSpecies = getPokemonSpecies( randPkmSpecies.getTrainerSpeciesForLevel(startingLevel, true, PartyMemberStrength.STRONGER), ); @@ -143,7 +143,7 @@ const dailyBiomeWeights: BiomeWeights = { }; export function getDailyStartingBiome(): Biome { - const biomes = Utils.getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END); + const biomes = getEnumValues(Biome).filter(b => b !== Biome.TOWN && b !== Biome.END); let totalWeight = 0; const biomeThresholds: number[] = []; @@ -155,7 +155,7 @@ export function getDailyStartingBiome(): Biome { biomeThresholds.push(totalWeight); } - const randInt = Utils.randSeedInt(totalWeight); + const randInt = randSeedInt(totalWeight); for (let i = 0; i < biomes.length; i++) { if (randInt < biomeThresholds[i]) { @@ -164,5 +164,5 @@ export function getDailyStartingBiome(): Biome { } // Fallback in case something went wrong - return biomes[Utils.randSeedInt(biomes.length)]; + return biomes[randSeedInt(biomes.length)]; } diff --git a/src/data/data-lists.ts b/src/data/data-lists.ts new file mode 100644 index 00000000000..d3c31abc851 --- /dev/null +++ b/src/data/data-lists.ts @@ -0,0 +1,3 @@ +import type { Ability } from "./abilities/ability-class"; + +export const allAbilities: Ability[] = []; diff --git a/src/data/egg.ts b/src/data/egg.ts index 0dabf8f1119..55a253e843f 100644 --- a/src/data/egg.ts +++ b/src/data/egg.ts @@ -4,7 +4,7 @@ import type PokemonSpecies from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { speciesStarterCosts } from "#app/data/balance/starters"; import { VariantTier } from "#enums/variant-tier"; -import * as Utils from "#app/utils"; +import { randInt, randomString, randSeedInt, getIvsFromId } from "#app/utils/common"; import Overrides from "#app/overrides"; import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; import type { PlayerPokemon } from "#app/field/pokemon"; @@ -171,7 +171,7 @@ export class Egg { this.checkForPityTierOverrides(); } - this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier); + this._id = eggOptions?.id ?? randInt(EGG_SEED, EGG_SEED * this._tier); this._sourceType = eggOptions?.sourceType ?? undefined; this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves(); @@ -203,7 +203,7 @@ export class Egg { } }; - const seedOverride = Utils.randomString(24); + const seedOverride = randomString(24); globalScene.executeWithSeedOffset( () => { generateEggProperties(eggOptions); @@ -248,18 +248,15 @@ export class Egg { let pokemonSpecies = getPokemonSpecies(this._species); // Special condition to have Phione eggs also have a chance of generating Manaphy if (this._species === Species.PHIONE && this._sourceType === EggSourceType.SAME_SPECIES_EGG) { - pokemonSpecies = getPokemonSpecies( - Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY, - ); + pokemonSpecies = getPokemonSpecies(randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY); } // Sets the hidden ability if a hidden ability exists and // the override is set or the egg hits the chance let abilityIndex: number | undefined = undefined; const sameSpeciesEggHACheck = - this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE); - const gachaEggHACheck = - !(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !Utils.randSeedInt(GACHA_EGG_HA_RATE); + this._sourceType === EggSourceType.SAME_SPECIES_EGG && !randSeedInt(SAME_SPECIES_EGG_HA_RATE); + const gachaEggHACheck = !(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !randSeedInt(GACHA_EGG_HA_RATE); if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || sameSpeciesEggHACheck || gachaEggHACheck)) { abilityIndex = 2; } @@ -269,7 +266,7 @@ export class Egg { ret.shiny = this._isShiny; ret.variant = this._variantTier; - const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295)); + const secondaryIvs = getIvsFromId(randSeedInt(4294967295)); for (let s = 0; s < ret.ivs.length; s++) { ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]); @@ -370,7 +367,7 @@ export class Egg { } const tierMultiplier = this.isManaphyEgg() ? 2 : Math.pow(2, 3 - this.tier); - return Utils.randSeedInt(baseChance * tierMultiplier) ? Utils.randSeedInt(3) : 3; + return randSeedInt(baseChance * tierMultiplier) ? randSeedInt(3) : 3; } private getEggTierDefaultHatchWaves(eggTier?: EggTier): number { @@ -392,7 +389,7 @@ export class Egg { private rollEggTier(): EggTier { const tierValueOffset = this._sourceType === EggSourceType.GACHA_LEGENDARY ? GACHA_LEGENDARY_UP_THRESHOLD_OFFSET : 0; - const tierValue = Utils.randInt(256); + const tierValue = randInt(256); return tierValue >= GACHA_DEFAULT_COMMON_EGG_THRESHOLD + tierValueOffset ? EggTier.COMMON : tierValue >= GACHA_DEFAULT_RARE_EGG_THRESHOLD + tierValueOffset @@ -417,11 +414,11 @@ export class Egg { * when Utils.randSeedInt(8) = 1, and by making the generatePlayerPokemon() species * check pass when Utils.randSeedInt(8) = 0, we can tell them apart during tests. */ - const rand = Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1; + const rand = randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1; return rand ? Species.PHIONE : Species.MANAPHY; } if (this.tier === EggTier.LEGENDARY && this._sourceType === EggSourceType.GACHA_LEGENDARY) { - if (!Utils.randSeedInt(2)) { + if (!randSeedInt(2)) { return getLegendaryGachaSpeciesForTimestamp(this.timestamp); } } @@ -501,7 +498,7 @@ export class Egg { let species: Species; - const rand = Utils.randSeedInt(totalWeight); + const rand = randSeedInt(totalWeight); for (let s = 0; s < speciesWeights.length; s++) { if (rand < speciesWeights[s]) { species = speciesPool[s]; @@ -539,7 +536,7 @@ export class Egg { break; } - return !Utils.randSeedInt(shinyChance); + return !randSeedInt(shinyChance); } // Uses the same logic as pokemon.generateVariant(). I would like to only have this logic in one @@ -550,7 +547,7 @@ export class Egg { return VariantTier.STANDARD; } - const rand = Utils.randSeedInt(10); + const rand = randSeedInt(10); if (rand >= SHINY_VARIANT_CHANCE) { return VariantTier.STANDARD; // 6/10 } diff --git a/src/data/moves/invalid-moves.ts b/src/data/moves/invalid-moves.ts index 5cd45de7939..025c0383f43 100644 --- a/src/data/moves/invalid-moves.ts +++ b/src/data/moves/invalid-moves.ts @@ -240,3 +240,18 @@ export const invalidMirrorMoveMoves: ReadonlySet = new Set([ Moves.WATER_SPORT, Moves.WIDE_GUARD, ]); + +/** Set of moves that can never have their type overridden by an ability like Pixilate or Normalize + * + * Excludes tera blast and tera starstorm, as these are only conditionally forbidden + */ +export const noAbilityTypeOverrideMoves: ReadonlySet = new Set([ + Moves.WEATHER_BALL, + Moves.JUDGMENT, + Moves.REVELATION_DANCE, + Moves.MULTI_ATTACK, + Moves.TERRAIN_PULSE, + Moves.NATURAL_GIFT, + Moves.TECHNO_BLAST, + Moves.HIDDEN_POWER, +]); diff --git a/src/data/moves/move-utils.ts b/src/data/moves/move-utils.ts new file mode 100644 index 00000000000..3323d6f4a0c --- /dev/null +++ b/src/data/moves/move-utils.ts @@ -0,0 +1,20 @@ +import { MoveTarget } from "#enums/MoveTarget"; +import type Move from "./move"; + +/** + * Return whether the move targets the field + * + * Examples include + * - Hazard moves like spikes + * - Weather moves like rain dance + * - User side moves like reflect and safeguard + */ +export function isFieldTargeted(move: Move): boolean { + switch (move.moveTarget) { + case MoveTarget.BOTH_SIDES: + case MoveTarget.USER_SIDE: + case MoveTarget.ENEMY_SIDE: + return true; + } + return false; +} diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 2624fe6cda9..d09613123bb 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -29,14 +29,11 @@ import { } from "../status-effect"; import { getTypeDamageMultiplier } from "../type"; import { PokemonType } from "#enums/pokemon-type"; -import type { Constructor } from "#app/utils"; -import { NumberHolder } from "#app/utils"; -import * as Utils from "../../utils"; +import { BooleanHolder, NumberHolder, isNullOrUndefined, toDmgValue, randSeedItem, randSeedInt, getEnumValues, toReadableString, type Constructor } from "#app/utils/common"; import { WeatherType } from "#enums/weather-type"; import type { ArenaTrapTag } from "../arena-tag"; import { ArenaTagSide, WeakenMoveTypeTag } from "../arena-tag"; import { - allAbilities, AllyMoveCategoryPowerBoostAbAttr, applyAbAttrs, applyPostAttackAbAttrs, @@ -63,11 +60,13 @@ import { MoveTypeChangeAbAttr, PostDamageForceSwitchAbAttr, PostItemLostAbAttr, + ReflectStatusMoveAbAttr, ReverseDrainAbAttr, UserFieldMoveTypePowerBoostAbAttr, VariableMovePowerAbAttr, WonderSkinAbAttr, -} from "../ability"; +} from "../abilities/ability"; +import { allAbilities } from "../data-lists"; import { AttackTypeBoosterModifier, BerryModifier, @@ -77,7 +76,7 @@ import { PreserveBerryModifier, } from "../../modifier/modifier"; import type { BattlerIndex } from "../../battle"; -import { BattleType } from "../../battle"; +import { BattleType } from "#enums/battle-type"; import { TerrainType } from "../terrain"; import { ModifierPoolType } from "#app/modifier/modifier-type"; import { Command } from "../../ui/command-ui-handler"; @@ -123,6 +122,7 @@ import { MoveFlags } from "#enums/MoveFlags"; import { MoveEffectTrigger } from "#enums/MoveEffectTrigger"; import { MultiHitType } from "#enums/MultiHitType"; import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves"; +import { SelectBiomePhase } from "#app/phases/select-biome-phase"; type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean; @@ -346,13 +346,13 @@ export default class Move implements Localizable { * @param target The {@linkcode Pokemon} targeted by this move * @returns `true` if the move can bypass the target's Substitute; `false` otherwise. */ - hitsSubstitute(user: Pokemon, target: Pokemon | null): boolean { + hitsSubstitute(user: Pokemon, target?: Pokemon): boolean { if ([ MoveTarget.USER, MoveTarget.USER_SIDE, MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES ].includes(this.moveTarget) || !target?.getTag(BattlerTagType.SUBSTITUTE)) { return false; } - const bypassed = new Utils.BooleanHolder(false); + const bypassed = new BooleanHolder(false); // TODO: Allow this to be simulated applyAbAttrs(InfiltratorAbAttr, user, null, false, bypassed); @@ -618,12 +618,30 @@ export default class Move implements Localizable { /** * Checks if the move flag applies to the pokemon(s) using/receiving the move + * + * This method will take the `user`'s ability into account when reporting flags, e.g. + * calling this method for {@linkcode MoveFlags.MAKES_CONTACT | MAKES_CONTACT} + * will return `false` if the user has a {@linkcode Abilities.LONG_REACH} that is not being suppressed. + * + * **Note:** This method only checks if the move should have effectively have the flag applied to its use. + * It does *not* check whether the flag will trigger related effects. + * For example using this method to check {@linkcode MoveFlags.WIND_MOVE} + * will not consider {@linkcode Abilities.WIND_RIDER | Wind Rider }. + * + * To simply check whether the move has a flag, use {@linkcode hasFlag}. * @param flag {@linkcode MoveFlags} MoveFlag to check on user and/or target * @param user {@linkcode Pokemon} the Pokemon using the move * @param target {@linkcode Pokemon} the Pokemon receiving the move + * @param isFollowUp (defaults to `false`) `true` if the move was used as a follow up * @returns boolean + * @see {@linkcode hasFlag} */ - checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon | null): boolean { + doesFlagEffectApply({ flag, user, target, isFollowUp = false }: { + flag: MoveFlags; + user: Pokemon; + target?: Pokemon; + isFollowUp?: boolean; + }): boolean { // special cases below, eg: if the move flag is MAKES_CONTACT, and the user pokemon has an ability that ignores contact (like "Long Reach"), then overrides and move does not make contact switch (flag) { case MoveFlags.MAKES_CONTACT: @@ -633,19 +651,32 @@ export default class Move implements Localizable { break; case MoveFlags.IGNORE_ABILITIES: if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) { - const abilityEffectsIgnored = new Utils.BooleanHolder(false); + const abilityEffectsIgnored = new BooleanHolder(false); applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, false, this); if (abilityEffectsIgnored.value) { return true; } + // Sunsteel strike, Moongeist beam, and photon geyser will not ignore abilities if invoked + // by another move, such as via metronome. } - break; + return this.hasFlag(MoveFlags.IGNORE_ABILITIES) && !isFollowUp; case MoveFlags.IGNORE_PROTECT: if (user.hasAbilityWithAttr(IgnoreProtectOnContactAbAttr) - && this.checkFlag(MoveFlags.MAKES_CONTACT, user, null)) { + && this.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user })) { return true; } break; + case MoveFlags.REFLECTABLE: + // If the target is not semi-invulnerable and either has magic coat active or an unignored magic bounce ability + if ( + target?.getTag(SemiInvulnerableTag) || + !(target?.getTag(BattlerTagType.MAGIC_COAT) || + (!this.doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user, target }) && + target?.hasAbilityWithAttr(ReflectStatusMoveAbAttr))) + ) { + return false; + } + break; } return !!(this.flags & flag); @@ -735,7 +766,7 @@ export default class Move implements Localizable { * @returns The calculated accuracy of the move. */ calculateBattleAccuracy(user: Pokemon, target: Pokemon, simulated: boolean = false) { - const moveAccuracy = new Utils.NumberHolder(this.accuracy); + const moveAccuracy = new NumberHolder(this.accuracy); applyMoveAttrs(VariableAccuracyAttr, user, target, this, moveAccuracy); applyPreDefendAbAttrs(WonderSkinAbAttr, target, user, this, { value: false }, simulated, moveAccuracy); @@ -777,10 +808,11 @@ export default class Move implements Localizable { return -1; } - const power = new Utils.NumberHolder(this.power); - const typeChangeMovePowerMultiplier = new Utils.NumberHolder(1); + const power = new NumberHolder(this.power); + const typeChangeMovePowerMultiplier = new NumberHolder(1); + const typeChangeHolder = new NumberHolder(this.type); - applyPreAttackAbAttrs(MoveTypeChangeAbAttr, source, target, this, true, null, typeChangeMovePowerMultiplier); + applyPreAttackAbAttrs(MoveTypeChangeAbAttr, source, target, this, true, typeChangeHolder, typeChangeMovePowerMultiplier); const sourceTeraType = source.getTeraType(); if (source.isTerastallized && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr(MultiHitAttr) && !globalScene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) { @@ -789,7 +821,7 @@ export default class Move implements Localizable { applyPreAttackAbAttrs(VariableMovePowerAbAttr, source, target, this, simulated, power); const ally = source.getAlly(); - if (!Utils.isNullOrUndefined(ally)) { + if (!isNullOrUndefined(ally)) { applyPreAttackAbAttrs(AllyMoveCategoryPowerBoostAbAttr, ally, target, this, simulated, power); } @@ -810,7 +842,7 @@ export default class Move implements Localizable { power.value *= typeChangeMovePowerMultiplier.value; - const typeBoost = source.findTag(t => t instanceof TypeBoostTag && t.boostedType === this.type) as TypeBoostTag; + const typeBoost = source.findTag(t => t instanceof TypeBoostTag && t.boostedType === typeChangeHolder.value) as TypeBoostTag; if (typeBoost) { power.value *= typeBoost.boostValue; } @@ -818,8 +850,8 @@ export default class Move implements Localizable { applyMoveAttrs(VariablePowerAttr, source, target, this, power); if (!this.hasAttr(TypelessAttr)) { - globalScene.arena.applyTags(WeakenMoveTypeTag, simulated, this.type, power); - globalScene.applyModifiers(AttackTypeBoosterModifier, source.isPlayer(), source, this.type, power); + globalScene.arena.applyTags(WeakenMoveTypeTag, simulated, typeChangeHolder.value, power); + globalScene.applyModifiers(AttackTypeBoosterModifier, source.isPlayer(), source, typeChangeHolder.value, power); } if (source.getTag(HelpingHandTag)) { @@ -830,7 +862,7 @@ export default class Move implements Localizable { } getPriority(user: Pokemon, simulated: boolean = true) { - const priority = new Utils.NumberHolder(this.priority); + const priority = new NumberHolder(this.priority); applyMoveAttrs(IncrementMovePriorityAttr, user, null, this, priority); applyAbAttrs(ChangeMovePriorityAbAttr, user, null, simulated, this, priority); @@ -912,7 +944,7 @@ export default class Move implements Localizable { // ...and cannot enhance Pollen Puff when targeting an ally. const ally = user.getAlly(); - const exceptPollenPuffAlly: boolean = this.id === Moves.POLLEN_PUFF && !Utils.isNullOrUndefined(ally) && targets.includes(ally.getBattlerIndex()) + const exceptPollenPuffAlly: boolean = this.id === Moves.POLLEN_PUFF && !isNullOrUndefined(ally) && targets.includes(ally.getBattlerIndex()) return (!restrictSpread || !isMultiTarget) && !this.isChargingMove() @@ -951,7 +983,7 @@ export class AttackMove extends Move { const effectiveness = target.getAttackTypeEffectiveness(this.type, user, undefined, undefined, this); attackScore = Math.pow(effectiveness - 1, 2) * (effectiveness < 1 ? -2 : 2); const [ thisStat, offStat ]: EffectiveStat[] = this.category === MoveCategory.PHYSICAL ? [ Stat.ATK, Stat.SPATK ] : [ Stat.SPATK, Stat.ATK ]; - const statHolder = new Utils.NumberHolder(user.getEffectiveStat(thisStat, target)); + const statHolder = new NumberHolder(user.getEffectiveStat(thisStat, target)); const offStatValue = user.getEffectiveStat(offStat, target); applyMoveAttrs(VariableAtkAttr, user, target, move, statHolder); const statRatio = offStatValue / statHolder.value; @@ -961,7 +993,7 @@ export class AttackMove extends Move { attackScore *= 1.5; } - const power = new Utils.NumberHolder(this.calculateEffectivePower()); + const power = new NumberHolder(this.calculateEffectivePower()); applyMoveAttrs(VariablePowerAttr, user, target, move, power); attackScore += Math.floor(power.value / 5); @@ -1214,7 +1246,7 @@ 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.checkFlag(MoveFlags.IGNORE_PROTECT, user, target)); + move.doesFlagEffectApply({ flag: MoveFlags.IGNORE_PROTECT, user, target })); } /** Applies move effects so long as they are able based on {@linkcode canApply} */ @@ -1232,7 +1264,7 @@ export class MoveEffectAttr extends MoveAttr { * @returns Move effect chance value. */ getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): number { - const moveChance = new Utils.NumberHolder(this.effectChanceOverride ?? move.chance); + const moveChance = new NumberHolder(this.effectChanceOverride ?? move.chance); applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, !showAbility, moveChance, move); @@ -1395,7 +1427,7 @@ export class RespectAttackTypeImmunityAttr extends MoveAttr { } export class IgnoreOpponentStatStagesAttr extends MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.BooleanHolder).value = true; + (args[0] as BooleanHolder).value = true; return true; } @@ -1403,7 +1435,7 @@ export class IgnoreOpponentStatStagesAttr extends MoveAttr { export class HighCritAttr extends MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value++; + (args[0] as NumberHolder).value++; return true; } @@ -1415,7 +1447,7 @@ export class HighCritAttr extends MoveAttr { export class CritOnlyAttr extends MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.BooleanHolder).value = true; + (args[0] as BooleanHolder).value = true; return true; } @@ -1435,7 +1467,7 @@ export class FixedDamageAttr extends MoveAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = this.getDamage(user, target, move); + (args[0] as NumberHolder).value = this.getDamage(user, target, move); return true; } @@ -1451,7 +1483,7 @@ export class UserHpDamageAttr extends FixedDamageAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = user.hp; + (args[0] as NumberHolder).value = user.hp; return true; } @@ -1472,7 +1504,7 @@ export class TargetHalfHpDamageAttr extends FixedDamageAttr { const lensCount = user.getHeldItems().find(i => i instanceof PokemonMultiHitModifier)?.getStackCount() ?? 0; if (lensCount <= 0) { // no multi lenses; we can just halve the target's hp and call it a day - (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(target.hp / 2); + (args[0] as NumberHolder).value = toDmgValue(target.hp / 2); return true; } @@ -1483,11 +1515,11 @@ export class TargetHalfHpDamageAttr extends FixedDamageAttr { this.initialHp = target.hp; default: // multi lens added hit; use initialHp tracker to ensure correct damage - (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(this.initialHp / 2); + (args[0] as NumberHolder).value = toDmgValue(this.initialHp / 2); return true; case lensCount + 1: // parental bond added hit; calc damage as normal - (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(target.hp / 2); + (args[0] as NumberHolder).value = toDmgValue(target.hp / 2); return true; } } @@ -1503,7 +1535,7 @@ export class MatchHpAttr extends FixedDamageAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = target.hp - user.hp; + (args[0] as NumberHolder).value = target.hp - user.hp; return true; } @@ -1533,7 +1565,7 @@ export class CounterDamageAttr extends FixedDamageAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const damage = user.turnData.attacksReceived.filter(ar => this.moveFilter(allMoves[ar.move])).reduce((total: number, ar: AttackMoveResult) => total + ar.damage, 0); - (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(damage * this.multiplier); + (args[0] as NumberHolder).value = toDmgValue(damage * this.multiplier); return true; } @@ -1559,13 +1591,13 @@ export class RandomLevelDamageAttr extends FixedDamageAttr { } getDamage(user: Pokemon, target: Pokemon, move: Move): number { - return Utils.toDmgValue(user.level * (user.randSeedIntRange(50, 150) * 0.01)); + return toDmgValue(user.level * (user.randSeedIntRange(50, 150) * 0.01)); } } export class ModifiedDamageAttr extends MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const initialDamage = args[0] as Utils.NumberHolder; + const initialDamage = args[0] as NumberHolder; initialDamage.value = this.getModifiedDamage(user, target, move, initialDamage.value); return true; @@ -1618,7 +1650,7 @@ export class RecoilAttr extends MoveEffectAttr { return false; } - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); if (!this.unblockable) { applyAbAttrs(BlockRecoilDamageAttr, user, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled); @@ -1635,7 +1667,7 @@ export class RecoilAttr extends MoveEffectAttr { const damageValue = (!this.useHp ? user.turnData.totalDamageDealt : user.getMaxHp()) * this.damageRatio; const minValue = user.turnData.totalDamageDealt ? 1 : 0; - const recoilDamage = Utils.toDmgValue(damageValue, minValue); + const recoilDamage = toDmgValue(damageValue, minValue); if (!recoilDamage) { return false; } @@ -1697,7 +1729,7 @@ export class SacrificialAttr extends MoveEffectAttr { **/ export class SacrificialAttrOnHit extends MoveEffectAttr { constructor() { - super(true, { trigger: MoveEffectTrigger.HIT }); + super(true); } /** @@ -1752,11 +1784,11 @@ export class HalfSacrificialAttr extends MoveEffectAttr { return false; } - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); // Check to see if the Pokemon has an ability that blocks non-direct damage applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled); if (!cancelled.value) { - user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT, ignoreSegments: true }); + user.damageAndUpdate(toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT, ignoreSegments: true }); globalScene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", { pokemonName: getPokemonNameWithAffix(user) })); // Queue recoil message } return true; @@ -1771,10 +1803,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr { } /** - * Attribute to put in a {@link https://bulbapedia.bulbagarden.net/wiki/Substitute_(doll) | Substitute Doll} - * for the user. - * @extends MoveEffectAttr - * @see {@linkcode apply} + * Attribute to put in a {@link https://bulbapedia.bulbagarden.net/wiki/Substitute_(doll) | Substitute Doll} for the user. */ export class AddSubstituteAttr extends MoveEffectAttr { /** The ratio of the user's max HP that is required to apply this effect */ @@ -1791,11 +1820,11 @@ export class AddSubstituteAttr extends MoveEffectAttr { /** * Removes 1/4 of the user's maximum HP (rounded down) to create a substitute for the user - * @param user the {@linkcode Pokemon} that used the move. - * @param target n/a - * @param move the {@linkcode Move} with this attribute. - * @param args n/a - * @returns true if the attribute successfully applies, false otherwise + * @param user - The {@linkcode Pokemon} that used the move. + * @param target - n/a + * @param move - The {@linkcode Move} with this attribute. + * @param args - n/a + * @returns `true` if the attribute successfully applies, `false` otherwise */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!super.apply(user, target, move, args)) { @@ -1816,12 +1845,12 @@ export class AddSubstituteAttr extends MoveEffectAttr { } getCondition(): MoveConditionFunc { - return (user, target, move) => !user.getTag(SubstituteTag) && user.hp > (this.roundUp ? Math.ceil(user.getMaxHp() * this.hpCost) : Math.floor(user.getMaxHp() * this.hpCost)) && user.getMaxHp() > 1; + return (user, _target, _move) => !user.getTag(SubstituteTag) && user.hp > (this.roundUp ? Math.ceil(user.getMaxHp() * this.hpCost) : Math.floor(user.getMaxHp() * this.hpCost)) && user.getMaxHp() > 1; } /** * Get the substitute-specific failure message if one should be displayed. - * @param user The pokemon using the move. + * @param user - The pokemon using the move. * @returns The substitute-specific failure message if the conditions apply, otherwise `undefined` */ getFailedText(user: Pokemon, _target: Pokemon, _move: Move): string | undefined { @@ -1862,7 +1891,7 @@ export class HealAttr extends MoveEffectAttr { */ addHealPhase(target: Pokemon, healRatio: number) { globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(), - Utils.toDmgValue(target.getMaxHp() * healRatio), i18next.t("moveTriggers:healHp", { pokemonName: getPokemonNameWithAffix(target) }), true, !this.showAnim)); + toDmgValue(target.getMaxHp() * healRatio), i18next.t("moveTriggers:healHp", { pokemonName: getPokemonNameWithAffix(target) }), true, !this.showAnim)); } getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { @@ -1936,6 +1965,14 @@ export class PartyStatusCureAttr extends MoveEffectAttr { * @extends MoveEffectAttr */ export class FlameBurstAttr extends MoveEffectAttr { + constructor() { + /** + * This is self-targeted to bypass immunity to target-facing secondary + * effects when the target has an active Substitute doll. + * TODO: Find a more intuitive way to implement Substitute bypassing. + */ + super(true); + } /** * @param user - n/a * @param target - The target Pokémon. @@ -1945,9 +1982,9 @@ export class FlameBurstAttr extends MoveEffectAttr { */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const targetAlly = target.getAlly(); - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); - if (!Utils.isNullOrUndefined(targetAlly)) { + if (!isNullOrUndefined(targetAlly)) { applyAbAttrs(BlockNonDirectDamageAbAttr, targetAlly, cancelled); } @@ -1960,7 +1997,7 @@ export class FlameBurstAttr extends MoveEffectAttr { } getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { - return !Utils.isNullOrUndefined(target.getAlly()) ? -5 : 0; + return !isNullOrUndefined(target.getAlly()) ? -5 : 0; } } @@ -2028,11 +2065,11 @@ export class IgnoreWeatherTypeDebuffAttr extends MoveAttr { * @param user {@linkcode Pokemon} that used the move * @param target N/A * @param move {@linkcode Move} with this attribute - * @param args [0] {@linkcode Utils.NumberHolder} for arenaAttackTypeMultiplier + * @param args [0] {@linkcode NumberHolder} for arenaAttackTypeMultiplier * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const weatherModifier = args[0] as Utils.NumberHolder; + const weatherModifier = args[0] as NumberHolder; //If the type-based attack power modifier due to weather (e.g. Water moves in Sun) is below 1, set it to 1 if (globalScene.arena.weather?.weatherType === this.weather) { weatherModifier.value = Math.max(weatherModifier.value, 1); @@ -2158,7 +2195,7 @@ export class HitHealAttr extends MoveEffectAttr { private healStat: EffectiveStat | null; constructor(healRatio?: number | null, healStat?: EffectiveStat) { - super(true, { trigger: MoveEffectTrigger.HIT }); + super(true); this.healRatio = healRatio ?? 0.5; this.healStat = healStat ?? null; @@ -2183,7 +2220,7 @@ export class HitHealAttr extends MoveEffectAttr { message = i18next.t("battle:drainMessage", { pokemonName: getPokemonNameWithAffix(target) }); } else { // Default healing formula used by draining moves like Absorb, Draining Kiss, Bitter Blade, etc. - healAmount = Utils.toDmgValue(user.turnData.singleHitDamageDealt * this.healRatio); + healAmount = toDmgValue(user.turnData.singleHitDamageDealt * this.healRatio); message = i18next.t("battle:regainHealth", { pokemonName: getPokemonNameWithAffix(user) }); } if (reverseDrain) { @@ -2241,7 +2278,7 @@ export class IncrementMovePriorityAttr extends MoveAttr { * @param user {@linkcode Pokemon} using this move * @param target {@linkcode Pokemon} target of this move * @param move {@linkcode Move} being used - * @param args [0] {@linkcode Utils.NumberHolder} for move priority. + * @param args [0] {@linkcode NumberHolder} for move priority. * @returns true if function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -2249,7 +2286,7 @@ export class IncrementMovePriorityAttr extends MoveAttr { return false; } - (args[0] as Utils.NumberHolder).value += this.increaseAmount; + (args[0] as NumberHolder).value += this.increaseAmount; return true; } } @@ -2287,15 +2324,15 @@ export class MultiHitAttr extends MoveAttr { * @param user {@linkcode Pokemon} that used the attack * @param target {@linkcode Pokemon} targeted by the attack * @param move {@linkcode Move} being used - * @param args [0] {@linkcode Utils.NumberHolder} storing the hit count of the attack + * @param args [0] {@linkcode NumberHolder} storing the hit count of the attack * @returns True */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const hitType = new Utils.NumberHolder(this.intrinsicMultiHitType); + const hitType = new NumberHolder(this.intrinsicMultiHitType); applyMoveAttrs(ChangeMultiHitTypeAttr, user, target, move, hitType); this.multiHitType = hitType.value; - (args[0] as Utils.NumberHolder).value = this.getHitCount(user, target); + (args[0] as NumberHolder).value = this.getHitCount(user, target); return true; } @@ -2316,7 +2353,7 @@ export class MultiHitAttr extends MoveAttr { case MultiHitType._2_TO_5: { const rand = user.randSeedInt(20); - const hitValue = new Utils.NumberHolder(rand); + const hitValue = new NumberHolder(rand); applyAbAttrs(MaxMultiHitAbAttr, user, null, false, hitValue); if (hitValue.value >= 13) { return 2; @@ -2394,7 +2431,7 @@ export class ChangeMultiHitTypeAttr extends MoveAttr { export class WaterShurikenMultiHitTypeAttr extends ChangeMultiHitTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (user.species.speciesId === Species.GRENINJA && user.hasAbility(Abilities.BATTLE_BOND) && user.formIndex === 2) { - (args[0] as Utils.NumberHolder).value = MultiHitType._3; + (args[0] as NumberHolder).value = MultiHitType._3; return true; } return false; @@ -2407,7 +2444,7 @@ export class StatusEffectAttr extends MoveEffectAttr { public overrideStatus: boolean = false; constructor(effect: StatusEffect, selfTarget?: boolean, turnsRemaining?: number, overrideStatus: boolean = false) { - super(selfTarget, { trigger: MoveEffectTrigger.HIT }); + super(selfTarget); this.effect = effect; this.turnsRemaining = turnsRemaining; @@ -2415,30 +2452,15 @@ export class StatusEffectAttr extends MoveEffectAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (!this.selfTarget && move.hitsSubstitute(user, target)) { - return false; - } - const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true); const statusCheck = moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance; if (statusCheck) { const pokemon = this.selfTarget ? user : target; - if (pokemon.status) { - if (this.overrideStatus) { - pokemon.resetStatus(); - } else { - return false; - } - } - - if (user !== target && target.isSafeguarded(user)) { - if (move.category === MoveCategory.STATUS) { - globalScene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target) })); - } + if (user !== target && move.category === MoveCategory.STATUS && !target.canSetStatus(this.effect, false, false, user, true)) { return false; } - if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0)) - && pokemon.trySetStatus(this.effect, true, user, this.turnsRemaining)) { + if (((!pokemon.status || this.overrideStatus) || (pokemon.status.effect === this.effect && moveChance < 0)) + && pokemon.trySetStatus(this.effect, true, user, this.turnsRemaining, null, this.overrideStatus, false)) { applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect); return true; } @@ -2464,7 +2486,7 @@ export class MultiStatusEffectAttr extends StatusEffectAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - this.effect = Utils.randSeedItem(this.effects); + this.effect = randSeedItem(this.effects); const result = super.apply(user, target, move, args); return result; } @@ -2480,7 +2502,7 @@ export class MultiStatusEffectAttr extends StatusEffectAttr { export class PsychoShiftEffectAttr extends MoveEffectAttr { constructor() { - super(false, { trigger: MoveEffectTrigger.HIT }); + super(false); } /** @@ -2510,40 +2532,40 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr { return !target.status && target.canSetStatus(user.status?.effect, true, false, user) ? -10 : 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." + * Attribute to steal items upon this move's use. + * Used for {@linkcode Moves.THIEF} and {@linkcode Moves.COVET}. */ export class StealHeldItemChanceAttr extends MoveEffectAttr { private chance: number; constructor(chance: number) { - super(false, { trigger: MoveEffectTrigger.HIT }); + super(false); this.chance = chance; } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (move.hitsSubstitute(user, target)) { - return false; - } - const rand = Phaser.Math.RND.realInRange(0, 1); if (rand >= this.chance) { return false; } + const heldItems = this.getTargetHeldItems(target).filter((i) => i.isTransferable); - 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); // TODO: is the bang after tier correct? - const tierHeldItems = heldItems.filter((m) => m.type.getOrInferTier(poolType) === highestItemTier); - const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; - if (globalScene.tryTransferHeldItemModifier(stolenItem, user, false)) { - globalScene.queueMessage(i18next.t("moveTriggers:stoleItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: stolenItem.type.name })); - return true; - } + if (!heldItems.length) { + return false; } - return false; + + 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); // TODO: is the bang after tier correct? + const tierHeldItems = heldItems.filter((m) => m.type.getOrInferTier(poolType) === highestItemTier); + const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; + if (!globalScene.tryTransferHeldItemModifier(stolenItem, user, false)) { + return false; + } + + globalScene.queueMessage(i18next.t("moveTriggers:stoleItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: stolenItem.type.name })); + return true; } getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] { @@ -2567,62 +2589,62 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { * 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." + * "If the Pokémon is knocked out by the attack, Sticky Hold does not protect the held item."" */ export class RemoveHeldItemAttr extends MoveEffectAttr { - /** Optional restriction for item pool to berries only i.e. Differentiating Incinerate and Knock Off */ + /** Optional restriction for item pool to berries only; i.e. Incinerate */ private berriesOnly: boolean; - constructor(berriesOnly: boolean) { - super(false, { trigger: MoveEffectTrigger.HIT }); + constructor(berriesOnly: boolean = false) { + super(false); this.berriesOnly = berriesOnly; } /** - * - * @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 + * Attempt to permanently remove a held + * @param user - The {@linkcode Pokemon} that used the move + * @param target - The {@linkcode Pokemon} targeted by the move + * @param move - N/A * @param args N/A - * @returns {boolean} True if an item was removed + * @returns `true` if an item was able to be removed */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!this.berriesOnly && target.isPlayer()) { // "Wild Pokemon cannot knock off Player Pokemon's held items" (See Bulbapedia) return false; } - if (move.hitsSubstitute(user, target)) { + // Check for abilities that block item theft + // TODO: This should not trigger if the target would faint beforehand + const cancelled = new BooleanHolder(false); + applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); + + if (cancelled.value) { 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). + // Considers entire transferrable item pool by default (Knock Off). + // Otherwise only consider berries (Incinerate). let heldItems = this.getTargetHeldItems(target).filter(i => i.isTransferable); 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)]; + if (!heldItems.length) { + return false; + } - // Decrease item amount and update icon - target.loseHeldItem(removedItem); - globalScene.updateModifiers(target.isPlayer()); + const removedItem = heldItems[user.randSeedInt(heldItems.length)]; + // Decrease item amount and update icon + target.loseHeldItem(removedItem); + globalScene.updateModifiers(target.isPlayer()); - if (this.berriesOnly) { - globalScene.queueMessage(i18next.t("moveTriggers:incineratedItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name })); - } else { - globalScene.queueMessage(i18next.t("moveTriggers:knockedOffItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name })); - } + if (this.berriesOnly) { + globalScene.queueMessage(i18next.t("moveTriggers:incineratedItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name })); + } else { + globalScene.queueMessage(i18next.t("moveTriggers:knockedOffItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name })); } return true; @@ -2648,34 +2670,43 @@ export class RemoveHeldItemAttr extends MoveEffectAttr { * Attribute that causes targets of the move to eat a berry. Used for Teatime, Stuff Cheeks */ export class EatBerryAttr extends MoveEffectAttr { - protected chosenBerry: BerryModifier | undefined; - constructor() { - super(true, { trigger: MoveEffectTrigger.HIT }); + protected chosenBerry: BerryModifier; + constructor(selfTarget: boolean) { + super(selfTarget); } + /** * Causes the target to eat a berry. - * @param user {@linkcode Pokemon} Pokemon that used the move - * @param target {@linkcode Pokemon} Pokemon that will eat a berry - * @param move {@linkcode Move} The move being used + * @param user The {@linkcode Pokemon} Pokemon that used the move + * @param target The {@linkcode Pokemon} Pokemon that will eat the berry + * @param move The {@linkcode Move} being used * @param args Unused - * @returns {boolean} true if the function succeeds + * @returns `true` if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!super.apply(user, target, move, args)) { return false; } - const heldBerries = this.getTargetHeldBerries(target); + const pokemon = this.selfTarget ? user : target; + + const heldBerries = this.getTargetHeldBerries(pokemon); if (heldBerries.length <= 0) { return false; } + + // pick a random berry to gobble and check if we preserve it this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)]; - const preserve = new Utils.BooleanHolder(false); - globalScene.applyModifiers(PreserveBerryModifier, target.isPlayer(), target, preserve); // check for berry pouch preservation + const preserve = new BooleanHolder(false); + // check for berry pouch preservation + globalScene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), pokemon, preserve); if (!preserve.value) { - this.reduceBerryModifier(target); + this.reduceBerryModifier(pokemon); } - this.eatBerry(target); + + // Don't update harvest for berries preserved via Berry pouch (no item dupes lol) + this.eatBerry(target, undefined, !preserve.value); + return true; } @@ -2691,49 +2722,64 @@ export class EatBerryAttr extends MoveEffectAttr { globalScene.updateModifiers(target.isPlayer()); } - eatBerry(consumer: Pokemon, berryOwner?: Pokemon) { - getBerryEffectFunc(this.chosenBerry!.berryType)(consumer, berryOwner); // consumer eats the berry - applyAbAttrs(HealFromBerryUseAbAttr, consumer, new Utils.BooleanHolder(false)); + + /** + * Internal function to apply berry effects. + * + * @param consumer - The {@linkcode Pokemon} eating the berry; assumed to also be owner if `berryOwner` is omitted + * @param berryOwner - The {@linkcode Pokemon} whose berry is being eaten; defaults to `consumer` if not specified. + * @param updateHarvest - Whether to prevent harvest from tracking berries; + * defaults to whether `consumer` equals `berryOwner` (i.e. consuming own berry). + */ + protected eatBerry(consumer: Pokemon, berryOwner: Pokemon = consumer, updateHarvest = consumer === berryOwner) { + // consumer eats berry, owner triggers unburden and similar effects + getBerryEffectFunc(this.chosenBerry.berryType)(consumer); + applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner, false); + applyAbAttrs(HealFromBerryUseAbAttr, consumer, new BooleanHolder(false)); + consumer.recordEatenBerry(this.chosenBerry.berryType, updateHarvest); } } /** - * Attribute used for moves that steal a random berry from the target. The user then eats the stolen berry. - * Used for Pluck & Bug Bite. + * Attribute used for moves that steal and eat a random berry from the target. + * Used for {@linkcode Moves.PLUCK} & {@linkcode Moves.BUG_BITE}. */ export class StealEatBerryAttr extends EatBerryAttr { constructor() { - super(); + super(false); } + /** * User steals a random berry from the target and then eats it. - * @param {Pokemon} user Pokemon that used the move and will eat the stolen berry - * @param {Pokemon} target Pokemon that will have its berry stolen - * @param {Move} move Move being used - * @param {any[]} args Unused - * @returns {boolean} true if the function succeeds + * @param user - The {@linkcode Pokemon} using the move; will eat the stolen berry + * @param target - The {@linkcode Pokemon} having its berry stolen + * @param move - The {@linkcode Move} being used + * @param args N/A + * @returns `true` if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (move.hitsSubstitute(user, target)) { - return false; - } - const cancelled = new Utils.BooleanHolder(false); - applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // check for abilities that block item theft + // check for abilities that block item theft + const cancelled = new BooleanHolder(false); + applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); if (cancelled.value === true) { return false; } + // check if the target even _has_ a berry in the first place + // TODO: Check on cart if Pluck displays messages when used against sticky hold mons w/o berries const heldBerries = this.getTargetHeldBerries(target); if (heldBerries.length <= 0) { return false; } - // if the target has berries, pick a random berry and steal it + + // pick a random berry and eat it this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)]; applyPostItemLostAbAttrs(PostItemLostAbAttr, target, false); const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name }); globalScene.queueMessage(message); this.reduceBerryModifier(target); this.eatBerry(user, target); + return true; } } @@ -2767,10 +2813,6 @@ export class HealStatusEffectAttr extends MoveEffectAttr { return false; } - if (!this.selfTarget && move.hitsSubstitute(user, target)) { - return false; - } - // Special edge case for shield dust blocking Sparkling Aria curing burn const moveTargets = getMoveTargets(user, move.id); if (target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && move.id === Moves.SPARKLING_ARIA && moveTargets.targets.length === 1) { @@ -2830,11 +2872,11 @@ export class BypassBurnDamageReductionAttr extends MoveAttr { * @param user N/A * @param target N/A * @param move {@linkcode Move} with this attribute - * @param args [0] {@linkcode Utils.BooleanHolder} for burnDamageReductionCancelled + * @param args [0] {@linkcode BooleanHolder} for burnDamageReductionCancelled * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.BooleanHolder).value = true; + (args[0] as BooleanHolder).value = true; return true; } @@ -2915,14 +2957,14 @@ export class OneHitKOAttr extends MoveAttr { return false; } - (args[0] as Utils.BooleanHolder).value = true; + (args[0] as BooleanHolder).value = true; return true; } getCondition(): MoveConditionFunc { return (user, target, move) => { - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); applyAbAttrs(BlockOneHitKOAbAttr, target, cancelled); return !cancelled.value && user.level >= target.level; }; @@ -2949,12 +2991,12 @@ export class InstantChargeAttr extends MoveAttr { * @param target n/a * @param move the {@linkcode Move} associated with this attribute * @param args - * - `[0]` a {@linkcode Utils.BooleanHolder | BooleanHolder} for the "instant charge" flag + * - `[0]` a {@linkcode BooleanHolder | BooleanHolder} for the "instant charge" flag * @returns `true` if the instant charge condition is met; `false` otherwise. */ override apply(user: Pokemon, target: Pokemon | null, move: Move, args: any[]): boolean { const instantCharge = args[0]; - if (!(instantCharge instanceof Utils.BooleanHolder)) { + if (!(instantCharge instanceof BooleanHolder)) { return false; } @@ -2976,7 +3018,7 @@ export class WeatherInstantChargeAttr extends InstantChargeAttr { super((user, move) => { const currentWeather = globalScene.arena.weather; - if (Utils.isNullOrUndefined(currentWeather?.weatherType)) { + if (isNullOrUndefined(currentWeather?.weatherType)) { return false; } else { return !currentWeather?.isEffectSuppressed() @@ -3019,7 +3061,7 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr { return true; } - const overridden = args[0] as Utils.BooleanHolder; + const overridden = args[0] as BooleanHolder; const virtual = args[1] as boolean; if (!virtual) { @@ -3053,7 +3095,7 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr { * @param target n/a * @param move the {@linkcode Move} being used * @param args - * - [0] a {@linkcode Utils.BooleanHolder} indicating whether the move's base + * - [0] a {@linkcode BooleanHolder} indicating whether the move's base * effects should be overridden this turn. * @returns `true` if base move effects were overridden; `false` otherwise */ @@ -3064,7 +3106,7 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr { return false; } - const overridden = args[0] as Utils.BooleanHolder; + const overridden = args[0] as BooleanHolder; const allyMovePhase = globalScene.findPhase((phase) => phase instanceof MovePhase && phase.pokemon.isPlayer() === user.isPlayer()); if (allyMovePhase) { @@ -3148,14 +3190,6 @@ export class StatStageChangeAttr extends MoveEffectAttr { return this.options?.showMessage ?? true; } - /** - * Indicates when the stat change should trigger - * @default MoveEffectTrigger.HIT - */ - public override get trigger () { - return this.options?.trigger ?? MoveEffectTrigger.HIT; - } - /** * Attempts to change stats of the user or target (depending on value of selfTarget) if conditions are met * @param user {@linkcode Pokemon} the user of the move @@ -3169,10 +3203,6 @@ export class StatStageChangeAttr extends MoveEffectAttr { return false; } - if (!this.selfTarget && move.hitsSubstitute(user, target)) { - return false; - } - const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true); if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) { const stages = this.getLevels(user); @@ -3435,7 +3465,7 @@ export class CutHpStatStageBoostAttr extends StatStageChangeAttr { this.messageCallback = messageCallback; } override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / this.cutRatio), { result: HitResult.INDIRECT }); + user.damageAndUpdate(toDmgValue(user.getMaxHp() / this.cutRatio), { result: HitResult.INDIRECT }); user.updateInfo(); const ret = super.apply(user, target, move, args); if (this.messageCallback) { @@ -3457,7 +3487,7 @@ export class CutHpStatStageBoostAttr extends StatStageChangeAttr { */ export class OrderUpStatBoostAttr extends MoveEffectAttr { constructor() { - super(true, { trigger: MoveEffectTrigger.HIT }); + super(true); } override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean { @@ -3534,17 +3564,15 @@ export class ResetStatsAttr extends MoveEffectAttr { this.targetAllPokemon = targetAllPokemon; } - override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + override apply(_user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean { if (this.targetAllPokemon) { // Target all pokemon on the field when Freezy Frost or Haze are used const activePokemon = globalScene.getField(true); activePokemon.forEach((p) => this.resetStats(p)); globalScene.queueMessage(i18next.t("moveTriggers:statEliminated")); } else { // Affects only the single target when Clear Smog is used - if (!move.hitsSubstitute(user, target)) { - this.resetStats(target); - globalScene.queueMessage(i18next.t("moveTriggers:resetStats", { pokemonName: getPokemonNameWithAffix(target) })); - } + this.resetStats(target); + globalScene.queueMessage(i18next.t("moveTriggers:resetStats", { pokemonName: getPokemonNameWithAffix(target) })); } return true; } @@ -3647,7 +3675,7 @@ export class LessPPMorePowerAttr extends VariablePowerAttr { * @param user {@linkcode Pokemon} using this move * @param target {@linkcode Pokemon} target of this move * @param move {@linkcode Move} being used - * @param args [0] {@linkcode Utils.NumberHolder} of power + * @param args [0] {@linkcode NumberHolder} of power * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -3660,7 +3688,7 @@ export class LessPPMorePowerAttr extends VariablePowerAttr { ppRemains = 0; } - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; switch (ppRemains) { case 0: @@ -3693,7 +3721,7 @@ export class MovePowerMultiplierAttr extends VariablePowerAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; power.value *= this.powerMultiplierFunc(user, target, move); return true; @@ -3733,7 +3761,7 @@ export class BeatUpAttr extends VariablePowerAttr { * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const party = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty(); const allyCount = party.filter(pokemon => { @@ -3748,7 +3776,7 @@ export class BeatUpAttr extends VariablePowerAttr { const doublePowerChanceMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => { let message: string = ""; globalScene.executeWithSeedOffset(() => { - const rand = Utils.randSeedInt(100); + const rand = randSeedInt(100); if (rand < move.chance) { message = i18next.t("moveTriggers:goingAllOutForAttack", { pokemonName: getPokemonNameWithAffix(user) }); } @@ -3759,9 +3787,9 @@ const doublePowerChanceMessageFunc = (user: Pokemon, target: Pokemon, move: Move export class DoublePowerChanceAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { let rand: number; - globalScene.executeWithSeedOffset(() => rand = Utils.randSeedInt(100), globalScene.currentBattle.turn << 6, globalScene.waveSeed); + globalScene.executeWithSeedOffset(() => rand = randSeedInt(100), globalScene.currentBattle.turn << 6, globalScene.waveSeed); if (rand! < move.chance) { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; power.value *= 2; return true; } @@ -3815,7 +3843,7 @@ export class ConsecutiveUseMultiBasePowerAttr extends ConsecutiveUsePowerMultipl export class WeightPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const targetWeight = target.getWeight(); const weightThresholds = [ 10, 25, 50, 100, 200 ]; @@ -3849,7 +3877,7 @@ export class ElectroBallPowerAttr extends VariablePowerAttr { * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const statRatio = target.getEffectiveStat(Stat.SPD) / user.getEffectiveStat(Stat.SPD); const statThresholds = [ 0.25, 1 / 3, 0.5, 1, -1 ]; @@ -3884,7 +3912,7 @@ export class GyroBallPowerAttr extends VariablePowerAttr { * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const userSpeed = user.getEffectiveStat(Stat.SPD); if (userSpeed < 1) { // Gen 6+ always have 1 base power @@ -3899,7 +3927,7 @@ export class GyroBallPowerAttr extends VariablePowerAttr { export class LowHpPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const hpRatio = user.getHpRatio(); switch (true) { @@ -3929,7 +3957,7 @@ export class LowHpPowerAttr extends VariablePowerAttr { export class CompareWeightPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const userWeight = user.getWeight(); const targetWeight = target.getWeight(); @@ -3963,7 +3991,7 @@ export class CompareWeightPowerAttr extends VariablePowerAttr { export class HpPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(150 * user.getHpRatio()); + (args[0] as NumberHolder).value = toDmgValue(150 * user.getHpRatio()); return true; } @@ -3991,7 +4019,7 @@ export class OpponentHighHpPowerAttr extends VariablePowerAttr { * @returns true */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(this.maxBasePower * target.getHpRatio()); + (args[0] as NumberHolder).value = toDmgValue(this.maxBasePower * target.getHpRatio()); return true; } @@ -4001,7 +4029,7 @@ export class FirstAttackDoublePowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { console.log(target.getLastXMoves(1), globalScene.currentBattle.turn); if (!target.getLastXMoves(1).find(m => m.turn === globalScene.currentBattle.turn)) { - (args[0] as Utils.NumberHolder).value *= 2; + (args[0] as NumberHolder).value *= 2; return true; } @@ -4013,7 +4041,7 @@ export class FirstAttackDoublePowerAttr extends VariablePowerAttr { export class TurnDamagedDoublePowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (user.turnData.attacksReceived.find(r => r.damage && r.sourceId === target.id)) { - (args[0] as Utils.NumberHolder).value *= 2; + (args[0] as NumberHolder).value *= 2; return true; } @@ -4026,7 +4054,7 @@ const magnitudeMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => { globalScene.executeWithSeedOffset(() => { const magnitudeThresholds = [ 5, 15, 35, 65, 75, 95 ]; - const rand = Utils.randSeedInt(100); + const rand = randSeedInt(100); let m = 0; for (; m < magnitudeThresholds.length; m++) { @@ -4042,14 +4070,14 @@ const magnitudeMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => { export class MagnitudePowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const magnitudeThresholds = [ 5, 15, 35, 65, 75, 95 ]; const magnitudePowers = [ 10, 30, 50, 70, 90, 100, 110, 150 ]; let rand: number; - globalScene.executeWithSeedOffset(() => rand = Utils.randSeedInt(100), globalScene.currentBattle.turn << 6, globalScene.waveSeed); + globalScene.executeWithSeedOffset(() => rand = randSeedInt(100), globalScene.currentBattle.turn << 6, globalScene.waveSeed); let m = 0; for (; m < magnitudeThresholds.length; m++) { @@ -4067,7 +4095,7 @@ export class MagnitudePowerAttr extends VariablePowerAttr { export class AntiSunlightPowerDecreaseAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!globalScene.arena.weather?.isEffectSuppressed()) { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const weatherType = globalScene.arena.weather?.weatherType || WeatherType.NONE; switch (weatherType) { case WeatherType.RAIN: @@ -4094,7 +4122,7 @@ export class FriendshipPowerAttr extends VariablePowerAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const friendshipPower = Math.floor(Math.min(user instanceof PlayerPokemon ? user.friendship : user.species.baseFriendship, 255) / 2.5); power.value = Math.max(!this.invert ? friendshipPower : 102 - friendshipPower, 1); @@ -4105,30 +4133,23 @@ export class FriendshipPowerAttr extends VariablePowerAttr { /** * This Attribute calculates the current power of {@linkcode Moves.RAGE_FIST}. - * The counter for power calculation does not reset on every wave but on every new arena encounter + * The counter for power calculation does not reset on every wave but on every new arena encounter. + * Self-inflicted confusion damage and hits taken by a Subsitute are ignored. */ export class RageFistPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const { hitCount, prevHitCount } = user.battleData; - const basePower: Utils.NumberHolder = args[0]; - - this.updateHitReceivedCount(user, hitCount, prevHitCount); - - basePower.value = 50 + (Math.min(user.customPokemonData.hitsRecCount, 6) * 50); + /* Reasons this works correctly: + * Confusion calls user.damageAndUpdate() directly (no counter increment), + * Substitute hits call user.damageAndUpdate() with a damage value of 0, also causing + no counter increment + */ + const hitCount = user.battleData.hitCount; + const basePower: NumberHolder = args[0]; + basePower.value = 50 * (1 + Math.min(hitCount, 6)); return true; } - /** - * Updates the number of hits the Pokemon has taken in battle - * @param user Pokemon calling Rage Fist - * @param hitCount The number of received hits this battle - * @param previousHitCount The number of received hits this battle since last time Rage Fist was used - */ - protected updateHitReceivedCount(user: Pokemon, hitCount: number, previousHitCount: number): void { - user.customPokemonData.hitsRecCount += (hitCount - previousHitCount); - user.battleData.prevHitCount = hitCount; - } } /** @@ -4155,7 +4176,7 @@ export class PositiveStatStagePowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const positiveStatStages: number = countPositiveStatStages(user); - (args[0] as Utils.NumberHolder).value += positiveStatStages * 20; + (args[0] as NumberHolder).value += positiveStatStages * 20; return true; } } @@ -4178,7 +4199,7 @@ export class PunishmentPowerAttr extends VariablePowerAttr { */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const positiveStatStages: number = countPositiveStatStages(target); - (args[0] as Utils.NumberHolder).value = Math.min( + (args[0] as NumberHolder).value = Math.min( this.PUNISHMENT_MAX_BASE_POWER, this.PUNISHMENT_MIN_BASE_POWER + positiveStatStages * 20 ); @@ -4194,18 +4215,19 @@ export class PresentPowerAttr extends VariablePowerAttr { */ const firstHit = (user.turnData.hitCount === user.turnData.hitsLeft); - const powerSeed = Utils.randSeedInt(firstHit ? 100 : 80); + const powerSeed = randSeedInt(firstHit ? 100 : 80); if (powerSeed <= 40) { - (args[0] as Utils.NumberHolder).value = 40; + (args[0] as NumberHolder).value = 40; } else if (40 < powerSeed && powerSeed <= 70) { - (args[0] as Utils.NumberHolder).value = 80; + (args[0] as NumberHolder).value = 80; } else if (70 < powerSeed && powerSeed <= 80) { - (args[0] as Utils.NumberHolder).value = 120; + (args[0] as NumberHolder).value = 120; } else if (80 < powerSeed && powerSeed <= 100) { // If this move is multi-hit, disable all other hits - user.stopMultiHit(); + user.turnData.hitCount = 1; + user.turnData.hitsLeft = 1; globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(), - Utils.toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", { pokemonName: getPokemonNameWithAffix(target) }), true)); + toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", { pokemonName: getPokemonNameWithAffix(target) }), true)); } return true; @@ -4215,7 +4237,7 @@ export class PresentPowerAttr extends VariablePowerAttr { 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) { - (args[0] as Utils.NumberHolder).value = 20; + (args[0] as NumberHolder).value = 20; return true; } return false; @@ -4237,7 +4259,7 @@ export class SpitUpPowerAttr extends VariablePowerAttr { const stockpilingTag = user.getTag(StockpilingTag); if (stockpilingTag && stockpilingTag.stockpiledCount > 0) { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; power.value = this.multiplier * stockpilingTag.stockpiledCount; return true; } @@ -4305,12 +4327,12 @@ export class MultiHitPowerIncrementAttr extends VariablePowerAttr { * @param user {@linkcode Pokemon} that used the move * @param target {@linkcode Pokemon} that the move was used on * @param move {@linkcode Move} with this attribute - * @param args [0] {@linkcode Utils.NumberHolder} for final calculated power of move + * @param args [0] {@linkcode NumberHolder} for final calculated power of move * @returns true if attribute application succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const hitsTotal = user.turnData.hitCount - Math.max(user.turnData.hitsLeft, 0); - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; power.value = move.power * (1 + hitsTotal % this.maxHits); @@ -4342,11 +4364,11 @@ export class LastMoveDoublePowerAttr extends VariablePowerAttr { * @param user {@linkcode Pokemon} that used the move * @param target N/A * @param move N/A - * @param args [0] {@linkcode Utils.NumberHolder} that holds the resulting power of the move + * @param args [0] {@linkcode NumberHolder} that holds the resulting power of the move * @returns true if attribute application succeeds, false otherwise */ apply(user: Pokemon, _target: Pokemon, _move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; const enemy = user.getOpponent(0); const pokemonActed: Pokemon[] = []; @@ -4358,10 +4380,10 @@ export class LastMoveDoublePowerAttr extends VariablePowerAttr { const userAlly = user.getAlly(); const enemyAlly = enemy?.getAlly(); - if (!Utils.isNullOrUndefined(userAlly) && userAlly.turnData.acted) { + if (userAlly?.turnData.acted) { pokemonActed.push(userAlly); } - if (!Utils.isNullOrUndefined(enemyAlly) && enemyAlly.turnData.acted) { + if (enemyAlly?.turnData.acted) { pokemonActed.push(enemyAlly); } } @@ -4391,7 +4413,7 @@ export class LastMoveDoublePowerAttr extends VariablePowerAttr { export class CombinedPledgePowerAttr extends VariablePowerAttr { override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const power = args[0]; - if (!(power instanceof Utils.NumberHolder)) { + if (!(power instanceof NumberHolder)) { return false; } const combinedPledgeMove = user.turnData.combiningPledge; @@ -4410,7 +4432,7 @@ export class CombinedPledgePowerAttr extends VariablePowerAttr { export class CombinedPledgeStabBoostAttr extends MoveAttr { override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const stabMultiplier = args[0]; - if (!(stabMultiplier instanceof Utils.NumberHolder)) { + if (!(stabMultiplier instanceof NumberHolder)) { return false; } const combinedPledgeMove = user.turnData.combiningPledge; @@ -4429,13 +4451,10 @@ export class CombinedPledgeStabBoostAttr extends MoveAttr { * @extends VariablePowerAttr */ export class RoundPowerAttr extends VariablePowerAttr { - override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + override apply(user: Pokemon, target: Pokemon, move: Move, args: [NumberHolder]): boolean { const power = args[0]; - if (!(power instanceof Utils.NumberHolder)) { - return false; - } - if (user.turnData?.joinedRound) { + if (user.turnData.joinedRound) { power.value *= 2; return true; } @@ -4556,7 +4575,7 @@ export class TargetAtkUserAtkAttr extends VariableAtkAttr { super(); } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = target.getEffectiveStat(Stat.ATK, target); + (args[0] as NumberHolder).value = target.getEffectiveStat(Stat.ATK, target); return true; } } @@ -4567,7 +4586,7 @@ export class DefAtkAttr extends VariableAtkAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = user.getEffectiveStat(Stat.DEF, target); + (args[0] as NumberHolder).value = user.getEffectiveStat(Stat.DEF, target); return true; } } @@ -4589,7 +4608,7 @@ export class DefDefAttr extends VariableDefAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = target.getEffectiveStat(Stat.DEF, user); + (args[0] as NumberHolder).value = target.getEffectiveStat(Stat.DEF, user); return true; } } @@ -4607,7 +4626,7 @@ export class VariableAccuracyAttr extends MoveAttr { export class ThunderAccuracyAttr extends VariableAccuracyAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!globalScene.arena.weather?.isEffectSuppressed()) { - const accuracy = args[0] as Utils.NumberHolder; + const accuracy = args[0] as NumberHolder; const weatherType = globalScene.arena.weather?.weatherType || WeatherType.NONE; switch (weatherType) { case WeatherType.SUNNY: @@ -4633,7 +4652,7 @@ export class ThunderAccuracyAttr extends VariableAccuracyAttr { export class StormAccuracyAttr extends VariableAccuracyAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!globalScene.arena.weather?.isEffectSuppressed()) { - const accuracy = args[0] as Utils.NumberHolder; + const accuracy = args[0] as NumberHolder; const weatherType = globalScene.arena.weather?.weatherType || WeatherType.NONE; switch (weatherType) { case WeatherType.RAIN: @@ -4664,7 +4683,7 @@ export class AlwaysHitMinimizeAttr extends VariableAccuracyAttr { */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (target.getTag(BattlerTagType.MINIMIZED)) { - const accuracy = args[0] as Utils.NumberHolder; + const accuracy = args[0] as NumberHolder; accuracy.value = -1; return true; @@ -4677,7 +4696,7 @@ export class AlwaysHitMinimizeAttr extends VariableAccuracyAttr { export class ToxicAccuracyAttr extends VariableAccuracyAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (user.isOfType(PokemonType.POISON)) { - const accuracy = args[0] as Utils.NumberHolder; + const accuracy = args[0] as NumberHolder; accuracy.value = -1; return true; } @@ -4689,7 +4708,7 @@ export class ToxicAccuracyAttr extends VariableAccuracyAttr { export class BlizzardAccuracyAttr extends VariableAccuracyAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!globalScene.arena.weather?.isEffectSuppressed()) { - const accuracy = args[0] as Utils.NumberHolder; + const accuracy = args[0] as NumberHolder; const weatherType = globalScene.arena.weather?.weatherType || WeatherType.NONE; if (weatherType === WeatherType.HAIL || weatherType === WeatherType.SNOW) { accuracy.value = -1; @@ -4709,7 +4728,7 @@ export class VariableMoveCategoryAttr extends MoveAttr { export class PhotonGeyserCategoryAttr extends VariableMoveCategoryAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const category = (args[0] as Utils.NumberHolder); + const category = (args[0] as NumberHolder); if (user.getEffectiveStat(Stat.ATK, target, move) > user.getEffectiveStat(Stat.SPATK, target, move)) { category.value = MoveCategory.PHYSICAL; @@ -4729,7 +4748,7 @@ export class PhotonGeyserCategoryAttr extends VariableMoveCategoryAttr { */ export class TeraMoveCategoryAttr extends VariableMoveCategoryAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const category = (args[0] as Utils.NumberHolder); + const category = (args[0] as NumberHolder); if (user.isTerastallized && user.getEffectiveStat(Stat.ATK, target, move, true, true, false, false, true) > user.getEffectiveStat(Stat.SPATK, target, move, true, true, false, false, true)) { @@ -4753,12 +4772,12 @@ export class TeraBlastPowerAttr extends VariablePowerAttr { * @param target n/a * @param move {@linkcode Move} the Move with this attribute (i.e. Tera Blast) * @param args - * - [0] {@linkcode Utils.NumberHolder} the applied move's power, factoring in + * - [0] {@linkcode NumberHolder} the applied move's power, factoring in * previously applied power modifiers. * @returns */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const power = args[0] as Utils.NumberHolder; + const power = args[0] as NumberHolder; if (user.isTerastallized && user.getTeraType() === PokemonType.STELLAR) { power.value = 100; return true; @@ -4778,11 +4797,11 @@ export class StatusCategoryOnAllyAttr extends VariableMoveCategoryAttr { * @param user {@linkcode Pokemon} using the move * @param target {@linkcode Pokemon} target of the move * @param move {@linkcode Move} with this attribute - * @param args [0] {@linkcode Utils.NumberHolder} The category of the move + * @param args [0] {@linkcode NumberHolder} The category of the move * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const category = (args[0] as Utils.NumberHolder); + const category = (args[0] as NumberHolder); if (user.getAlly() === target) { category.value = MoveCategory.STATUS; @@ -4795,10 +4814,10 @@ export class StatusCategoryOnAllyAttr extends VariableMoveCategoryAttr { export class ShellSideArmCategoryAttr extends VariableMoveCategoryAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const category = (args[0] as Utils.NumberHolder); + const category = (args[0] as NumberHolder); - const predictedPhysDmg = target.getBaseDamage(user, move, MoveCategory.PHYSICAL, true, true, true, true); - const predictedSpecDmg = target.getBaseDamage(user, move, MoveCategory.SPECIAL, true, true, true, true); + const predictedPhysDmg = target.getBaseDamage({source: user, move, moveCategory: MoveCategory.PHYSICAL, ignoreAbility: true, ignoreSourceAbility: true, ignoreAllyAbility: true, ignoreSourceAllyAbility: true, simulated: true}); + const predictedSpecDmg = target.getBaseDamage({source: user, move, moveCategory: MoveCategory.SPECIAL, ignoreAbility: true, ignoreSourceAbility: true, ignoreAllyAbility: true, ignoreSourceAllyAbility: true, simulated: true}); if (predictedPhysDmg > predictedSpecDmg) { category.value = MoveCategory.PHYSICAL; @@ -4820,7 +4839,7 @@ export class VariableMoveTypeAttr extends MoveAttr { export class FormChangeItemTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -4831,14 +4850,19 @@ export class FormChangeItemTypeAttr extends VariableMoveTypeAttr { return true; } - return false; + // Force move to have its original typing if it changed + if (moveType.value === move.type) { + return false; + } + moveType.value = move.type + return true; } } export class TechnoBlastTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -4872,7 +4896,7 @@ export class TechnoBlastTypeAttr extends VariableMoveTypeAttr { export class AuraWheelTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -4897,7 +4921,7 @@ export class AuraWheelTypeAttr extends VariableMoveTypeAttr { export class RagingBullTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -4925,7 +4949,7 @@ export class RagingBullTypeAttr extends VariableMoveTypeAttr { export class IvyCudgelTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -4960,7 +4984,7 @@ export class IvyCudgelTypeAttr extends VariableMoveTypeAttr { export class WeatherBallTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -4982,7 +5006,11 @@ export class WeatherBallTypeAttr extends VariableMoveTypeAttr { moveType.value = PokemonType.ICE; break; default: - return false; + if (moveType.value === move.type) { + return false; + } + moveType.value = move.type; + break; } return true; } @@ -5002,12 +5030,12 @@ export class TerrainPulseTypeAttr extends VariableMoveTypeAttr { * @param user {@linkcode Pokemon} using this move * @param target N/A * @param move N/A - * @param args [0] {@linkcode Utils.NumberHolder} The move's type to be modified + * @param args [0] {@linkcode NumberHolder} The move's type to be modified * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -5030,7 +5058,12 @@ export class TerrainPulseTypeAttr extends VariableMoveTypeAttr { moveType.value = PokemonType.PSYCHIC; break; default: - return false; + if (moveType.value === move.type) { + return false; + } + // force move to have its original typing if it was changed + moveType.value = move.type; + break; } return true; } @@ -5043,7 +5076,7 @@ export class TerrainPulseTypeAttr extends VariableMoveTypeAttr { export class HiddenPowerTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -5078,7 +5111,7 @@ export class TeraBlastTypeAttr extends VariableMoveTypeAttr { */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -5101,12 +5134,12 @@ export class TeraStarstormTypeAttr extends VariableMoveTypeAttr { * @param user the {@linkcode Pokemon} using the move * @param target n/a * @param move n/a - * @param args[0] {@linkcode Utils.NumberHolder} the move type + * @param args[0] {@linkcode NumberHolder} the move type * @returns `true` if the move type is changed to {@linkcode PokemonType.STELLAR}, `false` otherwise */ override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (user.isTerastallized && user.hasSpecies(Species.TERAPAGOS)) { - const moveType = args[0] as Utils.NumberHolder; + const moveType = args[0] as NumberHolder; moveType.value = PokemonType.STELLAR; return true; @@ -5118,7 +5151,7 @@ export class TeraStarstormTypeAttr extends VariableMoveTypeAttr { export class MatchUserTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } const userTypes = user.getTypes(true); @@ -5144,7 +5177,7 @@ export class MatchUserTypeAttr extends VariableMoveTypeAttr { export class CombinedPledgeTypeAttr extends VariableMoveTypeAttr { override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveType = args[0]; - if (!(moveType instanceof Utils.NumberHolder)) { + if (!(moveType instanceof NumberHolder)) { return false; } @@ -5187,7 +5220,7 @@ export class VariableMoveTypeMultiplierAttr extends MoveAttr { export class NeutralDamageAgainstFlyingTypeMultiplierAttr extends VariableMoveTypeMultiplierAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!target.getTag(BattlerTagType.IGNORE_FLYING)) { - const multiplier = args[0] as Utils.NumberHolder; + const multiplier = args[0] as NumberHolder; //When a flying type is hit, the first hit is always 1x multiplier. if (target.isOfType(PokemonType.FLYING)) { multiplier.value = 1; @@ -5205,11 +5238,11 @@ export class IceNoEffectTypeAttr extends VariableMoveTypeMultiplierAttr { * @param user n/a * @param target The {@linkcode Pokemon} targeted by the move * @param move n/a - * @param args `[0]` a {@linkcode Utils.NumberHolder | NumberHolder} containing a type effectiveness multiplier + * @param args `[0]` a {@linkcode NumberHolder | NumberHolder} containing a type effectiveness multiplier * @returns `true` if this Ice-type immunity applies; `false` otherwise */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const multiplier = args[0] as Utils.NumberHolder; + const multiplier = args[0] as NumberHolder; if (target.isOfType(PokemonType.ICE)) { multiplier.value = 0; return true; @@ -5220,7 +5253,7 @@ export class IceNoEffectTypeAttr extends VariableMoveTypeMultiplierAttr { export class FlyingTypeMultiplierAttr extends VariableMoveTypeMultiplierAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const multiplier = args[0] as Utils.NumberHolder; + const multiplier = args[0] as NumberHolder; multiplier.value *= target.getAttackTypeEffectiveness(PokemonType.FLYING, user); return true; } @@ -5249,7 +5282,7 @@ export class VariableMoveTypeChartAttr extends MoveAttr { */ export class FreezeDryAttr extends VariableMoveTypeChartAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const multiplier = args[0] as Utils.NumberHolder; + const multiplier = args[0] as NumberHolder; const defType = args[1] as PokemonType; if (defType === PokemonType.WATER) { @@ -5263,7 +5296,7 @@ export class FreezeDryAttr extends VariableMoveTypeChartAttr { export class OneHitKOAccuracyAttr extends VariableAccuracyAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const accuracy = args[0] as Utils.NumberHolder; + const accuracy = args[0] as NumberHolder; if (user.level < target.level) { accuracy.value = 0; } else { @@ -5285,7 +5318,7 @@ export class SheerColdAccuracyAttr extends OneHitKOAccuracyAttr { * @returns Returns true if move is successful, false if misses. */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const accuracy = args[0] as Utils.NumberHolder; + const accuracy = args[0] as NumberHolder; if (user.level < target.level) { accuracy.value = 0; } else { @@ -5327,15 +5360,15 @@ export class NoEffectAttr extends MoveAttr { } const crashDamageFunc = (user: Pokemon, move: Move) => { - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled); if (cancelled.value) { return false; } - user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT }); + user.damageAndUpdate(toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT }); globalScene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", { pokemonName: getPokemonNameWithAffix(user) })); - user.turnData.damageTaken += Utils.toDmgValue(user.getMaxHp() / 2); + user.turnData.damageTaken += toDmgValue(user.getMaxHp() / 2); return true; }; @@ -5357,7 +5390,7 @@ export class BypassRedirectAttr extends MoveAttr { export class FrenzyAttr extends MoveEffectAttr { constructor() { - super(true, { trigger: MoveEffectTrigger.HIT, lastHitOnly: true }); + super(true, { lastHitOnly: true }); } canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { @@ -5429,22 +5462,20 @@ export class AddBattlerTagAttr extends MoveEffectAttr { protected cancelOnFail: boolean; private failOnOverlap: boolean; - constructor(tagType: BattlerTagType, selfTarget: boolean = false, failOnOverlap: boolean = false, turnCountMin: number = 0, turnCountMax?: number, lastHitOnly: boolean = false, cancelOnFail: boolean = false) { + constructor(tagType: BattlerTagType, selfTarget: boolean = false, failOnOverlap: boolean = false, turnCountMin: number = 0, turnCountMax?: number, lastHitOnly: boolean = false) { super(selfTarget, { lastHitOnly: lastHitOnly }); this.tagType = tagType; this.turnCountMin = turnCountMin; this.turnCountMax = turnCountMax !== undefined ? turnCountMax : turnCountMin; this.failOnOverlap = !!failOnOverlap; - this.cancelOnFail = cancelOnFail; } canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (!super.canApply(user, target, move, args) || (this.cancelOnFail === true && user.getLastXMoves(1)[0]?.result === MoveResult.FAIL)) { + if (!super.canApply(user, target, move, args)) { return false; - } else { - return true; } + return true; } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -5535,19 +5566,6 @@ export class LeechSeedAttr extends AddBattlerTagAttr { constructor() { super(BattlerTagType.SEEDED); } - - /** - * Adds a Seeding effect to the target if the target does not have an active Substitute. - * @param user the {@linkcode Pokemon} using the move - * @param target the {@linkcode Pokemon} targeted by the move - * @param move the {@linkcode Move} invoking this effect - * @param args n/a - * @returns `true` if the effect successfully applies; `false` otherwise - */ - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - return !move.hitsSubstitute(user, target) - && super.apply(user, target, move, args); - } } /** @@ -5723,13 +5741,6 @@ export class FlinchAttr extends AddBattlerTagAttr { constructor() { super(BattlerTagType.FLINCHED, false); } - - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (!move.hitsSubstitute(user, target)) { - return super.apply(user, target, move, args); - } - return false; - } } export class ConfuseAttr extends AddBattlerTagAttr { @@ -5745,16 +5756,13 @@ export class ConfuseAttr extends AddBattlerTagAttr { return false; } - if (!move.hitsSubstitute(user, target)) { - return super.apply(user, target, move, args); - } - return false; + return super.apply(user, target, move, args); } } export class RechargeAttr extends AddBattlerTagAttr { constructor() { - super(BattlerTagType.RECHARGING, true, false, 1, 1, true, true); + super(BattlerTagType.RECHARGING, true, false, 1, 1, true); } } @@ -5908,7 +5916,7 @@ export class AddArenaTagAttr extends MoveEffectAttr { } if ((move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) && user.getLastXMoves(1)[0]?.result === MoveResult.SUCCESS) { - const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; + const side = ((this.selfSideTarget ? user : target).isPlayer() !== (move.hasAttr(AddArenaTrapTagAttr) && target === user)) ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; globalScene.arena.addTag(this.tagType, this.turnCount, move.id, user.id, side); return true; } @@ -5957,7 +5965,7 @@ export class RemoveArenaTagsAttr extends MoveEffectAttr { export class AddArenaTrapTagAttr extends AddArenaTagAttr { getCondition(): MoveConditionFunc { return (user, target, move) => { - const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; + const side = (this.selfSideTarget !== user.isPlayer()) ? ArenaTagSide.ENEMY : ArenaTagSide.PLAYER; const tag = globalScene.arena.getTagOnSide(this.tagType, side) as ArenaTrapTag; if (!tag) { return true; @@ -6137,7 +6145,7 @@ export class AddPledgeEffectAttr extends AddArenaTagAttr { * @see {@linkcode apply} */ export class RevivalBlessingAttr extends MoveEffectAttr { - constructor(user?: boolean) { + constructor() { super(true); } @@ -6160,11 +6168,11 @@ export class RevivalBlessingAttr extends MoveEffectAttr { const faintedPokemon = globalScene.getEnemyParty().filter((p) => p.isFainted() && !p.isBoss()); const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length)]; const slotIndex = globalScene.getEnemyParty().findIndex((p) => pokemon.id === p.id); - pokemon.resetStatus(); - pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); + pokemon.resetStatus(true, false, false, true); + pokemon.heal(Math.min(toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); globalScene.queueMessage(i18next.t("moveTriggers:revivalBlessing", { pokemonName: getPokemonNameWithAffix(pokemon) }), 0, true); const allyPokemon = user.getAlly(); - if (globalScene.currentBattle.double && globalScene.getEnemyParty().length > 1 && !Utils.isNullOrUndefined(allyPokemon)) { + if (globalScene.currentBattle.double && globalScene.getEnemyParty().length > 1 && !isNullOrUndefined(allyPokemon)) { // Handle cases where revived pokemon needs to get switched in on same turn if (allyPokemon.isFainted() || allyPokemon === pokemon) { // Enemy switch phase should be removed and replaced with the revived pkmn switching in @@ -6282,9 +6290,10 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { return false; } else if (globalScene.currentBattle.battleType !== BattleType.WILD) { // Switch out logic for enemy trainers // Find indices of off-field Pokemon that are eligible to be switched into + const isPartnerTrainer = globalScene.currentBattle.trainer?.isPartner(); const eligibleNewIndices: number[] = []; globalScene.getEnemyParty().forEach((pokemon, index) => { - if (pokemon.isAllowedInBattle() && !pokemon.isOnField()) { + if (pokemon.isAllowedInBattle() && !pokemon.isOnField() && (!isPartnerTrainer || pokemon.trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)) { eligibleNewIndices.push(index); } }); @@ -6334,15 +6343,6 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { } } - if (globalScene.currentBattle.waveIndex % 10 === 0) { - return false; - } - - // Don't allow wild mons to flee with U-turn et al. - if (this.selfSwitch && !user.isPlayer() && move.category !== MoveCategory.STATUS) { - return false; - } - const allyPokemon = switchOutTarget.getAlly(); if (switchOutTarget.hp > 0) { @@ -6350,18 +6350,22 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { globalScene.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500); // in double battles redirect potential moves off fled pokemon - if (globalScene.currentBattle.double && !Utils.isNullOrUndefined(allyPokemon)) { + if (globalScene.currentBattle.double && !isNullOrUndefined(allyPokemon)) { globalScene.redirectPokemonMoves(switchOutTarget, allyPokemon); } } - if (!allyPokemon?.isActive(true)) { - globalScene.clearEnemyHeldItemModifiers(); + // clear out enemy held item modifiers of the switch out target + globalScene.clearEnemyHeldItemModifiers(switchOutTarget); - if (switchOutTarget.hp) { + if (!allyPokemon?.isActive(true) && switchOutTarget.hp) { globalScene.pushPhase(new BattleEndPhase(false)); + + if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { + globalScene.pushPhase(new SelectBiomePhase()); + } + globalScene.pushPhase(new NewBattlePhase()); - } } } @@ -6373,23 +6377,20 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { } getFailedText(_user: Pokemon, target: Pokemon, _move: Move): string | undefined { - const blockedByAbility = new Utils.BooleanHolder(false); + const blockedByAbility = new BooleanHolder(false); applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, blockedByAbility); if (blockedByAbility.value) { return i18next.t("moveTriggers:cannotBeSwitchedOut", { pokemonName: getPokemonNameWithAffix(target) }); } } + getSwitchOutCondition(): MoveConditionFunc { return (user, target, move) => { const switchOutTarget = (this.selfSwitch ? user : target); const player = switchOutTarget instanceof PlayerPokemon; if (!this.selfSwitch) { - if (move.hitsSubstitute(user, target)) { - return false; - } - // Dondozo with an allied Tatsugiri in its mouth cannot be forced out const commandedTag = switchOutTarget.getTag(BattlerTagType.COMMANDED); if (commandedTag?.getSourcePokemon()?.isActive(true)) { @@ -6401,25 +6402,25 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { return false; } - const blockedByAbility = new Utils.BooleanHolder(false); + const blockedByAbility = new BooleanHolder(false); applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, blockedByAbility); - return !blockedByAbility.value; + if (blockedByAbility.value) { + return false; + } } + if (!player && globalScene.currentBattle.battleType === BattleType.WILD) { - if (this.isBatonPass()) { - return false; - } - // Don't allow wild opponents to flee on the boss stage since it can ruin a run early on - if (globalScene.currentBattle.waveIndex % 10 === 0) { - return false; - } + // wild pokemon cannot switch out with baton pass. + return !this.isBatonPass() + && globalScene.currentBattle.waveIndex % 10 !== 0 + // Don't allow wild mons to flee with U-turn et al. + && !(this.selfSwitch && MoveCategory.STATUS !== move.category); } const party = player ? globalScene.getPlayerParty() : globalScene.getEnemyParty(); - return (!player && !globalScene.currentBattle.battleType) - || party.filter(p => p.isAllowedInBattle() - && (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > globalScene.currentBattle.getBattlerCount(); + return party.filter(p => p.isAllowedInBattle() && !p.isOnField() + && (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > 0; }; } @@ -6644,7 +6645,7 @@ export class ChangeTypeAttr extends MoveEffectAttr { private type: PokemonType; constructor(type: PokemonType) { - super(false, { trigger: MoveEffectTrigger.HIT }); + super(false); this.type = type; } @@ -6667,7 +6668,7 @@ export class AddTypeAttr extends MoveEffectAttr { private type: PokemonType; constructor(type: PokemonType) { - super(false, { trigger: MoveEffectTrigger.HIT }); + super(false); this.type = type; } @@ -6760,7 +6761,7 @@ export class RandomMoveAttr extends CallMoveAttr { * @param args Unused */ override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const moveIds = Utils.getEnumValues(Moves).map(m => !this.invalidMoves.has(m) && !allMoves[m].name.endsWith(" (N)") ? m : Moves.NONE); + const moveIds = getEnumValues(Moves).map(m => !this.invalidMoves.has(m) && !allMoves[m].name.endsWith(" (N)") ? m : Moves.NONE); let moveId: Moves = Moves.NONE; do { moveId = this.getMoveOverride() ?? moveIds[user.randSeedInt(moveIds.length)]; @@ -7031,7 +7032,7 @@ export class RepeatMoveAttr extends MoveEffectAttr { const firstTarget = globalScene.getField()[moveTargets[0]]; if (globalScene.currentBattle.double && moveTargets.length === 1 && firstTarget.isFainted() && firstTarget !== target.getAlly()) { const ally = firstTarget.getAlly(); - if (!Utils.isNullOrUndefined(ally) && ally.isActive()) { // ally exists, is not dead and can sponge the blast + if (!isNullOrUndefined(ally) && ally.isActive()) { // ally exists, is not dead and can sponge the blast moveTargets = [ ally.getBattlerIndex() ]; } } @@ -7363,7 +7364,7 @@ export class AbilityChangeAttr extends MoveEffectAttr { public ability: Abilities; constructor(ability: Abilities, selfTarget?: boolean) { - super(selfTarget, { trigger: MoveEffectTrigger.HIT }); + super(selfTarget); this.ability = ability; } @@ -7375,11 +7376,13 @@ export class AbilityChangeAttr extends MoveEffectAttr { const moveTarget = this.selfTarget ? user : target; - globalScene.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix((this.selfTarget ? user : target)), abilityName: allAbilities[this.ability].name })); - + globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger); + if (moveTarget.breakIllusion()) { + globalScene.queueMessage(i18next.t("abilityTriggers:illusionBreak", { pokemonName: getPokemonNameWithAffix(moveTarget) })); + } + globalScene.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix(moveTarget), abilityName: allAbilities[this.ability].name })); moveTarget.setTempAbility(allAbilities[this.ability]); globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger); - return true; } @@ -7392,7 +7395,7 @@ export class AbilityCopyAttr extends MoveEffectAttr { public copyToPartner: boolean; constructor(copyToPartner: boolean = false) { - super(false, { trigger: MoveEffectTrigger.HIT }); + super(false); this.copyToPartner = copyToPartner; } @@ -7407,7 +7410,7 @@ export class AbilityCopyAttr extends MoveEffectAttr { user.setTempAbility(target.getAbility()); const ally = user.getAlly(); - if (this.copyToPartner && globalScene.currentBattle?.double && !Utils.isNullOrUndefined(ally) && ally.hp) { // TODO is this the best way to check that the ally is active? + if (this.copyToPartner && globalScene.currentBattle?.double && !isNullOrUndefined(ally) && ally.hp) { // TODO is this the best way to check that the ally is active? globalScene.queueMessage(i18next.t("moveTriggers:copiedTargetAbility", { pokemonName: getPokemonNameWithAffix(ally), targetName: getPokemonNameWithAffix(target), abilityName: allAbilities[target.getAbility().id].name })); ally.setTempAbility(target.getAbility()); } @@ -7433,7 +7436,7 @@ export class AbilityGiveAttr extends MoveEffectAttr { public copyToPartner: boolean; constructor() { - super(false, { trigger: MoveEffectTrigger.HIT }); + super(false); } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -7696,23 +7699,9 @@ export class AverageStatsAttr extends MoveEffectAttr { } } -export class DiscourageFrequentUseAttr extends MoveAttr { - getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { - const lastMoves = user.getLastXMoves(4); - console.log(lastMoves); - for (let m = 0; m < lastMoves.length; m++) { - if (lastMoves[m].move === move.id) { - return (4 - (m + 1)) * -10; - } - } - - return 0; - } -} - export class MoneyAttr extends MoveEffectAttr { constructor() { - super(true, { trigger: MoveEffectTrigger.HIT, firstHitOnly: true }); + super(true, {firstHitOnly: true }); } apply(user: Pokemon, target: Pokemon, move: Move): boolean { @@ -7779,7 +7768,7 @@ export class StatusIfBoostedAttr extends MoveEffectAttr { public effect: StatusEffect; constructor(effect: StatusEffect) { - super(true, { trigger: MoveEffectTrigger.HIT }); + super(true); this.effect = effect; } @@ -7798,17 +7787,27 @@ export class StatusIfBoostedAttr extends MoveEffectAttr { } } +/** + * Attribute to fail move usage unless all of the user's other moves have been used at least once. + * Used by {@linkcode Moves.LAST_RESORT}. + */ export class LastResortAttr extends MoveAttr { + // TODO: Verify behavior as Bulbapedia page is _extremely_ poorly documented getCondition(): MoveConditionFunc { - return (user: Pokemon, target: Pokemon, move: Move) => { - const uniqueUsedMoveIds = new Set(); - const movesetMoveIds = user.getMoveset().map(m => m.moveId); - user.getMoveHistory().map(m => { - if (m.move !== move.id && movesetMoveIds.find(mm => mm === m.move)) { - uniqueUsedMoveIds.add(m.move); - } - }); - return uniqueUsedMoveIds.size >= movesetMoveIds.length - 1; + return (user: Pokemon, _target: Pokemon, move: Move) => { + const movesInMoveset = new Set(user.getMoveset().map(m => m.moveId)); + if (!movesInMoveset.delete(move.id) || !movesInMoveset.size) { + return false; // Last resort fails if used when not in user's moveset or no other moves exist + } + + const movesInHistory = new Set( + user.getMoveHistory() + .filter(m => !m.virtual) // TODO: Change to (m) => m < MoveUseType.INDIRECT after Dancer PR refactors virtual into enum + .map(m => m.move) + ); + + // Since `Set.intersection()` is only present in ESNext, we have to coerce it to an array to check inclusion + return [...movesInMoveset].every(m => movesInHistory.has(m)) }; } } @@ -7823,7 +7822,7 @@ export class VariableTargetAttr extends MoveAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const targetVal = args[0] as Utils.NumberHolder; + const targetVal = args[0] as NumberHolder; targetVal.value = this.targetChangeFunc(user, target, move); return true; } @@ -7914,7 +7913,7 @@ const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.i const failIfSingleBattle: MoveConditionFunc = (user, target, move) => globalScene.currentBattle.double; const failIfDampCondition: MoveConditionFunc = (user, target, move) => { - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); globalScene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled)); // Queue a message if an ability prevented usage of the move if (cancelled.value) { @@ -8016,13 +8015,18 @@ export class MoveCondition { } } +/** + * Condition to allow a move's use only on the first turn this Pokemon is sent into battle + * (or the start of a new wave, whichever comes first). + */ + export class FirstMoveCondition extends MoveCondition { constructor() { - super((user, target, move) => user.battleSummonData?.waveTurnCount === 1); + super((user, _target, _move) => user.tempSummonData.waveTurnCount === 1); } - getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { - return this.apply(user, target, move) ? 10 : -20; + getUserBenefitScore(user: Pokemon, _target: Pokemon, _move: Move): number { + return this.apply(user, _target, _move) ? 10 : -20; } } @@ -8049,7 +8053,7 @@ export class UpperHandCondition extends MoveCondition { export class hitsSameTypeAttr extends VariableMoveTypeMultiplierAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const multiplier = args[0] as Utils.NumberHolder; + const multiplier = args[0] as NumberHolder; if (!user.getTypes().some(type => target.getTypes().includes(type))) { multiplier.value = 0; return true; @@ -8100,7 +8104,7 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr { } const type = validTypes[user.randSeedInt(validTypes.length)]; user.summonData.types = [ type ]; - globalScene.queueMessage(i18next.t("battle:transformedIntoType", { pokemonName: getPokemonNameWithAffix(user), type: Utils.toReadableString(PokemonType[type]) })); + globalScene.queueMessage(i18next.t("battle:transformedIntoType", { pokemonName: getPokemonNameWithAffix(user), type: toReadableString(PokemonType[type]) })); user.updateInfo(); return true; @@ -8174,8 +8178,8 @@ export type MoveTargetSet = { }; export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveTarget): MoveTargetSet { - const variableTarget = new Utils.NumberHolder(0); - user.getOpponents().forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget)); + const variableTarget = new NumberHolder(0); + user.getOpponents(false).forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget)); let moveTarget: MoveTarget | undefined; if (allMoves[move].hasAttr(VariableTargetAttr)) { @@ -8187,7 +8191,7 @@ export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveT } else if (move === undefined) { moveTarget = MoveTarget.NEAR_ENEMY; } - const opponents = user.getOpponents(); + const opponents = user.getOpponents(false); let set: Pokemon[] = []; let multiple = false; @@ -8202,7 +8206,7 @@ export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveT case MoveTarget.OTHER: case MoveTarget.ALL_NEAR_OTHERS: case MoveTarget.ALL_OTHERS: - set = !Utils.isNullOrUndefined(ally) ? (opponents.concat([ ally ])) : opponents; + set = !isNullOrUndefined(ally) ? (opponents.concat([ ally ])) : opponents; multiple = moveTarget === MoveTarget.ALL_NEAR_OTHERS || moveTarget === MoveTarget.ALL_OTHERS; break; case MoveTarget.NEAR_ENEMY: @@ -8219,21 +8223,21 @@ export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveT return { targets: [ -1 as BattlerIndex ], multiple: false }; case MoveTarget.NEAR_ALLY: case MoveTarget.ALLY: - set = !Utils.isNullOrUndefined(ally) ? [ ally ] : []; + set = !isNullOrUndefined(ally) ? [ ally ] : []; break; case MoveTarget.USER_OR_NEAR_ALLY: case MoveTarget.USER_AND_ALLIES: case MoveTarget.USER_SIDE: - set = !Utils.isNullOrUndefined(ally) ? [ user, ally ] : [ user ]; + set = !isNullOrUndefined(ally) ? [ user, ally ] : [ user ]; multiple = moveTarget !== MoveTarget.USER_OR_NEAR_ALLY; break; case MoveTarget.ALL: case MoveTarget.BOTH_SIDES: - set = (!Utils.isNullOrUndefined(ally) ? [ user, ally ] : [ user ]).concat(opponents); + set = (!isNullOrUndefined(ally) ? [ user, ally ] : [ user ]).concat(opponents); multiple = true; break; case MoveTarget.CURSE: - const extraTargets = !Utils.isNullOrUndefined(ally) ? [ ally ] : []; + const extraTargets = !isNullOrUndefined(ally) ? [ ally ] : []; set = user.getTypes(true).includes(PokemonType.GHOST) ? (opponents.concat(extraTargets)) : [ user ]; break; } @@ -8392,7 +8396,7 @@ export function initMoves() { .attr(AddBattlerTagAttr, BattlerTagType.DISABLED, false, true) .condition((user, target, move) => { const lastRealMove = target.getLastXMoves(-1).find(m => !m.virtual); - return !Utils.isNullOrUndefined(lastRealMove) && lastRealMove.move !== Moves.NONE && lastRealMove.move !== Moves.STRUGGLE; + return !isNullOrUndefined(lastRealMove) && lastRealMove.move !== Moves.NONE && lastRealMove.move !== Moves.STRUGGLE; }) .ignoresSubstitute() .reflectable(), @@ -8659,9 +8663,13 @@ export function initMoves() { .makesContact(false), new StatusMove(Moves.TRANSFORM, PokemonType.NORMAL, -1, 10, -1, 0, 1) .attr(TransformAttr) + .condition((user, target, move) => !target.getTag(BattlerTagType.SUBSTITUTE)) + .condition((user, target, move) => !target.summonData.illusion && !user.summonData.illusion) // transforming from or into fusion pokemon causes various problems (such as crashes) .condition((user, target, move) => !target.getTag(BattlerTagType.SUBSTITUTE) && !user.fusionSpecies && !target.fusionSpecies) - .ignoresProtect(), + .ignoresProtect() + // Transforming should copy the target's rage fist hit count + .edgeCase(), new AttackMove(Moves.BUBBLE, PokemonType.WATER, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1) .attr(StatStageChangeAttr, [ Stat.SPD ], -1) .target(MoveTarget.ALL_NEAR_ENEMIES), @@ -8731,7 +8739,10 @@ export function initMoves() { .attr(MultiHitPowerIncrementAttr, 3) .checkAllHits(), new AttackMove(Moves.THIEF, PokemonType.DARK, MoveCategory.PHYSICAL, 60, 100, 25, -1, 0, 2) - .attr(StealHeldItemChanceAttr, 0.3), + .attr(StealHeldItemChanceAttr, 0.3) + .edgeCase(), + // Should not be able to steal held item if user faints due to Rough Skin, Iron Barbs, etc. + // Should be able to steal items from pokemon with Sticky Hold if the damage causes them to faint new StatusMove(Moves.SPIDER_WEB, PokemonType.BUG, -1, 10, -1, 0, 2) .condition(failIfGhostTypeCondition) .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1) @@ -9021,6 +9032,7 @@ export function initMoves() { .soundBased() .target(MoveTarget.RANDOM_NEAR_ENEMY) .partial(), // Does not lock the user, does not stop Pokemon from sleeping + // Likely can make use of FrenzyAttr and an ArenaTag (just without the FrenzyMissFunc) new SelfStatusMove(Moves.STOCKPILE, PokemonType.NORMAL, -1, 20, -1, 0, 3) .condition(user => (user.getTag(StockpilingTag)?.stockpiledCount ?? 0) < 3) .attr(AddBattlerTagAttr, BattlerTagType.STOCKPILING, true), @@ -9118,7 +9130,10 @@ export function initMoves() { .reflectable(), new AttackMove(Moves.KNOCK_OFF, PokemonType.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3) .attr(MovePowerMultiplierAttr, (user, target, move) => target.getHeldItems().filter(i => i.isTransferable).length > 0 ? 1.5 : 1) - .attr(RemoveHeldItemAttr, false), + .attr(RemoveHeldItemAttr, false) + .edgeCase(), + // Should not be able to remove held item if user faints due to Rough Skin, Iron Barbs, etc. + // Should be able to remove items from pokemon with Sticky Hold if the damage causes them to faint new AttackMove(Moves.ENDEAVOR, PokemonType.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 3) .attr(MatchHpAttr) .condition(failOnBossCondition), @@ -9306,7 +9321,10 @@ export function initMoves() { .attr(HighCritAttr) .attr(StatusEffectAttr, StatusEffect.POISON), new AttackMove(Moves.COVET, PokemonType.NORMAL, MoveCategory.PHYSICAL, 60, 100, 25, -1, 0, 3) - .attr(StealHeldItemChanceAttr, 0.3), + .attr(StealHeldItemChanceAttr, 0.3) + .edgeCase(), + // Should not be able to steal held item if user faints due to Rough Skin, Iron Barbs, etc. + // Should be able to steal items from pokemon with Sticky Hold if the damage causes them to faint new AttackMove(Moves.VOLT_TACKLE, PokemonType.ELECTRIC, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 3) .attr(RecoilAttr, false, 0.33) .attr(StatusEffectAttr, StatusEffect.PARALYSIS) @@ -9368,6 +9386,11 @@ export function initMoves() { new AttackMove(Moves.NATURAL_GIFT, PokemonType.NORMAL, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 4) .makesContact(false) .unimplemented(), + /* + NOTE: To whoever tries to implement this, reminder to push to battleData.berriesEaten + and enable the harvest test.. + Do NOT push to berriesEatenLast or else cud chew will puke the berry. + */ new AttackMove(Moves.FEINT, PokemonType.NORMAL, MoveCategory.PHYSICAL, 30, 100, 10, -1, 2, 4) .attr(RemoveBattlerTagAttr, [ BattlerTagType.PROTECTED ]) .attr(RemoveArenaTagsAttr, [ ArenaTagType.QUICK_GUARD, ArenaTagType.WIDE_GUARD, ArenaTagType.MAT_BLOCK, ArenaTagType.CRAFTY_SHIELD ], false) @@ -9445,7 +9468,8 @@ export function initMoves() { .makesContact(true) .attr(PunishmentPowerAttr), new AttackMove(Moves.LAST_RESORT, PokemonType.NORMAL, MoveCategory.PHYSICAL, 140, 100, 5, -1, 0, 4) - .attr(LastResortAttr), + .attr(LastResortAttr) + .edgeCase(), // May or may not need to ignore remotely called moves depending on how it works new StatusMove(Moves.WORRY_SEED, PokemonType.GRASS, 100, 10, -1, 0, 4) .attr(AbilityChangeAttr, Abilities.INSOMNIA) .reflectable(), @@ -9700,7 +9724,7 @@ export function initMoves() { .condition(failOnGravityCondition) .condition((_user, target, _move) => ![ Species.DIGLETT, Species.DUGTRIO, Species.ALOLA_DIGLETT, Species.ALOLA_DUGTRIO, Species.SANDYGAST, Species.PALOSSAND, Species.WIGLETT, Species.WUGTRIO ].includes(target.species.speciesId)) .condition((_user, target, _move) => !(target.species.speciesId === Species.GENGAR && target.getFormKey() === "mega")) - .condition((_user, target, _move) => Utils.isNullOrUndefined(target.getTag(BattlerTagType.INGRAIN)) && Utils.isNullOrUndefined(target.getTag(BattlerTagType.IGNORE_FLYING))) + .condition((_user, target, _move) => isNullOrUndefined(target.getTag(BattlerTagType.INGRAIN)) && isNullOrUndefined(target.getTag(BattlerTagType.IGNORE_FLYING))) .attr(AddBattlerTagAttr, BattlerTagType.TELEKINESIS, false, true, 3) .attr(AddBattlerTagAttr, BattlerTagType.FLOATING, false, true, 3) .reflectable(), @@ -9708,7 +9732,7 @@ export function initMoves() { .ignoresProtect() .target(MoveTarget.BOTH_SIDES) .unimplemented(), - new AttackMove(Moves.SMACK_DOWN, PokemonType.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5) + new AttackMove(Moves.SMACK_DOWN, PokemonType.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, -1, 0, 5) .attr(FallDownAttr) .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) .attr(RemoveBattlerTagAttr, [ BattlerTagType.FLYING, BattlerTagType.FLOATING, BattlerTagType.TELEKINESIS ]) @@ -9812,7 +9836,9 @@ export function initMoves() { .hidesTarget(), new AttackMove(Moves.INCINERATE, PokemonType.FIRE, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 5) .target(MoveTarget.ALL_NEAR_ENEMIES) - .attr(RemoveHeldItemAttr, true), + .attr(RemoveHeldItemAttr, true) + .edgeCase(), + // Should be able to remove items from pokemon with Sticky Hold if the damage causes them to faint new StatusMove(Moves.QUASH, PokemonType.DARK, 100, 15, -1, 0, 5) .condition(failIfSingleBattle) .condition((user, target, move) => !target.turnData.acted) @@ -9875,7 +9901,7 @@ export function initMoves() { .attr(MovePowerMultiplierAttr, (user, target, move) => globalScene.arena.getTerrainType() === TerrainType.GRASSY && target.isGrounded() ? 0.5 : 1) .makesContact(false) .target(MoveTarget.ALL_NEAR_OTHERS), - new AttackMove(Moves.FROST_BREATH, PokemonType.ICE, MoveCategory.SPECIAL, 60, 90, 10, 100, 0, 5) + new AttackMove(Moves.FROST_BREATH, PokemonType.ICE, MoveCategory.SPECIAL, 60, 90, 10, -1, 0, 5) .attr(CritOnlyAttr), new AttackMove(Moves.DRAGON_TAIL, PokemonType.DRAGON, MoveCategory.PHYSICAL, 60, 90, 10, -1, -6, 5) .attr(ForceSwitchOutAttr, false, SwitchType.FORCE_SWITCH) @@ -9987,7 +10013,7 @@ export function initMoves() { .condition(new FirstMoveCondition()) .condition(failIfLastCondition), new AttackMove(Moves.BELCH, PokemonType.POISON, MoveCategory.SPECIAL, 120, 90, 10, -1, 0, 6) - .condition((user, target, move) => user.battleData.berriesEaten.length > 0), + .condition((user, target, move) => user.battleData.hasEatenBerry), new StatusMove(Moves.ROTOTILLER, PokemonType.GROUND, -1, 10, -1, 0, 6) .target(MoveTarget.ALL) .condition((user, target, move) => { @@ -10517,7 +10543,7 @@ export function initMoves() { .attr(AddArenaTagAttr, ArenaTagType.LIGHT_SCREEN, 5, false, true), new AttackMove(Moves.BADDY_BAD, PokemonType.DARK, MoveCategory.SPECIAL, 80, 95, 15, -1, 0, 7) .attr(AddArenaTagAttr, ArenaTagType.REFLECT, 5, false, true), - new AttackMove(Moves.SAPPY_SEED, PokemonType.GRASS, MoveCategory.PHYSICAL, 100, 90, 10, 100, 0, 7) + new AttackMove(Moves.SAPPY_SEED, PokemonType.GRASS, MoveCategory.PHYSICAL, 100, 90, 10, -1, 0, 7) .attr(LeechSeedAttr) .makesContact(false), new AttackMove(Moves.FREEZY_FROST, PokemonType.ICE, MoveCategory.SPECIAL, 100, 90, 10, -1, 0, 7) @@ -10546,8 +10572,7 @@ export function initMoves() { } else { return 1; } - }) - .attr(DiscourageFrequentUseAttr), + }), new AttackMove(Moves.SNIPE_SHOT, PokemonType.WATER, MoveCategory.SPECIAL, 80, 100, 15, -1, 0, 8) .attr(HighCritAttr) @@ -10556,7 +10581,7 @@ export function initMoves() { .attr(JawLockAttr) .bitingMove(), new SelfStatusMove(Moves.STUFF_CHEEKS, PokemonType.NORMAL, -1, 10, -1, 0, 8) - .attr(EatBerryAttr) + .attr(EatBerryAttr, true) .attr(StatStageChangeAttr, [ Stat.DEF ], 2, true) .condition((user) => { const userBerries = globalScene.findModifiers(m => m instanceof BerryModifier, user.isPlayer()); @@ -10580,7 +10605,7 @@ export function initMoves() { .makesContact(false) .partial(), // smart targetting is unimplemented new StatusMove(Moves.TEATIME, PokemonType.NORMAL, -1, 10, -1, 0, 8) - .attr(EatBerryAttr) + .attr(EatBerryAttr, false) .target(MoveTarget.ALL), new StatusMove(Moves.OCTOLOCK, PokemonType.FIGHTING, 100, 15, -1, 0, 8) .condition(failIfGhostTypeCondition) @@ -10845,7 +10870,7 @@ export function initMoves() { .attr(StatStageChangeAttr, [ Stat.SPD ], 1, true), new AttackMove(Moves.BITTER_MALICE, PokemonType.GHOST, MoveCategory.SPECIAL, 75, 100, 10, 100, 0, 8) .attr(StatStageChangeAttr, [ Stat.ATK ], -1), - new SelfStatusMove(Moves.SHELTER, PokemonType.STEEL, -1, 10, 100, 0, 8) + new SelfStatusMove(Moves.SHELTER, PokemonType.STEEL, -1, 10, -1, 0, 8) .attr(StatStageChangeAttr, [ Stat.DEF ], 2, true), new AttackMove(Moves.TRIPLE_ARROWS, PokemonType.FIGHTING, MoveCategory.PHYSICAL, 90, 100, 10, 30, 0, 8) .makesContact(false) @@ -11054,7 +11079,7 @@ export function initMoves() { .attr(CutHpStatStageBoostAttr, [ Stat.ATK, Stat.SPATK, Stat.SPD ], 2, 2), new AttackMove(Moves.KOWTOW_CLEAVE, PokemonType.DARK, MoveCategory.PHYSICAL, 85, -1, 10, -1, 0, 9) .slicingMove(), - new AttackMove(Moves.FLOWER_TRICK, PokemonType.GRASS, MoveCategory.PHYSICAL, 70, -1, 10, 100, 0, 9) + new AttackMove(Moves.FLOWER_TRICK, PokemonType.GRASS, MoveCategory.PHYSICAL, 70, -1, 10, -1, 0, 9) .attr(CritOnlyAttr) .makesContact(false), new AttackMove(Moves.TORCH_SONG, PokemonType.FIRE, MoveCategory.SPECIAL, 80, 100, 10, 100, 0, 9) @@ -11114,7 +11139,6 @@ export function initMoves() { new AttackMove(Moves.TWIN_BEAM, PokemonType.PSYCHIC, MoveCategory.SPECIAL, 40, 100, 10, -1, 0, 9) .attr(MultiHitAttr, MultiHitType._2), new AttackMove(Moves.RAGE_FIST, PokemonType.GHOST, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 9) - .edgeCase() // Counter incorrectly increases on confusion self-hits .attr(RageFistPowerAttr) .punchingMove(), new AttackMove(Moves.ARMOR_CANNON, PokemonType.FIRE, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 9) @@ -11173,7 +11197,7 @@ export function initMoves() { .attr(StatusEffectAttr, StatusEffect.BURN) .target(MoveTarget.ALL_NEAR_ENEMIES) .triageMove(), - new AttackMove(Moves.SYRUP_BOMB, PokemonType.GRASS, MoveCategory.SPECIAL, 60, 85, 10, -1, 0, 9) + new AttackMove(Moves.SYRUP_BOMB, PokemonType.GRASS, MoveCategory.SPECIAL, 60, 85, 10, 100, 0, 9) .attr(AddBattlerTagAttr, BattlerTagType.SYRUP_BOMB, false, false, 3) .ballBombMove(), new AttackMove(Moves.IVY_CUDGEL, PokemonType.GRASS, MoveCategory.PHYSICAL, 100, 100, 10, -1, 0, 9) @@ -11187,11 +11211,12 @@ export function initMoves() { new AttackMove(Moves.TERA_STARSTORM, PokemonType.NORMAL, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 9) .attr(TeraMoveCategoryAttr) .attr(TeraStarstormTypeAttr) - .attr(VariableTargetAttr, (user, target, move) => user.hasSpecies(Species.TERAPAGOS) && user.isTerastallized ? MoveTarget.ALL_NEAR_ENEMIES : MoveTarget.NEAR_OTHER) + .attr(VariableTargetAttr, (user, target, move) => user.hasSpecies(Species.TERAPAGOS) && (user.isTerastallized || globalScene.currentBattle.preTurnCommands[user.getFieldIndex()]?.command === Command.TERA) ? MoveTarget.ALL_NEAR_ENEMIES : MoveTarget.NEAR_OTHER) .partial(), /** Does not ignore abilities that affect stats, relevant in determining the move's category {@see TeraMoveCategoryAttr} */ new AttackMove(Moves.FICKLE_BEAM, PokemonType.DRAGON, MoveCategory.SPECIAL, 80, 100, 5, 30, 0, 9) .attr(PreMoveMessageAttr, doublePowerChanceMessageFunc) - .attr(DoublePowerChanceAttr), + .attr(DoublePowerChanceAttr) + .edgeCase(), // Should not interact with Sheer Force new SelfStatusMove(Moves.BURNING_BULWARK, PokemonType.FIRE, -1, 10, -1, 4, 9) .attr(ProtectAttr, BattlerTagType.BURNING_BULWARK) .condition(failIfLastCondition), @@ -11214,16 +11239,18 @@ export function initMoves() { new StatusMove(Moves.DRAGON_CHEER, PokemonType.DRAGON, -1, 15, -1, 0, 9) .attr(AddBattlerTagAttr, BattlerTagType.DRAGON_CHEER, false, true) .target(MoveTarget.NEAR_ALLY), - new AttackMove(Moves.ALLURING_VOICE, PokemonType.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 9) + new AttackMove(Moves.ALLURING_VOICE, PokemonType.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, 100, 0, 9) .attr(AddBattlerTagIfBoostedAttr, BattlerTagType.CONFUSED) .soundBased(), new AttackMove(Moves.TEMPER_FLARE, PokemonType.FIRE, MoveCategory.PHYSICAL, 75, 100, 10, -1, 0, 9) .attr(MovePowerMultiplierAttr, (user, target, move) => user.getLastXMoves(2)[1]?.result === MoveResult.MISS || user.getLastXMoves(2)[1]?.result === MoveResult.FAIL ? 2 : 1), new AttackMove(Moves.SUPERCELL_SLAM, PokemonType.ELECTRIC, MoveCategory.PHYSICAL, 100, 95, 15, -1, 0, 9) + .attr(AlwaysHitMinimizeAttr) + .attr(HitsTagForDoubleDamageAttr, BattlerTagType.MINIMIZED) .attr(MissEffectAttr, crashDamageFunc) .attr(NoEffectAttr, crashDamageFunc) .recklessMove(), - new AttackMove(Moves.PSYCHIC_NOISE, PokemonType.PSYCHIC, MoveCategory.SPECIAL, 75, 100, 10, -1, 0, 9) + new AttackMove(Moves.PSYCHIC_NOISE, PokemonType.PSYCHIC, MoveCategory.SPECIAL, 75, 100, 10, 100, 0, 9) .soundBased() .attr(AddBattlerTagAttr, BattlerTagType.HEAL_BLOCK, false, false, 2), new AttackMove(Moves.UPPER_HAND, PokemonType.FIGHTING, MoveCategory.PHYSICAL, 65, 100, 15, 100, 3, 9) diff --git a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts index a49157f8e88..48b36369190 100644 --- a/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts +++ b/src/data/mystery-encounters/encounters/a-trainers-test-encounter.ts @@ -14,7 +14,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { TrainerType } from "#enums/trainer-type"; import { Species } from "#enums/species"; import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; -import { randSeedInt } from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import i18next from "i18next"; import type { IEggOptions } from "#app/data/egg"; import { EggSourceType } from "#enums/egg-source-types"; @@ -22,7 +22,7 @@ import { EggTier } from "#enums/egg-type"; import { PartyHealPhase } from "#app/phases/party-heal-phase"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/aTrainersTest"; diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts index 85f40a41e51..acfc8cb16a1 100644 --- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts +++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts @@ -24,7 +24,7 @@ import { BerryModifier, PokemonInstantReviveModifier } from "#app/modifier/modif import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Moves } from "#enums/moves"; import { BattlerTagType } from "#enums/battler-tag-type"; -import { randInt } from "#app/utils"; +import { randInt } from "#app/utils/common"; import { BattlerIndex } from "#app/battle"; import { applyModifierTypeToPlayerPokemon, @@ -37,7 +37,6 @@ import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; import type { BerryType } from "#enums/berry-type"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { Stat } from "#enums/stat"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import i18next from "i18next"; /** the i18n namespace for this encounter */ @@ -52,8 +51,8 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde MysteryEncounterType.ABSOLUTE_AVARICE, ) .withEncounterTier(MysteryEncounterTier.GREAT) - .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) - .withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 4)) // Must have at least 4 berries to spawn + .withSceneWaveRangeRequirement(20, 180) + .withSceneRequirement(new PersistentModifierRequirement("BerryModifier", 6)) // Must have at least 6 berries to spawn .withFleeAllowed(false) .withIntroSpriteConfigs([ { @@ -220,9 +219,9 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde // Do NOT remove the real berries yet or else it will be persisted in the session data - // SpDef buff below wave 50, +1 to all stats otherwise + // +1 SpDef below wave 50, SpDef and Speed otherwise const statChangesForBattle: (Stat.ATK | Stat.DEF | Stat.SPATK | Stat.SPDEF | Stat.SPD | Stat.ACC | Stat.EVA)[] = - globalScene.currentBattle.waveIndex < 50 ? [Stat.SPDEF] : [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD]; + globalScene.currentBattle.waveIndex < 50 ? [Stat.SPDEF] : [Stat.SPDEF, Stat.SPD]; // Calculate boss mon const config: EnemyPartyConfig = { @@ -233,7 +232,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde isBoss: true, bossSegments: 3, shiny: false, // Shiny lock because of consistency issues between the different options - moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH], + moveSet: [Moves.THRASH, Moves.CRUNCH, Moves.BODY_PRESS, Moves.SLACK_OFF], modifierConfigs: bossModifierConfigs, tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], mysteryEncounterBattleEffects: (pokemon: Pokemon) => { diff --git a/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts b/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts index b66052cfd16..b403c5f291c 100644 --- a/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts +++ b/src/data/mystery-encounters/encounters/an-offer-you-cant-refuse-encounter.ts @@ -23,7 +23,7 @@ import { speciesStarterCosts } from "#app/data/balance/starters"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import i18next from "i18next"; /** the i18n namespace for this encounter */ diff --git a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts index 94e27e32773..7f54e51565e 100644 --- a/src/data/mystery-encounters/encounters/berries-abound-encounter.ts +++ b/src/data/mystery-encounters/encounters/berries-abound-encounter.ts @@ -13,7 +13,7 @@ import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import type { BerryModifierType, ModifierTypeOption } from "#app/modifier/modifier-type"; import { ModifierPoolType, modifierTypes, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type"; -import { randSeedInt } from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { globalScene } from "#app/global-scene"; @@ -36,7 +36,7 @@ import i18next from "#app/plugins/i18n"; import { BerryType } from "#enums/berry-type"; import { PERMANENT_STATS, Stat } from "#enums/stat"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/berriesAbound"; diff --git a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts index 1e4c9a3b957..87b223d5245 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -16,7 +16,7 @@ import { TrainerSlot } from "#enums/trainer-slot"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PartyMemberStrength } from "#enums/party-member-strength"; import { globalScene } from "#app/global-scene"; -import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils"; +import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils/common"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -52,7 +52,7 @@ import i18next from "i18next"; import MoveInfoOverlay from "#app/ui/move-info-overlay"; import { allMoves } from "#app/data/moves/move"; import { ModifierTier } from "#app/modifier/modifier-tier"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; /** the i18n namespace for the encounter */ @@ -146,24 +146,34 @@ const POOL_4_POKEMON = [Species.GENESECT, Species.SLITHER_WING, Species.BUZZWOLE const PHYSICAL_TUTOR_MOVES = [ Moves.MEGAHORN, - Moves.X_SCISSOR, Moves.ATTACK_ORDER, - Moves.PIN_MISSILE, + Moves.BUG_BITE, Moves.FIRST_IMPRESSION, + Moves.LUNGE ]; -const SPECIAL_TUTOR_MOVES = [Moves.SILVER_WIND, Moves.BUG_BUZZ, Moves.SIGNAL_BEAM, Moves.POLLEN_PUFF]; +const SPECIAL_TUTOR_MOVES = [ + Moves.SILVER_WIND, + Moves.SIGNAL_BEAM, + Moves.BUG_BUZZ, + Moves.POLLEN_PUFF, + Moves.STRUGGLE_BUG +]; -const STATUS_TUTOR_MOVES = [Moves.STRING_SHOT, Moves.STICKY_WEB, Moves.SILK_TRAP, Moves.RAGE_POWDER, Moves.HEAL_ORDER]; +const STATUS_TUTOR_MOVES = [ + Moves.STRING_SHOT, + Moves.DEFEND_ORDER, + Moves.RAGE_POWDER, + Moves.STICKY_WEB, + Moves.SILK_TRAP +]; const MISC_TUTOR_MOVES = [ - Moves.BUG_BITE, Moves.LEECH_LIFE, - Moves.DEFEND_ORDER, - Moves.QUIVER_DANCE, - Moves.TAIL_GLOW, - Moves.INFESTATION, Moves.U_TURN, + Moves.HEAL_ORDER, + Moves.QUIVER_DANCE, + Moves.INFESTATION, ]; /** diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts index eca99fc0c13..ce5eb2cfdd1 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -31,14 +31,14 @@ import { import { PokemonType } from "#enums/pokemon-type"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -import { randSeedInt, randSeedShuffle } from "#app/utils"; +import { randSeedInt, randSeedShuffle } from "#app/utils/common"; import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler"; import type { PlayerPokemon } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon"; -import { Ability } from "#app/data/ability"; +import { Ability } from "#app/data/abilities/ability-class"; import { BerryModifier } from "#app/modifier/modifier"; import { BerryType } from "#enums/berry-type"; import { BattlerIndex } from "#app/battle"; @@ -46,7 +46,7 @@ import { Moves } from "#enums/moves"; import { EncounterBattleAnim } from "#app/data/battle-anims"; import { MoveCategory } from "#enums/MoveCategory"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { EncounterAnim } from "#enums/encounter-anims"; import { Challenges } from "#enums/challenges"; @@ -397,9 +397,6 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder newTypes.push(secondType); // Apply the type changes (to both base and fusion, if pokemon is fused) - if (!pokemon.customPokemonData) { - pokemon.customPokemonData = new CustomPokemonData(); - } pokemon.customPokemonData.types = newTypes; if (pokemon.isFusion()) { if (!pokemon.fusionCustomPokemonData) { @@ -437,7 +434,7 @@ async function handleSwapAbility() { await showEncounterDialogue(`${namespace}:option.1.apply_ability_dialogue`, `${namespace}:speaker`); await showEncounterText(`${namespace}:option.1.apply_ability_message`); - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { displayYesNoOptions(resolve); }); }); @@ -467,7 +464,7 @@ function displayYesNoOptions(resolve) { maxOptions: 7, yOffset: 0, }; - globalScene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true); + globalScene.ui.setModeWithoutClear(UiMode.OPTION_SELECT, config, null, true); } function onYesAbilitySwap(resolve) { @@ -477,11 +474,11 @@ function onYesAbilitySwap(resolve) { applyAbilityOverrideToPokemon(pokemon, encounter.misc.ability); encounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender()); - globalScene.ui.setMode(Mode.MESSAGE).then(() => resolve(true)); + globalScene.ui.setMode(UiMode.MESSAGE).then(() => resolve(true)); }; const onPokemonNotSelected = () => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { displayYesNoOptions(resolve); }); }; diff --git a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts index 75527e1f8c1..bdd4bfaacaa 100644 --- a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts +++ b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts @@ -24,7 +24,7 @@ import { TrainerSlot } from "#enums/trainer-slot"; import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { modifierTypes } from "#app/modifier/modifier-type"; import { LearnMovePhase } from "#app/phases/learn-move-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; diff --git a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts index 6c4c8f26deb..e746b13c6a5 100644 --- a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts +++ b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts @@ -1,5 +1,5 @@ import type { PokemonType } from "#enums/pokemon-type"; -import { isNullOrUndefined, randSeedInt } from "#app/utils"; +import { isNullOrUndefined, randSeedInt } from "#app/utils/common"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import { globalScene } from "#app/global-scene"; @@ -19,7 +19,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import type { PokemonHeldItemModifier } from "#app/modifier/modifier"; import { PokemonFormChangeItemModifier } from "#app/modifier/modifier"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { Challenges } from "#enums/challenges"; /** i18n namespace for encounter */ diff --git a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts index 364484cb511..7040bb47d19 100644 --- a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts +++ b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts @@ -18,7 +18,7 @@ import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/u import { getPokemonSpecies } from "#app/data/pokemon-species"; import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import type { PokemonHeldItemModifier, PokemonInstantReviveModifier } from "#app/modifier/modifier"; import { BerryModifier, @@ -32,7 +32,7 @@ import { modifierTypes } from "#app/modifier/modifier-type"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import i18next from "#app/plugins/i18n"; import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; -import { randSeedItem } from "#app/utils"; +import { randSeedItem } from "#app/utils/common"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; diff --git a/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts index 9b8e2e24d12..39341bef2d5 100644 --- a/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts +++ b/src/data/mystery-encounters/encounters/department-store-sale-encounter.ts @@ -4,13 +4,13 @@ import { } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import type { ModifierTypeFunc } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { randSeedInt } from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; /** i18n namespace for encounter */ const namespace = "mysteryEncounters/departmentStoreSale"; diff --git a/src/data/mystery-encounters/encounters/field-trip-encounter.ts b/src/data/mystery-encounters/encounters/field-trip-encounter.ts index a1964aa5ab4..2cd6123838b 100644 --- a/src/data/mystery-encounters/encounters/field-trip-encounter.ts +++ b/src/data/mystery-encounters/encounters/field-trip-encounter.ts @@ -18,7 +18,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { Stat } from "#enums/stat"; import i18next from "i18next"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; /** i18n namespace for the encounter */ const namespace = "mysteryEncounters/fieldTrip"; diff --git a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts index 6118fe3d0de..0364b98abe2 100644 --- a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts +++ b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts @@ -30,7 +30,7 @@ import { PokemonMove } from "#app/field/pokemon"; import { Moves } from "#enums/moves"; import { EncounterBattleAnim } from "#app/data/battle-anims"; import { WeatherType } from "#enums/weather-type"; -import { isNullOrUndefined, randSeedInt } from "#app/utils"; +import { isNullOrUndefined, randSeedInt } from "#app/utils/common"; import { StatusEffect } from "#enums/status-effect"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { @@ -41,12 +41,12 @@ import { import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { EncounterAnim } from "#enums/encounter-anims"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { Stat } from "#enums/stat"; -import { Ability } from "#app/data/ability"; +import { Ability } from "#app/data/abilities/ability-class"; import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups"; /** the i18n namespace for the encounter */ diff --git a/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts b/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts index 595d13cf727..ecc2e17a06f 100644 --- a/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts +++ b/src/data/mystery-encounters/encounters/fight-or-flight-encounter.ts @@ -31,9 +31,9 @@ import { import PokemonData from "#app/system/pokemon-data"; import { BattlerTagType } from "#enums/battler-tag-type"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; -import { randSeedInt } from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/fightOrFlight"; diff --git a/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts b/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts index 282c6c149ff..2d0828b8c0c 100644 --- a/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts +++ b/src/data/mystery-encounters/encounters/fun-and-games-encounter.ts @@ -30,7 +30,7 @@ import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; import { PostSummonPhase } from "#app/phases/post-summon-phase"; import { modifierTypes } from "#app/modifier/modifier-type"; import { Nature } from "#enums/nature"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; /** the i18n namespace for the encounter */ diff --git a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts index f80620647b0..bb41bc7883c 100644 --- a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts +++ b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts @@ -23,7 +23,14 @@ import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import { getTypeRgb } from "#app/data/type"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -import { NumberHolder, isNullOrUndefined, randInt, randSeedInt, randSeedShuffle, randSeedItem } from "#app/utils"; +import { + NumberHolder, + isNullOrUndefined, + randInt, + randSeedInt, + randSeedShuffle, + randSeedItem, +} from "#app/utils/common"; import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; @@ -41,7 +48,7 @@ import { Gender, getGenderSymbol } from "#app/data/gender"; import { getNatureName } from "#app/data/nature"; import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball"; import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import type { PokeballType } from "#enums/pokeball"; import { doShinySparkleAnim } from "#app/field/anims"; @@ -677,7 +684,7 @@ function doPokemonTradeSequence(tradedPokemon: PlayerPokemon, receivedPokemon: P sprite.setPipelineData("shiny", tradedPokemon.shiny); sprite.setPipelineData("variant", tradedPokemon.variant); ["spriteColors", "fusionSpriteColors"].map(k => { - if (tradedPokemon.summonData?.speciesForm) { + if (tradedPokemon.summonData.speciesForm) { k += "Base"; } sprite.pipelineData[k] = tradedPokemon.getSprite().pipelineData[k]; @@ -703,7 +710,7 @@ function doPokemonTradeSequence(tradedPokemon: PlayerPokemon, receivedPokemon: P sprite.setPipelineData("shiny", receivedPokemon.shiny); sprite.setPipelineData("variant", receivedPokemon.variant); ["spriteColors", "fusionSpriteColors"].map(k => { - if (receivedPokemon.summonData?.speciesForm) { + if (receivedPokemon.summonData.speciesForm) { k += "Base"; } sprite.pipelineData[k] = receivedPokemon.getSprite().pipelineData[k]; diff --git a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts index 97fd5783ebb..6d8a1fc8c6b 100644 --- a/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts +++ b/src/data/mystery-encounters/encounters/lost-at-sea-encounter.ts @@ -10,7 +10,7 @@ import { leaveEncounterWithoutBattle, setEncounterExp } from "../utils/encounter import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { PokemonMove } from "#app/field/pokemon"; const OPTION_1_REQUIRED_MOVE = Moves.SURF; diff --git a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts index 11924f93df4..6907e18cfdc 100644 --- a/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-challengers-encounter.ts @@ -12,11 +12,11 @@ import { modifierTypes } from "#app/modifier/modifier-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PartyMemberStrength } from "#enums/party-member-strength"; import { globalScene } from "#app/global-scene"; -import * as Utils from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/mysteriousChallengers"; @@ -46,7 +46,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter const normalConfig = trainerConfigs[normalTrainerType].clone(); let female = false; if (normalConfig.hasGenders) { - female = !!Utils.randSeedInt(2); + female = !!randSeedInt(2); } const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly); encounter.enemyPartyConfigs.push({ @@ -76,7 +76,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter hardConfig.setPartyTemplates(hardTemplate); female = false; if (hardConfig.hasGenders) { - female = !!Utils.randSeedInt(2); + female = !!randSeedInt(2); } const hardSpriteKey = hardConfig.getSpriteKey(female, hardConfig.doubleOnly); encounter.enemyPartyConfigs.push({ @@ -96,7 +96,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = MysteryEncounter brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func female = false; if (brutalConfig.hasGenders) { - female = !!Utils.randSeedInt(2); + female = !!randSeedInt(2); } const brutalSpriteKey = brutalConfig.getSpriteKey(female, brutalConfig.doubleOnly); encounter.enemyPartyConfigs.push({ diff --git a/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts index c295e36749a..e6c11378163 100644 --- a/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts @@ -15,10 +15,10 @@ import { koPlayerPokemon, } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getPokemonSpecies } from "#app/data/pokemon-species"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { GameOverPhase } from "#app/phases/game-over-phase"; -import { randSeedInt } from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import { Moves } from "#enums/moves"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -29,8 +29,8 @@ import { Species } from "#enums/species"; const namespace = "mysteryEncounters/mysteriousChest"; const RAND_LENGTH = 100; -const TRAP_PERCENT = 35; -const COMMON_REWARDS_PERCENT = 20; +const TRAP_PERCENT = 30; +const COMMON_REWARDS_PERCENT = 25; const ULTRA_REWARDS_PERCENT = 30; const ROGUE_REWARDS_PERCENT = 10; const MASTER_REWARDS_PERCENT = 5; diff --git a/src/data/mystery-encounters/encounters/part-timer-encounter.ts b/src/data/mystery-encounters/encounters/part-timer-encounter.ts index 61b48353997..1074eaf8c81 100644 --- a/src/data/mystery-encounters/encounters/part-timer-encounter.ts +++ b/src/data/mystery-encounters/encounters/part-timer-encounter.ts @@ -20,7 +20,7 @@ import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-enco import i18next from "i18next"; import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; /** the i18n namespace for the encounter */ diff --git a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts index 8c45fde3079..7a12c86edff 100644 --- a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts +++ b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts @@ -15,7 +15,7 @@ import { HiddenAbilityRateBoosterModifier, IvScannerModifier } from "#app/modifi import type { EnemyPokemon } from "#app/field/pokemon"; import { PokeballType } from "#enums/pokeball"; import { PlayerGender } from "#enums/player-gender"; -import { NumberHolder, randSeedInt } from "#app/utils"; +import { NumberHolder, randSeedInt } from "#app/utils/common"; import type PokemonSpecies from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; @@ -31,7 +31,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { ScanIvsPhase } from "#app/phases/scan-ivs-phase"; import { SummonPhase } from "#app/phases/summon-phase"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; /** the i18n namespace for the encounter */ diff --git a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts index b9476d49fec..daf4d860cdf 100644 --- a/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts +++ b/src/data/mystery-encounters/encounters/shady-vitamin-dealer-encounter.ts @@ -8,7 +8,7 @@ import { import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { randSeedInt } from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Species } from "#enums/species"; import { globalScene } from "#app/global-scene"; @@ -26,7 +26,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import type { Nature } from "#enums/nature"; import { getNatureName } from "#app/data/nature"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import i18next from "i18next"; /** the i18n namespace for this encounter */ diff --git a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts index bfa1204a8ba..2654f6b18d8 100644 --- a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts +++ b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts @@ -19,6 +19,7 @@ import { setEncounterRewards, } from "../utils/encounter-phase-utils"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; +import { Nature } from "#enums/nature"; import { Moves } from "#enums/moves"; import { BattlerIndex } from "#app/battle"; import { AiType, PokemonMove } from "#app/field/pokemon"; @@ -26,9 +27,10 @@ import { getPokemonSpecies } from "#app/data/pokemon-species"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { PartyHealPhase } from "#app/phases/party-heal-phase"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { BerryType } from "#enums/berry-type"; +import { Stat } from "#enums/stat"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; +import { randSeedInt } from "#app/utils/common"; /** i18n namespace for the encounter */ const namespace = "mysteryEncounters/slumberingSnorlax"; @@ -42,7 +44,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil MysteryEncounterType.SLUMBERING_SNORLAX, ) .withEncounterTier(MysteryEncounterTier.GREAT) - .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) + .withSceneWaveRangeRequirement(15, 150) .withCatchAllowed(true) .withHideWildIntroMessage(true) .withFleeAllowed(false) @@ -72,16 +74,26 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil species: bossSpecies, isBoss: true, shiny: false, // Shiny lock because shiny is rolled only if the battle option is picked - status: [StatusEffect.SLEEP, 5], // Extra turns on timer for Snorlax's start of fight moves - moveSet: [Moves.REST, Moves.SLEEP_TALK, Moves.CRUNCH, Moves.GIGA_IMPACT], + status: [StatusEffect.SLEEP, 6], // Extra turns on timer for Snorlax's start of fight moves + nature: Nature.DOCILE, + moveSet: [Moves.BODY_SLAM, Moves.CRUNCH, Moves.SLEEP_TALK, Moves.REST], modifierConfigs: [ { modifier: generateModifierType(modifierTypes.BERRY, [BerryType.SITRUS]) as PokemonHeldItemModifierType, - stackCount: 2, }, { modifier: generateModifierType(modifierTypes.BERRY, [BerryType.ENIGMA]) as PokemonHeldItemModifierType, - stackCount: 2, + }, + { + modifier: generateModifierType(modifierTypes.BASE_STAT_BOOSTER, [Stat.HP]) as PokemonHeldItemModifierType, + }, + { + modifier: generateModifierType(modifierTypes.SOOTHE_BELL) as PokemonHeldItemModifierType, + stackCount: randSeedInt(2, 0), + }, + { + modifier: generateModifierType(modifierTypes.LUCKY_EGG) as PokemonHeldItemModifierType, + stackCount: randSeedInt(2, 0), }, ], customPokemonData: new CustomPokemonData({ spriteScale: 1.25 }), @@ -128,12 +140,6 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil move: new PokemonMove(Moves.SNORE), ignorePp: true, }, - { - sourceBattlerIndex: BattlerIndex.ENEMY, - targets: [BattlerIndex.PLAYER], - move: new PokemonMove(Moves.SNORE), - ignorePp: true, - }, ); await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]); }, diff --git a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts index 806a89a7131..28c7fe4644f 100644 --- a/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts +++ b/src/data/mystery-encounters/encounters/teleporting-hijinks-encounter.ts @@ -7,7 +7,7 @@ import { transitionMysteryEncounterIntroVisuals, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { randSeedInt } from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { globalScene } from "#app/global-scene"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; @@ -29,7 +29,7 @@ import { BattlerTagType } from "#enums/battler-tag-type"; import { getPokemonNameWithAffix } from "#app/messages"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { Stat } from "#enums/stat"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { getEncounterPokemonLevelForWave, STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER, diff --git a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts index c189e341089..15063bc2763 100644 --- a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts @@ -7,11 +7,10 @@ import { import { trainerConfigs } from "#app/data/trainers/trainer-config"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { globalScene } from "#app/global-scene"; -import { randSeedShuffle } from "#app/utils"; +import { randSeedShuffle } from "#app/utils/common"; import type MysteryEncounter from "../mystery-encounter"; import { MysteryEncounterBuilder } from "../mystery-encounter"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { Biome } from "#enums/biome"; import { TrainerType } from "#enums/trainer-type"; import i18next from "i18next"; @@ -123,7 +122,7 @@ export const TheExpertPokemonBreederEncounter: MysteryEncounter = MysteryEncount MysteryEncounterType.THE_EXPERT_POKEMON_BREEDER, ) .withEncounterTier(MysteryEncounterTier.ULTRA) - .withSceneWaveRangeRequirement(...CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES) + .withSceneWaveRangeRequirement(25, 180) .withScenePartySizeRequirement(4, 6, true) // Must have at least 4 legal pokemon in party .withIntroSpriteConfigs([]) // These are set in onInit() .withIntroDialogue([ @@ -483,9 +482,9 @@ function getPartyConfig(): EnemyPartyConfig { abilityIndex: 1, // Magic Guard shiny: false, nature: Nature.ADAMANT, - moveSet: [Moves.METEOR_MASH, Moves.FIRE_PUNCH, Moves.ICE_PUNCH, Moves.THUNDER_PUNCH], + moveSet: [Moves.FIRE_PUNCH, Moves.ICE_PUNCH, Moves.THUNDER_PUNCH, Moves.METEOR_MASH], ivs: [31, 31, 31, 31, 31, 31], - tera: PokemonType.STEEL, + tera: PokemonType.FAIRY, }, ], }; diff --git a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts index fb55c55a1a3..25798de3b4a 100644 --- a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts @@ -3,7 +3,7 @@ import { transitionMysteryEncounterIntroVisuals, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { isNullOrUndefined, randSeedInt } from "#app/utils"; +import { isNullOrUndefined, NumberHolder, randSeedInt, randSeedItem } from "#app/utils/common"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { globalScene } from "#app/global-scene"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; @@ -26,9 +26,10 @@ import { showEncounterDialogue } from "#app/data/mystery-encounters/utils/encoun import PokemonData from "#app/system/pokemon-data"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { Abilities } from "#enums/abilities"; -import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; +import { NON_LEGEND_PARADOX_POKEMON, NON_LEGEND_ULTRA_BEASTS } from "#app/data/balance/special-species-groups"; +import { timedEventManager } from "#app/global-event-manager"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounters/thePokemonSalesman"; @@ -38,6 +39,9 @@ const MAX_POKEMON_PRICE_MULTIPLIER = 4; /** Odds of shiny magikarp will be 1/value */ const SHINY_MAGIKARP_WEIGHT = 100; +/** Odds of event sale will be value/100 */ +const EVENT_THRESHOLD = 50; + /** * Pokemon Salesman encounter. * @see {@link https://github.com/pagefaultgames/pokerogue/issues/3799 | GitHub Issue #3799} @@ -82,16 +86,74 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui tries++; } + const r = randSeedInt(SHINY_MAGIKARP_WEIGHT); + + let validEventEncounters = timedEventManager + .getEventEncounters() + .filter( + s => + !getPokemonSpecies(s.species).legendary && + !getPokemonSpecies(s.species).subLegendary && + !getPokemonSpecies(s.species).mythical && + !NON_LEGEND_PARADOX_POKEMON.includes(s.species) && + !NON_LEGEND_ULTRA_BEASTS.includes(s.species), + ); + let pokemon: PlayerPokemon; + /** + * Mon is determined as follows: + * If you roll the 1% for Shiny Magikarp, you get Magikarp with a random variant + * If an event with more than 1 valid event encounter species is active, you have 20% chance to get one of those + * If the rolled species has no HA, and there are valid event encounters, you will get one of those + * If the rolled species has no HA and there are no valid event encounters, you will get Shiny Magikarp + * Mons rolled from the event encounter pool get 3 extra shiny rolls + */ if ( - randSeedInt(SHINY_MAGIKARP_WEIGHT) === 0 || - isNullOrUndefined(species.abilityHidden) || - species.abilityHidden === Abilities.NONE + r === 0 || + ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) && + (validEventEncounters.length === 0)) ) { - // If no HA mon found or you roll 1%, give shiny Magikarp with random variant + // If you roll 1%, give shiny Magikarp with random variant species = getPokemonSpecies(Species.MAGIKARP); - pokemon = new PlayerPokemon(species, 5, 2, species.formIndex, undefined, true); - } else { + pokemon = new PlayerPokemon(species, 5, 2, undefined, undefined, true); + } + else if ( + (validEventEncounters.length > 0 && (r <= EVENT_THRESHOLD || + (isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE))) + ) { + tries = 0; + do { + // If you roll 20%, give event encounter with 3 extra shiny rolls and its HA, if it has one + const enc = randSeedItem(validEventEncounters); + species = getPokemonSpecies(enc.species); + pokemon = new PlayerPokemon(species, 5, species.abilityHidden === Abilities.NONE ? undefined : 2, enc.formIndex); + pokemon.trySetShinySeed(); + pokemon.trySetShinySeed(); + pokemon.trySetShinySeed(); + if (pokemon.shiny || pokemon.abilityIndex === 2) { + break; + } + tries++; + } while (tries < 6); + if (!pokemon.shiny && pokemon.abilityIndex !== 2) { + // If, after 6 tries, you STILL somehow don't have an HA or shiny mon, pick from only the event mons that have an HA. + if (validEventEncounters.some(s => !!getPokemonSpecies(s.species).abilityHidden)) { + validEventEncounters.filter(s => !!getPokemonSpecies(s.species).abilityHidden); + const enc = randSeedItem(validEventEncounters); + species = getPokemonSpecies(enc.species); + pokemon = new PlayerPokemon(species, 5, 2, enc.formIndex); + pokemon.trySetShinySeed(); + pokemon.trySetShinySeed(); + pokemon.trySetShinySeed(); + } + else { + // If there's, and this would never happen, no eligible event encounters with a hidden ability, just do Magikarp + species = getPokemonSpecies(Species.MAGIKARP); + pokemon = new PlayerPokemon(species, 5, 2, undefined, undefined, true); + } + } + } + else { pokemon = new PlayerPokemon(species, 5, 2, species.formIndex); } pokemon.generateAndPopulateMoveset(); diff --git a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts index c994c6e993f..294f1a78b34 100644 --- a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts @@ -28,7 +28,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { Stat } from "#enums/stat"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/theStrongStuff"; diff --git a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts index aca04ad50ed..3cbe42591d8 100644 --- a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts @@ -24,7 +24,7 @@ import { PokemonType } from "#enums/pokemon-type"; import { BerryType } from "#enums/berry-type"; import { Stat } from "#enums/stat"; import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms"; -import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/ability"; +import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/abilities/ability"; import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { PartyHealPhase } from "#app/phases/party-heal-phase"; @@ -32,7 +32,7 @@ import { ShowTrainerPhase } from "#app/phases/show-trainer-phase"; import { ReturnPhase } from "#app/phases/return-phase"; import i18next from "i18next"; import { ModifierTier } from "#app/modifier/modifier-tier"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { BattlerTagType } from "#enums/battler-tag-type"; /** the i18n namespace for the encounter */ @@ -222,7 +222,8 @@ function endTrainerBattleAndShowDialogue(): Promise { globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeAbilityTrigger); } - pokemon.resetBattleData(); + // Each trainer battle is supposed to be a new fight, so reset all per-battle activation effects + pokemon.resetBattleAndWaveData(); applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon); } diff --git a/src/data/mystery-encounters/encounters/training-session-encounter.ts b/src/data/mystery-encounters/encounters/training-session-encounter.ts index cc56f3efa42..597a6b009b3 100644 --- a/src/data/mystery-encounters/encounters/training-session-encounter.ts +++ b/src/data/mystery-encounters/encounters/training-session-encounter.ts @@ -1,5 +1,5 @@ -import type { Ability } from "#app/data/ability"; -import { allAbilities } from "#app/data/ability"; +import type { Ability } from "#app/data/abilities/ability-class"; +import { allAbilities } from "#app/data/data-lists"; import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { initBattleWithEnemyConfig, @@ -15,7 +15,7 @@ import type { PokemonHeldItemModifier } from "#app/modifier/modifier"; import { AbilityAttr } from "#app/system/game-data"; import PokemonData from "#app/system/pokemon-data"; import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; -import { isNullOrUndefined, randSeedShuffle } from "#app/utils"; +import { isNullOrUndefined, randSeedShuffle } from "#app/utils/common"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { globalScene } from "#app/global-scene"; @@ -28,7 +28,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; import i18next from "i18next"; import { getStatKey } from "#enums/stat"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import type { Nature } from "#enums/nature"; diff --git a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts index e60fe0ddc18..1e1db14705a 100644 --- a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts +++ b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts @@ -26,8 +26,8 @@ import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Moves } from "#enums/moves"; import { BattlerIndex } from "#app/battle"; import { PokemonMove } from "#app/field/pokemon"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; -import { randSeedInt } from "#app/utils"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; +import { randSeedInt } from "#app/utils/common"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounters/trashToTreasure"; diff --git a/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts b/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts index ed1866c7a1b..f4eec5b0923 100644 --- a/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts +++ b/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts @@ -27,7 +27,7 @@ import { getSpriteKeysFromPokemon, } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import PokemonData from "#app/system/pokemon-data"; -import { isNullOrUndefined, randSeedInt } from "#app/utils"; +import { isNullOrUndefined, randSeedInt } from "#app/utils/common"; import type { Moves } from "#enums/moves"; import { BattlerIndex } from "#app/battle"; import { SelfStatusMove } from "#app/data/moves/move"; @@ -37,7 +37,7 @@ import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encoun import { BerryModifier } from "#app/modifier/modifier"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { Stat } from "#enums/stat"; -import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/uncommonBreed"; diff --git a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index 22ec52e976c..cceda25fcb4 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -17,13 +17,12 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon"; -import { NumberHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils"; +import { NumberHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils/common"; import type PokemonSpecies from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import type { PokemonHeldItemModifier } from "#app/modifier/modifier"; import { HiddenAbilityRateBoosterModifier, PokemonFormChangeItemModifier } from "#app/modifier/modifier"; import { achvs } from "#app/system/achv"; -import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type"; @@ -601,9 +600,6 @@ async function postProcessTransformedPokemon( newType = randSeedInt(18) as PokemonType; } newTypes.push(newType); - if (!newPokemon.customPokemonData) { - newPokemon.customPokemonData = new CustomPokemonData(); - } newPokemon.customPokemonData.types = newTypes; // Enable passive if previous had it diff --git a/src/data/mystery-encounters/mystery-encounter-option.ts b/src/data/mystery-encounters/mystery-encounter-option.ts index f360658c2dc..57dd50fa972 100644 --- a/src/data/mystery-encounters/mystery-encounter-option.ts +++ b/src/data/mystery-encounters/mystery-encounter-option.ts @@ -12,7 +12,7 @@ import { } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import type { CanLearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement"; import { CanLearnMoveRequirement } from "./requirements/can-learn-move-requirement"; -import { isNullOrUndefined, randSeedInt } from "#app/utils"; +import { isNullOrUndefined, randSeedInt } from "#app/utils/common"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; // biome-ignore lint/suspicious/noConfusingVoidType: void unions in callbacks are OK diff --git a/src/data/mystery-encounters/mystery-encounter-requirements.ts b/src/data/mystery-encounters/mystery-encounter-requirements.ts index f9aedf2c1a7..49fd632932c 100644 --- a/src/data/mystery-encounters/mystery-encounter-requirements.ts +++ b/src/data/mystery-encounters/mystery-encounter-requirements.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "../data-lists"; import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { Nature } from "#enums/nature"; import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; @@ -9,7 +9,7 @@ import { WeatherType } from "#enums/weather-type"; import type { PlayerPokemon } from "#app/field/pokemon"; import { AttackTypeBoosterModifier } from "#app/modifier/modifier"; import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; import type { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; diff --git a/src/data/mystery-encounters/mystery-encounter-save-data.ts b/src/data/mystery-encounters/mystery-encounter-save-data.ts index 7c8110628f0..dd633390e46 100644 --- a/src/data/mystery-encounters/mystery-encounter-save-data.ts +++ b/src/data/mystery-encounters/mystery-encounter-save-data.ts @@ -1,6 +1,6 @@ import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT } from "#app/data/mystery-encounters/mystery-encounters"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; import type { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; export class SeenEncounterData { diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index 53e976cda8a..e305252ed0f 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -1,11 +1,11 @@ import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; -import { capitalizeFirstLetter, isNullOrUndefined } from "#app/utils"; +import { capitalizeFirstLetter, isNullOrUndefined } from "#app/utils/common"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro"; import MysteryEncounterIntroVisuals from "#app/field/mystery-encounter-intro"; -import * as Utils from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import type { StatusEffect } from "#enums/status-effect"; import type { OptionTextDisplay } from "./mystery-encounter-dialogue"; import type MysteryEncounterDialogue from "./mystery-encounter-dialogue"; @@ -378,13 +378,13 @@ export default class MysteryEncounter implements IMysteryEncounter { } if (truePrimaryPool.length > 0) { // Always choose from the non-overlapping pokemon first - this.primaryPokemon = truePrimaryPool[Utils.randSeedInt(truePrimaryPool.length, 0)]; + this.primaryPokemon = truePrimaryPool[randSeedInt(truePrimaryPool.length, 0)]; return true; } // If there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool if (overlap.length > 1 || this.secondaryPokemon.length - overlap.length >= 1) { // is this working? - this.primaryPokemon = overlap[Utils.randSeedInt(overlap.length, 0)]; + this.primaryPokemon = overlap[randSeedInt(overlap.length, 0)]; this.secondaryPokemon = this.secondaryPokemon.filter(supp => supp !== this.primaryPokemon); return true; } @@ -394,7 +394,7 @@ export default class MysteryEncounter implements IMysteryEncounter { return false; } // this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly. - this.primaryPokemon = qualified[Utils.randSeedInt(qualified.length, 0)]; + this.primaryPokemon = qualified[randSeedInt(qualified.length, 0)]; return true; } diff --git a/src/data/mystery-encounters/mystery-encounters.ts b/src/data/mystery-encounters/mystery-encounters.ts index 5dd952b2bce..1a36dc27df2 100644 --- a/src/data/mystery-encounters/mystery-encounters.ts +++ b/src/data/mystery-encounters/mystery-encounters.ts @@ -226,9 +226,9 @@ const anyBiomeEncounters: MysteryEncounterType[] = [ */ export const mysteryEncountersByBiome = new Map([ [Biome.TOWN, []], - [Biome.PLAINS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]], + [Biome.PLAINS, [MysteryEncounterType.SLUMBERING_SNORLAX]], [Biome.GRASS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]], - [Biome.TALL_GRASS, [MysteryEncounterType.ABSOLUTE_AVARICE]], + [Biome.TALL_GRASS, [MysteryEncounterType.SLUMBERING_SNORLAX, MysteryEncounterType.ABSOLUTE_AVARICE]], [Biome.METROPOLIS, []], [Biome.FOREST, [MysteryEncounterType.SAFARI_ZONE, MysteryEncounterType.ABSOLUTE_AVARICE]], [Biome.SEA, [MysteryEncounterType.LOST_AT_SEA]], diff --git a/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts b/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts index a7ffe3e26ca..37194aef78e 100644 --- a/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts +++ b/src/data/mystery-encounters/requirements/can-learn-move-requirement.ts @@ -1,7 +1,7 @@ import type { Moves } from "#app/enums/moves"; import type { PlayerPokemon } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; import { EncounterPokemonRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { globalScene } from "#app/global-scene"; diff --git a/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts b/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts index 94790145687..296d94093d9 100644 --- a/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-dialogue-utils.ts @@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene"; import type { TextStyle } from "#app/ui/text"; import { getTextWithColors } from "#app/ui/text"; import { UiTheme } from "#enums/ui-theme"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; import i18next from "i18next"; /** diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index 76d07bf01ba..0215928bbe8 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -1,5 +1,6 @@ import type Battle from "#app/battle"; -import { BattlerIndex, BattleType } from "#app/battle"; +import { BattlerIndex } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import { biomeLinks, BiomePoolTier } from "#app/data/balance/biomes"; import type MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option"; import { @@ -9,7 +10,7 @@ import { import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import type { AiType, PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; -import { EnemyPokemon, FieldPosition, PokemonMove, PokemonSummonData } from "#app/field/pokemon"; +import { EnemyPokemon, FieldPosition, PokemonMove } from "#app/field/pokemon"; import type { CustomModifierSettings, ModifierType } from "#app/modifier/modifier-type"; import { getPartyLuckValue, @@ -29,9 +30,8 @@ import type PokemonData from "#app/system/pokemon-data"; import type { OptionSelectConfig, OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import type { PartyOption, PokemonSelectFilter } from "#app/ui/party-ui-handler"; import { PartyUiMode } from "#app/ui/party-ui-handler"; -import { Mode } from "#app/ui/ui"; -import * as Utils from "#app/utils"; -import { isNullOrUndefined, randSeedInt, randSeedItem } from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import { isNullOrUndefined, randSeedInt, randomString, randSeedItem } from "#app/utils/common"; import type { BattlerTagType } from "#enums/battler-tag-type"; import { Biome } from "#enums/biome"; import type { TrainerType } from "#enums/trainer-type"; @@ -58,7 +58,7 @@ import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { GameOverPhase } from "#app/phases/game-over-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import { PartyExpPhase } from "#app/phases/party-exp-phase"; -import type { Variant } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; import { StatusEffect } from "#enums/status-effect"; import { globalScene } from "#app/global-scene"; import { getPokemonSpecies } from "#app/data/pokemon-species"; @@ -168,7 +168,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig): const doubleTrainer = trainerConfig.doubleOnly || (trainerConfig.hasDouble && !!partyConfig.doubleBattle); doubleBattle = doubleTrainer; - const trainerFemale = isNullOrUndefined(partyConfig.female) ? !!Utils.randSeedInt(2) : partyConfig.female; + const trainerFemale = isNullOrUndefined(partyConfig.female) ? !!randSeedInt(2) : partyConfig.female; const newTrainer = new Trainer( trainerConfig.trainerType, doubleTrainer ? TrainerVariant.DOUBLE : trainerFemale ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT, @@ -286,7 +286,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig): // Generate new id, reset status and HP in case using data source if (config.dataSource) { - enemyPokemon.id = Utils.randSeedInt(4294967296); + enemyPokemon.id = randSeedInt(4294967296); } // Set form @@ -348,11 +348,6 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig): enemyPokemon.status = new Status(status, 0, cureTurn); } - // Set summon data fields - if (!enemyPokemon.summonData) { - enemyPokemon.summonData = new PokemonSummonData(); - } - // Set ability if (!isNullOrUndefined(config.abilityIndex)) { enemyPokemon.abilityIndex = config.abilityIndex; @@ -390,14 +385,11 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig): } } - // mysteryEncounterBattleEffects will only be used IFF MYSTERY_ENCOUNTER_POST_SUMMON tag is applied + // mysteryEncounterBattleEffects will only be used if MYSTERY_ENCOUNTER_POST_SUMMON tag is applied if (config.mysteryEncounterBattleEffects) { enemyPokemon.mysteryEncounterBattleEffects = config.mysteryEncounterBattleEffects; } - // Requires re-priming summon data to update everything properly - enemyPokemon.primeSummonData(enemyPokemon.summonData); - if (enemyPokemon.isShiny() && !enemyPokemon["shinySparkle"]) { enemyPokemon.initShinySparkle(); } @@ -424,6 +416,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig): console.log( `Pokemon: ${getPokemonNameWithAffix(enemyPokemon)}`, `| Species ID: ${enemyPokemon.species.speciesId}`, + `| Level: ${enemyPokemon.level}`, `| Nature: ${getNatureName(enemyPokemon.nature, true, true, true)}`, ); console.log(`Stats (IVs): ${stats}`); @@ -563,7 +556,7 @@ export function selectPokemonForOption( // Open party screen to choose pokemon globalScene.ui.setMode( - Mode.PARTY, + UiMode.PARTY, PartyUiMode.SELECT, -1, (slotIndex: number, _option: PartyOption) => { @@ -581,7 +574,7 @@ export function selectPokemonForOption( } // There is a second option to choose after selecting the Pokemon - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { const displayOptions = () => { // Always appends a cancel option to bottom of options const fullOptions = secondaryOptions @@ -623,7 +616,7 @@ export function selectPokemonForOption( if (fullOptions[0].onHover) { fullOptions[0].onHover(); } - globalScene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true); + globalScene.ui.setModeWithoutClear(UiMode.OPTION_SELECT, config, null, true); }; const textPromptKey = @@ -673,20 +666,20 @@ export function selectOptionThenPokemon( const modeToSetOnExit = globalScene.ui.getMode(); const displayOptions = (config: OptionSelectConfig) => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { if (!optionSelectPromptKey) { // Do hover over the starting selection option if (fullOptions[0].onHover) { fullOptions[0].onHover(); } - globalScene.ui.setMode(Mode.OPTION_SELECT, config); + globalScene.ui.setMode(UiMode.OPTION_SELECT, config); } else { showEncounterText(optionSelectPromptKey).then(() => { // Do hover over the starting selection option if (fullOptions[0].onHover) { fullOptions[0].onHover(); } - globalScene.ui.setMode(Mode.OPTION_SELECT, config); + globalScene.ui.setMode(UiMode.OPTION_SELECT, config); }); } }); @@ -695,7 +688,7 @@ export function selectOptionThenPokemon( const selectPokemonAfterOption = (selectedOptionIndex: number) => { // Open party screen to choose a Pokemon globalScene.ui.setMode( - Mode.PARTY, + UiMode.PARTY, PartyUiMode.SELECT, -1, (slotIndex: number, _option: PartyOption) => { @@ -1075,8 +1068,8 @@ export function getRandomEncounterSpecies(level: number, isBoss = false, rerollH ret.formIndex = formIndex; } - //Reroll shiny for event encounters - if (isEventEncounter && !ret.shiny) { + //Reroll shiny or variant for event encounters + if (isEventEncounter) { ret.trySetShinySeed(); } //Reroll hidden ability @@ -1115,7 +1108,7 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) { const validMEfloorsByBiome = new Map(biomes.map(b => [b, 0])); let currentBiome = Biome.TOWN; let currentArena = globalScene.newArena(currentBiome); - globalScene.setSeed(Utils.randomString(24)); + globalScene.setSeed(randomString(24)); globalScene.resetSeed(); for (let i = 10; i < 180; i++) { // Boss @@ -1130,16 +1123,16 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) { globalScene.executeWithSeedOffset(() => { biomes = (biomeLinks[currentBiome] as (Biome | [Biome, number])[]) .filter(b => { - return !Array.isArray(b) || !Utils.randSeedInt(b[1]); + return !Array.isArray(b) || !randSeedInt(b[1]); }) .map(b => (!Array.isArray(b) ? b : b[0])); }, i * 100); if (biomes! && biomes.length > 0) { const specialBiomes = biomes.filter(b => alwaysPickTheseBiomes.includes(b)); if (specialBiomes.length > 0) { - currentBiome = specialBiomes[Utils.randSeedInt(specialBiomes.length)]; + currentBiome = specialBiomes[randSeedInt(specialBiomes.length)]; } else { - currentBiome = biomes[Utils.randSeedInt(biomes.length)]; + currentBiome = biomes[randSeedInt(biomes.length)]; } } } else if (biomeLinks.hasOwnProperty(currentBiome)) { @@ -1167,7 +1160,7 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) { // Otherwise, roll encounter - const roll = Utils.randSeedInt(256); + const roll = randSeedInt(256); validMEfloorsByBiome.set(Biome[currentBiome], (validMEfloorsByBiome.get(Biome[currentBiome]) ?? 0) + 1); // If total number of encounters is lower than expected for the run, slightly favor a new encounter @@ -1192,7 +1185,7 @@ export function calculateMEAggregateStats(baseSpawnWeight: number) { tierWeights[1] = tierWeights[1] - 4 * numEncounters[1]; const totalWeight = tierWeights.reduce((a, b) => a + b); - const tierValue = Utils.randSeedInt(totalWeight); + const tierValue = randSeedInt(totalWeight); const commonThreshold = totalWeight - tierWeights[0]; // 64 - 32 = 32 const uncommonThreshold = totalWeight - tierWeights[0] - tierWeights[1]; // 64 - 32 - 16 = 16 const rareThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2]; // 64 - 32 - 16 - 10 = 6 @@ -1281,7 +1274,7 @@ export function calculateRareSpawnAggregateStats(luckValue: number) { const calculateNumRareEncounters = (): any[] => { const bossEncountersByRarity = [0, 0, 0, 0]; - globalScene.setSeed(Utils.randomString(24)); + globalScene.setSeed(randomString(24)); globalScene.resetSeed(); // There are 12 wild boss floors for (let i = 0; i < 12; i++) { @@ -1291,7 +1284,7 @@ export function calculateRareSpawnAggregateStats(luckValue: number) { if (!Number.isNaN(luckValue)) { luckModifier = luckValue * 0.5; } - const tierValue = Utils.randSeedInt(64 - luckModifier); + const tierValue = randSeedInt(64 - luckModifier); const tier = tierValue >= 20 ? BiomePoolTier.BOSS diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index a4787e819b8..a6a87b4ab9a 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import i18next from "i18next"; -import { isNullOrUndefined, randSeedInt } from "#app/utils"; +import { isNullOrUndefined, randSeedInt } from "#app/utils/common"; import { PokemonHeldItemModifier } from "#app/modifier/modifier"; import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; @@ -14,7 +14,7 @@ import { PlayerGender } from "#enums/player-gender"; import { addPokeballCaptureStars, addPokeballOpenParticles } from "#app/field/anims"; import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect"; import { achvs } from "#app/system/achv"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type { PartyOption } from "#app/ui/party-ui-handler"; import { PartyUiMode } from "#app/ui/party-ui-handler"; import { Species } from "#enums/species"; @@ -714,7 +714,7 @@ export async function catchPokemon( () => { globalScene.pokemonInfoContainer.makeRoomForConfirmUi(1, true); globalScene.ui.setMode( - Mode.CONFIRM, + UiMode.CONFIRM, () => { const newPokemon = globalScene.addPlayerPokemon( pokemon.species, @@ -729,12 +729,12 @@ export async function catchPokemon( pokemon, ); globalScene.ui.setMode( - Mode.SUMMARY, + UiMode.SUMMARY, newPokemon, 0, SummaryUiMode.DEFAULT, () => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { promptRelease(); }); }, @@ -749,13 +749,13 @@ export async function catchPokemon( female: pokemon.gender === Gender.FEMALE, }; globalScene.ui.setOverlayMode( - Mode.POKEDEX_PAGE, + UiMode.POKEDEX_PAGE, pokemon.species, pokemon.formIndex, attributes, null, () => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { promptRelease(); }); }, @@ -763,11 +763,11 @@ export async function catchPokemon( }, () => { globalScene.ui.setMode( - Mode.PARTY, + UiMode.PARTY, PartyUiMode.RELEASE, 0, (slotIndex: number, _option: PartyOption) => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { if (slotIndex < 6) { addToParty(slotIndex); } else { @@ -778,7 +778,7 @@ export async function catchPokemon( ); }, () => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { removePokemon(); end(); }); @@ -1031,9 +1031,6 @@ export function applyAbilityOverrideToPokemon(pokemon: Pokemon, ability: Abiliti } pokemon.fusionCustomPokemonData.ability = ability; } else { - if (!pokemon.customPokemonData) { - pokemon.customPokemonData = new CustomPokemonData(); - } pokemon.customPokemonData.ability = ability; } } diff --git a/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts b/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts index 15085bb2bf8..ebef47eac2d 100644 --- a/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts +++ b/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts @@ -1,5 +1,5 @@ import type { PlayerPokemon } from "#app/field/pokemon"; -import { getFrameMs } from "#app/utils"; +import { getFrameMs } from "#app/utils/common"; import { cos, sin } from "#app/field/anims"; import { getTypeRgb } from "#app/data/type"; import { globalScene } from "#app/global-scene"; @@ -88,7 +88,7 @@ export function doPokemonTransformationSequence( sprite.setPipelineData("shiny", previousPokemon.shiny); sprite.setPipelineData("variant", previousPokemon.variant); ["spriteColors", "fusionSpriteColors"].map(k => { - if (previousPokemon.summonData?.speciesForm) { + if (previousPokemon.summonData.speciesForm) { k += "Base"; } sprite.pipelineData[k] = previousPokemon.getSprite().pipelineData[k]; @@ -108,7 +108,7 @@ export function doPokemonTransformationSequence( sprite.setPipelineData("shiny", transformPokemon.shiny); sprite.setPipelineData("variant", transformPokemon.variant); ["spriteColors", "fusionSpriteColors"].map(k => { - if (transformPokemon.summonData?.speciesForm) { + if (transformPokemon.summonData.speciesForm) { k += "Base"; } sprite.pipelineData[k] = transformPokemon.getSprite().pipelineData[k]; diff --git a/src/data/nature.ts b/src/data/nature.ts index e23d92c14b0..83b3ee7538d 100644 --- a/src/data/nature.ts +++ b/src/data/nature.ts @@ -1,4 +1,4 @@ -import * as Utils from "../utils"; +import { toReadableString } from "#app/utils/common"; import { TextStyle, getBBCodeFrag } from "../ui/text"; import { Nature } from "#enums/nature"; import { UiTheme } from "#enums/ui-theme"; @@ -12,7 +12,7 @@ export function getNatureName( ignoreBBCode = false, uiTheme: UiTheme = UiTheme.DEFAULT, ): string { - let ret = Utils.toReadableString(Nature[nature]); + let ret = toReadableString(Nature[nature]); //Translating nature if (i18next.exists(`nature:${ret}`)) { ret = i18next.t(`nature:${ret}` as any); diff --git a/src/data/pokeball.ts b/src/data/pokeball.ts index b0744237755..7a44ebdda7c 100644 --- a/src/data/pokeball.ts +++ b/src/data/pokeball.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import { CriticalCatchChanceBoosterModifier } from "#app/modifier/modifier"; -import { NumberHolder } from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { PokeballType } from "#enums/pokeball"; import i18next from "i18next"; diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 63e166c7fc4..f76462d2725 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -3,7 +3,7 @@ import type Pokemon from "../field/pokemon"; import { StatusEffect } from "#enums/status-effect"; import { allMoves } from "./moves/move"; import { MoveCategory } from "#enums/MoveCategory"; -import type { Constructor, nil } from "#app/utils"; +import type { Constructor, nil } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 929d632eb0b..59167ba47f6 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -8,7 +8,7 @@ import type { AnySound } from "#app/battle-scene"; import { globalScene } from "#app/global-scene"; import type { GameMode } from "#app/game-mode"; import { DexAttr, type StarterMoveset } from "#app/system/game-data"; -import * as Utils from "#app/utils"; +import { isNullOrUndefined, capitalizeString, randSeedInt, randSeedGauss, randSeedItem } from "#app/utils/common"; import { uncatchableSpecies } from "#app/data/balance/biomes"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { GrowthRate } from "#app/data/exp"; @@ -26,11 +26,14 @@ import { pokemonSpeciesLevelMoves, } from "#app/data/balance/pokemon-level-moves"; import type { Stat } from "#enums/stat"; -import type { Variant, VariantSet } from "#app/data/variant"; -import { variantData } from "#app/data/variant"; +import type { Variant, VariantSet } from "#app/sprites/variant"; +import { populateVariantColorCache, variantColorCache, variantData } from "#app/sprites/variant"; import { speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters"; import { SpeciesFormKey } from "#enums/species-form-key"; import { starterPassiveAbilities } from "#app/data/balance/passives"; +import { loadPokemonVariantAssets } from "#app/sprites/pokemon-sprite"; +import { hasExpSprite } from "#app/sprites/sprite-utils"; +import { Gender } from "./gender"; export enum Region { NORMAL, @@ -289,7 +292,7 @@ export abstract class PokemonSpeciesForm { * @returns The id of the ability */ getPassiveAbility(formIndex?: number): Abilities { - if (Utils.isNullOrUndefined(formIndex)) { + if (isNullOrUndefined(formIndex)) { formIndex = this.formIndex; } let starterSpeciesId = this.speciesId; @@ -387,16 +390,23 @@ export abstract class PokemonSpeciesForm { return `${/_[1-3]$/.test(spriteId) ? "variant/" : ""}${spriteId}`; } - getSpriteId(female: boolean, formIndex?: number, shiny?: boolean, variant = 0, back?: boolean): string { + getBaseSpriteKey(female: boolean, formIndex?: number): string { if (formIndex === undefined || this instanceof PokemonForm) { formIndex = this.formIndex; } const formSpriteKey = this.getFormSpriteKey(formIndex); const showGenderDiffs = - this.genderDiffs && female && ![SpeciesFormKey.MEGA, SpeciesFormKey.GIGANTAMAX].find(k => formSpriteKey === k); + this.genderDiffs && + female && + ![SpeciesFormKey.MEGA, SpeciesFormKey.GIGANTAMAX].includes(formSpriteKey as SpeciesFormKey); - const baseSpriteKey = `${showGenderDiffs ? "female__" : ""}${this.speciesId}${formSpriteKey ? `-${formSpriteKey}` : ""}`; + return `${showGenderDiffs ? "female__" : ""}${this.speciesId}${formSpriteKey ? `-${formSpriteKey}` : ""}`; + } + + /** Compute the sprite ID of the pokemon form. */ + getSpriteId(female: boolean, formIndex?: number, shiny?: boolean, variant = 0, back = false): string { + const baseSpriteKey = this.getBaseSpriteKey(female, formIndex); let config = variantData; `${back ? "back__" : ""}${baseSpriteKey}`.split("__").map(p => (config ? (config = config[p]) : null)); @@ -476,6 +486,7 @@ export abstract class PokemonSpeciesForm { break; case Species.ZACIAN: case Species.ZAMAZENTA: + // biome-ignore lint/suspicious/noFallthroughSwitchClause: Falls through if (formSpriteKey.startsWith("behemoth")) { formSpriteKey = "crowned"; } @@ -585,18 +596,60 @@ export abstract class PokemonSpeciesForm { return true; } - loadAssets( + /** + * Load the variant colors for the species into the variant color cache + * + * @param spriteKey - The sprite key to use + * @param female - Whether to load female instead of male + * @param back - Whether the back sprite is being loaded + * + */ + async loadVariantColors( + spriteKey: string, + female: boolean, + variant: Variant, + back = false, + formIndex?: number, + ): Promise { + let baseSpriteKey = this.getBaseSpriteKey(female, formIndex); + if (back) { + baseSpriteKey = "back__" + baseSpriteKey; + } + + if (variantColorCache.hasOwnProperty(baseSpriteKey)) { + // Variant colors have already been loaded + return; + } + + const variantInfo = variantData[this.getVariantDataIndex(formIndex)]; + // Do nothing if there is no variant information or the variant does not have color replacements + if (!variantInfo || variantInfo[variant] !== 1) { + return; + } + + await populateVariantColorCache( + "pkmn__" + baseSpriteKey, + globalScene.experimentalSprites && hasExpSprite(spriteKey), + baseSpriteKey.replace("__", "/"), + ); + } + + async loadAssets( female: boolean, formIndex?: number, - shiny?: boolean, + shiny = false, variant?: Variant, - startLoad?: boolean, - back?: boolean, + startLoad = false, + back = false, ): Promise { - return new Promise(resolve => { - const spriteKey = this.getSpriteKey(female, formIndex, shiny, variant, back); - globalScene.loadPokemonAtlas(spriteKey, this.getSpriteAtlasPath(female, formIndex, shiny, variant, back)); - globalScene.load.audio(`${this.getCryKey(formIndex)}`, `audio/${this.getCryKey(formIndex)}.m4a`); + // We need to populate the color cache for this species' variant + const spriteKey = this.getSpriteKey(female, formIndex, shiny, variant, back); + globalScene.loadPokemonAtlas(spriteKey, this.getSpriteAtlasPath(female, formIndex, shiny, variant, back)); + globalScene.load.audio(this.getCryKey(formIndex), `audio/${this.getCryKey(formIndex)}.m4a`); + if (!isNullOrUndefined(variant)) { + await this.loadVariantColors(spriteKey, female, variant, back, formIndex); + } + return new Promise(resolve => { globalScene.load.once(Phaser.Loader.Events.COMPLETE, () => { const originalWarn = console.warn; // Ignore warnings for missing frames, because there will be a lot @@ -621,7 +674,9 @@ export abstract class PokemonSpeciesForm { const spritePath = this.getSpriteAtlasPath(female, formIndex, shiny, variant, back) .replace("variant/", "") .replace(/_[1-3]$/, ""); - globalScene.loadPokemonVariantAssets(spriteKey, spritePath, variant).then(() => resolve()); + if (!isNullOrUndefined(variant)) { + loadPokemonVariantAssets(spriteKey, spritePath, variant).then(() => resolve()); + } }); if (startLoad) { if (!globalScene.load.isLoading()) { @@ -695,7 +750,7 @@ export abstract class PokemonSpeciesForm { let paletteColors: Map = new Map(); const originalRandom = Math.random; - Math.random = () => Phaser.Math.RND.realInRange(0, 1); + Math.random = Phaser.Math.RND.frac; globalScene.executeWithSeedOffset( () => { @@ -825,6 +880,21 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali return this.name; } + /** + * Pick and return a random {@linkcode Gender} for a {@linkcode Pokemon}. + * @returns A randomly rolled gender based on this Species' {@linkcode malePercent}. + */ + generateGender(): Gender { + if (isNullOrUndefined(this.malePercent)) { + return Gender.GENDERLESS; + } + + if (Phaser.Math.RND.realInRange(0, 1) <= this.malePercent) { + return Gender.MALE; + } + return Gender.FEMALE; + } + /** * Find the name of species with proper attachments for regionals and separate starter forms (Floette, Ursaluna) * @returns a string with the region name or other form name attached @@ -845,8 +915,8 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali */ getFormNameToDisplay(formIndex = 0, append = false): string { const formKey = this.forms?.[formIndex!]?.formKey; - const formText = Utils.capitalizeString(formKey, "-", false, false) || ""; - const speciesName = Utils.capitalizeString(Species[this.speciesId], "_", true, false); + const formText = capitalizeString(formKey, "-", false, false) || ""; + const speciesName = capitalizeString(Species[this.speciesId], "_", true, false); let ret = ""; const region = this.getRegion(); @@ -877,7 +947,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali if (i18next.exists(i18key)) { ret = i18next.t(i18key); } else { - const rootSpeciesName = Utils.capitalizeString(Species[this.getRootSpeciesId()], "_", true, false); + const rootSpeciesName = capitalizeString(Species[this.getRootSpeciesId()], "_", true, false); const i18RootKey = `pokemonForm:${rootSpeciesName}${formText}`; ret = i18next.exists(i18RootKey) ? i18next.t(i18RootKey) : formText; } @@ -1072,7 +1142,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali return this.speciesId; } - const randValue = evolutionPool.size === 1 ? 0 : Utils.randSeedInt(totalWeight); + const randValue = evolutionPool.size === 1 ? 0 : randSeedInt(totalWeight); for (const weight of evolutionPool.keys()) { if (randValue < weight) { @@ -1157,7 +1227,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali Math.min( Math.max( evolution?.level! + - Math.round(Utils.randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5) - + Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5) - 1, 2, evolution?.level!, @@ -1175,7 +1245,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali Math.min( Math.max( lastPrevolutionLevel + - Math.round(Utils.randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5), + Math.round(randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution?.wildDelay!, 0.5) * 5), lastPrevolutionLevel + 1, evolution?.level!, ), @@ -1360,7 +1430,7 @@ export function getPokerusStarters(): PokemonSpecies[] { globalScene.executeWithSeedOffset( () => { while (pokerusStarters.length < POKERUS_STARTER_COUNT) { - const randomSpeciesId = Number.parseInt(Utils.randSeedItem(Object.keys(speciesStarterCosts)), 10); + const randomSpeciesId = Number.parseInt(randSeedItem(Object.keys(speciesStarterCosts)), 10); const species = getPokemonSpecies(randomSpeciesId); if (!pokerusStarters.includes(species)) { pokerusStarters.push(species); diff --git a/src/data/status-effect.ts b/src/data/status-effect.ts index fe4fa380d46..a90304c9f7d 100644 --- a/src/data/status-effect.ts +++ b/src/data/status-effect.ts @@ -1,4 +1,4 @@ -import { randIntRange } from "#app/utils"; +import { randIntRange } from "#app/utils/common"; import { StatusEffect } from "#enums/status-effect"; import type { ParseKeys } from "i18next"; import i18next from "i18next"; diff --git a/src/data/terrain.ts b/src/data/terrain.ts index 894fb8a7955..5b6063cee68 100644 --- a/src/data/terrain.ts +++ b/src/data/terrain.ts @@ -59,7 +59,7 @@ export class Terrain { // Cancels move if the move has positive priority and targets a Pokemon grounded on the Psychic Terrain return ( move.getPriority(user) > 0 && - user.getOpponents().some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()) + user.getOpponents(true).some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()) ); } } diff --git a/src/data/trainer-names.ts b/src/data/trainer-names.ts index 26cea19070f..8714dad0fc9 100644 --- a/src/data/trainer-names.ts +++ b/src/data/trainer-names.ts @@ -1,12 +1,12 @@ import { TrainerType } from "#enums/trainer-type"; -import * as Utils from "../utils"; +import { toReadableString } from "#app/utils/common"; class TrainerNameConfig { public urls: string[]; public femaleUrls: string[] | null; constructor(type: TrainerType, ...urls: string[]) { - this.urls = urls.length ? urls : [Utils.toReadableString(TrainerType[type]).replace(/ /g, "_")]; + this.urls = urls.length ? urls : [toReadableString(TrainerType[type]).replace(/ /g, "_")]; } hasGenderVariant(...femaleUrls: string[]): TrainerNameConfig { diff --git a/src/data/trainers/TrainerPartyTemplate.ts b/src/data/trainers/TrainerPartyTemplate.ts index adbaacc6b55..1952bcc179e 100644 --- a/src/data/trainers/TrainerPartyTemplate.ts +++ b/src/data/trainers/TrainerPartyTemplate.ts @@ -1,6 +1,8 @@ -import { startingWave } from "#app/battle-scene"; +import { startingWave } from "#app/starting-wave"; import { globalScene } from "#app/global-scene"; import { PartyMemberStrength } from "#enums/party-member-strength"; +import { GameModes } from "#app/game-mode"; +import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves"; export class TrainerPartyTemplate { public size: number; @@ -222,19 +224,18 @@ export const trainerPartyTemplates = { */ export function getEvilGruntPartyTemplate(): TrainerPartyTemplate { const waveIndex = globalScene.currentBattle?.waveIndex; - if (waveIndex < 40) { - return trainerPartyTemplates.TWO_AVG; + switch (waveIndex) { + case ClassicFixedBossWaves.EVIL_GRUNT_1: + return trainerPartyTemplates.TWO_AVG; + case ClassicFixedBossWaves.EVIL_GRUNT_2: + return trainerPartyTemplates.THREE_AVG; + case ClassicFixedBossWaves.EVIL_GRUNT_3: + return trainerPartyTemplates.TWO_AVG_ONE_STRONG; + case ClassicFixedBossWaves.EVIL_ADMIN_1: + return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger + default: + return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger } - if (waveIndex < 63) { - return trainerPartyTemplates.THREE_AVG; - } - if (waveIndex < 65) { - return trainerPartyTemplates.TWO_AVG_ONE_STRONG; - } - if (waveIndex < 112) { - return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger - } - return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger } export function getWavePartyTemplate(...templates: TrainerPartyTemplate[]) { @@ -245,11 +246,36 @@ export function getWavePartyTemplate(...templates: TrainerPartyTemplate[]) { } export function getGymLeaderPartyTemplate() { - return getWavePartyTemplate( - trainerPartyTemplates.GYM_LEADER_1, - trainerPartyTemplates.GYM_LEADER_2, - trainerPartyTemplates.GYM_LEADER_3, - trainerPartyTemplates.GYM_LEADER_4, - trainerPartyTemplates.GYM_LEADER_5, - ); + const { currentBattle, gameMode } = globalScene; + switch (gameMode.modeId) { + case GameModes.DAILY: + if (currentBattle?.waveIndex <= 20) { + return trainerPartyTemplates.GYM_LEADER_2 + } + return trainerPartyTemplates.GYM_LEADER_3; + case GameModes.CHALLENGE: // In the future, there may be a ChallengeType to call here. For now, use classic's. + case GameModes.CLASSIC: + if (currentBattle?.waveIndex <= 20) { + return trainerPartyTemplates.GYM_LEADER_1; // 1 avg 1 strong + } + else if (currentBattle?.waveIndex <= 30) { + return trainerPartyTemplates.GYM_LEADER_2; // 1 avg 1 strong 1 stronger + } + else if (currentBattle?.waveIndex <= 60) { // 50 and 60 + return trainerPartyTemplates.GYM_LEADER_3; // 2 avg 1 strong 1 stronger + } + else if (currentBattle?.waveIndex <= 90) { // 80 and 90 + return trainerPartyTemplates.GYM_LEADER_4; // 3 avg 1 strong 1 stronger + } + // 110+ + return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger + default: + return getWavePartyTemplate( + trainerPartyTemplates.GYM_LEADER_1, + trainerPartyTemplates.GYM_LEADER_2, + trainerPartyTemplates.GYM_LEADER_3, + trainerPartyTemplates.GYM_LEADER_4, + trainerPartyTemplates.GYM_LEADER_5, + ); + } } diff --git a/src/data/trainers/trainer-config.ts b/src/data/trainers/trainer-config.ts index a5ba19290fe..50acf84efa6 100644 --- a/src/data/trainers/trainer-config.ts +++ b/src/data/trainers/trainer-config.ts @@ -1,7 +1,7 @@ import { globalScene } from "#app/global-scene"; import { modifierTypes } from "#app/modifier/modifier-type"; import { PokemonMove } from "#app/field/pokemon"; -import * as Utils from "#app/utils"; +import { toReadableString, isNullOrUndefined, randSeedItem, randSeedInt } from "#app/utils/common"; import { pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { tmSpecies } from "#app/data/balance/tms"; @@ -116,7 +116,6 @@ export class TrainerConfig { public modifierRewardFuncs: ModifierTypeFunc[] = []; public partyTemplates: TrainerPartyTemplate[]; public partyTemplateFunc: PartyTemplateFunc; - public eventRewardFuncs: ModifierTypeFunc[] = []; public partyMemberFuncs: PartyMemberFuncs = {}; public speciesPools: TrainerTierPools; public speciesFilter: PokemonSpeciesFilter; @@ -139,7 +138,7 @@ export class TrainerConfig { constructor(trainerType: TrainerType, allowLegendaries?: boolean) { this.trainerType = trainerType; this.trainerAI = new TrainerAI(); - this.name = Utils.toReadableString(TrainerType[this.getDerivedType()]); + this.name = toReadableString(TrainerType[this.getDerivedType()]); this.battleBgm = "battle_trainer"; this.mixedBattleBgm = "battle_trainer"; this.victoryBgm = "victory_trainer"; @@ -482,10 +481,10 @@ export class TrainerConfig { .fill(null) .map((_, i) => i) .filter(i => shedinjaCanTera || party[i].species.speciesId !== Species.SHEDINJA); // Shedinja can only Tera on Bug specialty type (or no specialty type) - const setPartySlot = !Utils.isNullOrUndefined(slot) ? Phaser.Math.Wrap(slot, 0, party.length) : -1; // If we have a tera slot defined, wrap it to party size. + const setPartySlot = !isNullOrUndefined(slot) ? Phaser.Math.Wrap(slot, 0, party.length) : -1; // If we have a tera slot defined, wrap it to party size. for (let t = 0; t < Math.min(count(), party.length); t++) { const randomIndex = - partyMemberIndexes.indexOf(setPartySlot) > -1 ? setPartySlot : Utils.randSeedItem(partyMemberIndexes); + partyMemberIndexes.indexOf(setPartySlot) > -1 ? setPartySlot : randSeedItem(partyMemberIndexes); partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1); if (this.hasSpecialtyType()) { party[randomIndex].teraType = this.specialtyType; @@ -517,16 +516,6 @@ export class TrainerConfig { // return ret; // } - /** - * Sets eventRewardFuncs to the active event rewards for the specified wave - * @param wave Associated with {@linkcode getFixedBattleEventRewards} - * @returns this - */ - setEventModifierRewardFuncs(wave: number): TrainerConfig { - this.eventRewardFuncs = timedEventManager.getFixedBattleEventRewards(wave).map(r => modifierTypes[r]); - return this; - } - setModifierRewardFuncs(...modifierTypeFuncs: (() => ModifierTypeFunc)[]): TrainerConfig { this.modifierRewardFuncs = modifierTypeFuncs.map(func => () => { const modifierTypeFunc = func(); @@ -555,7 +544,7 @@ export class TrainerConfig { initI18n(); } - if (!Utils.isNullOrUndefined(specialtyType)) { + if (!isNullOrUndefined(specialtyType)) { this.setSpecialtyType(specialtyType); } @@ -636,7 +625,7 @@ export class TrainerConfig { } this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); }); - if (!Utils.isNullOrUndefined(specialtyType)) { + if (!isNullOrUndefined(specialtyType)) { this.setSpeciesFilter(p => p.isOfType(specialtyType)); this.setSpecialtyType(specialtyType); } @@ -718,11 +707,11 @@ export class TrainerConfig { /** * Initializes the trainer configuration for an Elite Four member. - * @param {Species | Species[]} signatureSpecies The signature species for the Elite Four member. - * @param isMale Whether the Elite Four Member is Male or Female (for localization of the title). - * @param specialtyType {PokemonType} The specialty type for the Elite Four member. - * @param teraSlot Optional, sets the party member in this slot to Terastallize. - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @param signatureSpecies - The signature species for the Elite Four member. + * @param isMale - Whether the Elite Four Member is Male or Female (for localization of the title). + * @param specialtyType - The specialty type for the Elite Four member. + * @param teraSlot - Optional, sets the party member in this slot to Terastallize. + * @returns The updated TrainerConfig instance. **/ initForEliteFour( signatureSpecies: (Species | Species[])[], @@ -749,7 +738,7 @@ export class TrainerConfig { }); // Set species filter and specialty type if provided, otherwise filter by base total. - if (!Utils.isNullOrUndefined(specialtyType)) { + if (!isNullOrUndefined(specialtyType)) { this.setSpeciesFilter(p => p.isOfType(specialtyType) && p.baseTotal >= ELITE_FOUR_MINIMUM_BST); this.setSpecialtyType(specialtyType); } else { @@ -927,7 +916,7 @@ export class TrainerConfig { * @returns true if specialtyType is defined and not Type.UNKNOWN */ hasSpecialtyType(): boolean { - return !Utils.isNullOrUndefined(this.specialtyType) && this.specialtyType !== PokemonType.UNKNOWN; + return !isNullOrUndefined(this.specialtyType) && this.specialtyType !== PokemonType.UNKNOWN; } /** @@ -1006,7 +995,7 @@ export function getRandomPartyMemberFunc( postProcess?: (enemyPokemon: EnemyPokemon) => void, ) { return (level: number, strength: PartyMemberStrength) => { - let species = Utils.randSeedItem(speciesPool); + let species = randSeedItem(speciesPool); if (!ignoreEvolution) { species = getPokemonSpecies(species).getTrainerSpeciesForLevel( level, @@ -1329,7 +1318,16 @@ export const trainerConfigs: TrainerConfigs = { [TrainerPoolTier.RARE]: [Species.BELLOSSOM, Species.HITMONTOP, Species.MIME_JR, Species.ORICORIO], [TrainerPoolTier.SUPER_RARE]: [Species.QUAXLY, Species.JANGMO_O], }), - [TrainerType.DEPOT_AGENT]: new TrainerConfig(++t).setMoneyMultiplier(1.45).setEncounterBgm(TrainerType.CLERK), + [TrainerType.DEPOT_AGENT]: new TrainerConfig(++t) + .setMoneyMultiplier(1.45) + .setEncounterBgm(TrainerType.CLERK) + .setPartyTemplates( + trainerPartyTemplates.TWO_AVG, + trainerPartyTemplates.THREE_WEAK, + trainerPartyTemplates.THREE_AVG, + trainerPartyTemplates.FOUR_WEAK, + ) + .setSpeciesFilter(s => s.isOfType(PokemonType.GROUND)), [TrainerType.DOCTOR]: new TrainerConfig(++t) .setHasGenders("Nurse", "lass") .setHasDouble("Medical Team") @@ -1380,7 +1378,6 @@ export const trainerConfigs: TrainerConfigs = { Species.CHINCHOU, Species.CORSOLA, Species.WAILMER, - Species.BARBOACH, Species.CLAMPERL, Species.LUVDISC, Species.MANTYKE, @@ -2236,12 +2233,7 @@ export const trainerConfigs: TrainerConfigs = { Species.PHANTUMP, Species.PUMPKABOO, ], - [TrainerPoolTier.RARE]: [ - Species.SNEASEL, - Species.LITWICK, - Species.PAWNIARD, - Species.NOIBAT, - ], + [TrainerPoolTier.RARE]: [Species.SNEASEL, Species.LITWICK, Species.PAWNIARD, Species.NOIBAT], [TrainerPoolTier.SUPER_RARE]: [Species.SLIGGOO, Species.HISUI_SLIGGOO, Species.HISUI_AVALUGG], }), [TrainerType.BRYONY]: new TrainerConfig(++t) @@ -2587,252 +2579,252 @@ export const trainerConfigs: TrainerConfigs = { ), [TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)) - .initForGymLeader(signatureSpecies["BROCK"], true, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["BROCK"], true, PokemonType.ROCK, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.MISTY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MISTY"], false, PokemonType.WATER) + .initForGymLeader(signatureSpecies["MISTY"], false, PokemonType.WATER, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.LT_SURGE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["LT_SURGE"], true, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["LT_SURGE"], true, PokemonType.ELECTRIC, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.ERIKA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ERIKA"], false, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["ERIKA"], false, PokemonType.GRASS, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.JANINE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["JANINE"], false, PokemonType.POISON) + .initForGymLeader(signatureSpecies["JANINE"], false, PokemonType.POISON, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.SABRINA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["SABRINA"], false, PokemonType.PSYCHIC) + .initForGymLeader(signatureSpecies["SABRINA"], false, PokemonType.PSYCHIC, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.BLAINE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BLAINE"], true, PokemonType.FIRE) + .initForGymLeader(signatureSpecies["BLAINE"], true, PokemonType.FIRE, false, -1) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.GIOVANNI]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["GIOVANNI"], true, PokemonType.DARK) + .initForGymLeader(signatureSpecies["GIOVANNI"], true, PokemonType.GROUND, false, -2) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym"), [TrainerType.FALKNER]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["FALKNER"], true, PokemonType.FLYING) + .initForGymLeader(signatureSpecies["FALKNER"], true, PokemonType.FLYING, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.BUGSY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BUGSY"], true, PokemonType.BUG) + .initForGymLeader(signatureSpecies["BUGSY"], true, PokemonType.BUG, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.WHITNEY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["WHITNEY"], false, PokemonType.NORMAL) + .initForGymLeader(signatureSpecies["WHITNEY"], false, PokemonType.NORMAL, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.MORTY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MORTY"], true, PokemonType.GHOST) + .initForGymLeader(signatureSpecies["MORTY"], true, PokemonType.GHOST, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.CHUCK]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CHUCK"], true, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["CHUCK"], true, PokemonType.FIGHTING, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.JASMINE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["JASMINE"], false, PokemonType.STEEL) + .initForGymLeader(signatureSpecies["JASMINE"], false, PokemonType.STEEL, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.PRYCE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["PRYCE"], true, PokemonType.ICE) + .initForGymLeader(signatureSpecies["PRYCE"], true, PokemonType.ICE, false, -1) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.CLAIR]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CLAIR"], false, PokemonType.DRAGON) + .initForGymLeader(signatureSpecies["CLAIR"], false, PokemonType.DRAGON, false, -3) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym"), [TrainerType.ROXANNE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ROXANNE"], false, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["ROXANNE"], false, PokemonType.ROCK, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.BRAWLY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BRAWLY"], true, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["BRAWLY"], true, PokemonType.FIGHTING, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.WATTSON]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["WATTSON"], true, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["WATTSON"], true, PokemonType.ELECTRIC, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.FLANNERY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["FLANNERY"], false, PokemonType.FIRE) + .initForGymLeader(signatureSpecies["FLANNERY"], false, PokemonType.FIRE, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.NORMAN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["NORMAN"], true, PokemonType.NORMAL) + .initForGymLeader(signatureSpecies["NORMAN"], true, PokemonType.NORMAL, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.WINONA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["WINONA"], false, PokemonType.FLYING) + .initForGymLeader(signatureSpecies["WINONA"], false, PokemonType.FLYING, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.TATE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["TATE"], true, PokemonType.PSYCHIC) + .initForGymLeader(signatureSpecies["TATE"], true, PokemonType.PSYCHIC, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym") .setHasDouble("tate_liza_double") .setDoubleTrainerType(TrainerType.LIZA) .setDoubleTitle("gym_leader_double"), [TrainerType.LIZA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["LIZA"], false, PokemonType.PSYCHIC) + .initForGymLeader(signatureSpecies["LIZA"], false, PokemonType.PSYCHIC, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym") .setHasDouble("liza_tate_double") .setDoubleTrainerType(TrainerType.TATE) .setDoubleTitle("gym_leader_double"), [TrainerType.JUAN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["JUAN"], true, PokemonType.WATER) + .initForGymLeader(signatureSpecies["JUAN"], true, PokemonType.WATER, false, -1) .setBattleBgm("battle_hoenn_gym") .setMixedBattleBgm("battle_hoenn_gym"), [TrainerType.ROARK]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ROARK"], true, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["ROARK"], true, PokemonType.ROCK, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.GARDENIA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["GARDENIA"], false, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["GARDENIA"], false, PokemonType.GRASS, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.MAYLENE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MAYLENE"], false, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["MAYLENE"], false, PokemonType.FIGHTING, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.CRASHER_WAKE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CRASHER_WAKE"], true, PokemonType.WATER) + .initForGymLeader(signatureSpecies["CRASHER_WAKE"], true, PokemonType.WATER, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.FANTINA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["FANTINA"], false, PokemonType.GHOST) + .initForGymLeader(signatureSpecies["FANTINA"], false, PokemonType.GHOST, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.BYRON]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BYRON"], true, PokemonType.STEEL) + .initForGymLeader(signatureSpecies["BYRON"], true, PokemonType.STEEL, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.CANDICE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CANDICE"], false, PokemonType.ICE) + .initForGymLeader(signatureSpecies["CANDICE"], false, PokemonType.ICE, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.VOLKNER]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["VOLKNER"], true, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["VOLKNER"], true, PokemonType.ELECTRIC, false, -1) .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym"), [TrainerType.CILAN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CILAN"], true, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["CILAN"], true, PokemonType.GRASS, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.CHILI]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CHILI"], true, PokemonType.FIRE) + .initForGymLeader(signatureSpecies["CHILI"], true, PokemonType.FIRE, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.CRESS]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CRESS"], true, PokemonType.WATER) + .initForGymLeader(signatureSpecies["CRESS"], true, PokemonType.WATER, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.CHEREN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CHEREN"], true, PokemonType.NORMAL) + .initForGymLeader(signatureSpecies["CHEREN"], true, PokemonType.NORMAL, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.LENORA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["LENORA"], false, PokemonType.NORMAL) + .initForGymLeader(signatureSpecies["LENORA"], false, PokemonType.NORMAL, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.ROXIE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ROXIE"], false, PokemonType.POISON) + .initForGymLeader(signatureSpecies["ROXIE"], false, PokemonType.POISON, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.BURGH]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BURGH"], true, PokemonType.BUG) + .initForGymLeader(signatureSpecies["BURGH"], true, PokemonType.BUG, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.ELESA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["ELESA"], false, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["ELESA"], false, PokemonType.ELECTRIC, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.CLAY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CLAY"], true, PokemonType.GROUND) + .initForGymLeader(signatureSpecies["CLAY"], true, PokemonType.GROUND, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.SKYLA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["SKYLA"], false, PokemonType.FLYING) + .initForGymLeader(signatureSpecies["SKYLA"], false, PokemonType.FLYING, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.BRYCEN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BRYCEN"], true, PokemonType.ICE) + .initForGymLeader(signatureSpecies["BRYCEN"], true, PokemonType.ICE, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.DRAYDEN]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["DRAYDEN"], true, PokemonType.DRAGON) + .initForGymLeader(signatureSpecies["DRAYDEN"], true, PokemonType.DRAGON, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.MARLON]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MARLON"], true, PokemonType.WATER) + .initForGymLeader(signatureSpecies["MARLON"], true, PokemonType.WATER, false, -1) .setMixedBattleBgm("battle_unova_gym"), [TrainerType.VIOLA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["VIOLA"], false, PokemonType.BUG) + .initForGymLeader(signatureSpecies["VIOLA"], false, PokemonType.BUG, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.GRANT]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["GRANT"], true, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["GRANT"], true, PokemonType.ROCK, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.KORRINA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["KORRINA"], false, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["KORRINA"], false, PokemonType.FIGHTING, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.RAMOS]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["RAMOS"], true, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["RAMOS"], true, PokemonType.GRASS, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.CLEMONT]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["CLEMONT"], true, PokemonType.ELECTRIC) + .initForGymLeader(signatureSpecies["CLEMONT"], true, PokemonType.ELECTRIC, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.VALERIE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["VALERIE"], false, PokemonType.FAIRY) + .initForGymLeader(signatureSpecies["VALERIE"], false, PokemonType.FAIRY, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.OLYMPIA]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["OLYMPIA"], false, PokemonType.PSYCHIC) + .initForGymLeader(signatureSpecies["OLYMPIA"], false, PokemonType.PSYCHIC, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.WULFRIC]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["WULFRIC"], true, PokemonType.ICE) + .initForGymLeader(signatureSpecies["WULFRIC"], true, PokemonType.ICE, false, -1) .setMixedBattleBgm("battle_kalos_gym"), [TrainerType.MILO]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MILO"], true, PokemonType.GRASS) + .initForGymLeader(signatureSpecies["MILO"], true, PokemonType.GRASS, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.NESSA]: new TrainerConfig(++t) .setName("Nessa") - .initForGymLeader(signatureSpecies["NESSA"], false, PokemonType.WATER) + .initForGymLeader(signatureSpecies["NESSA"], false, PokemonType.WATER, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.KABU]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["KABU"], true, PokemonType.FIRE) + .initForGymLeader(signatureSpecies["KABU"], true, PokemonType.FIRE, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.BEA]: new TrainerConfig(++t) .setName("Bea") - .initForGymLeader(signatureSpecies["BEA"], false, PokemonType.FIGHTING) + .initForGymLeader(signatureSpecies["BEA"], false, PokemonType.FIGHTING, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.ALLISTER]: new TrainerConfig(++t) .setName("Allister") - .initForGymLeader(signatureSpecies["ALLISTER"], true, PokemonType.GHOST) + .initForGymLeader(signatureSpecies["ALLISTER"], true, PokemonType.GHOST, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.OPAL]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["OPAL"], false, PokemonType.FAIRY) + .initForGymLeader(signatureSpecies["OPAL"], false, PokemonType.FAIRY, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.BEDE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["BEDE"], true, PokemonType.FAIRY) + .initForGymLeader(signatureSpecies["BEDE"], true, PokemonType.FAIRY, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.GORDIE]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["GORDIE"], true, PokemonType.ROCK) + .initForGymLeader(signatureSpecies["GORDIE"], true, PokemonType.ROCK, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.MELONY]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["MELONY"], false, PokemonType.ICE) + .initForGymLeader(signatureSpecies["MELONY"], false, PokemonType.ICE, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.PIERS]: new TrainerConfig(++t) - .initForGymLeader(signatureSpecies["PIERS"], true, PokemonType.DARK) + .initForGymLeader(signatureSpecies["PIERS"], true, PokemonType.DARK, false, -3) .setHasDouble("piers_marnie_double") .setDoubleTrainerType(TrainerType.MARNIE) .setDoubleTitle("gym_leader_double") .setMixedBattleBgm("battle_galar_gym"), [TrainerType.MARNIE]: new TrainerConfig(++t) .setName("Marnie") - .initForGymLeader(signatureSpecies["MARNIE"], false, PokemonType.DARK) + .initForGymLeader(signatureSpecies["MARNIE"], false, PokemonType.DARK, false, -4) .setHasDouble("marnie_piers_double") .setDoubleTrainerType(TrainerType.PIERS) .setDoubleTitle("gym_leader_double") .setMixedBattleBgm("battle_galar_gym"), [TrainerType.RAIHAN]: new TrainerConfig(++t) .setName("Raihan") - .initForGymLeader(signatureSpecies["RAIHAN"], true, PokemonType.DRAGON) + .initForGymLeader(signatureSpecies["RAIHAN"], true, PokemonType.DRAGON, false, -1) .setMixedBattleBgm("battle_galar_gym"), [TrainerType.KATY]: new TrainerConfig(++t) .initForGymLeader(signatureSpecies["KATY"], false, PokemonType.BUG, true, -1) @@ -2861,146 +2853,688 @@ export const trainerConfigs: TrainerConfigs = { .setMixedBattleBgm("battle_paldea_gym"), [TrainerType.LORELEI]: new TrainerConfig((t = TrainerType.LORELEI)) - .initForEliteFour(signatureSpecies["LORELEI"], false, PokemonType.ICE) + .initForEliteFour(signatureSpecies["LORELEI"], false, PokemonType.ICE, 2) .setBattleBgm("battle_kanto_gym") - .setMixedBattleBgm("battle_kanto_gym"), + .setMixedBattleBgm("battle_kanto_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DEWGONG], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 0; // Thick Fat + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SLOWBRO, Species.GALAR_SLOWBRO], TrainerSlot.TRAINER, true, p => { // Tera Ice Slowbro/G-Slowbro + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.ICE_BEAM)) { // Check if Ice Beam is in the moveset, if not, replace the third move with Ice Beam. + p.moveset[2] = new PokemonMove(Moves.ICE_BEAM); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.JYNX])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CLOYSTER, Species.ALOLA_SANDSLASH])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.LAPRAS], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.BRUNO]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["BRUNO"], true, PokemonType.FIGHTING) + .initForEliteFour(signatureSpecies["BRUNO"], true, PokemonType.FIGHTING, 2) .setBattleBgm("battle_kanto_gym") - .setMixedBattleBgm("battle_kanto_gym"), + .setMixedBattleBgm("battle_kanto_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.HITMONLEE, Species.HITMONCHAN, Species.HITMONTOP])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.STEELIX], TrainerSlot.TRAINER, true, p => { // Tera Fighting Steelix + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.BODY_PRESS)) { // Check if Body Press is in the moveset, if not, replace the third move with Body Press. + p.moveset[2] = new PokemonMove(Moves.BODY_PRESS); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.POLIWRATH])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ANNIHILAPE])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.MACHAMP], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.AGATHA]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["AGATHA"], false, PokemonType.GHOST) + .initForEliteFour(signatureSpecies["AGATHA"], false, PokemonType.GHOST, 2) .setBattleBgm("battle_kanto_gym") - .setMixedBattleBgm("battle_kanto_gym"), + .setMixedBattleBgm("battle_kanto_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.MISMAGIUS])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.ARBOK, Species.WEEZING], TrainerSlot.TRAINER, true, p => { // Tera Ghost Arbok/Weezing + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TERA_BLAST)) { // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. + p.moveset[2] = new PokemonMove(Moves.TERA_BLAST); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.ALOLA_MAROWAK])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CURSOLA])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GENGAR], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.LANCE]: new TrainerConfig(++t) .setName("Lance") - .initForEliteFour(signatureSpecies["LANCE"], true, PokemonType.DRAGON) + .initForEliteFour(signatureSpecies["LANCE"], true, PokemonType.DRAGON, 2) .setBattleBgm("battle_kanto_gym") - .setMixedBattleBgm("battle_kanto_gym"), + .setMixedBattleBgm("battle_kanto_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.KINGDRA])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.GYARADOS, Species.AERODACTYL], TrainerSlot.TRAINER, true, p => { // Tera Dragon Gyarados/Aerodactyl + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TERA_BLAST)) { // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. + p.moveset[2] = new PokemonMove(Moves.TERA_BLAST); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.ALOLA_EXEGGUTOR])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SALAMENCE])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.DRAGONITE], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.WILL]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["WILL"], true, PokemonType.PSYCHIC) + .initForEliteFour(signatureSpecies["WILL"], true, PokemonType.PSYCHIC, 2) .setBattleBgm("battle_johto_gym") - .setMixedBattleBgm("battle_johto_gym"), + .setMixedBattleBgm("battle_johto_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.JYNX])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SLOWKING, Species.GALAR_SLOWKING])) // Tera Psychic Slowking/G-Slowking + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.EXEGGUTOR])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.WYRDEER, Species.FARIGIRAF])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.XATU], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.KOGA]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["KOGA"], true, PokemonType.POISON) + .initForEliteFour(signatureSpecies["KOGA"], true, PokemonType.POISON, 2) .setBattleBgm("battle_johto_gym") - .setMixedBattleBgm("battle_johto_gym"), + .setMixedBattleBgm("battle_johto_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.VENOMOTH], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Tinted Lens + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.MUK, Species.WEEZING])) // Tera Poison Muk/Weezing + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.TENTACRUEL])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SNEASLER, Species.OVERQWIL])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.CROBAT], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.KAREN]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["KAREN"], false, PokemonType.DARK) + .initForEliteFour(signatureSpecies["KAREN"], false, PokemonType.DARK, 2) .setBattleBgm("battle_johto_gym") - .setMixedBattleBgm("battle_johto_gym"), + .setMixedBattleBgm("battle_johto_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.UMBREON])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.GENGAR], TrainerSlot.TRAINER, true, p => { // Tera Dark Gengar + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.DARK_PULSE)) { // Check if Dark Pulse is in the moveset, if not, replace the third move with Dark Pulse. + p.moveset[2] = new PokemonMove(Moves.DARK_PULSE); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.HONCHKROW])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.WEAVILE])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.HOUNDOOM], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.SIDNEY]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["SIDNEY"], true, PokemonType.DARK) - .setMixedBattleBgm("battle_hoenn_elite"), + .initForEliteFour(signatureSpecies["SIDNEY"], true, PokemonType.DARK, 2) + .setMixedBattleBgm("battle_hoenn_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.MIGHTYENA], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 0; // Intimidate + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.OBSTAGOON])) // Tera Dark Obstagoon + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.SHIFTRY, Species.CACTURNE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SHARPEDO, Species.CRAWDAUNT])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.ABSOL], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.PHOEBE]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["PHOEBE"], false, PokemonType.GHOST) - .setMixedBattleBgm("battle_hoenn_elite"), + .initForEliteFour(signatureSpecies["PHOEBE"], false, PokemonType.GHOST, 2) + .setMixedBattleBgm("battle_hoenn_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SABLEYE])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.BANETTE])) // Tera Ghost Banette + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.DRIFBLIM, Species.MISMAGIUS])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ORICORIO, Species.ALOLA_MAROWAK], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.formIndex = p.species.speciesId === Species.ORICORIO ? 3 : 0; // Oricorio-Sensu + }), + ) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.DUSKNOIR], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.GLACIA]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["GLACIA"], false, PokemonType.ICE) - .setMixedBattleBgm("battle_hoenn_elite"), + .initForEliteFour(signatureSpecies["GLACIA"], false, PokemonType.ICE, 2) + .setMixedBattleBgm("battle_hoenn_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ABOMASNOW], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 0; // Snow Warning + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.GLALIE])) // Tera Ice Glalie + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.FROSLASS])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ALOLA_NINETALES])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.WALREIN], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.DRAKE]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["DRAKE"], true, PokemonType.DRAGON) - .setMixedBattleBgm("battle_hoenn_elite"), + .initForEliteFour(signatureSpecies["DRAKE"], true, PokemonType.DRAGON, 2) + .setMixedBattleBgm("battle_hoenn_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ALTARIA])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.DHELMISE], TrainerSlot.TRAINER, true, p => { // Tera Dragon Dhelmise + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TERA_BLAST)) { // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. + p.moveset[2] = new PokemonMove(Moves.TERA_BLAST); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.FLYGON])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.KINGDRA])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.SALAMENCE], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.AARON]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["AARON"], true, PokemonType.BUG) + .initForEliteFour(signatureSpecies["AARON"], true, PokemonType.BUG, 5) .setBattleBgm("battle_sinnoh_gym") - .setMixedBattleBgm("battle_sinnoh_gym"), + .setMixedBattleBgm("battle_sinnoh_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.YANMEGA])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.HERACROSS])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.VESPIQUEN])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SCIZOR, Species.KLEAVOR])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.DRAPION], TrainerSlot.TRAINER, true, p => { // Tera Bug Drapion + p.setBoss(true, 2); + p.abilityIndex = 1; // Sniper + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.X_SCISSOR)) { // Check if X-Scissor is in the moveset, if not, replace the third move with X-Scissor. + p.moveset[2] = new PokemonMove(Moves.X_SCISSOR); + } + }), + ), [TrainerType.BERTHA]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["BERTHA"], false, PokemonType.GROUND) + .initForEliteFour(signatureSpecies["BERTHA"], false, PokemonType.GROUND, 2) .setBattleBgm("battle_sinnoh_gym") - .setMixedBattleBgm("battle_sinnoh_gym"), + .setMixedBattleBgm("battle_sinnoh_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.WHISCASH])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.HIPPOWDON], TrainerSlot.TRAINER, true, p => { // Tera Ground Hippowdon + p.abilityIndex = 0; // Sand Stream + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GLISCOR])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.MAMOSWINE, Species.URSALUNA])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.RHYPERIOR], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.abilityIndex = 1; // Solid Rock + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.FLINT]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["FLINT"], true, PokemonType.FIRE, 3) + .initForEliteFour(signatureSpecies["FLINT"], true, PokemonType.FIRE, 2) .setBattleBgm("battle_sinnoh_gym") - .setMixedBattleBgm("battle_sinnoh_gym"), + .setMixedBattleBgm("battle_sinnoh_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.RAPIDASH])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.STEELIX, Species.LOPUNNY], TrainerSlot.TRAINER, true, p => { // Tera Fire Steelix/Lopunny + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TERA_BLAST)) { // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. + p.moveset[2] = new PokemonMove(Moves.TERA_BLAST); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.INFERNAPE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ARCANINE, Species.HISUI_ARCANINE])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.MAGMORTAR], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.LUCIAN]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["LUCIAN"], true, PokemonType.PSYCHIC) + .initForEliteFour(signatureSpecies["LUCIAN"], true, PokemonType.PSYCHIC, 2) .setBattleBgm("battle_sinnoh_gym") - .setMixedBattleBgm("battle_sinnoh_gym"), + .setMixedBattleBgm("battle_sinnoh_gym") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ESPEON, Species.ALAKAZAM])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.FARIGIRAF])) // Tera Psychic Farigiraf + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.BRONZONG])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.MR_RIME, Species.HISUI_BRAVIARY])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GALLADE], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.abilityIndex = 1; // Sharpness + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.SHAUNTAL]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["SHAUNTAL"], false, PokemonType.GHOST) - .setMixedBattleBgm("battle_unova_elite"), + .initForEliteFour(signatureSpecies["SHAUNTAL"], false, PokemonType.GHOST, 2) + .setMixedBattleBgm("battle_unova_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.COFAGRIGUS])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.GOLURK])) // Tera Ghost Golurk + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.JELLICENT])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.MISMAGIUS, Species.FROSLASS ])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.CHANDELURE], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.MARSHAL]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["MARSHAL"], true, PokemonType.FIGHTING) - .setMixedBattleBgm("battle_unova_elite"), + .initForEliteFour(signatureSpecies["MARSHAL"], true, PokemonType.FIGHTING, 2) + .setMixedBattleBgm("battle_unova_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.THROH, Species.SAWK])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.MIENSHAO])) // Tera Fighting Mienshao + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.EMBOAR])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.BRELOOM, Species.TOXICROAK])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.CONKELDURR], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.GRIMSLEY]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["GRIMSLEY"], true, PokemonType.DARK) - .setMixedBattleBgm("battle_unova_elite"), + .initForEliteFour(signatureSpecies["GRIMSLEY"], true, PokemonType.DARK, 2) + .setMixedBattleBgm("battle_unova_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.LIEPARD])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.KROOKODILE])) // Tera Dark Krookodile + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.SCRAFTY])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ZOROARK, Species.HISUI_SAMUROTT])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.KINGAMBIT], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.CAITLIN]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["CAITLIN"], false, PokemonType.PSYCHIC) - .setMixedBattleBgm("battle_unova_elite"), + .initForEliteFour(signatureSpecies["CAITLIN"], false, PokemonType.PSYCHIC, 2) + .setMixedBattleBgm("battle_unova_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.MUSHARNA])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.REUNICLUS])) // Tera Psychic Reuniclus + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GALLADE], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Sharpness + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SIGILYPH, Species.HISUI_BRAVIARY])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.GOTHITELLE], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.MALVA]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["MALVA"], false, PokemonType.FIRE) - .setMixedBattleBgm("battle_kalos_elite"), + .initForEliteFour(signatureSpecies["MALVA"], false, PokemonType.FIRE, 2) + .setMixedBattleBgm("battle_kalos_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PYROAR], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.gender = Gender.FEMALE; + }), + ) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.HOUNDOOM])) // Tera Fire Houndoom + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.TORKOAL], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Drought + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CHANDELURE, Species.DELPHOX])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.TALONFLAME], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.SIEBOLD]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["SIEBOLD"], true, PokemonType.WATER) - .setMixedBattleBgm("battle_kalos_elite"), + .initForEliteFour(signatureSpecies["SIEBOLD"], true, PokemonType.WATER, 2) + .setMixedBattleBgm("battle_kalos_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.CLAWITZER])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.GYARADOS])) // Tera Water Gyarados + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.STARMIE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.BLASTOISE, Species.DONDOZO])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.BARBARACLE], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.abilityIndex = 1; // Tough Claws + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.WIKSTROM]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["WIKSTROM"], true, PokemonType.STEEL) - .setMixedBattleBgm("battle_kalos_elite"), + .initForEliteFour(signatureSpecies["WIKSTROM"], true, PokemonType.STEEL, 2) + .setMixedBattleBgm("battle_kalos_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.KLEFKI])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.CERULEDGE], TrainerSlot.TRAINER, true, p => { // Tera Steel Ceruledge + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.IRON_HEAD)) { // Check if Iron Head is in the moveset, if not, replace the third move with Iron Head. + p.moveset[2] = new PokemonMove(Moves.IRON_HEAD); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.SCIZOR])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CORVIKNIGHT])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.AEGISLASH], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.DRASNA]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["DRASNA"], false, PokemonType.DRAGON) - .setMixedBattleBgm("battle_kalos_elite"), + .initForEliteFour(signatureSpecies["DRASNA"], false, PokemonType.DRAGON, 2) + .setMixedBattleBgm("battle_kalos_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DRAGALGE])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.GARCHOMP])) // Tera Dragon Garchomp + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.ALTARIA])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.DRUDDIGON])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.NOIVERN], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.HALA]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["HALA"], true, PokemonType.FIGHTING) - .setMixedBattleBgm("battle_alola_elite"), + .initForEliteFour(signatureSpecies["HALA"], true, PokemonType.FIGHTING, 2) + .setMixedBattleBgm("battle_alola_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.HARIYAMA])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.INCINEROAR], TrainerSlot.TRAINER, true, p => { // Tera Fighting Incineroar + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.CROSS_CHOP)) { // Check if Cross Chop is in the moveset, if not, replace the third move with Cross Chop. + p.moveset[2] = new PokemonMove(Moves.CROSS_CHOP); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.BEWEAR])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.POLIWRATH, Species.ANNIHILAPE])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.CRABOMINABLE], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.MOLAYNE]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["MOLAYNE"], true, PokemonType.STEEL) - .setMixedBattleBgm("battle_alola_elite"), + .initForEliteFour(signatureSpecies["MOLAYNE"], true, PokemonType.STEEL, 2) + .setMixedBattleBgm("battle_alola_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.KLEFKI])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.ALOLA_SANDSLASH])) // Tera Steel A-Sandslash + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.MAGNEZONE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.METAGROSS, Species.KINGAMBIT])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.ALOLA_DUGTRIO], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.OLIVIA]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["OLIVIA"], false, PokemonType.ROCK) - .setMixedBattleBgm("battle_alola_elite"), + .initForEliteFour(signatureSpecies["OLIVIA"], false, PokemonType.ROCK, 2) + .setMixedBattleBgm("battle_alola_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GIGALITH], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Sand Stream + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.PROBOPASS])) // Tera Rock Probopass + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.ALOLA_GOLEM])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.RELICANTH, Species.CARBINK])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.LYCANROC], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.formIndex = 1; + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.ACEROLA]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["ACEROLA"], false, PokemonType.GHOST) - .setMixedBattleBgm("battle_alola_elite"), + .initForEliteFour(signatureSpecies["ACEROLA"], false, PokemonType.GHOST, 2) + .setMixedBattleBgm("battle_alola_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DRIFBLIM])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.MIMIKYU])) // Tera Ghost Mimikyu + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.DHELMISE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.FROSLASS])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.PALOSSAND], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.KAHILI]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["KAHILI"], false, PokemonType.FLYING) - .setMixedBattleBgm("battle_alola_elite"), + .initForEliteFour(signatureSpecies["KAHILI"], false, PokemonType.FLYING, 2) + .setMixedBattleBgm("battle_alola_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.HAWLUCHA])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.DECIDUEYE], TrainerSlot.TRAINER, true, p => { // Tera Flying Decidueye + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.BRAVE_BIRD)) { // Check if Brave Bird is in the moveset, if not, replace the third move with Brave Bird. + p.moveset[2] = new PokemonMove(Moves.BRAVE_BIRD); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.BRAVIARY, Species.MANDIBUZZ])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ORICORIO])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.TOUCANNON], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.MARNIE_ELITE]: new TrainerConfig(++t) .setName("Marnie") - .initForEliteFour(signatureSpecies["MARNIE_ELITE"], false, PokemonType.DARK) - .setMixedBattleBgm("battle_galar_elite"), + .initForEliteFour(signatureSpecies["MARNIE_ELITE"], false, PokemonType.DARK, 2) + .setMixedBattleBgm("battle_galar_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.LIEPARD])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.TOXICROAK], TrainerSlot.TRAINER, true, p => { // Tera Dark Toxicroak + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.SUCKER_PUNCH)) { + // Check if Sucker Punch is in the moveset, if not, replace the third move with Sucker Punch. + p.moveset[2] = new PokemonMove(Moves.SUCKER_PUNCH); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.SCRAFTY, Species.PANGORO])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.MORPEKO])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GRIMMSNARL], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.NESSA_ELITE]: new TrainerConfig(++t) .setName("Nessa") - .initForEliteFour(signatureSpecies["NESSA_ELITE"], false, PokemonType.WATER) - .setMixedBattleBgm("battle_galar_elite"), + .initForEliteFour(signatureSpecies["NESSA_ELITE"], false, PokemonType.WATER, 2) + .setMixedBattleBgm("battle_galar_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GOLISOPOD])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.EISCUE], TrainerSlot.TRAINER, true, p => { // Tera Water Eiscue + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.LIQUIDATION)) { // Check if Liquidation is in the moveset, if not, replace the third move with Liquidation. + p.moveset[2] = new PokemonMove(Moves.LIQUIDATION); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.PELIPPER], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Drizzle + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.TOXAPEX])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.DREDNAW], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.BEA_ELITE]: new TrainerConfig(++t) .setName("Bea") - .initForEliteFour(signatureSpecies["BEA_ELITE"], false, PokemonType.FIGHTING) - .setMixedBattleBgm("battle_galar_elite"), + .initForEliteFour(signatureSpecies["BEA_ELITE"], false, PokemonType.FIGHTING, 2) + .setMixedBattleBgm("battle_galar_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.HAWLUCHA])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SIRFETCHD])) // Tera Fighting Sirfetch'd + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GRAPPLOCT, Species.FALINKS])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.HITMONTOP])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.MACHAMP], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.ALLISTER_ELITE]: new TrainerConfig(++t) .setName("Allister") - .initForEliteFour(signatureSpecies["ALLISTER_ELITE"], true, PokemonType.GHOST) - .setMixedBattleBgm("battle_galar_elite"), + .initForEliteFour(signatureSpecies["ALLISTER_ELITE"], true, PokemonType.GHOST, 2) + .setMixedBattleBgm("battle_galar_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DUSKNOIR])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.RUNERIGUS])) // Tera Ghost Runerigus + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.POLTEAGEIST, Species.SINISTCHA])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CURSOLA])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GENGAR], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.RAIHAN_ELITE]: new TrainerConfig(++t) .setName("Raihan") - .initForEliteFour(signatureSpecies["RAIHAN_ELITE"], true, PokemonType.DRAGON) - .setMixedBattleBgm("battle_galar_elite"), + .initForEliteFour(signatureSpecies["RAIHAN_ELITE"], true, PokemonType.DRAGON, 2) + .setMixedBattleBgm("battle_galar_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.FLYGON])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.TORKOAL], TrainerSlot.TRAINER, true, p => { // Tera Dragon Torkoal + p.abilityIndex = 1; // Drought + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TERA_BLAST)) { // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. + p.moveset[2] = new PokemonMove(Moves.TERA_BLAST); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GOODRA])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.TURTONATOR])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.ARCHALUDON], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.RIKA]: new TrainerConfig(++t) .initForEliteFour(signatureSpecies["RIKA"], false, PokemonType.GROUND, 5) - .setMixedBattleBgm("battle_paldea_elite"), + .setMixedBattleBgm("battle_paldea_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DUGTRIO])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.DONPHAN])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.SWAMPERT, Species.TORTERRA])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CAMERUPT])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.CLODSIRE], TrainerSlot.TRAINER, true, p => { // Tera Ground Clodsire + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.POPPY]: new TrainerConfig(++t) .initForEliteFour(signatureSpecies["POPPY"], false, PokemonType.STEEL, 5) - .setMixedBattleBgm("battle_paldea_elite"), + .setMixedBattleBgm("battle_paldea_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.COPPERAJAH])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.MAGNEZONE])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.BRONZONG, Species.CORVIKNIGHT], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = p.species.speciesId === Species.BRONZONG ? 0 : 1; // Levitate Bronzong, Unnerve Corviknight + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.STEELIX])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.TINKATON], TrainerSlot.TRAINER, true, p => { // Tera Steel Tinkaton + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.LARRY_ELITE]: new TrainerConfig(++t) .setName("Larry") .initForEliteFour(signatureSpecies["LARRY_ELITE"], true, PokemonType.FLYING, 5) - .setMixedBattleBgm("battle_paldea_elite"), + .setMixedBattleBgm("battle_paldea_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ALTARIA])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.BOMBIRDIER])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.TROPIUS])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.STARAPTOR])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.FLAMIGO], TrainerSlot.TRAINER, true, p => { // Tera Flying Flamigo + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.HASSEL]: new TrainerConfig(++t) .initForEliteFour(signatureSpecies["HASSEL"], true, PokemonType.DRAGON, 5) - .setMixedBattleBgm("battle_paldea_elite"), + .setMixedBattleBgm("battle_paldea_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.NOIVERN])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.DRAGALGE])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.FLAPPLE, Species.APPLETUN, Species.HYDRAPPLE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.HAXORUS])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.BAXCALIBUR], TrainerSlot.TRAINER, true, p => { // Tera Dragon Baxcalibur + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.CRISPIN]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["CRISPIN"], true, PokemonType.FIRE, 5) - .setMixedBattleBgm("battle_bb_elite"), + .initForEliteFour(signatureSpecies["CRISPIN"], true, PokemonType.FIRE, 2) + .setMixedBattleBgm("battle_bb_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ROTOM], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; // Heat Rotom + p.generateAndPopulateMoveset(); + }), + ) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.EXEGGUTOR], TrainerSlot.TRAINER, true, p => { // Tera Fire Exeggutor + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TERA_BLAST)) { // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. + p.moveset[2] = new PokemonMove(Moves.TERA_BLAST); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.TALONFLAME], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.SUNNY_DAY)) { // Check if Sunny Day is in the moveset, if not, replace the third move with Sunny Day. + p.moveset[2] = new PokemonMove(Moves.SUNNY_DAY); + } + }), + ) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.MAGMORTAR])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.BLAZIKEN], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.AMARYS]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["AMARYS"], false, PokemonType.STEEL, 5) - .setMixedBattleBgm("battle_bb_elite"), + .initForEliteFour(signatureSpecies["AMARYS"], false, PokemonType.STEEL, 2) + .setMixedBattleBgm("battle_bb_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SKARMORY])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.REUNICLUS], TrainerSlot.TRAINER, true, p => { // Tera Steel Reuniclus + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.FLASH_CANNON)) { // Check if Flash Cannon is in the moveset, if not, replace the third move with Flash Cannon. + p.moveset[2] = new PokemonMove(Moves.FLASH_CANNON); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.EMPOLEON])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SCIZOR])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.METAGROSS], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.LACEY]: new TrainerConfig(++t) .initForEliteFour(signatureSpecies["LACEY"], false, PokemonType.FAIRY, 5) - .setMixedBattleBgm("battle_bb_elite"), + .setMixedBattleBgm("battle_bb_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.WHIMSICOTT])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.PRIMARINA])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GRANBULL])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ALCREMIE])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.EXCADRILL], TrainerSlot.TRAINER, true, p => { // Tera Fairy Excadrill + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TERA_BLAST)) { // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. + p.moveset[2] = new PokemonMove(Moves.TERA_BLAST); + } + }), + ), [TrainerType.DRAYTON]: new TrainerConfig(++t) - .initForEliteFour(signatureSpecies["DRAYTON"], true, PokemonType.DRAGON, 5) - .setMixedBattleBgm("battle_bb_elite"), + .initForEliteFour(signatureSpecies["DRAYTON"], true, PokemonType.DRAGON, 2) + .setMixedBattleBgm("battle_bb_elite") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DRAGONITE])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SCEPTILE], TrainerSlot.TRAINER, true, p => { // Tera Dragon Sceptile + p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.DUAL_CHOP)) { // Check if Dual Chop is in the moveset, if not, replace the third move with Dual Chop. + p.moveset[2] = new PokemonMove(Moves.DUAL_CHOP); + } + }), + ) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.HAXORUS])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.KINGDRA, Species.DRACOVISH])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.ARCHALUDON], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + }), + ), [TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)) .initForChampion(true) @@ -3011,29 +3545,18 @@ export const trainerConfigs: TrainerConfigs = { .setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ALAKAZAM])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.MACHAMP])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.HO_OH], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.HO_OH], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.RHYPERIOR, Species.ELECTIVIRE, Species.MAGMORTAR])) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc( - [Species.ARCANINE, Species.EXEGGUTOR, Species.GYARADOS], - TrainerSlot.TRAINER, - true, - p => { + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.RHYPERIOR, Species.ELECTIVIRE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ARCANINE, Species.EXEGGUTOR, Species.GYARADOS], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.setBoss(true, 2); - }, - ), + }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.PIDGEOT], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.PIDGEOT], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // Mega Pidgeot p.generateAndPopulateMoveset(); p.generateName(); @@ -3048,9 +3571,7 @@ export const trainerConfigs: TrainerConfigs = { .setHasDouble("red_blue_double") .setDoubleTrainerType(TrainerType.BLUE) .setDoubleTitle("champion_double") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.PIKACHU], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PIKACHU], TrainerSlot.TRAINER, true, p => { p.formIndex = 8; // G-Max Pikachu p.generateAndPopulateMoveset(); p.generateName(); @@ -3058,34 +3579,24 @@ export const trainerConfigs: TrainerConfigs = { }), ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.ESPEON, Species.UMBREON, Species.SYLVEON])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.LUGIA], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.LUGIA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR])) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.SNORLAX], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SNORLAX], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.setBoss(true, 2); }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc( - [Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE], - TrainerSlot.TRAINER, - true, - p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc( + [Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // Mega Venusaur, Mega Charizard X, or Mega Blastoise p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.MALE; - }, - ), + }), ) .setInstantTera(3), // Tera Grass Meganium / Fire Typhlosion / Water Feraligatr [TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t) @@ -3095,25 +3606,20 @@ export const trainerConfigs: TrainerConfigs = { .setMixedBattleBgm("battle_johto_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GYARADOS, Species.KINGDRA])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.AERODACTYL])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.SALAMENCE], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SALAMENCE], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // Mega Salamence p.generateAndPopulateMoveset(); p.generateName(); }), ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.CHARIZARD])) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.TYRANITAR, Species.GARCHOMP, Species.KOMMO_O], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.TYRANITAR, Species.GARCHOMP, Species.KOMMO_O], TrainerSlot.TRAINER, true, p => { p.teraType = PokemonType.DRAGON; + p.generateAndPopulateMoveset(); p.abilityIndex = p.species.speciesId === Species.KOMMO_O ? 1 : 2; // Soundproof Kommo-o, Unnerve Tyranitar, Rough Skin Garchomp }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.DRAGONITE], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.DRAGONITE], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.gender = Gender.MALE; p.setBoss(true, 2); @@ -3129,24 +3635,18 @@ export const trainerConfigs: TrainerConfigs = { .setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SKARMORY])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.CRADILY, Species.ARMALDO])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.AGGRON], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.AGGRON], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.setBoss(true, 2); }), ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GOLURK, Species.RUNERIGUS])) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.REGIROCK, Species.REGICE, Species.REGISTEEL], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.REGIROCK, Species.REGICE, Species.REGISTEEL], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.METAGROSS], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.METAGROSS], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // Mega Metagross p.generateAndPopulateMoveset(); p.generateName(); @@ -3160,17 +3660,13 @@ export const trainerConfigs: TrainerConfigs = { .setHasDouble("wallace_steven_double") .setDoubleTrainerType(TrainerType.STEVEN) .setDoubleTitle("champion_double") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.PELIPPER], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PELIPPER], TrainerSlot.TRAINER, true, p => { p.abilityIndex = 1; // Drizzle p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.LUDICOLO])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.LATIAS, Species.LATIOS], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.LATIAS, Species.LATIOS], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // Mega Latios or Mega Latias p.generateAndPopulateMoveset(); p.generateName(); @@ -3178,16 +3674,12 @@ export const trainerConfigs: TrainerConfigs = { }), ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.SWAMPERT, Species.GASTRODON, Species.SEISMITOAD])) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.REGIELEKI, Species.REGIDRAGO], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.REGIELEKI, Species.REGIDRAGO], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.MILOTIC], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.MILOTIC], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.gender = Gender.FEMALE; p.setBoss(true, 2); @@ -3198,41 +3690,24 @@ export const trainerConfigs: TrainerConfigs = { .initForChampion(false) .setBattleBgm("battle_sinnoh_champion") .setMixedBattleBgm("battle_sinnoh_champion") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.SPIRITOMB], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - }), - ) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SPIRITOMB])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.LUCARIO])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.GIRATINA], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.GIRATINA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) - .setPartyMemberFunc( - 3, - getRandomPartyMemberFunc( - [Species.MILOTIC, Species.ROSERADE, Species.HISUI_ARCANINE], - TrainerSlot.TRAINER, - true, - p => { - p.teraType = p.species.type1; - }, - ), + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.MILOTIC, Species.ROSERADE, Species.HISUI_ARCANINE], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.teraType = p.species.type1; + }), ) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.TOGEKISS], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.TOGEKISS], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.setBoss(true, 2); }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.GARCHOMP], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GARCHOMP], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // Mega Garchomp p.generateAndPopulateMoveset(); p.generateName(); @@ -3248,46 +3723,28 @@ export const trainerConfigs: TrainerConfigs = { .setBattleBgm("battle_champion_alder") .setMixedBattleBgm("battle_champion_alder") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.BOUFFALANT, Species.BRAVIARY])) - .setPartyMemberFunc( - 1, - getRandomPartyMemberFunc( - [Species.HISUI_LILLIGANT, Species.HISUI_ZOROARK, Species.BASCULEGION], - TrainerSlot.TRAINER, - true, - p => { + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.HISUI_LILLIGANT, Species.HISUI_ZOROARK, Species.BASCULEGION], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ROGUE_BALL; - }, - ), + }), ) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.ZEKROM], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.ZEKROM], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) - .setPartyMemberFunc( - 3, - getRandomPartyMemberFunc([Species.KELDEO], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.KELDEO], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc( - [Species.CHANDELURE, Species.KROOKODILE, Species.REUNICLUS, Species.CONKELDURR], - TrainerSlot.TRAINER, - true, - p => { - p.teraType = p.species.speciesId === Species.KROOKODILE ? PokemonType.DARK : p.species.type1; - }, - ), + .setPartyMemberFunc(4, getRandomPartyMemberFunc( + [Species.CHANDELURE, Species.KROOKODILE, Species.REUNICLUS, Species.CONKELDURR], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.teraType = p.species.speciesId === Species.KROOKODILE ? PokemonType.DARK : p.species.type1; + }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.VOLCARONA], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.VOLCARONA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.gender = Gender.MALE; p.setBoss(true, 2); @@ -3303,35 +3760,23 @@ export const trainerConfigs: TrainerConfigs = { .setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DRUDDIGON])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.ARCHEOPS])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.RESHIRAM], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.RESHIRAM], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) - .setPartyMemberFunc( - 3, - getRandomPartyMemberFunc( - [Species.SALAMENCE, Species.HYDREIGON, Species.ARCHALUDON], - TrainerSlot.TRAINER, - true, - p => { - p.teraType = PokemonType.DRAGON; - }, - ), + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.SALAMENCE, Species.HYDREIGON, Species.ARCHALUDON], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.teraType = PokemonType.DRAGON; + }), ) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.LAPRAS], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.LAPRAS], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // G-Max Lapras p.generateAndPopulateMoveset(); p.generateName(); }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.HAXORUS], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.HAXORUS], TrainerSlot.TRAINER, true, p => { p.abilityIndex = 1; // Mold Breaker p.generateAndPopulateMoveset(); p.gender = Gender.FEMALE; @@ -3342,38 +3787,28 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.DIANTHA]: new TrainerConfig(++t) .initForChampion(false) .setMixedBattleBgm("battle_kalos_champion") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.HAWLUCHA], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.HAWLUCHA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.TREVENANT, Species.GOURGEIST])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.XERNEAS], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.XERNEAS], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) - .setPartyMemberFunc( - 3, - getRandomPartyMemberFunc([Species.TYRANTRUM, Species.AURORUS], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.TYRANTRUM, Species.AURORUS], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.abilityIndex = 2; // Rock Head Tyrantrum, Snow Warning Aurorus p.teraType = p.species.type2!; }), ) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.GOODRA], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.GOODRA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.setBoss(true, 2); }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.GARDEVOIR], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GARDEVOIR], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // Mega Gardevoir p.generateAndPopulateMoveset(); p.generateName(); @@ -3384,45 +3819,29 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.KUKUI]: new TrainerConfig(++t) .initForChampion(true) .setMixedBattleBgm("battle_champion_kukui") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.LYCANROC], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.LYCANROC], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.formIndex = 2; // Dusk Lycanroc }), ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.MAGNEZONE, Species.ALOLA_NINETALES])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc( - [Species.TORNADUS, Species.THUNDURUS, Species.LANDORUS], - TrainerSlot.TRAINER, - true, - p => { - p.formIndex = 1; // Therian Formes + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.TORNADUS, Species.THUNDURUS, Species.LANDORUS], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // Therian Formes p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; - }, - ), + }), ) - .setPartyMemberFunc( - 3, - getRandomPartyMemberFunc([Species.TAPU_KOKO, Species.TAPU_FINI], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.TAPU_KOKO, Species.TAPU_FINI], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.setBoss(true, 2); p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.SNORLAX], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SNORLAX], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.formIndex = 1; // G-Max Snorlax }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.INCINEROAR, Species.HISUI_DECIDUEYE], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.INCINEROAR, Species.HISUI_DECIDUEYE], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.gender = Gender.MALE; p.teraType = p.species.type2!; @@ -3432,39 +3851,26 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.HAU]: new TrainerConfig(++t) .initForChampion(true) .setMixedBattleBgm("battle_alola_champion") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.ALOLA_RAICHU], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - }), - ) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ALOLA_RAICHU])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.NOIVERN])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.SOLGALEO], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SOLGALEO], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) - .setPartyMemberFunc( - 3, - getRandomPartyMemberFunc([Species.TAPU_LELE, Species.TAPU_BULU], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.TAPU_LELE, Species.TAPU_BULU], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.teraType = p.species.type1; }), ) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.ZYGARDE], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ZYGARDE], TrainerSlot.TRAINER, true, p => { p.formIndex = 1; // Zygarde 10% forme, Aura Break p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ROGUE_BALL; }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.DECIDUEYE, Species.PRIMARINA], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.DECIDUEYE, Species.PRIMARINA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.setBoss(true, 2); p.gender = p.species.speciesId === Species.PRIMARINA ? Gender.FEMALE : Gender.MALE; @@ -3474,36 +3880,20 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.LEON]: new TrainerConfig(++t) .initForChampion(true) .setMixedBattleBgm("battle_galar_champion") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.AEGISLASH], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - }), - ) + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.AEGISLASH])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.RHYPERIOR, Species.SEISMITOAD, Species.MR_RIME])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.ZACIAN], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.ZACIAN], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.DRAGAPULT])) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc( - [Species.RILLABOOM, Species.CINDERACE, Species.INTELEON], - TrainerSlot.TRAINER, - true, - p => { + .setPartyMemberFunc(4,getRandomPartyMemberFunc([Species.RILLABOOM, Species.CINDERACE, Species.INTELEON], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.setBoss(true, 2); - }, - ), + }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.CHARIZARD], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.CHARIZARD], TrainerSlot.TRAINER, true, p => { p.formIndex = 3; // G-Max Charizard p.generateAndPopulateMoveset(); p.generateName(); @@ -3514,79 +3904,65 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.MUSTARD]: new TrainerConfig(++t) .initForChampion(true) .setMixedBattleBgm("battle_mustard") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.CORVIKNIGHT], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.CORVIKNIGHT], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setPartyMemberFunc( - 1, - getRandomPartyMemberFunc([Species.KOMMO_O], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.KOMMO_O], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.GALAR_SLOWBRO, Species.GALAR_SLOWKING], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.GALAR_SLOWBRO, Species.GALAR_SLOWKING], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; - p.teraType = PokemonType.PSYCHIC; + p.teraType = p.species.type1; }), ) - .setPartyMemberFunc( - 3, - getRandomPartyMemberFunc([Species.GALAR_DARMANITAN], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GALAR_DARMANITAN], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.BLASTOISE, Species.VENUSAUR], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.BLASTOISE, Species.VENUSAUR], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.setBoss(true, 2); p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.URSHIFU], TrainerSlot.TRAINER, true, p => { - p.formIndex = Utils.randSeedInt(2, 2); // Random G-Max Urshifu + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.URSHIFU], TrainerSlot.TRAINER, true, p => { + p.formIndex = randSeedInt(2, 2); // Random G-Max Urshifu p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.MALE; p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setInstantTera(2), // Tera Psychic Galar-Slowbro / Galar-Slowking + .setInstantTera(2), // Tera Poison Galar-Slowbro / Galar-Slowking [TrainerType.GEETA]: new TrainerConfig(++t) .initForChampion(false) .setMixedBattleBgm("battle_champion_geeta") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.GLIMMORA], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GLIMMORA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.gender = Gender.MALE; p.setBoss(true, 2); }), ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.ESPATHRA, Species.VELUZA])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.MIRAIDON], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.MIRAIDON], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.BAXCALIBUR])) .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA])) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.KINGAMBIT], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.KINGAMBIT], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TERA_BLAST)) { + // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. + p.moveset[2] = new PokemonMove(Moves.TERA_BLAST); + } p.abilityIndex = 1; // Supreme Overlord p.teraType = PokemonType.FLYING; }), @@ -3595,87 +3971,60 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.NEMONA]: new TrainerConfig(++t) .initForChampion(false) .setMixedBattleBgm("battle_champion_nemona") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.LYCANROC], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.LYCANROC], TrainerSlot.TRAINER, true, p => { p.formIndex = 0; // Midday form p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.PAWMOT])) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.KORAIDON], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.KORAIDON], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GHOLDENGO])) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.ARMAROUGE, Species.CERULEDGE], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ARMAROUGE, Species.CERULEDGE], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); p.teraType = p.species.type2!; }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc( - [Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL], - TrainerSlot.TRAINER, - true, - p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.gender = Gender.MALE; p.setBoss(true, 2); - }, - ), + }), ) .setInstantTera(4), // Tera Psychic Armarouge / Ghost Ceruledge [TrainerType.KIERAN]: new TrainerConfig(++t) .initForChampion(true) .setMixedBattleBgm("battle_champion_kieran") - .setPartyMemberFunc( - 0, - getRandomPartyMemberFunc([Species.POLIWRATH, Species.POLITOED], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - }), - ) - .setPartyMemberFunc( - 1, - getRandomPartyMemberFunc([Species.INCINEROAR, Species.GRIMMSNARL], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.POLIWRATH, Species.POLITOED])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.INCINEROAR, Species.GRIMMSNARL], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.abilityIndex = p.species.speciesId === Species.INCINEROAR ? 2 : 0; // Intimidate Incineroar, Prankster Grimmsnarl }), ) - .setPartyMemberFunc( - 2, - getRandomPartyMemberFunc([Species.TERAPAGOS], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.TERAPAGOS], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; }), ) - .setPartyMemberFunc( - 3, - getRandomPartyMemberFunc([Species.URSALUNA, Species.BLOODMOON_URSALUNA], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.URSALUNA, Species.BLOODMOON_URSALUNA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; }), ) - .setPartyMemberFunc( - 4, - getRandomPartyMemberFunc([Species.OGERPON], TrainerSlot.TRAINER, true, p => { - p.formIndex = Utils.randSeedInt(4); // Random Ogerpon Tera Mask + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.OGERPON], TrainerSlot.TRAINER, true, p => { + p.formIndex = randSeedInt(4); // Random Ogerpon Tera Mask p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; - if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.IVY_CUDGEL)) { + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.IVY_CUDGEL)) { // Check if Ivy Cudgel is in the moveset, if not, replace the first move with Ivy Cudgel. p.moveset[0] = new PokemonMove(Moves.IVY_CUDGEL); } }), ) - .setPartyMemberFunc( - 5, - getRandomPartyMemberFunc([Species.HYDRAPPLE], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.HYDRAPPLE], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.gender = Gender.MALE; p.setBoss(true, 2); @@ -3697,7 +4046,6 @@ export const trainerConfigs: TrainerConfigs = { () => modifierTypes.SUPER_EXP_CHARM, () => modifierTypes.EXP_SHARE, ) - .setEventModifierRewardFuncs(8) .setPartyMemberFunc( 0, getRandomPartyMemberFunc( @@ -3765,7 +4113,6 @@ export const trainerConfigs: TrainerConfigs = { .setMixedBattleBgm("battle_rival") .setPartyTemplates(trainerPartyTemplates.RIVAL_2) .setModifierRewardFuncs(() => modifierTypes.EXP_SHARE) - .setEventModifierRewardFuncs(25) .setPartyMemberFunc( 0, getRandomPartyMemberFunc( @@ -4718,10 +5065,10 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 2, getRandomPartyMemberFunc([Species.SILVALLY], TrainerSlot.TRAINER, true, p => { - p.formIndex = Utils.randSeedInt(18); // Random Silvally Form + p.formIndex = randSeedInt(18); // Random Silvally Form p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ROGUE_BALL; - if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.MULTI_ATTACK)) { + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.MULTI_ATTACK)) { // Check if Multi Attack is in the moveset, if not, replace the first move with Multi Attack. p.moveset[0] = new PokemonMove(Moves.MULTI_ATTACK); } @@ -4838,9 +5185,9 @@ export const trainerConfigs: TrainerConfigs = { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; - p.formIndex = Utils.randSeedInt(4, 1); // Shock, Burn, Chill, or Douse Drive - if (!p.moveset.some(move => !Utils.isNullOrUndefined(move) && move.moveId === Moves.TECHNO_BLAST)) { - // Check if Techno Blast is in the moveset, if not, replace the first move with Techno Blast. + p.formIndex = randSeedInt(4, 1); // Shock, Burn, Chill, or Douse Drive + if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === Moves.TECHNO_BLAST)) { + // Check if Techno Blast is in the moveset, if not, replace the third move with Techno Blast. p.moveset[2] = new PokemonMove(Moves.TECHNO_BLAST); } }), @@ -5011,7 +5358,7 @@ export const trainerConfigs: TrainerConfigs = { 1, getRandomPartyMemberFunc([Species.ROTOM], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); - p.formIndex = Utils.randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow + p.formIndex = randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow }), ) .setPartyMemberFunc( @@ -5024,7 +5371,7 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 3, getRandomPartyMemberFunc([Species.REVAVROOM], TrainerSlot.TRAINER, true, p => { - p.formIndex = Utils.randSeedInt(5, 1); // Random Starmobile form + p.formIndex = randSeedInt(5, 1); // Random Starmobile form p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ROGUE_BALL; }), diff --git a/src/data/variant.ts b/src/data/variant.ts deleted file mode 100644 index 13c11b0bb40..00000000000 --- a/src/data/variant.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { VariantTier } from "#app/enums/variant-tier"; - -export type Variant = 0 | 1 | 2; - -export type VariantSet = [Variant, Variant, Variant]; - -export const variantData: any = {}; - -export const variantColorCache = {}; - -export function getVariantTint(variant: Variant): number { - switch (variant) { - case 0: - return 0xf8c020; - case 1: - return 0x20f8f0; - case 2: - return 0xe81048; - } -} - -export function getVariantIcon(variant: Variant): number { - switch (variant) { - case 0: - return VariantTier.STANDARD; - case 1: - return VariantTier.RARE; - case 2: - return VariantTier.EPIC; - } -} diff --git a/src/data/weather.ts b/src/data/weather.ts index 34978232377..be9107798df 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -5,8 +5,8 @@ import type Pokemon from "../field/pokemon"; import { PokemonType } from "#enums/pokemon-type"; import type Move from "./moves/move"; import { AttackMove } from "./moves/move"; -import * as Utils from "../utils"; -import { SuppressWeatherEffectAbAttr } from "./ability"; +import { randSeedInt } from "#app/utils/common"; +import { SuppressWeatherEffectAbAttr } from "./abilities/ability"; import { TerrainType, getTerrainName } from "./terrain"; import i18next from "i18next"; import { globalScene } from "#app/global-scene"; @@ -369,6 +369,7 @@ export function getRandomWeatherType(arena: Arena): WeatherType { if (hasSun) { weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 2 }); } + break; case Biome.VOLCANO: weatherPool = [ { @@ -416,7 +417,7 @@ export function getRandomWeatherType(arena: Arena): WeatherType { totalWeight += w.weight; } - const rand = Utils.randSeedInt(totalWeight); + const rand = randSeedInt(totalWeight); let w = 0; for (const weather of weatherPool) { w += weather.weight; diff --git a/src/enums/MoveEffectTrigger.ts b/src/enums/MoveEffectTrigger.ts index 1e7753d94fa..d22953c3690 100644 --- a/src/enums/MoveEffectTrigger.ts +++ b/src/enums/MoveEffectTrigger.ts @@ -1,7 +1,6 @@ export enum MoveEffectTrigger { PRE_APPLY, POST_APPLY, - HIT, /** Triggers one time after all target effects have applied */ POST_TARGET } diff --git a/src/enums/battle-type.ts b/src/enums/battle-type.ts new file mode 100644 index 00000000000..81cf89ef488 --- /dev/null +++ b/src/enums/battle-type.ts @@ -0,0 +1,6 @@ +export enum BattleType { + WILD, + TRAINER, + CLEAR, + MYSTERY_ENCOUNTER +} diff --git a/src/enums/biome.ts b/src/enums/biome.ts index bb9eaf454cc..7284528767d 100644 --- a/src/enums/biome.ts +++ b/src/enums/biome.ts @@ -1,4 +1,5 @@ export enum Biome { + // TODO: Should -1 be part of the enum signature (for "unknown place") TOWN, PLAINS, GRASS, diff --git a/src/enums/fixed-boss-waves.ts b/src/enums/fixed-boss-waves.ts new file mode 100644 index 00000000000..623d9035472 --- /dev/null +++ b/src/enums/fixed-boss-waves.ts @@ -0,0 +1,22 @@ +export enum ClassicFixedBossWaves { + TOWN_YOUNGSTER = 5, + RIVAL_1 = 8, + RIVAL_2 = 25, + EVIL_GRUNT_1 = 35, + RIVAL_3 = 55, + EVIL_GRUNT_2 = 62, + EVIL_GRUNT_3 = 64, + EVIL_ADMIN_1 = 66, + RIVAL_4 = 95, + EVIL_GRUNT_4 = 112, + EVIL_ADMIN_2 = 114, + EVIL_BOSS_1 = 115, + RIVAL_5 = 145, + EVIL_BOSS_2 = 165, + ELITE_FOUR_1 = 182, + ELITE_FOUR_2 = 184, + ELITE_FOUR_3 = 186, + ELITE_FOUR_4 = 188, + CHAMPION = 190, + RIVAL_6 = 195 +} diff --git a/src/enums/hit-check-result.ts b/src/enums/hit-check-result.ts new file mode 100644 index 00000000000..cf8a2b17194 --- /dev/null +++ b/src/enums/hit-check-result.ts @@ -0,0 +1,23 @@ +/** The result of a hit check calculation */ +export const HitCheckResult = { + /** Hit checks haven't been evaluated yet in this pass */ + PENDING: 0, + /** The move hits the target successfully */ + HIT: 1, + /** The move has no effect on the target */ + NO_EFFECT: 2, + /** The move has no effect on the target, but doesn't proc the default "no effect" message */ + NO_EFFECT_NO_MESSAGE: 3, + /** The target protected itself against the move */ + PROTECTED: 4, + /** The move missed the target */ + MISS: 5, + /** The move is reflected by magic coat or magic bounce */ + REFLECTED: 6, + /** The target is no longer on the field */ + TARGET_NOT_ON_FIELD: 7, + /** The move failed unexpectedly */ + ERROR: 8, +} as const; + +export type HitCheckResult = typeof HitCheckResult[keyof typeof HitCheckResult]; diff --git a/src/enums/ui-mode.ts b/src/enums/ui-mode.ts new file mode 100644 index 00000000000..dcf6bd2a238 --- /dev/null +++ b/src/enums/ui-mode.ts @@ -0,0 +1,47 @@ +export enum UiMode { + MESSAGE, + TITLE, + COMMAND, + FIGHT, + BALL, + TARGET_SELECT, + MODIFIER_SELECT, + SAVE_SLOT, + PARTY, + SUMMARY, + STARTER_SELECT, + EVOLUTION_SCENE, + EGG_HATCH_SCENE, + EGG_HATCH_SUMMARY, + CONFIRM, + OPTION_SELECT, + MENU, + MENU_OPTION_SELECT, + SETTINGS, + SETTINGS_DISPLAY, + SETTINGS_AUDIO, + SETTINGS_GAMEPAD, + GAMEPAD_BINDING, + SETTINGS_KEYBOARD, + KEYBOARD_BINDING, + ACHIEVEMENTS, + GAME_STATS, + EGG_LIST, + EGG_GACHA, + POKEDEX, + POKEDEX_SCAN, + POKEDEX_PAGE, + LOGIN_FORM, + REGISTRATION_FORM, + LOADING, + SESSION_RELOAD, + UNAVAILABLE, + CHALLENGE_SELECT, + RENAME_POKEMON, + RUN_HISTORY, + RUN_INFO, + TEST_DIALOGUE, + AUTO_COMPLETE, + ADMIN, + MYSTERY_ENCOUNTER +} diff --git a/src/field/anims.ts b/src/field/anims.ts index cd6209dddff..2fd23e4262b 100644 --- a/src/field/anims.ts +++ b/src/field/anims.ts @@ -1,7 +1,7 @@ import { globalScene } from "#app/global-scene"; import { PokeballType } from "#enums/pokeball"; -import type { Variant } from "#app/data/variant"; -import { getFrameMs, randGauss } from "#app/utils"; +import type { Variant } from "#app/sprites/variant"; +import { getFrameMs, randGauss } from "#app/utils/common"; export function addPokeballOpenParticles(x: number, y: number, pokeballType: PokeballType): void { switch (pokeballType) { diff --git a/src/field/arena.ts b/src/field/arena.ts index cf48647e45e..f083180490b 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -1,8 +1,7 @@ import { globalScene } from "#app/global-scene"; import type { BiomeTierTrainerPools, PokemonPools } from "#app/data/balance/biomes"; import { biomePokemonPools, BiomePoolTier, biomeTrainerPools } from "#app/data/balance/biomes"; -import type { Constructor } from "#app/utils"; -import * as Utils from "#app/utils"; +import { randSeedInt, NumberHolder, isNullOrUndefined, type Constructor } from "#app/utils/common"; import type PokemonSpecies from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { @@ -27,7 +26,7 @@ import { PostTerrainChangeAbAttr, PostWeatherChangeAbAttr, TerrainEventTypeChangeAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; import type Pokemon from "#app/field/pokemon"; import Overrides from "#app/overrides"; import { TagAddedEvent, TagRemovedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena"; @@ -124,7 +123,7 @@ export class Arena { if (typeof luckValue !== "undefined") { luckModifier = luckValue * (isBossSpecies ? 0.5 : 2); } - const tierValue = Utils.randSeedInt(randVal - luckModifier); + const tierValue = randSeedInt(randVal - luckModifier); let tier = !isBossSpecies ? tierValue >= 156 ? BiomePoolTier.COMMON @@ -153,7 +152,7 @@ export class Arena { if (!tierPool.length) { ret = globalScene.randomSpecies(waveIndex, level); } else { - const entry = tierPool[Utils.randSeedInt(tierPool.length)]; + const entry = tierPool[randSeedInt(tierPool.length)]; let species: Species; if (typeof entry === "number") { species = entry as Species; @@ -164,7 +163,7 @@ export class Arena { if (level >= levelThreshold) { const speciesIds = entry[levelThreshold]; if (speciesIds.length > 1) { - species = speciesIds[Utils.randSeedInt(speciesIds.length)]; + species = speciesIds[randSeedInt(speciesIds.length)]; } else { species = speciesIds[0]; } @@ -211,7 +210,7 @@ export class Arena { !!this.trainerPool[BiomePoolTier.BOSS].length && (globalScene.gameMode.isTrainerBoss(waveIndex, this.biomeType, globalScene.offsetGym) || isBoss); console.log(isBoss, this.trainerPool); - const tierValue = Utils.randSeedInt(!isTrainerBoss ? 512 : 64); + const tierValue = randSeedInt(!isTrainerBoss ? 512 : 64); let tier = !isTrainerBoss ? tierValue >= 156 ? BiomePoolTier.COMMON @@ -235,7 +234,7 @@ export class Arena { tier--; } const tierPool = this.trainerPool[tier] || []; - return !tierPool.length ? TrainerType.BREEDER : tierPool[Utils.randSeedInt(tierPool.length)]; + return !tierPool.length ? TrainerType.BREEDER : tierPool[randSeedInt(tierPool.length)]; } getSpeciesFormIndex(species: PokemonSpecies): number { @@ -336,9 +335,9 @@ export class Arena { return false; } - const weatherDuration = new Utils.NumberHolder(0); + const weatherDuration = new NumberHolder(0); - if (!Utils.isNullOrUndefined(user)) { + if (!isNullOrUndefined(user)) { weatherDuration.value = 5; globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, weatherDuration); } @@ -417,9 +416,9 @@ export class Arena { const oldTerrainType = this.terrain?.terrainType || TerrainType.NONE; - const terrainDuration = new Utils.NumberHolder(0); + const terrainDuration = new NumberHolder(0); - if (!Utils.isNullOrUndefined(user)) { + if (!isNullOrUndefined(user)) { terrainDuration.value = 5; globalScene.applyModifier(FieldEffectModifier, user.isPlayer(), user, terrainDuration); } @@ -1013,7 +1012,7 @@ export class ArenaBase extends Phaser.GameObjects.Container { if (!this.player) { globalScene.executeWithSeedOffset( () => { - this.propValue = propValue === undefined ? (hasProps ? Utils.randSeedInt(8) : 0) : propValue; + this.propValue = propValue === undefined ? (hasProps ? randSeedInt(8) : 0) : propValue; this.props.forEach((prop, p) => { const propKey = `${biomeKey}_b${hasProps ? `_${p + 1}` : ""}`; prop.setTexture(propKey); diff --git a/src/field/damage-number-handler.ts b/src/field/damage-number-handler.ts index 9e0010a0c10..bfb85018dd6 100644 --- a/src/field/damage-number-handler.ts +++ b/src/field/damage-number-handler.ts @@ -2,7 +2,7 @@ import { TextStyle, addTextObject } from "../ui/text"; import type { DamageResult } from "./pokemon"; import type Pokemon from "./pokemon"; import { HitResult } from "./pokemon"; -import * as Utils from "../utils"; +import { formatStat, fixedInt } from "#app/utils/common"; import type { BattlerIndex } from "../battle"; import { globalScene } from "#app/global-scene"; @@ -30,7 +30,7 @@ export default class DamageNumberHandler { const damageNumber = addTextObject( target.x, -(globalScene.game.canvas.height / 6) + target.y - target.getSprite().height / 2, - Utils.formatStat(amount, true), + formatStat(amount, true), TextStyle.SUMMARY, ); damageNumber.setName("text-damage-number"); @@ -86,14 +86,14 @@ export default class DamageNumberHandler { if (globalScene.damageNumbersMode === 1) { globalScene.tweens.add({ targets: damageNumber, - duration: Utils.fixedInt(750), + duration: fixedInt(750), alpha: 1, y: "-=32", }); globalScene.tweens.add({ delay: 375, targets: damageNumber, - duration: Utils.fixedInt(625), + duration: fixedInt(625), alpha: 0, ease: "Sine.easeIn", onComplete: () => { @@ -110,7 +110,7 @@ export default class DamageNumberHandler { targets: damageNumber, tweens: [ { - duration: Utils.fixedInt(250), + duration: fixedInt(250), alpha: 1, scaleX: 0.75 * baseScale, scaleY: 1.25 * baseScale, @@ -118,7 +118,7 @@ export default class DamageNumberHandler { ease: "Cubic.easeOut", }, { - duration: Utils.fixedInt(175), + duration: fixedInt(175), alpha: 1, scaleX: 0.875 * baseScale, scaleY: 1.125 * baseScale, @@ -126,59 +126,59 @@ export default class DamageNumberHandler { ease: "Cubic.easeIn", }, { - duration: Utils.fixedInt(100), + duration: fixedInt(100), scaleX: 1.25 * baseScale, scaleY: 0.75 * baseScale, ease: "Cubic.easeOut", }, { - duration: Utils.fixedInt(175), + duration: fixedInt(175), scaleX: 0.875 * baseScale, scaleY: 1.125 * baseScale, y: "-=8", ease: "Cubic.easeOut", }, { - duration: Utils.fixedInt(50), + duration: fixedInt(50), scaleX: 0.925 * baseScale, scaleY: 1.075 * baseScale, y: "+=8", ease: "Cubic.easeIn", }, { - duration: Utils.fixedInt(100), + duration: fixedInt(100), scaleX: 1.125 * baseScale, scaleY: 0.875 * baseScale, ease: "Cubic.easeOut", }, { - duration: Utils.fixedInt(175), + duration: fixedInt(175), scaleX: 0.925 * baseScale, scaleY: 1.075 * baseScale, y: "-=4", ease: "Cubic.easeOut", }, { - duration: Utils.fixedInt(50), + duration: fixedInt(50), scaleX: 0.975 * baseScale, scaleY: 1.025 * baseScale, y: "+=4", ease: "Cubic.easeIn", }, { - duration: Utils.fixedInt(100), + duration: fixedInt(100), scaleX: 1.075 * baseScale, scaleY: 0.925 * baseScale, ease: "Cubic.easeOut", }, { - duration: Utils.fixedInt(25), + duration: fixedInt(25), scaleX: baseScale, scaleY: baseScale, ease: "Cubic.easeOut", }, { - delay: Utils.fixedInt(500), + delay: fixedInt(500), alpha: 0, onComplete: () => { this.damageNumbers diff --git a/src/field/mystery-encounter-intro.ts b/src/field/mystery-encounter-intro.ts index 649a969d415..b6212b6b031 100644 --- a/src/field/mystery-encounter-intro.ts +++ b/src/field/mystery-encounter-intro.ts @@ -2,11 +2,12 @@ import type { GameObjects } from "phaser"; import { globalScene } from "#app/global-scene"; import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import type { Species } from "#enums/species"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; -import type { Variant } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; import { doShinySparkleAnim } from "#app/field/anims"; import PlayAnimationConfig = Phaser.Types.Animations.PlayAnimationConfig; +import { loadPokemonVariantAssets } from "#app/sprites/pokemon-sprite"; type KnownFileRoot = | "arenas" @@ -233,8 +234,8 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con this.spriteConfigs.forEach(config => { if (config.isPokemon) { globalScene.loadPokemonAtlas(config.spriteKey, config.fileRoot); - if (config.isShiny) { - shinyPromises.push(globalScene.loadPokemonVariantAssets(config.spriteKey, config.fileRoot, config.variant)); + if (config.isShiny && !isNullOrUndefined(config.variant)) { + shinyPromises.push(loadPokemonVariantAssets(config.spriteKey, config.fileRoot, config.variant)); } } else if (config.isItem) { globalScene.loadAtlas("items", ""); diff --git a/src/field/pokemon-sprite-sparkle-handler.ts b/src/field/pokemon-sprite-sparkle-handler.ts index 0d5dcca7989..cceb0bd7717 100644 --- a/src/field/pokemon-sprite-sparkle-handler.ts +++ b/src/field/pokemon-sprite-sparkle-handler.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import Pokemon from "./pokemon"; -import * as Utils from "../utils"; +import { fixedInt, randInt } from "#app/utils/common"; export default class PokemonSpriteSparkleHandler { private sprites: Set; @@ -9,7 +9,7 @@ export default class PokemonSpriteSparkleHandler { this.sprites = new Set(); globalScene.tweens.addCounter({ - duration: Utils.fixedInt(200), + duration: fixedInt(200), from: 0, to: 1, yoyo: true, @@ -36,7 +36,7 @@ export default class PokemonSpriteSparkleHandler { const parent = (pokemon || s).parentContainer; const texture = s.texture; const [width, height] = [texture.source[0].width, texture.source[0].height]; - const [pixelX, pixelY] = [Utils.randInt(width), Utils.randInt(height)]; + const [pixelX, pixelY] = [randInt(width), randInt(height)]; const ratioX = s.width / width; const ratioY = s.height / height; const pixel = texture.manager.getPixel(pixelX, pixelY, texture.key, "__BASE"); @@ -51,7 +51,7 @@ export default class PokemonSpriteSparkleHandler { sparkle.setName("sprite-tera-sparkle"); sparkle.play("tera_sparkle"); parent.add(sparkle); - s.scene.time.delayedCall(Utils.fixedInt(Math.floor((1000 / 12) * 13)), () => sparkle.destroy()); + s.scene.time.delayedCall(fixedInt(Math.floor((1000 / 12) * 13)), () => sparkle.destroy()); } } } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index f89319a6e30..b9c64ad071c 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2,9 +2,9 @@ import Phaser from "phaser"; import type { AnySound } from "#app/battle-scene"; import type BattleScene from "#app/battle-scene"; import { globalScene } from "#app/global-scene"; -import type { Variant, VariantSet } from "#app/data/variant"; -import { variantColorCache } from "#app/data/variant"; -import { variantData } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; +import { populateVariantColors, variantColorCache } from "#app/sprites/variant"; +import { variantData } from "#app/sprites/variant"; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo, @@ -12,7 +12,6 @@ import BattleInfo, { import type Move from "#app/data/moves/move"; import { HighCritAttr, - StatChangeBeforeDmgCalcAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, @@ -55,9 +54,7 @@ import { getStarterValueFriendshipCap, speciesStarterCosts, } from "#app/data/balance/starters"; -import type { Constructor } from "#app/utils"; -import { isNullOrUndefined, randSeedInt, type nil } from "#app/utils"; -import * as Utils from "#app/utils"; +import { NumberHolder, randSeedInt, getIvsFromId, BooleanHolder, randSeedItem, isNullOrUndefined, getEnumValues, toDmgValue, fixedInt, rgbaToInt, rgbHexToRgba, rgbToHsv, deltaRgb, isBetween, type nil, type Constructor } from "#app/utils/common"; import type { TypeDamageMultiplier } from "#app/data/type"; import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type"; import { PokemonType } from "#enums/pokemon-type"; @@ -72,10 +69,8 @@ import { EFFECTIVE_STATS, } from "#enums/stat"; import { - DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, - EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, BaseStatModifier, @@ -96,7 +91,6 @@ import { } from "#app/modifier/modifier"; import { PokeballType } from "#enums/pokeball"; import { Gender } from "#app/data/gender"; -import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims"; import { Status, getRandomStatus } from "#app/data/status-effect"; import type { SpeciesFormEvolution, @@ -122,7 +116,6 @@ import { TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, - TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, @@ -131,6 +124,8 @@ import { TarShotTag, AutotomizedTag, PowerTrickTag, + loadBattlerTag, + type GrudgeTag, } from "../data/battler-tags"; import { WeatherType } from "#enums/weather-type"; import { @@ -139,7 +134,8 @@ import { WeakenMoveScreenTag, } from "#app/data/arena-tag"; import type { SuppressAbilitiesTag } from "#app/data/arena-tag"; -import type { Ability, AbAttr } from "#app/data/ability"; +import type { Ability } from "#app/data/abilities/ability-class"; +import type { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr"; import { StatMultiplierAbAttr, BlockCritAbAttr, @@ -154,7 +150,6 @@ import { StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, - allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, @@ -176,10 +171,7 @@ import { MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, - CheckTrappedAbAttr, - PostSetStatusAbAttr, - applyPostSetStatusAbAttrs, - InfiltratorAbAttr, + CheckTrappedAbAttr, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, @@ -194,10 +186,11 @@ import { applyAllyStatMultiplierAbAttrs, AllyStatMultiplierAbAttr, MoveAbilityBypassAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; +import { allAbilities } from "#app/data/data-lists"; import type PokemonData from "#app/system/pokemon-data"; import { BattlerIndex } from "#app/battle"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type { PartyOption } from "#app/ui/party-ui-handler"; import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; @@ -206,7 +199,7 @@ import { EVOLVE_MOVE, RELEARN_MOVE, } from "#app/data/balance/pokemon-level-moves"; -import { DamageAchv, achvs } from "#app/system/achv"; +import { achvs } from "#app/system/achv"; import type { StarterDataEntry, StarterMoveset } from "#app/system/game-data"; import { DexAttr } from "#app/system/game-data"; import { @@ -220,8 +213,7 @@ import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeMoveLearnedTrigger, - SpeciesFormChangePostMoveTrigger, - SpeciesFormChangeStatusEffectTrigger, + SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms"; import { TerrainType } from "#app/data/terrain"; import type { TrainerSlot } from "#enums/trainer-slot"; @@ -253,6 +245,7 @@ import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { SwitchType } from "#enums/switch-type"; import { SpeciesFormKey } from "#enums/species-form-key"; +import { getStatusEffectOverlapText } from "#app/data/status-effect"; import { BASE_HIDDEN_ABILITY_CHANCE, BASE_SHINY_CHANCE, @@ -264,6 +257,8 @@ import { StatusEffect } from "#enums/status-effect"; import { doShinySparkleAnim } from "#app/field/anims"; import { MoveFlags } from "#enums/MoveFlags"; import { timedEventManager } from "#app/global-event-manager"; +import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader"; +import { ResetStatusPhase } from "#app/phases/reset-status-phase"; export enum LearnMoveSituation { MISC, @@ -280,7 +275,43 @@ export enum FieldPosition { RIGHT, } +/** Base typeclass for damage parameter methods, used for DRY */ +type damageParams = { + /** The attacking {@linkcode Pokemon} */ + source: Pokemon; + /** The move used in the attack */ + move: Move; + /** The move's {@linkcode MoveCategory} after variable-category effects are applied */ + moveCategory: MoveCategory; + /** If `true`, ignores this Pokemon's defensive ability effects */ + ignoreAbility?: boolean; + /** If `true`, ignores the attacking Pokemon's ability effects */ + ignoreSourceAbility?: boolean; + /** If `true`, ignores the ally Pokemon's ability effects */ + ignoreAllyAbility?: boolean; + /** If `true`, ignores the ability effects of the attacking pokemon's ally */ + ignoreSourceAllyAbility?: boolean; + /** If `true`, calculates damage for a critical hit */ + isCritical?: boolean; + /** If `true`, suppresses changes to game state during the calculation */ + simulated?: boolean; + /** If defined, used in place of calculated effectiveness values */ + effectiveness?: number; +} + +/** Type for the parameters of {@linkcode Pokemon#getBaseDamage | getBaseDamage} */ +type getBaseDamageParams = Omit + +/** Type for the parameters of {@linkcode Pokemon#getAttackDamage | getAttackDamage} */ +type getAttackDamageParams = Omit; + export default abstract class Pokemon extends Phaser.GameObjects.Container { + /** + * This pokemon's {@link https://bulbapedia.bulbagarden.net/wiki/Personality_value | Personality value/PID}, + * used to determine various parameters of this Pokemon. + * Represented as a random 32-bit unsigned integer. + * TODO: Stop treating this like a unique ID and stop treating 0 as no pokemon + */ public id: number; public name: string; public nickname: string; @@ -310,7 +341,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public luck: number; public pauseEvolutions: boolean; public pokerus: boolean; - public switchOutStatus: boolean; + public switchOutStatus = false; public evoCounter: number; public teraType: PokemonType; public isTerastallized: boolean; @@ -326,13 +357,23 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public fusionCustomPokemonData: CustomPokemonData | null; public fusionTeraType: PokemonType; - private summonDataPrimer: PokemonSummonData | null; + public customPokemonData: CustomPokemonData = new CustomPokemonData(); - public summonData: PokemonSummonData; - public battleData: PokemonBattleData; - public battleSummonData: PokemonBattleSummonData; - public turnData: PokemonTurnData; - public customPokemonData: CustomPokemonData; + /* Pokemon data types, in vaguely decreasing order of precedence */ + + /** + * Data that resets only on *battle* end (hit count, harvest berries, etc.) + * Kept between waves. + */ + public battleData: PokemonBattleData = new PokemonBattleData(); + /** Data that resets on switch or battle end (stat stages, battler tags, etc.) */ + public summonData: PokemonSummonData = new PokemonSummonData(); + /** Similar to {@linkcode PokemonSummonData}, but is reset on reload (not saved to file). */ + public tempSummonData: PokemonTempSummonData = new PokemonTempSummonData(); + /** Wave data correponding to moves/ability information revealed */ + public waveData: PokemonWaveData = new PokemonWaveData(); + /** Per-turn data like hit count & flinch tracking */ + public turnData: PokemonTurnData = new PokemonTurnData(); /** Used by Mystery Encounters to execute pokemon-specific logic (such as stat boosts) at start of battle */ public mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void; @@ -346,6 +387,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { private shinySparkle: Phaser.GameObjects.Sprite; + // TODO: Rework this eventually constructor( x: number, y: number, @@ -366,38 +408,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { throw `Cannot create a player Pokemon for species '${species.getName(formIndex)}'`; } - const hiddenAbilityChance = new Utils.NumberHolder( - BASE_HIDDEN_ABILITY_CHANCE, - ); - if (!this.hasTrainer()) { - globalScene.applyModifiers( - HiddenAbilityRateBoosterModifier, - true, - hiddenAbilityChance, - ); - } - this.species = species; this.pokeball = dataSource?.pokeball || PokeballType.POKEBALL; this.level = level; - this.switchOutStatus = false; - // Determine the ability index - if (abilityIndex !== undefined) { - this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined - } else { - // If abilityIndex is not provided, determine it based on species and hidden ability - const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value); - const randAbilityIndex = Utils.randSeedInt(2); - if (species.abilityHidden && hasHiddenAbility) { - // If the species has a hidden ability and the hidden ability is present - this.abilityIndex = 2; - } else { - // If there is no hidden ability or species does not have a hidden ability - this.abilityIndex = - species.ability2 !== species.ability1 ? randAbilityIndex : 0; // Use random ability index if species has a second ability, otherwise use 0 - } - } + this.abilityIndex = abilityIndex ?? this.generateAbilityIndex() + if (formIndex !== undefined) { this.formIndex = formIndex; } @@ -413,6 +429,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.exp = dataSource?.exp || getLevelTotalExp(this.level, species.growthRate); this.levelExp = dataSource?.levelExp || 0; + if (dataSource) { this.id = dataSource.id; this.hp = dataSource.hp; @@ -464,8 +481,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.isTerastallized = dataSource.isTerastallized; this.stellarTypesBoosted = dataSource.stellarTypesBoosted ?? []; } else { - this.id = Utils.randSeedInt(4294967296); - this.ivs = ivs || Utils.getIvsFromId(this.id); + this.id = randSeedInt(4294967296); + this.ivs = ivs || getIvsFromId(this.id); if (this.gender === undefined) { this.generateGender(); @@ -488,8 +505,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.variant = this.shiny ? this.generateShinyVariant() : 0; } - this.customPokemonData = new CustomPokemonData(); - if (nature !== undefined) { this.setNature(nature); } else { @@ -508,7 +523,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.pokerus = false; if (level > 1) { - const fused = new Utils.BooleanHolder( + const fused = new BooleanHolder( globalScene.gameMode.isSplicedOnly, ); if (!fused.value && !this.isPlayer() && !this.hasTrainer()) { @@ -525,11 +540,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { (this.fusionShiny ? this.fusionVariant + 1 : 0); this.fusionLuck = this.luck; - this.teraType = Utils.randSeedItem(this.getTypes(false, false, true)); + this.teraType = randSeedItem(this.getTypes(false, false, true)); this.isTerastallized = false; this.stellarTypesBoosted = []; } + this.summonData = new PokemonSummonData(dataSource?.summonData); + this.battleData = new PokemonBattleData(dataSource?.battleData); + this.generateName(); if (!species.isObtainable()) { @@ -539,23 +557,36 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (!dataSource) { this.calculateStats(); } + } - getNameToRender() { + /** + * @param {boolean} useIllusion - Whether we want the fake name or the real name of the Pokemon (for Illusion ability). + */ + getNameToRender(useIllusion: boolean = true) { + const name: string = (!useIllusion && this.summonData.illusion) ? this.summonData.illusion.basePokemon.name : this.name; + const nickname: string = (!useIllusion && this.summonData.illusion) ? this.summonData.illusion.basePokemon.nickname : this.nickname; try { - if (this.nickname) { - return decodeURIComponent(escape(atob(this.nickname))); + if (nickname) { + return decodeURIComponent(escape(atob(nickname))); } - return this.name; + return name; } catch (err) { - console.error(`Failed to decode nickname for ${this.name}`, err); - return this.name; + console.error(`Failed to decode nickname for ${name}`, err); + return name; + } + } + + getPokeball(useIllusion = false){ + if(useIllusion){ + return this.summonData.illusion?.pokeball ?? this.pokeball + } else { + return this.pokeball } } init(): void { this.fieldPosition = FieldPosition.CENTER; - this.initBattleInfo(); globalScene.fieldUI.addAt(this.battleInfo, 0); @@ -589,7 +620,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.addAt(sprite, 0); this.addAt(tintSprite, 1); - if (this.isShiny() && !this.shinySparkle) { + if (this.isShiny(true) && !this.shinySparkle) { this.initShinySparkle(); } } @@ -633,7 +664,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @returns {boolean} `true` if pokemon is allowed in battle */ public isAllowedInChallenge(): boolean { - const challengeAllowed = new Utils.BooleanHolder(true); + const challengeAllowed = new BooleanHolder(true); applyChallenges( ChallengeType.POKEMON_IN_BATTLE, this, @@ -643,9 +674,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } /** - * Checks if the pokemon is allowed in battle (ie: not fainted, and allowed under any active challenges). - * @param onField `true` to also check if the pokemon is currently on the field, defaults to `false` - * @returns `true` if the pokemon is "active". Returns `false` if there is no active {@linkcode BattleScene} + * Checks if this {@linkcode Pokemon} is allowed in battle (ie: not fainted, and allowed under any active challenges). + * @param onField `true` to also check if the pokemon is currently on the field; default `false` + * @returns `true` if the pokemon is "active", as described above. + * Returns `false` if there is no active {@linkcode BattleScene} or the pokemon is disallowed. */ public isActive(onField = false): boolean { if (!globalScene) { @@ -687,6 +719,119 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } + /** Generate `abilityIndex` based on species and hidden ability if not pre-defined. */ + private generateAbilityIndex(): number { + + // Roll for hidden ability chance, applying any ability charms for enemy mons + const hiddenAbilityChance = new NumberHolder( + BASE_HIDDEN_ABILITY_CHANCE, + ); + if (!this.hasTrainer()) { + globalScene.applyModifiers( + HiddenAbilityRateBoosterModifier, + true, + hiddenAbilityChance, + ); + } + + // If the roll succeeded and we have one, use HA; otherwise pick a random ability + const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value); + if (this.species.abilityHidden && hasHiddenAbility) { + return 2; + } + + // only use random ability if species has a second ability + return this.species.ability2 !== this.species.ability1 ? randSeedInt(2) : 0; + } + + + + /** + * Generate an illusion of the last pokemon in the party, as other wild pokemon in the area. + */ + setIllusion(pokemon: Pokemon): boolean { + if (this.summonData.illusion) { + this.breakIllusion(); + } + if (this.hasTrainer()) { + const speciesId = pokemon.species.speciesId; + + this.summonData.illusion = { + basePokemon: { + name: this.name, + nickname: this.nickname, + shiny: this.shiny, + variant: this.variant, + fusionShiny: this.fusionShiny, + fusionVariant: this.fusionVariant + }, + species: speciesId, + formIndex: pokemon.formIndex, + gender: pokemon.gender, + pokeball: pokemon.pokeball, + fusionFormIndex: pokemon.fusionFormIndex, + fusionSpecies: pokemon.fusionSpecies || undefined, + fusionGender: pokemon.fusionGender + }; + + this.name = pokemon.name; + this.nickname = pokemon.nickname; + this.shiny = pokemon.shiny; + this.variant = pokemon.variant; + this.fusionVariant = pokemon.fusionVariant; + this.fusionShiny = pokemon.fusionShiny; + if (this.shiny) { + this.initShinySparkle(); + } + this.loadAssets(false, true).then(() => this.playAnim()); + this.updateInfo(); + } else { + const randomIllusion: PokemonSpecies = globalScene.arena.randomSpecies(globalScene.currentBattle.waveIndex, this.level); + + this.summonData.illusion = { + basePokemon: { + name: this.name, + nickname: this.nickname, + shiny: this.shiny, + variant: this.variant, + fusionShiny: this.fusionShiny, + fusionVariant: this.fusionVariant + }, + species: randomIllusion.speciesId, + formIndex: randomIllusion.formIndex, + gender: this.gender, + pokeball: this.pokeball + }; + + this.name = randomIllusion.name; + this.loadAssets(false, true).then(() => this.playAnim()); + } + return true; + } + + breakIllusion(): boolean { + if (!this.summonData.illusion) { + return false; + } else { + this.name = this.summonData.illusion.basePokemon.name; + this.nickname = this.summonData.illusion.basePokemon.nickname; + this.shiny = this.summonData.illusion.basePokemon.shiny; + this.variant = this.summonData.illusion.basePokemon.variant; + this.fusionVariant = this.summonData.illusion.basePokemon.fusionVariant; + this.fusionShiny = this.summonData.illusion.basePokemon.fusionShiny; + this.summonData.illusion = null; + } + if (this.isOnField()) { + globalScene.playSound("PRSFX- Transform"); + } + if (this.shiny) { + this.initShinySparkle(); + } + this.loadAssets(false).then(() => this.playAnim()); + this.updateInfo(true); + return true; + } + abstract isPlayer(): boolean; abstract hasTrainer(): boolean; @@ -695,115 +840,96 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { abstract getBattlerIndex(): BattlerIndex; - loadAssets(ignoreOverride = true): Promise { - return new Promise(resolve => { - const moveIds = this.getMoveset().map(m => m.getMove().id); - Promise.allSettled(moveIds.map(m => initMoveAnim(m))).then(() => { - loadMoveAnimAssets(moveIds); - this.getSpeciesForm().loadAssets( - this.getGender() === Gender.FEMALE, - this.formIndex, - this.shiny, - this.variant, - ); - if (this.isPlayer() || this.getFusionSpeciesForm()) { - globalScene.loadPokemonAtlas( - this.getBattleSpriteKey(true, ignoreOverride), - this.getBattleSpriteAtlasPath(true, ignoreOverride), - ); - } - if (this.getFusionSpeciesForm()) { - this.getFusionSpeciesForm().loadAssets( - this.getFusionGender() === Gender.FEMALE, - this.fusionFormIndex, - this.fusionShiny, - this.fusionVariant, - ); - globalScene.loadPokemonAtlas( - this.getFusionBattleSpriteKey(true, ignoreOverride), - this.getFusionBattleSpriteAtlasPath(true, ignoreOverride), - ); - } - globalScene.load.once(Phaser.Loader.Events.COMPLETE, () => { - if (this.isPlayer()) { - const originalWarn = console.warn; - // Ignore warnings for missing frames, because there will be a lot - console.warn = () => {}; - const battleFrameNames = globalScene.anims.generateFrameNames( - this.getBattleSpriteKey(), - { zeroPad: 4, suffix: ".png", start: 1, end: 400 }, - ); - console.warn = originalWarn; - if (!globalScene.anims.exists(this.getBattleSpriteKey())) { - globalScene.anims.create({ - key: this.getBattleSpriteKey(), - frames: battleFrameNames, - frameRate: 10, - repeat: -1, - }); - } - } - this.playAnim(); - const updateFusionPaletteAndResolve = () => { - this.updateFusionPalette(); - if (this.summonData?.speciesForm) { - this.updateFusionPalette(true); - } - resolve(); - }; - if (this.shiny) { - const populateVariantColors = ( - isBackSprite = false, - ): Promise => { - return new Promise(async resolve => { - const battleSpritePath = this.getBattleSpriteAtlasPath( - isBackSprite, - ignoreOverride, - ) - .replace("variant/", "") - .replace(/_[1-3]$/, ""); - let config = variantData; - const useExpSprite = - globalScene.experimentalSprites && - globalScene.hasExpSprite( - this.getBattleSpriteKey(isBackSprite, ignoreOverride), - ); - battleSpritePath - .split("/") - .map(p => (config ? (config = config[p]) : null)); - const variantSet: VariantSet = config as VariantSet; - if (variantSet && variantSet[this.variant] === 1) { - const cacheKey = this.getBattleSpriteKey(isBackSprite); - if (!variantColorCache.hasOwnProperty(cacheKey)) { - await this.populateVariantColorCache( - cacheKey, - useExpSprite, - battleSpritePath, - ); - } - } - resolve(); - }); - }; - if (this.isPlayer()) { - Promise.all([ - populateVariantColors(false), - populateVariantColors(true), - ]).then(() => updateFusionPaletteAndResolve()); - } else { - populateVariantColors(false).then(() => - updateFusionPaletteAndResolve(), - ); - } - } else { - updateFusionPaletteAndResolve(); - } - }); - if (!globalScene.load.isLoading()) { - globalScene.load.start(); - } + /** +   * @param useIllusion - Whether we want the illusion or not. +   */ + async loadAssets(ignoreOverride = true, useIllusion: boolean = false): Promise { + /** Promises that are loading assets and can be run concurrently. */ + const loadPromises: Promise[] = []; + // Assets for moves + loadPromises.push(loadMoveAnimations(this.getMoveset().map(m => m.getMove().id))); + + // Load the assets for the species form + const formIndex = useIllusion && this.summonData.illusion ? this.summonData.illusion.formIndex : this.formIndex; + loadPromises.push( + this.getSpeciesForm(false, useIllusion).loadAssets( + this.getGender(useIllusion) === Gender.FEMALE, + formIndex, + this.isShiny(useIllusion), + this.getVariant(useIllusion) + ), + ); + + if (this.isPlayer() || this.getFusionSpeciesForm(false, useIllusion)) { + globalScene.loadPokemonAtlas( + this.getBattleSpriteKey(true, ignoreOverride), + this.getBattleSpriteAtlasPath(true, ignoreOverride), + ); + } + if (this.getFusionSpeciesForm()) { + const fusionFormIndex = useIllusion && this.summonData.illusion ? this.summonData.illusion.fusionFormIndex : this.fusionFormIndex; + const fusionShiny = !useIllusion && this.summonData.illusion?.basePokemon ? this.summonData.illusion.basePokemon.fusionShiny : this.fusionShiny; + const fusionVariant = !useIllusion && this.summonData.illusion?.basePokemon ? this.summonData.illusion.basePokemon.fusionVariant : this.fusionVariant; + loadPromises.push(this.getFusionSpeciesForm(false, useIllusion).loadAssets( + this.getFusionGender(false, useIllusion) === Gender.FEMALE, + fusionFormIndex, + fusionShiny, + fusionVariant + )); + globalScene.loadPokemonAtlas( + this.getFusionBattleSpriteKey(true, ignoreOverride), + this.getFusionBattleSpriteAtlasPath(true, ignoreOverride), + ); + } + + if (this.isShiny(true)) { + loadPromises.push(populateVariantColors(this, false, ignoreOverride)) + if (this.isPlayer()) { + loadPromises.push(populateVariantColors(this, true, ignoreOverride)); + } + } + + await Promise.allSettled(loadPromises); + + // This must be initiated before we queue loading, otherwise the load could have finished before + // we reach the line of code that adds the listener, causing a deadlock. + const waitOnLoadPromise = new Promise(resolve => globalScene.load.once(Phaser.Loader.Events.COMPLETE, resolve)); + + if (!globalScene.load.isLoading()) { + globalScene.load.start(); + } + + // Wait for the assets we queued to load to finish loading, then... + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#creating_a_promise_around_an_old_callback_api + await waitOnLoadPromise; + + // With the sprites loaded, generate the animation frame information + if (this.isPlayer()) { + const originalWarn = console.warn; + // Ignore warnings for missing frames, because there will be a lot + console.warn = () => {}; + const battleFrameNames = globalScene.anims.generateFrameNames(this.getBattleSpriteKey(), { + zeroPad: 4, + suffix: ".png", + start: 1, + end: 400, }); - }); + console.warn = originalWarn; + globalScene.anims.create({ + key: this.getBattleSpriteKey(), + frames: battleFrameNames, + frameRate: 10, + repeat: -1, + }); + } + // With everything loaded, now begin playing the animation. + this.playAnim(); + + // update the fusion palette + this.updateFusionPalette(); + if (this.summonData.speciesForm) { + this.updateFusionPalette(true); + } } /** @@ -911,11 +1037,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } getSpriteId(ignoreOverride?: boolean): string { - return this.getSpeciesForm(ignoreOverride).getSpriteId( - this.getGender(ignoreOverride) === Gender.FEMALE, - this.formIndex, + const formIndex = this.summonData.illusion?.formIndex ?? this.formIndex; + return this.getSpeciesForm(ignoreOverride, true).getSpriteId( + this.getGender(ignoreOverride, true) === Gender.FEMALE, + formIndex, this.shiny, - this.variant, + this.variant ); } @@ -923,21 +1050,24 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (back === undefined) { back = this.isPlayer(); } - return this.getSpeciesForm(ignoreOverride).getSpriteId( - this.getGender(ignoreOverride) === Gender.FEMALE, - this.formIndex, + + const formIndex = this.summonData.illusion?.formIndex ?? this.formIndex; + + return this.getSpeciesForm(ignoreOverride, true).getSpriteId( + this.getGender(ignoreOverride, true) === Gender.FEMALE, + formIndex, this.shiny, this.variant, - back, + back ); } getSpriteKey(ignoreOverride?: boolean): string { - return this.getSpeciesForm(ignoreOverride).getSpriteKey( + return this.getSpeciesForm(ignoreOverride, false).getSpriteKey( this.getGender(ignoreOverride) === Gender.FEMALE, this.formIndex, - this.shiny, - this.variant, + this.summonData.illusion?.basePokemon.shiny ?? this.shiny, + this.summonData.illusion?.basePokemon.variant ?? this.variant ); } @@ -946,11 +1076,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } getFusionSpriteId(ignoreOverride?: boolean): string { - return this.getFusionSpeciesForm(ignoreOverride).getSpriteId( - this.getFusionGender(ignoreOverride) === Gender.FEMALE, - this.fusionFormIndex, + const fusionFormIndex = this.summonData.illusion?.fusionFormIndex ?? this.fusionFormIndex; + return this.getFusionSpeciesForm(ignoreOverride, true).getSpriteId( + this.getFusionGender(ignoreOverride, true) === Gender.FEMALE, + fusionFormIndex, this.fusionShiny, - this.fusionVariant, + this.fusionVariant ); } @@ -958,12 +1089,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (back === undefined) { back = this.isPlayer(); } - return this.getFusionSpeciesForm(ignoreOverride).getSpriteId( - this.getFusionGender(ignoreOverride) === Gender.FEMALE, - this.fusionFormIndex, + + const fusionFormIndex = this.summonData.illusion?.fusionFormIndex ?? this.fusionFormIndex; + + return this.getFusionSpeciesForm(ignoreOverride, true).getSpriteId( + this.getFusionGender(ignoreOverride, true) === Gender.FEMALE, + fusionFormIndex, this.fusionShiny, this.fusionVariant, - back, + back ); } @@ -982,62 +1116,80 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } getIconAtlasKey(ignoreOverride?: boolean): string { - return this.getSpeciesForm(ignoreOverride).getIconAtlasKey( - this.formIndex, + const formIndex = this.summonData.illusion?.formIndex ?? this.formIndex; + return this.getSpeciesForm(ignoreOverride, true).getIconAtlasKey( + formIndex, this.shiny, - this.variant, + this.variant ); } getFusionIconAtlasKey(ignoreOverride?: boolean): string { - return this.getFusionSpeciesForm(ignoreOverride).getIconAtlasKey( + return this.getFusionSpeciesForm(ignoreOverride, true).getIconAtlasKey( this.fusionFormIndex, this.fusionShiny, - this.fusionVariant, + this.fusionVariant ); } getIconId(ignoreOverride?: boolean): string { - return this.getSpeciesForm(ignoreOverride).getIconId( - this.getGender(ignoreOverride) === Gender.FEMALE, - this.formIndex, + const formIndex = this.summonData.illusion?.formIndex ?? this.formIndex; + return this.getSpeciesForm(ignoreOverride, true).getIconId( + this.getGender(ignoreOverride, true) === Gender.FEMALE, + formIndex, this.shiny, - this.variant, + this.variant ); } getFusionIconId(ignoreOverride?: boolean): string { - return this.getFusionSpeciesForm(ignoreOverride).getIconId( - this.getFusionGender(ignoreOverride) === Gender.FEMALE, - this.fusionFormIndex, + const fusionFormIndex = this.summonData.illusion?.fusionFormIndex ?? this.fusionFormIndex; + return this.getFusionSpeciesForm(ignoreOverride, true).getIconId( + this.getFusionGender(ignoreOverride, true) === Gender.FEMALE, + fusionFormIndex, this.fusionShiny, - this.fusionVariant, + this.fusionVariant ); } - getSpeciesForm(ignoreOverride?: boolean): PokemonSpeciesForm { - if (!ignoreOverride && this.summonData?.speciesForm) { + /** + * Get this {@linkcode Pokemon}'s {@linkcode PokemonSpeciesForm}. + * @param ignoreOverride - Whether to ignore overridden species from {@linkcode Moves.TRANSFORM}, default `false`. + * This overrides `useIllusion` if `true`. + * @param useIllusion - `true` to use the speciesForm of the illusion; default `false`. + */ + getSpeciesForm(ignoreOverride: boolean = false, useIllusion: boolean = false): PokemonSpeciesForm { + if (!ignoreOverride && this.summonData.speciesForm) { return this.summonData.speciesForm; } - if (this.species.forms && this.species.forms.length > 0) { - return this.species.forms[this.formIndex]; + + const species: PokemonSpecies = useIllusion && this.summonData.illusion ? getPokemonSpecies(this.summonData.illusion.species) : this.species; + const formIndex = useIllusion && this.summonData.illusion ? this.summonData.illusion.formIndex : this.formIndex; + + if (species.forms && species.forms.length > 0) { + return species.forms[formIndex]; } - return this.species; + return species; } - getFusionSpeciesForm(ignoreOverride?: boolean): PokemonSpeciesForm { - if (!ignoreOverride && this.summonData?.speciesForm) { + /** + * @param {boolean} useIllusion - Whether we want the fusionSpeciesForm of the illusion or not. + */ + getFusionSpeciesForm(ignoreOverride?: boolean, useIllusion: boolean = false): PokemonSpeciesForm { + const fusionSpecies: PokemonSpecies = useIllusion && this.summonData.illusion ? this.summonData.illusion.fusionSpecies! : this.fusionSpecies!; + const fusionFormIndex = useIllusion && this.summonData.illusion ? this.summonData.illusion.fusionFormIndex! : this.fusionFormIndex; + + if (!ignoreOverride && this.summonData.fusionSpeciesForm) { return this.summonData.fusionSpeciesForm; } if ( - !this.fusionSpecies?.forms?.length || - this.fusionFormIndex >= this.fusionSpecies?.forms.length + !fusionSpecies?.forms?.length || + fusionFormIndex >= fusionSpecies?.forms.length ) { - //@ts-ignore - return this.fusionSpecies; // TODO: I don't even know how to fix this... A complete cluster of classes involved + null + return fusionSpecies; } - return this.fusionSpecies?.forms[this.fusionFormIndex]; + return fusionSpecies?.forms[fusionFormIndex]; } getSprite(): Phaser.GameObjects.Sprite { @@ -1060,12 +1212,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { formKey === "ruchbah-starmobile" || formKey === "caph-starmobile" ) { + // G-Max and starmobiles have flat 1.5x scale return 1.5; } - if (this.customPokemonData.spriteScale > 0) { - return this.customPokemonData.spriteScale; + + // TODO: Rather than using -1 as a default... why don't we just change it to 1???????? + if (this.customPokemonData.spriteScale <= 0) { + return 1; } - return 1; + return this.customPokemonData.spriteScale; } /** Resets the pokemon's field sprite properties, including position, alpha, and scale */ @@ -1259,12 +1414,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } /** - * Retrieves the entire set of stats of the {@linkcode Pokemon}. - * @param bypassSummonData prefer actual stats (`true` by default) or in-battle overriden stats (`false`) - * @returns the numeric values of the {@linkcode Pokemon}'s stats + * Retrieves the entire set of stats of this {@linkcode Pokemon}. + * @param bypassSummonData - whether to use actual stats or in-battle overriden stats from Transform; default `true` + * @returns the numeric values of this {@linkcode Pokemon}'s stats */ getStats(bypassSummonData = true): number[] { - if (!bypassSummonData && this.summonData?.stats) { + if (!bypassSummonData && this.summonData.stats) { return this.summonData.stats; } return this.stats; @@ -1279,7 +1434,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { getStat(stat: PermanentStat, bypassSummonData = true): number { if ( !bypassSummonData && - this.summonData && this.summonData.stats[stat] !== 0 ) { return this.summonData.stats[stat]; @@ -1296,12 +1450,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param bypassSummonData write to actual stats (`true` by default) or in-battle overridden stats (`false`) */ setStat(stat: PermanentStat, value: number, bypassSummonData = true): void { - if (value >= 0) { - if (!bypassSummonData && this.summonData) { - this.summonData.stats[stat] = value; - } else { - this.stats[stat] = value; - } + if (value < 0) { + return; + } + + if (!bypassSummonData) { + this.summonData.stats[stat] = value; + } else { + this.stats[stat] = value; } } @@ -1330,44 +1486,26 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param value the desired numeric value */ setStatStage(stat: BattleStat, value: number): void { - if (this.summonData) { - if (value >= -6) { - this.summonData.statStages[stat - 1] = Math.min(value, 6); - } else { - this.summonData.statStages[stat - 1] = Math.max(value, -6); - } + if (value >= -6) { + this.summonData.statStages[stat - 1] = Math.min(value, 6); + } else { + this.summonData.statStages[stat - 1] = Math.max(value, -6); } } /** - * Retrieves the critical-hit stage considering the move used and the Pokemon - * who used it. - * @param source the {@linkcode Pokemon} who using the move - * @param move the {@linkcode Move} being used - * @returns the final critical-hit stage value + * Calculate the critical-hit stage of a move used against this pokemon by + * the given source + * @param source - The {@linkcode Pokemon} using the move + * @param move - The {@linkcode Move} being used + * @returns The final critical-hit stage value */ getCritStage(source: Pokemon, move: Move): number { - const critStage = new Utils.NumberHolder(0); + const critStage = new NumberHolder(0); applyMoveAttrs(HighCritAttr, source, this, move, critStage); - globalScene.applyModifiers( - CritBoosterModifier, - source.isPlayer(), - source, - critStage, - ); - globalScene.applyModifiers( - TempCritBoosterModifier, - source.isPlayer(), - critStage, - ); - const bonusCrit = new Utils.BooleanHolder(false); - //@ts-ignore - if (applyAbAttrs(BonusCritAbAttr, source, null, false, bonusCrit)) { - // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus. - if (bonusCrit.value) { - critStage.value += 1; - } - } + globalScene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critStage); + globalScene.applyModifiers(TempCritBoosterModifier, source.isPlayer(), critStage); + applyAbAttrs(BonusCritAbAttr, source, null, false, critStage); const critBoostTag = source.getTag(CritBoostTag); if (critBoostTag) { if (critBoostTag instanceof DragonCheerTag) { @@ -1383,6 +1521,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return critStage.value; } + /** + * Calculates the category of a move when used by this pokemon after + * category-changing move effects are applied. + * @param target - The {@linkcode Pokemon} using the move + * @param move - The {@linkcode Move} being used + * @returns The given move's final category + */ + getMoveCategory(target: Pokemon, move: Move): MoveCategory { + const moveCategory = new NumberHolder(move.category); + applyMoveAttrs(VariableMoveCategoryAttr, this, target, move, moveCategory); + return moveCategory.value; + } + /** * Calculates and retrieves the final value of a stat considering any held * items, move effects, opponent abilities, and whether there was a critical @@ -1409,7 +1560,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { simulated = true, ignoreHeldItems = false, ): number { - const statValue = new Utils.NumberHolder(this.getStat(stat, false)); + const statValue = new NumberHolder(this.getStat(stat, false)); if (!ignoreHeldItems) { globalScene.applyModifiers( StatBoosterModifier, @@ -1421,7 +1572,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } // The Ruin abilities here are never ignored, but they reveal themselves on summon anyway - const fieldApplied = new Utils.BooleanHolder(false); + const fieldApplied = new BooleanHolder(false); for (const pokemon of globalScene.getField(true)) { applyFieldStatMultiplierAbAttrs( FieldMultiplyStatAbAttr, @@ -1447,7 +1598,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } const ally = this.getAlly(); - if (!Utils.isNullOrUndefined(ally)) { + if (!isNullOrUndefined(ally)) { applyAllyStatMultiplierAbAttrs(AllyStatMultiplierAbAttr, ally, stat, statValue, simulated, this, move?.hasFlag(MoveFlags.IGNORE_ABILITIES) || ignoreAllyAbility); } @@ -1534,7 +1685,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const baseStats = this.calculateBaseStats(); // Using base stats, calculate and store stats one by one for (const s of PERMANENT_STATS) { - const statHolder = new Utils.NumberHolder( + const statHolder = new NumberHolder( Math.floor((2 * baseStats[s] + this.ivs[s]) * this.level * 0.01), ); if (s === Stat.HP) { @@ -1559,7 +1710,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } else { statHolder.value += 5; - const natureStatMultiplier = new Utils.NumberHolder( + const natureStatMultiplier = new NumberHolder( getNatureStatMultiplier(this.getNature(), s), ); globalScene.applyModifier( @@ -1661,9 +1812,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { generateNature(naturePool?: Nature[]): void { if (naturePool === undefined) { - naturePool = Utils.getEnumValues(Nature); + naturePool = getEnumValues(Nature); } - const nature = naturePool[Utils.randSeedInt(naturePool.length)]; + const nature = naturePool[randSeedInt(naturePool.length)]; this.setNature(nature); } @@ -1699,38 +1850,97 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } - getGender(ignoreOverride?: boolean): Gender { - if (!ignoreOverride && this.summonData?.gender !== undefined) { + /** + * @param {boolean} useIllusion - Whether we want the fake or real gender (illusion ability). + */ + getGender(ignoreOverride?: boolean, useIllusion: boolean = false): Gender { + if (useIllusion && this.summonData.illusion) { + return this.summonData.illusion.gender; + } else if (!ignoreOverride && !isNullOrUndefined(this.summonData.gender)) { return this.summonData.gender; } return this.gender; } - getFusionGender(ignoreOverride?: boolean): Gender { - if (!ignoreOverride && this.summonData?.fusionGender !== undefined) { + /** + * @param {boolean} useIllusion - Whether we want the fake or real gender (illusion ability). + */ + getFusionGender(ignoreOverride?: boolean, useIllusion: boolean = false): Gender { + if (useIllusion && this.summonData.illusion?.fusionGender) { + return this.summonData.illusion.fusionGender; + } else if (!ignoreOverride && !isNullOrUndefined(this.summonData.fusionGender)) { return this.summonData.fusionGender; } return this.fusionGender; } - isShiny(): boolean { - return this.shiny || (this.isFusion() && this.fusionShiny); + /** + * @param {boolean} useIllusion - Whether we want the fake or real shininess (illusion ability). + */ + isShiny(useIllusion: boolean = false): boolean { + if (!useIllusion && this.summonData.illusion) { + return this.summonData.illusion.basePokemon?.shiny || (this.summonData.illusion.fusionSpecies && this.summonData.illusion.basePokemon?.fusionShiny) || false; + } else { + return this.shiny || (this.isFusion(useIllusion) && this.fusionShiny); + } } - getVariant(): Variant { - return !this.isFusion() + /** + * + * @param useIllusion - Whether we want the fake or real shininess (illusion ability). + * @returns `true` if the {@linkcode Pokemon} is shiny and the fusion is shiny as well, `false` otherwise + */ + isDoubleShiny(useIllusion: boolean = false): boolean { + if (!useIllusion && this.summonData.illusion?.basePokemon) { + return this.isFusion(false) && this.summonData.illusion.basePokemon.shiny && this.summonData.illusion.basePokemon.fusionShiny; + } else { + return this.isFusion(useIllusion) && this.shiny && this.fusionShiny; + } + } + + /** + * @param {boolean} useIllusion - Whether we want the fake or real variant (illusion ability). + */ + getVariant(useIllusion: boolean = false): Variant { + if (!useIllusion && this.summonData.illusion) { + return !this.isFusion(false) + ? this.summonData.illusion.basePokemon!.variant + : Math.max(this.variant, this.fusionVariant) as Variant; + } else { + return !this.isFusion(true) ? this.variant - : (Math.max(this.variant, this.fusionVariant) as Variant); + : Math.max(this.variant, this.fusionVariant) as Variant; + } + } + + getBaseVariant(doubleShiny: boolean): Variant { + if (doubleShiny) { + return this.summonData.illusion?.basePokemon?.variant ?? this.variant; + } + + return this.getVariant(); } getLuck(): number { return this.luck + (this.isFusion() ? this.fusionLuck : 0); } - isFusion(): boolean { + isFusion(useIllusion: boolean = false): boolean { + if (useIllusion && this.summonData.illusion) { + return !!this.summonData.illusion.fusionSpecies; + } return !!this.fusionSpecies; } + /** + * @param {boolean} useIllusion - Whether we want the fake name or the real name of the Pokemon (for Illusion ability). + */ + getName(useIllusion: boolean = false): string { + return (!useIllusion && this.summonData.illusion?.basePokemon) + ? this.summonData.illusion.basePokemon.name + : this.name; + } + /** * Checks if the {@linkcode Pokemon} has a fusion with the specified {@linkcode Species}. * @param species the pokemon {@linkcode Species} to check @@ -1747,7 +1957,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @returns `true` if the pokemon is the species or is fused with it, `false` otherwise */ hasSpecies(species: Species, formKey?: string): boolean { - if (Utils.isNullOrUndefined(formKey)) { + if (isNullOrUndefined(formKey)) { return ( this.species.speciesId === species || this.fusionSpecies?.speciesId === species @@ -1761,7 +1971,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { getMoveset(ignoreOverride?: boolean): PokemonMove[] { const ret = - !ignoreOverride && this.summonData?.moveset + !ignoreOverride && this.summonData.moveset ? this.summonData.moveset : this.moveset; @@ -1843,12 +2053,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param includeTeraType - `true` to include tera-formed type; Default: `false` * @param forDefend - `true` if the pokemon is defending from an attack; Default: `false` * @param ignoreOverride - If `true`, ignore ability changing effects; Default: `false` + * @param useIllusion - `true` to return the types of the illusion instead of the actual types; "AUTO" will depend on forDefend param; Default: "AUTO" * @returns array of {@linkcode PokemonType} */ public getTypes( includeTeraType = false, - forDefend = false, - ignoreOverride = false, + forDefend: boolean = false, + ignoreOverride?: boolean, + useIllusion: boolean | "AUTO" = "AUTO" ): PokemonType[] { const types: PokemonType[] = []; @@ -1862,17 +2074,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } } - if (!types.length || !includeTeraType) { + + const doIllusion: boolean = (useIllusion === "AUTO") ? !forDefend : useIllusion; if ( !ignoreOverride && - this.summonData?.types && - this.summonData.types.length > 0 + this.summonData.types && + this.summonData.types.length > 0 && + (!this.summonData.illusion || !doIllusion) ) { this.summonData.types.forEach(t => types.push(t)); } else { - const speciesForm = this.getSpeciesForm(ignoreOverride); - const fusionSpeciesForm = this.getFusionSpeciesForm(ignoreOverride); + const speciesForm = this.getSpeciesForm(ignoreOverride, doIllusion); + const fusionSpeciesForm = this.getFusionSpeciesForm(ignoreOverride, doIllusion); const customTypes = this.customPokemonData.types?.length > 0; // First type, checking for "permanently changed" types from ME @@ -1909,7 +2123,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if ( secondType === PokemonType.UNKNOWN && - Utils.isNullOrUndefined(fusionType2) + isNullOrUndefined(fusionType2) ) { // If second pokemon was monotype and shared its primary type secondType = @@ -1948,10 +2162,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } - // the type added to Pokemon from moves like Forest's Curse or Trick Or Treat + // check type added to Pokemon from moves like Forest's Curse or Trick Or Treat if ( !ignoreOverride && - this.summonData && this.summonData.addedType && !types.includes(this.summonData.addedType) ) { @@ -1994,7 +2207,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @returns The non-passive {@linkcode Ability} of the pokemon */ public getAbility(ignoreOverride = false): Ability { - if (!ignoreOverride && this.summonData?.ability) { + if (!ignoreOverride && this.summonData.ability) { return allAbilities[this.summonData.ability]; } if (Overrides.ABILITY_OVERRIDE && this.isPlayer()) { @@ -2060,8 +2273,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * Accounts for all the various effects which can affect whether an ability will be present or * in effect, and both passive and non-passive. * @param attrType - {@linkcode AbAttr} The ability attribute to check for. - * @param canApply - If `false`, it doesn't check whether the ability is currently active; Default `true` - * @param ignoreOverride - If `true`, it ignores ability changing effects; Default `false` + * @param canApply - Whether to check if the ability is currently active; Default `true` + * @param ignoreOverride - Whether to ignore ability changing effects; Default `false` * @returns An array of all the ability attributes on this ability. */ public getAbilityAttrs( @@ -2173,7 +2386,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return false; } if ( - this.summonData?.abilitySuppressed && + this.summonData.abilitySuppressed && ability.isSuppressable ) { return false; @@ -2214,15 +2427,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * Checks whether a pokemon has the specified ability and it's in effect. Accounts for all the various * effects which can affect whether an ability will be present or in effect, and both passive and * non-passive. This is the primary way to check whether a pokemon has a particular ability. - * @param {Abilities} ability The ability to check for - * @param {boolean} canApply If false, it doesn't check whether the ability is currently active - * @param {boolean} ignoreOverride If true, it ignores ability changing effects - * @returns {boolean} Whether the ability is present and active + * @param ability The ability to check for + * @param canApply - Whether to check if the ability is currently active; default `true` + * @param ignoreOverride Whether to ignore ability changing effects; default `false` + * @returns `true` if the ability is present and active */ public hasAbility( ability: Abilities, canApply = true, - ignoreOverride?: boolean, + ignoreOverride = false, ): boolean { if ( this.getAbility(ignoreOverride).id === ability && @@ -2245,15 +2458,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * Accounts for all the various effects which can affect whether an ability will be present or * in effect, and both passive and non-passive. This is one of the two primary ways to check * whether a pokemon has a particular ability. - * @param {AbAttr} attrType The ability attribute to check for - * @param {boolean} canApply If false, it doesn't check whether the ability is currently active - * @param {boolean} ignoreOverride If true, it ignores ability changing effects - * @returns {boolean} Whether an ability with that attribute is present and active + * @param attrType The {@link AbAttr | ability attribute} to check for + * @param canApply - Whether to check if the ability is currently active; default `true` + * @param ignoreOverride Whether to ignore ability changing effects; default `false` + * @returns `true` if an ability with the given {@linkcode AbAttr} is present and active */ public hasAbilityWithAttr( attrType: Constructor, canApply = true, - ignoreOverride?: boolean, + ignoreOverride = false, ): boolean { if ( (!canApply || this.canApplyAbility()) && @@ -2279,11 +2492,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public getWeight(): number { const autotomizedTag = this.getTag(AutotomizedTag); let weightRemoved = 0; - if (!Utils.isNullOrUndefined(autotomizedTag)) { + if (!isNullOrUndefined(autotomizedTag)) { weightRemoved = 100 * autotomizedTag!.autotomizeCount; } const minWeight = 0.1; - const weight = new Utils.NumberHolder(this.species.weight - weightRemoved); + const weight = new NumberHolder(this.species.weight - weightRemoved); // This will trigger the ability overlay so only call this function when necessary applyAbAttrs(WeightMultiplierAbAttr, this, null, false, weight); @@ -2354,7 +2567,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return false; } - const trappedByAbility = new Utils.BooleanHolder(false); + const trappedByAbility = new BooleanHolder(false); /** * Contains opposing Pokemon (Enemy/Player Pokemon) depending on perspective * Afterwards, it filters out Pokemon that have been switched out of the field so trapped abilities/moves do not trigger @@ -2393,7 +2606,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @returns The {@linkcode PokemonType} of the move after attributes are applied */ public getMoveType(move: Move, simulated = true): PokemonType { - const moveTypeHolder = new Utils.NumberHolder(move.type); + const moveTypeHolder = new NumberHolder(move.type); applyMoveAttrs(VariableMoveTypeAttr, this, null, move, moveTypeHolder); applyPreAttackAbAttrs( @@ -2402,9 +2615,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { null, move, simulated, - moveTypeHolder, + moveTypeHolder ); + // If the user is terastallized and the move is tera blast, or tera starstorm that is stellar type, + // then bypass the check for ion deluge and electrify + if (this.isTerastallized && (move.id === Moves.TERA_BLAST || move.id === Moves.TERA_STARSTORM && moveTypeHolder.value === PokemonType.STELLAR)) { + return moveTypeHolder.value as PokemonType; + } + globalScene.arena.applyTags( ArenaTagType.ION_DELUGE, simulated, @@ -2424,8 +2643,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param move {@linkcode Move} The move being used by the attacking Pokémon. * @param ignoreAbility Whether to ignore abilities that might affect type effectiveness or immunity (defaults to `false`). * @param simulated Whether to apply abilities via simulated calls (defaults to `true`) - * @param cancelled {@linkcode Utils.BooleanHolder} Stores whether the move was cancelled by a non-type-based immunity. - * Currently only used by {@linkcode Pokemon.apply} to determine whether a "No effect" message should be shown. + * @param cancelled {@linkcode BooleanHolder} Stores whether the move was cancelled by a non-type-based immunity. + * @param useIllusion - Whether we want the attack move effectiveness on the illusion or not * @returns The type damage multiplier, indicating the effectiveness of the move */ getMoveEffectiveness( @@ -2433,9 +2652,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { move: Move, ignoreAbility = false, simulated = true, - cancelled?: Utils.BooleanHolder, + cancelled?: BooleanHolder, + useIllusion: boolean = false ): TypeDamageMultiplier { - if (!Utils.isNullOrUndefined(this.turnData?.moveEffectiveness)) { + if (!isNullOrUndefined(this.turnData?.moveEffectiveness)) { return this.turnData?.moveEffectiveness; } @@ -2444,18 +2664,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } const moveType = source.getMoveType(move); - const typeMultiplier = new Utils.NumberHolder( + const typeMultiplier = new NumberHolder( move.category !== MoveCategory.STATUS || - move.hasAttr(RespectAttackTypeImmunityAttr) - ? this.getAttackTypeEffectiveness( - moveType, - source, - false, - simulated, - move, - ) - : 1, - ); + move.hasAttr(RespectAttackTypeImmunityAttr) + ? this.getAttackTypeEffectiveness( + moveType, + source, + false, + simulated, + move, + useIllusion + ) + : 1); applyMoveAttrs( VariableMoveTypeMultiplierAttr, @@ -2474,7 +2694,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { typeMultiplier.value *= 2; } - const cancelledHolder = cancelled ?? new Utils.BooleanHolder(false); + const cancelledHolder = cancelled ?? new BooleanHolder(false); if (!ignoreAbility) { applyPreDefendAbAttrs( TypeImmunityAbAttr, @@ -2559,19 +2779,21 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param ignoreStrongWinds whether or not this ignores strong winds (anticipation, forewarn, stealth rocks) * @param simulated tag to only apply the strong winds effect message when the move is used * @param move (optional) the move whose type effectiveness is to be checked. Used for applying {@linkcode VariableMoveTypeChartAttr} + * @param useIllusion - Whether we want the attack type effectiveness on the illusion or not * @returns a multiplier for the type effectiveness */ getAttackTypeEffectiveness( moveType: PokemonType, source?: Pokemon, - ignoreStrongWinds = false, - simulated = true, + ignoreStrongWinds: boolean = false, + simulated: boolean = true, move?: Move, + useIllusion: boolean = false ): TypeDamageMultiplier { if (moveType === PokemonType.STELLAR) { return this.isTerastallized ? 2 : 1; } - const types = this.getTypes(true, true); + const types = this.getTypes(true, true, undefined, useIllusion); const arena = globalScene.arena; // Handle flying v ground type immunity without removing flying type so effective types are still effective @@ -2588,7 +2810,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let multiplier = types .map(defType => { - const multiplier = new Utils.NumberHolder( + const multiplier = new NumberHolder( getTypeDamageMultiplier(moveType, defType), ); applyChallenges( @@ -2606,7 +2828,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ); } if (source) { - const ignoreImmunity = new Utils.BooleanHolder(false); + const ignoreImmunity = new BooleanHolder(false); if ( source.isActive(true) && source.hasAbilityWithAttr(IgnoreTypeImmunityAbAttr) @@ -2639,7 +2861,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }) .reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier; - const typeMultiplierAgainstFlying = new Utils.NumberHolder( + const typeMultiplierAgainstFlying = new NumberHolder( getTypeDamageMultiplier(moveType, PokemonType.FLYING), ); applyChallenges( @@ -2670,7 +2892,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { */ getMatchupScore(opponent: Pokemon): number { const types = this.getTypes(true); - const enemyTypes = opponent.getTypes(true, true); + + const enemyTypes = opponent.getTypes(true, true, false, true); /** Is this Pokemon faster than the opponent? */ const outspeed = (this.isActive(true) @@ -2681,9 +2904,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * Based on how effective this Pokemon's types are offensively against the opponent's types. * This score is increased by 25 percent if this Pokemon is faster than the opponent. */ - let atkScore = - opponent.getAttackTypeEffectiveness(types[0], this) * - (outspeed ? 1.25 : 1); + let atkScore = opponent.getAttackTypeEffectiveness(types[0], this, false, true, undefined, true) * (outspeed ? 1.25 : 1); /** * Based on how effectively this Pokemon defends against the opponent's types. * This score cannot be higher than 4. @@ -2695,12 +2916,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { atkScore *= opponent.getAttackTypeEffectiveness(types[1], this); } if (enemyTypes.length > 1) { - defScore *= - 1 / - Math.max( - this.getAttackTypeEffectiveness(enemyTypes[1], opponent), - 0.25, - ); + defScore *= (1 / Math.max(this.getAttackTypeEffectiveness(enemyTypes[1], opponent, false, false, undefined, true), 0.25)); } /** * Based on this Pokemon's HP ratio compared to that of the opponent. @@ -2951,7 +3167,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } const move = new PokemonMove(moveId); this.moveset[moveIndex] = move; - if (this.summonData?.moveset) { + if (this.summonData.moveset) { this.summonData.moveset[moveIndex] = move; } } @@ -2982,7 +3198,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const E = globalScene.gameData.trainerId ^ globalScene.gameData.secretId; const F = rand1 ^ rand2; - const shinyThreshold = new Utils.NumberHolder(BASE_SHINY_CHANCE); + const shinyThreshold = new NumberHolder(BASE_SHINY_CHANCE); if (thresholdOverride === undefined) { if (timedEventManager.isEventActive()) { const tchance = timedEventManager.getClassicTrainerShinyChance(); @@ -3014,7 +3230,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * Function that tries to set a Pokemon shiny based on seed. * For manual use only, usually to roll a Pokemon's shiny chance a second time. - * If it rolls shiny, also sets a random variant and give the Pokemon the associated luck. + * If it rolls shiny, or if it's already shiny, also sets a random variant and give the Pokemon the associated luck. * * The base shiny odds are {@linkcode BASE_SHINY_CHANCE} / `65536` * @param thresholdOverride number that is divided by `2^16` (`65536`) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm) @@ -3025,29 +3241,31 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { thresholdOverride?: number, applyModifiersToOverride?: boolean, ): boolean { - const shinyThreshold = new Utils.NumberHolder(BASE_SHINY_CHANCE); - if (thresholdOverride === undefined || applyModifiersToOverride) { - if (thresholdOverride !== undefined && applyModifiersToOverride) { - shinyThreshold.value = thresholdOverride; - } - if (timedEventManager.isEventActive()) { - shinyThreshold.value *= timedEventManager.getShinyMultiplier(); - } - if (!this.hasTrainer()) { + if (!this.shiny) { + const shinyThreshold = new NumberHolder(BASE_SHINY_CHANCE); + if (thresholdOverride === undefined || applyModifiersToOverride) { + if (thresholdOverride !== undefined && applyModifiersToOverride) { + shinyThreshold.value = thresholdOverride; + } + if (timedEventManager.isEventActive()) { + shinyThreshold.value *= timedEventManager.getShinyMultiplier(); + } globalScene.applyModifiers( ShinyRateBoosterModifier, true, shinyThreshold, ); } - } else { - shinyThreshold.value = thresholdOverride; + else { + shinyThreshold.value = thresholdOverride; + } + + this.shiny = randSeedInt(65536) < shinyThreshold.value; } - this.shiny = randSeedInt(65536) < shinyThreshold.value; - if (this.shiny) { - this.variant = this.generateShinyVariant(); + this.variant = this.variant ?? 0; + this.variant = Math.max(this.generateShinyVariant(), this.variant) as Variant; // Don't set a variant lower than the current one this.luck = this.variant + 1 + (this.fusionShiny ? this.fusionVariant + 1 : 0); this.initShinySparkle(); @@ -3080,10 +3298,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ) { return 0; } - const rand = new Utils.NumberHolder(0); + const rand = new NumberHolder(0); globalScene.executeWithSeedOffset( () => { - rand.value = Utils.randSeedInt(10); + rand.value = randSeedInt(10); }, this.id, globalScene.waveSeed, @@ -3113,7 +3331,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (!this.species.abilityHidden) { return false; } - const haThreshold = new Utils.NumberHolder(BASE_HIDDEN_ABILITY_CHANCE); + const haThreshold = new NumberHolder(BASE_HIDDEN_ABILITY_CHANCE); if (thresholdOverride === undefined || applyModifiersToOverride) { if (thresholdOverride !== undefined && applyModifiersToOverride) { haThreshold.value = thresholdOverride; @@ -3137,7 +3355,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } public generateFusionSpecies(forStarter?: boolean): void { - const hiddenAbilityChance = new Utils.NumberHolder( + const hiddenAbilityChance = new NumberHolder( BASE_HIDDEN_ABILITY_CHANCE, ); if (!this.hasTrainer()) { @@ -3148,8 +3366,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ); } - const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value); - const randAbilityIndex = Utils.randSeedInt(2); + const hasHiddenAbility = !randSeedInt(hiddenAbilityChance.value); + const randAbilityIndex = randSeedInt(2); const filter = !forStarter ? this.species.getCompatibleFusionSpeciesFilter() @@ -3466,7 +3684,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (stabMovePool.length) { const totalWeight = stabMovePool.reduce((v, m) => v + m[1], 0); - let rand = Utils.randSeedInt(totalWeight); + let rand = randSeedInt(totalWeight); let index = 0; while (rand > stabMovePool[index][1]) { rand -= stabMovePool[index++][1]; @@ -3480,7 +3698,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ); if (attackMovePool.length) { const totalWeight = attackMovePool.reduce((v, m) => v + m[1], 0); - let rand = Utils.randSeedInt(totalWeight); + let rand = randSeedInt(totalWeight); let index = 0; while (rand > attackMovePool[index][1]) { rand -= attackMovePool[index++][1]; @@ -3532,7 +3750,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo.moveId)); } const totalWeight = movePool.reduce((v, m) => v + m[1], 0); - let rand = Utils.randSeedInt(totalWeight); + let rand = randSeedInt(totalWeight); let index = 0; while (rand > movePool[index][1]) { rand -= movePool[index++][1]; @@ -3690,18 +3908,23 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { getOpponent(targetIndex: number): Pokemon | null { const ret = this.getOpponents()[targetIndex]; - if (ret.summonData) { + if (ret.summonData) { // TODO: why does this check for summonData and can we remove it? return ret; } return null; } - getOpponents(): Pokemon[] { + /** + * Returns the pokemon that oppose this one and are active + * + * @param onField - whether to also check if the pokemon is currently on the field (defaults to true) + */ + getOpponents(onField = true): Pokemon[] { return ( (this.isPlayer() ? globalScene.getEnemyField() : globalScene.getPlayerField()) as Pokemon[] - ).filter(p => p.isActive()); + ).filter(p => p.isActive(onField)); } getOpponentDescriptor(): string { @@ -3756,8 +3979,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { simulated = true, ignoreHeldItems = false, ): number { - const statStage = new Utils.NumberHolder(this.getStatStage(stat)); - const ignoreStatStage = new Utils.BooleanHolder(false); + const statStage = new NumberHolder(this.getStatStage(stat)); + const ignoreStatStage = new BooleanHolder(false); if (opponent) { if (isCritical) { @@ -3794,7 +4017,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } if (!ignoreStatStage.value) { - const statStageMultiplier = new Utils.NumberHolder( + const statStageMultiplier = new NumberHolder( Math.max(2, 2 + statStage.value) / Math.max(2, 2 - statStage.value), ); if (!ignoreHeldItems) { @@ -3826,13 +4049,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return 1; } - const userAccStage = new Utils.NumberHolder(this.getStatStage(Stat.ACC)); - const targetEvaStage = new Utils.NumberHolder( + const userAccStage = new NumberHolder(this.getStatStage(Stat.ACC)); + const targetEvaStage = new NumberHolder( target.getStatStage(Stat.EVA), ); - const ignoreAccStatStage = new Utils.BooleanHolder(false); - const ignoreEvaStatStage = new Utils.BooleanHolder(false); + const ignoreAccStatStage = new BooleanHolder(false); + const ignoreEvaStatStage = new BooleanHolder(false); applyAbAttrs( IgnoreOpponentStatStagesAbAttr, @@ -3874,7 +4097,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { targetEvaStage.value = Math.min(0, targetEvaStage.value); } - const accuracyMultiplier = new Utils.NumberHolder(1); + const accuracyMultiplier = new NumberHolder(1); if (userAccStage.value !== targetEvaStage.value) { accuracyMultiplier.value = userAccStage.value > targetEvaStage.value @@ -3891,7 +4114,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { sourceMove, ); - const evasionMultiplier = new Utils.NumberHolder(1); + const evasionMultiplier = new NumberHolder(1); applyStatMultiplierAbAttrs( StatMultiplierAbAttr, target, @@ -3912,27 +4135,28 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * Calculates the base damage of the given move against this Pokemon when attacked by the given source. * Used during damage calculation and for Shell Side Arm's forecasting effect. - * @param source the attacking {@linkcode Pokemon}. - * @param move the {@linkcode Move} used in the attack. - * @param moveCategory the move's {@linkcode MoveCategory} after variable-category effects are applied. - * @param ignoreAbility if `true`, ignores this Pokemon's defensive ability effects (defaults to `false`). - * @param ignoreSourceAbility if `true`, ignore's the attacking Pokemon's ability effects (defaults to `false`). - * @param ignoreAllyAbility if `true`, ignores the ally Pokemon's ability effects (defaults to `false`). - * @param ignoreSourceAllyAbility if `true`, ignores the attacking Pokemon's ally's ability effects (defaults to `false`). - * @param isCritical if `true`, calculates effective stats as if the hit were critical (defaults to `false`). - * @param simulated if `true`, suppresses changes to game state during calculation (defaults to `true`). + * @param source - The attacking {@linkcode Pokemon}. + * @param move - The {@linkcode Move} used in the attack. + * @param moveCategory - The move's {@linkcode MoveCategory} after variable-category effects are applied. + * @param ignoreAbility - If `true`, ignores this Pokemon's defensive ability effects (defaults to `false`). + * @param ignoreSourceAbility - If `true`, ignore's the attacking Pokemon's ability effects (defaults to `false`). + * @param ignoreAllyAbility - If `true`, ignores the ally Pokemon's ability effects (defaults to `false`). + * @param ignoreSourceAllyAbility - If `true`, ignores the attacking Pokemon's ally's ability effects (defaults to `false`). + * @param isCritical - if `true`, calculates effective stats as if the hit were critical (defaults to `false`). + * @param simulated - if `true`, suppresses changes to game state during calculation (defaults to `true`). * @returns The move's base damage against this Pokemon when used by the source Pokemon. */ getBaseDamage( - source: Pokemon, - move: Move, - moveCategory: MoveCategory, + { + source, + move, + moveCategory, ignoreAbility = false, ignoreSourceAbility = false, ignoreAllyAbility = false, ignoreSourceAllyAbility = false, isCritical = false, - simulated = true, + simulated = true}: getBaseDamageParams ): number { const isPhysical = moveCategory === MoveCategory.PHYSICAL; @@ -3946,7 +4170,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * The attacker's offensive stat for the given move's category. * Critical hits cause negative stat stages to be ignored. */ - const sourceAtk = new Utils.NumberHolder( + const sourceAtk = new NumberHolder( source.getEffectiveStat( isPhysical ? Stat.ATK : Stat.SPATK, this, @@ -3964,7 +4188,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * This Pokemon's defensive stat for the given move's category. * Critical hits cause positive stat stages to be ignored. */ - const targetDef = new Utils.NumberHolder( + const targetDef = new NumberHolder( this.getEffectiveStat( isPhysical ? Stat.DEF : Stat.SPDEF, source, @@ -4000,37 +4224,93 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return baseDamage; } + + /** Determine the STAB multiplier for a move used against this pokemon. + * + * @param source - The attacking {@linkcode Pokemon} + * @param move - The {@linkcode Move} used in the attack + * @param ignoreSourceAbility - If `true`, ignores the attacking Pokemon's ability effects + * @param simulated - If `true`, suppresses changes to game state during the calculation + * + * @returns The STAB multiplier for the move used against this Pokemon + */ + calculateStabMultiplier(source: Pokemon, move: Move, ignoreSourceAbility: boolean, simulated: boolean): number { + // If the move has the Typeless attribute, it doesn't get STAB (e.g. struggle) + if (move.hasAttr(TypelessAttr)) { + return 1; + } + const sourceTypes = source.getTypes(); + const sourceTeraType = source.getTeraType(); + const moveType = source.getMoveType(move); + const matchesSourceType = sourceTypes.includes(source.getMoveType(move)); + const stabMultiplier = new NumberHolder(1); + if (matchesSourceType && moveType !== PokemonType.STELLAR) { + stabMultiplier.value += 0.5; + } + + applyMoveAttrs( + CombinedPledgeStabBoostAttr, + source, + this, + move, + stabMultiplier, + ); + + if (!ignoreSourceAbility) { + applyAbAttrs(StabBoostAbAttr, source, null, simulated, stabMultiplier); + } + + if ( + source.isTerastallized && + sourceTeraType === moveType && + moveType !== PokemonType.STELLAR + ) { + stabMultiplier.value += 0.5; + } + + if ( + source.isTerastallized && + source.getTeraType() === PokemonType.STELLAR && + (!source.stellarTypesBoosted.includes(moveType) || + source.hasSpecies(Species.TERAPAGOS)) + ) { + stabMultiplier.value += matchesSourceType ? 0.5 : 0.2; + } + + return Math.min(stabMultiplier.value, 2.25); + } + /** * Calculates the damage of an attack made by another Pokemon against this Pokemon * @param source {@linkcode Pokemon} the attacking Pokemon - * @param move {@linkcode Pokemon} the move used in the attack + * @param move The {@linkcode Move} used in the attack * @param ignoreAbility If `true`, ignores this Pokemon's defensive ability effects * @param ignoreSourceAbility If `true`, ignores the attacking Pokemon's ability effects * @param ignoreAllyAbility If `true`, ignores the ally Pokemon's ability effects * @param ignoreSourceAllyAbility If `true`, ignores the ability effects of the attacking pokemon's ally * @param isCritical If `true`, calculates damage for a critical hit. * @param simulated If `true`, suppresses changes to game state during the calculation. - * @returns a {@linkcode DamageCalculationResult} object with three fields: - * - `cancelled`: `true` if the move was cancelled by another effect. - * - `result`: {@linkcode HitResult} indicates the attack's type effectiveness. - * - `damage`: `number` the attack's final damage output. + * @param effectiveness If defined, used in place of calculated effectiveness values + * @returns The {@linkcode DamageCalculationResult} */ getAttackDamage( - source: Pokemon, - move: Move, - ignoreAbility = false, - ignoreSourceAbility = false, - ignoreAllyAbility = false, - ignoreSourceAllyAbility = false, - isCritical = false, - simulated = true, + { + source, + move, + ignoreAbility = false, + ignoreSourceAbility = false, + ignoreAllyAbility = false, + ignoreSourceAllyAbility = false, + isCritical = false, + simulated = true, + effectiveness}: getAttackDamageParams, ): DamageCalculationResult { - const damage = new Utils.NumberHolder(0); + const damage = new NumberHolder(0); const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; - const variableCategory = new Utils.NumberHolder(move.category); + const variableCategory = new NumberHolder(move.category); applyMoveAttrs( VariableMoveCategoryAttr, source, @@ -4044,7 +4324,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const moveType = source.getMoveType(move); /** If `value` is `true`, cancels the move and suppresses "No Effect" messages */ - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); /** * The effectiveness of the move being used. Along with type matchups, this @@ -4053,7 +4333,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * * Note that the source's abilities are not ignored here */ - const typeMultiplier = this.getMoveEffectiveness( + const typeMultiplier = effectiveness ?? this.getMoveEffectiveness( source, move, ignoreAbility, @@ -4064,7 +4344,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const isPhysical = moveCategory === MoveCategory.PHYSICAL; /** Combined damage multiplier from field effects such as weather, terrain, etc. */ - const arenaAttackTypeMultiplier = new Utils.NumberHolder( + const arenaAttackTypeMultiplier = new NumberHolder( globalScene.arena.getAttackTypeMultiplier(moveType, source.isGrounded()), ); applyMoveAttrs( @@ -4087,10 +4367,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } // If the attack deals fixed damage, return a result with that much damage - const fixedDamage = new Utils.NumberHolder(0); + const fixedDamage = new NumberHolder(0); applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage); if (fixedDamage.value) { - const multiLensMultiplier = new Utils.NumberHolder(1); + const multiLensMultiplier = new NumberHolder(1); globalScene.applyModifiers( PokemonMultiHitModifier, source.isPlayer(), @@ -4099,7 +4379,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { null, multiLensMultiplier, ); - fixedDamage.value = Utils.toDmgValue( + fixedDamage.value = toDmgValue( fixedDamage.value * multiLensMultiplier.value, ); @@ -4111,7 +4391,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } // If the attack is a one-hit KO move, return a result with damage equal to this Pokemon's HP - const isOneHitKo = new Utils.BooleanHolder(false); + const isOneHitKo = new BooleanHolder(false); applyMoveAttrs(OneHitKOAttr, source, this, move, isOneHitKo); if (isOneHitKo.value) { return { @@ -4125,7 +4405,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * The attack's base damage, as determined by the source's level, move power * and Attack stat as well as this Pokemon's Defense stat */ - const baseDamage = this.getBaseDamage( + const baseDamage = this.getBaseDamage({ source, move, moveCategory, @@ -4135,7 +4415,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ignoreSourceAllyAbility, isCritical, simulated, - ); + }); /** 25% damage debuff on moves hitting more than one non-fainted target (regardless of immunities) */ const { targets, multiple } = getMoveTargets(source, move.id); @@ -4143,7 +4423,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const targetMultiplier = numTargets > 1 ? 0.75 : 1; /** Multiplier for moves enhanced by Multi-Lens and/or Parental Bond */ - const multiStrikeEnhancementMultiplier = new Utils.NumberHolder(1); + const multiStrikeEnhancementMultiplier = new NumberHolder(1); globalScene.applyModifiers( PokemonMultiHitModifier, source.isPlayer(), @@ -4165,13 +4445,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } /** Doubles damage if this Pokemon's last move was Glaive Rush */ - const glaiveRushMultiplier = new Utils.NumberHolder(1); + const glaiveRushMultiplier = new NumberHolder(1); if (this.getTag(BattlerTagType.RECEIVE_DOUBLE_DAMAGE)) { glaiveRushMultiplier.value = 2; } /** The damage multiplier when the given move critically hits */ - const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1); + const criticalMultiplier = new NumberHolder(isCritical ? 1.5 : 1); applyAbAttrs(MultCritAbAttr, source, null, simulated, criticalMultiplier); /** @@ -4182,75 +4462,34 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ? 1 : this.randSeedIntRange(85, 100) / 100; - const sourceTypes = source.getTypes(); - const sourceTeraType = source.getTeraType(); - const matchesSourceType = sourceTypes.includes(moveType); + /** A damage multiplier for when the attack is of the attacker's type and/or Tera type. */ - const stabMultiplier = new Utils.NumberHolder(1); - if (matchesSourceType && moveType !== PokemonType.STELLAR) { - stabMultiplier.value += 0.5; - } - - if (!ignoreSourceAbility) { - applyAbAttrs(StabBoostAbAttr, source, null, simulated, stabMultiplier); - } - - applyMoveAttrs( - CombinedPledgeStabBoostAttr, - source, - this, - move, - stabMultiplier, - ); - - if ( - source.isTerastallized && - sourceTeraType === moveType && - moveType !== PokemonType.STELLAR - ) { - stabMultiplier.value += 0.5; - } - - if ( - source.isTerastallized && - source.getTeraType() === PokemonType.STELLAR && - (!source.stellarTypesBoosted.includes(moveType) || - source.hasSpecies(Species.TERAPAGOS)) - ) { - if (matchesSourceType) { - stabMultiplier.value += 0.5; - } else { - stabMultiplier.value += 0.2; - } - } - - stabMultiplier.value = Math.min(stabMultiplier.value, 2.25); + const stabMultiplier = this.calculateStabMultiplier(source, move, ignoreSourceAbility, simulated); /** Halves damage if the attacker is using a physical attack while burned */ - const burnMultiplier = new Utils.NumberHolder(1); + let burnMultiplier = 1; if ( isPhysical && source.status && - source.status.effect === StatusEffect.BURN + source.status.effect === StatusEffect.BURN && + !move.hasAttr(BypassBurnDamageReductionAttr) ) { - if (!move.hasAttr(BypassBurnDamageReductionAttr)) { - const burnDamageReductionCancelled = new Utils.BooleanHolder(false); - if (!ignoreSourceAbility) { - applyAbAttrs( - BypassBurnDamageReductionAbAttr, - source, - burnDamageReductionCancelled, - simulated, - ); - } - if (!burnDamageReductionCancelled.value) { - burnMultiplier.value = 0.5; - } + const burnDamageReductionCancelled = new BooleanHolder(false); + if (!ignoreSourceAbility) { + applyAbAttrs( + BypassBurnDamageReductionAbAttr, + source, + burnDamageReductionCancelled, + simulated, + ); + } + if (!burnDamageReductionCancelled.value) { + burnMultiplier = 0.5; } } /** Reduces damage if this Pokemon has a relevant screen (e.g. Light Screen for special attacks) */ - const screenMultiplier = new Utils.NumberHolder(1); + const screenMultiplier = new NumberHolder(1); // Critical hits should bypass screens if (!isCritical) { @@ -4270,7 +4509,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * AND * The move doubles damage when used against that tag */ - const hitsTagMultiplier = new Utils.NumberHolder(1); + const hitsTagMultiplier = new NumberHolder(1); move .getAttrs(HitsTagAttr) .filter(hta => hta.doubleDamage) @@ -4288,7 +4527,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ? 0.5 : 1; - damage.value = Utils.toDmgValue( + damage.value = toDmgValue( baseDamage * targetMultiplier * multiStrikeEnhancementMultiplier.value * @@ -4296,9 +4535,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { glaiveRushMultiplier.value * criticalMultiplier.value * randomMultiplier * - stabMultiplier.value * + stabMultiplier * typeMultiplier * - burnMultiplier.value * + burnMultiplier * screenMultiplier.value * hitsTagMultiplier.value * mistyTerrainMultiplier, @@ -4387,223 +4626,45 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }; } - /** - * Applies the results of a move to this pokemon - * @param source The {@linkcode Pokemon} using the move - * @param move The {@linkcode Move} being used - * @returns The {@linkcode HitResult} of the attack - */ - apply(source: Pokemon, move: Move): HitResult { - const defendingSide = this.isPlayer() - ? ArenaTagSide.PLAYER - : ArenaTagSide.ENEMY; - const moveCategory = new Utils.NumberHolder(move.category); - applyMoveAttrs(VariableMoveCategoryAttr, source, this, move, moveCategory); - if (moveCategory.value === MoveCategory.STATUS) { - const cancelled = new Utils.BooleanHolder(false); - const typeMultiplier = this.getMoveEffectiveness( - source, - move, - false, - false, - cancelled, - ); - - if (!cancelled.value && typeMultiplier === 0) { - globalScene.queueMessage( - i18next.t("battle:hitResultNoEffect", { - pokemonName: getPokemonNameWithAffix(this), - }), - ); - } - return typeMultiplier === 0 ? HitResult.NO_EFFECT : HitResult.STATUS; + /** Calculate whether the given move critically hits this pokemon + * @param source - The {@linkcode Pokemon} using the move + * @param move - The {@linkcode Move} being used + * @param simulated - If `true`, suppresses changes to game state during calculation (defaults to `true`) + * @returns whether the move critically hits the pokemon + */ + getCriticalHitResult(source: Pokemon, move: Move, simulated: boolean = true): boolean { + const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; + const noCritTag = globalScene.arena.getTagOnSide(NoCritTag, defendingSide); + if (noCritTag || Overrides.NEVER_CRIT_OVERRIDE || move.hasAttr(FixedDamageAttr)) { + return false; } - /** Determines whether the attack critically hits */ - let isCritical: boolean; - const critOnly = new Utils.BooleanHolder(false); - const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT); - applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly); - applyAbAttrs( - ConditionalCritAbAttr, - source, - null, - false, - critOnly, - this, - move, - ); - if (critOnly.value || critAlways) { - isCritical = true; - } else { + const isCritical = new BooleanHolder(false); + + if (source.getTag(BattlerTagType.ALWAYS_CRIT)) { + isCritical.value = true; + } + applyMoveAttrs(CritOnlyAttr, source, this, move, isCritical); + applyAbAttrs(ConditionalCritAbAttr, source, null, simulated, isCritical, this, move); + if (!isCritical.value) { const critChance = [24, 8, 2, 1][ Math.max(0, Math.min(this.getCritStage(source, move), 3)) ]; - isCritical = - critChance === 1 || !globalScene.randBattleSeedInt(critChance); + isCritical.value = critChance === 1 || !globalScene.randBattleSeedInt(critChance); } - const noCritTag = globalScene.arena.getTagOnSide(NoCritTag, defendingSide); - const blockCrit = new Utils.BooleanHolder(false); - applyAbAttrs(BlockCritAbAttr, this, null, false, blockCrit); - if (noCritTag || blockCrit.value || Overrides.NEVER_CRIT_OVERRIDE) { - isCritical = false; - } + applyAbAttrs(BlockCritAbAttr, this, null, simulated, isCritical); - /** - * Applies stat changes from {@linkcode move} and gives it to {@linkcode source} - * before damage calculation - */ - applyMoveAttrs(StatChangeBeforeDmgCalcAttr, source, this, move); + return isCritical.value; - const { - cancelled, - result, - damage: dmg, - } = this.getAttackDamage(source, move, false, false, false, false, isCritical, false); - - const typeBoost = source.findTag( - t => - t instanceof TypeBoostTag && t.boostedType === source.getMoveType(move), - ) as TypeBoostTag; - if (typeBoost?.oneUse) { - source.removeTag(typeBoost.tagType); - } - - if ( - cancelled || - result === HitResult.IMMUNE || - result === HitResult.NO_EFFECT - ) { - source.stopMultiHit(this); - - if (!cancelled) { - if (result === HitResult.IMMUNE) { - globalScene.queueMessage( - i18next.t("battle:hitResultImmune", { - pokemonName: getPokemonNameWithAffix(this), - }), - ); - } else { - globalScene.queueMessage( - i18next.t("battle:hitResultNoEffect", { - pokemonName: getPokemonNameWithAffix(this), - }), - ); - } - } - return result; - } - - // In case of fatal damage, this tag would have gotten cleared before we could lapse it. - const destinyTag = this.getTag(BattlerTagType.DESTINY_BOND); - const grudgeTag = this.getTag(BattlerTagType.GRUDGE); - - if (dmg) { - this.lapseTags(BattlerTagLapseType.HIT); - - const substitute = this.getTag(SubstituteTag); - const isBlockedBySubstitute = - !!substitute && move.hitsSubstitute(source, this); - if (isBlockedBySubstitute) { - substitute.hp -= dmg; - } - if (!this.isPlayer() && dmg >= this.hp) { - globalScene.applyModifiers(EnemyEndureChanceModifier, false, this); - } - - /** - * We explicitly require to ignore the faint phase here, as we want to show the messages - * about the critical hit and the super effective/not very effective messages before the faint phase. - */ - const damage = this.damageAndUpdate(isBlockedBySubstitute ? 0 : dmg, - { - result: result as DamageResult, - isCritical, - ignoreFaintPhase: true, - source - }); - - if (damage > 0) { - if (source.isPlayer()) { - globalScene.validateAchvs(DamageAchv, new Utils.NumberHolder(damage)); - if (damage > globalScene.gameData.gameStats.highestDamage) { - globalScene.gameData.gameStats.highestDamage = damage; - } - } - source.turnData.totalDamageDealt += damage; - source.turnData.singleHitDamageDealt = damage; - this.turnData.damageTaken += damage; - this.battleData.hitCount++; - - const attackResult = { - move: move.id, - result: result as DamageResult, - damage: damage, - critical: isCritical, - sourceId: source.id, - sourceBattlerIndex: source.getBattlerIndex(), - }; - this.turnData.attacksReceived.unshift(attackResult); - if (source.isPlayer() && !this.isPlayer()) { - globalScene.applyModifiers( - DamageMoneyRewardModifier, - true, - source, - new Utils.NumberHolder(damage), - ); - } - } - } - - if (isCritical) { - globalScene.queueMessage(i18next.t("battle:hitResultCriticalHit")); - } - - // want to include is.Fainted() in case multi hit move ends early, still want to render message - if (source.turnData.hitsLeft === 1 || this.isFainted()) { - switch (result) { - case HitResult.SUPER_EFFECTIVE: - globalScene.queueMessage(i18next.t("battle:hitResultSuperEffective")); - break; - case HitResult.NOT_VERY_EFFECTIVE: - globalScene.queueMessage( - i18next.t("battle:hitResultNotVeryEffective"), - ); - break; - case HitResult.ONE_HIT_KO: - globalScene.queueMessage(i18next.t("battle:hitResultOneHitKO")); - break; - } - } - - if (this.isFainted()) { - // set splice index here, so future scene queues happen before FaintedPhase - globalScene.setPhaseQueueSplice(); - globalScene.unshiftPhase( - new FaintPhase( - this.getBattlerIndex(), - false, - destinyTag, - grudgeTag, - source, - ), - ); - - this.destroySubstitute(); - this.lapseTag(BattlerTagType.COMMANDED); - this.resetSummonData(); - } - - return result; } /** * Called by damageAndUpdate() * @param damage integer * @param ignoreSegments boolean, not currently used - * @param preventEndure used to update damage if endure or sturdy - * @param ignoreFaintPhase flag on wheter to add FaintPhase if pokemon after applying damage faints - * @returns integer representing damage + * @param preventEndure used to update damage if endure or sturdy + * @param ignoreFaintPhas flag on whether to add FaintPhase if pokemon after applying damage faints + * @returns integer representing damage dealt */ damage( damage: number, @@ -4614,8 +4675,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (this.isFainted()) { return 0; } - const surviveDamage = new Utils.BooleanHolder(false); + const surviveDamage = new BooleanHolder(false); + // check for endure and other abilities that would prevent us from death if (!preventEndure && this.hp - damage <= 0) { if (this.hp >= 1 && this.getTag(BattlerTagType.ENDURING)) { surviveDamage.value = this.lapseTag(BattlerTagType.ENDURING); @@ -4653,13 +4715,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ); this.destroySubstitute(); this.lapseTag(BattlerTagType.COMMANDED); - this.resetSummonData(); } return damage; } /** - * Called by apply(), given the damage, adds a new DamagePhase and actually updates HP values, etc. + * Given the damage, adds a new DamagePhase and update HP values, etc. + * * Checks for 'Indirect' HitResults to account for Endure/Reviver Seed applying correctly * @param damage integer - passed to damage() * @param result an enum if it's super effective, not very, etc. @@ -4671,25 +4733,25 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { */ damageAndUpdate(damage: number, { - result = HitResult.EFFECTIVE, - isCritical = false, - ignoreSegments = false, - ignoreFaintPhase = false, + result = HitResult.EFFECTIVE, + isCritical = false, + ignoreSegments = false, + ignoreFaintPhase = false, source = undefined, }: { - result?: DamageResult, - isCritical?: boolean, - ignoreSegments?: boolean, - ignoreFaintPhase?: boolean, + result?: DamageResult, + isCritical?: boolean, + ignoreSegments?: boolean, + ignoreFaintPhase?: boolean, source?: Pokemon, } = {} ): number { const isIndirectDamage = [ HitResult.INDIRECT, HitResult.INDIRECT_KO ].includes(result); const damagePhase = new DamageAnimPhase( - this.getBattlerIndex(), - damage, - result as DamageResult, + this.getBattlerIndex(), + damage, + result as DamageResult, isCritical ); globalScene.unshiftPhase(damagePhase); @@ -4749,7 +4811,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const stubTag = new BattlerTag(tagType, 0, 0); - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); applyPreApplyBattlerTagAbAttrs( BattlerTagImmunityAbAttr, this, @@ -4787,7 +4849,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const newTag = getBattlerTag(tagType, turnCount, sourceMove!, sourceId!); // TODO: are the bangs correct? - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); applyPreApplyBattlerTagAbAttrs( BattlerTagImmunityAbAttr, this, @@ -4815,59 +4877,61 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (newTag.canAdd(this)) { this.summonData.tags.push(newTag); newTag.onAdd(this); - return true; } return false; } - /** @overload */ - getTag(tagType: BattlerTagType): BattlerTag | nil; + /**@overload */ + getTag(tagType: BattlerTagType.GRUDGE): GrudgeTag | nil; /** @overload */ - getTag(tagType: Constructor): T | nil; + getTag(tagType: BattlerTagType): BattlerTag | undefined; - getTag(tagType: BattlerTagType | Constructor): BattlerTag | nil { - if (!this.summonData) { - return null; - } + /** @overload */ + getTag(tagType: Constructor): T | undefined; + + getTag(tagType: BattlerTagType | Constructor): BattlerTag | undefined { return tagType instanceof Function ? this.summonData.tags.find(t => t instanceof tagType) : this.summonData.tags.find(t => t.tagType === tagType); } findTag(tagFilter: (tag: BattlerTag) => boolean) { - if (!this.summonData) { - return null; - } return this.summonData.tags.find(t => tagFilter(t)); } findTags(tagFilter: (tag: BattlerTag) => boolean): BattlerTag[] { - if (!this.summonData) { - return []; - } return this.summonData.tags.filter(t => tagFilter(t)); } + /** + * Tick down the first {@linkcode BattlerTag} found matching the given {@linkcode BattlerTagType}, + * removing it if its duration goes below 0. + * @param tagType the {@linkcode BattlerTagType} to check against + * @returns `true` if the tag was present + */ lapseTag(tagType: BattlerTagType): boolean { - if (!this.summonData) { - return false; - } const tags = this.summonData.tags; const tag = tags.find(t => t.tagType === tagType); - if (tag && !tag.lapse(this, BattlerTagLapseType.CUSTOM)) { + if (!tag) { + return false + } + + if (!tag.lapse(this, BattlerTagLapseType.CUSTOM)) { tag.onRemove(this); tags.splice(tags.indexOf(tag), 1); } - return !!tag; + return true } + /** + * Tick down all {@linkcode BattlerTags} matching the given {@linkcode BattlerTagLapseType}, + * removing any whose durations fall below 0. + * @param tagType the {@linkcode BattlerTagLapseType} to tick down + */ lapseTags(lapseType: BattlerTagLapseType): void { - if (!this.summonData) { - return; - } const tags = this.summonData.tags; tags .filter( @@ -4882,23 +4946,24 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }); } - removeTag(tagType: BattlerTagType): boolean { - if (!this.summonData) { - return false; - } + /** + * Remove the first tag matching the given {@linkcode BattlerTagType}. + * @param tagType the {@linkcode BattlerTagType} to search for and remove + */ + removeTag(tagType: BattlerTagType): void { const tags = this.summonData.tags; const tag = tags.find(t => t.tagType === tagType); if (tag) { tag.onRemove(this); tags.splice(tags.indexOf(tag), 1); } - return !!tag; } - findAndRemoveTags(tagFilter: (tag: BattlerTag) => boolean): boolean { - if (!this.summonData) { - return false; - } + /** + * Find and remove all {@linkcode BattlerTag}s matching the given function. + * @param tagFilter a function dictating which tags to remove + */ + findAndRemoveTags(tagFilter: (tag: BattlerTag) => boolean): void { const tags = this.summonData.tags; const tagsToRemove = tags.filter(t => tagFilter(t)); for (const tag of tagsToRemove) { @@ -4906,7 +4971,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { tag.onRemove(this); tags.splice(tags.indexOf(tag), 1); } - return true; } removeTagsBySourceId(sourceId: number): void { @@ -4914,13 +4978,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } transferTagsBySourceId(sourceId: number, newSourceId: number): void { - if (!this.summonData) { - return; - } - const tags = this.summonData.tags; - tags - .filter(t => t.sourceId === sourceId) - .forEach(t => (t.sourceId = newSourceId)); + this.summonData.tags.forEach(t => { + if (t.sourceId === sourceId) { + t.sourceId = newSourceId; + } + }) } /** @@ -4960,8 +5022,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * Gets whether the given move is currently disabled for this Pokemon. * - * @param {Moves} moveId {@linkcode Moves} ID of the move to check - * @returns {boolean} `true` if the move is disabled for this Pokemon, otherwise `false` + * @param moveId - The {@linkcode Moves} ID of the move to check + * @returns `true` if the move is disabled for this Pokemon, otherwise `false` * * @see {@linkcode MoveRestrictionBattlerTag} */ @@ -4972,9 +5034,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * Gets whether the given move is currently disabled for the user based on the player's target selection * - * @param {Moves} moveId {@linkcode Moves} ID of the move to check - * @param {Pokemon} user {@linkcode Pokemon} the move user - * @param {Pokemon} target {@linkcode Pokemon} the target of the move + * @param moveId - The {@linkcode Moves} ID of the move to check + * @param user - The move user + * @param target - The target of the move * * @returns {boolean} `true` if the move is disabled for this Pokemon due to the player's target selection * @@ -5004,10 +5066,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * Gets the {@link MoveRestrictionBattlerTag} that is restricting a move, if it exists. * - * @param {Moves} moveId {@linkcode Moves} ID of the move to check - * @param {Pokemon} user {@linkcode Pokemon} the move user, optional and used when the target is a factor in the move's restricted status - * @param {Pokemon} target {@linkcode Pokemon} the target of the move, optional and used when the target is a factor in the move's restricted status - * @returns {MoveRestrictionBattlerTag | null} the first tag on this Pokemon that restricts the move, or `null` if the move is not restricted. + * @param moveId - {@linkcode Moves} ID of the move to check + * @param user - {@linkcode Pokemon} the move user, optional and used when the target is a factor in the move's restricted status + * @param target - {@linkcode Pokemon} the target of the move, optional and used when the target is a factor in the move's restricted status + * @returns The first tag on this Pokemon that restricts the move, or `null` if the move is not restricted. */ getRestrictingTag( moveId: Moves, @@ -5036,7 +5098,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } public getMoveHistory(): TurnMove[] { - return this.battleSummonData.moveHistory; + return this.summonData.moveHistory; } public pushMoveHistory(turnMove: TurnMove): void { @@ -5069,20 +5131,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.summonData.moveQueue; } - /** - * If this Pokemon is using a multi-hit move, cancels all subsequent strikes - * @param {Pokemon} target If specified, this only cancels subsequent strikes against the given target - */ - stopMultiHit(target?: Pokemon): void { - const effectPhase = globalScene.getCurrentPhase(); - if ( - effectPhase instanceof MoveEffectPhase && - effectPhase.getUserPokemon() === this - ) { - effectPhase.stopMultiHit(target); - } - } - changeForm(formChange: SpeciesFormChange): Promise { return new Promise(resolve => { this.formIndex = Math.max( @@ -5112,23 +5160,23 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { sceneOverride?: BattleScene, ): AnySound { const scene = sceneOverride ?? globalScene; // TODO: is `sceneOverride` needed? - const cry = this.getSpeciesForm().cry(soundConfig); + const cry = this.getSpeciesForm(undefined, true).cry(soundConfig); let duration = cry.totalDuration * 1000; if ( this.fusionSpecies && - this.getSpeciesForm() !== this.getFusionSpeciesForm() + this.getSpeciesForm(undefined, true) !== this.getFusionSpeciesForm(undefined, true) ) { - let fusionCry = this.getFusionSpeciesForm().cry(soundConfig, true); + let fusionCry = this.getFusionSpeciesForm(undefined, true).cry(soundConfig, true); duration = Math.min(duration, fusionCry.totalDuration * 1000); fusionCry.destroy(); - scene.time.delayedCall(Utils.fixedInt(Math.ceil(duration * 0.4)), () => { + scene.time.delayedCall(fixedInt(Math.ceil(duration * 0.4)), () => { try { SoundFade.fadeOut( scene, cry, - Utils.fixedInt(Math.ceil(duration * 0.2)), + fixedInt(Math.ceil(duration * 0.2)), ); - fusionCry = this.getFusionSpeciesForm().cry( + fusionCry = this.getFusionSpeciesForm(undefined, true).cry( Object.assign( { seek: Math.max(fusionCry.totalDuration * 0.4, 0) }, soundConfig, @@ -5137,7 +5185,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { SoundFade.fadeIn( scene, fusionCry, - Utils.fixedInt(Math.ceil(duration * 0.2)), + fixedInt(Math.ceil(duration * 0.2)), scene.masterVolume * scene.fieldVolume, 0, ); @@ -5177,7 +5225,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let faintCryTimer: Phaser.Time.TimerEvent | null = globalScene.time.addEvent({ - delay: Utils.fixedInt(delay), + delay: fixedInt(delay), repeat: -1, callback: () => { frameThreshold = sprite.anims.msPerFrame / rate; @@ -5203,7 +5251,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }); // Failsafe - globalScene.time.delayedCall(Utils.fixedInt(3000), () => { + globalScene.time.delayedCall(fixedInt(3000), () => { if (!faintCryTimer || !globalScene) { return; } @@ -5262,7 +5310,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let faintCryTimer: Phaser.Time.TimerEvent | null = globalScene.time.addEvent({ - delay: Utils.fixedInt(delay), + delay: fixedInt(delay), repeat: -1, callback: () => { ++i; @@ -5279,7 +5327,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { SoundFade.fadeOut( globalScene, cry, - Utils.fixedInt(Math.ceil((duration / rate) * 0.2)), + fixedInt(Math.ceil((duration / rate) * 0.2)), ); fusionCry = globalScene.playSound( fusionCryKey, @@ -5291,7 +5339,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { SoundFade.fadeIn( globalScene, fusionCry, - Utils.fixedInt(Math.ceil((duration / rate) * 0.2)), + fixedInt(Math.ceil((duration / rate) * 0.2)), globalScene.masterVolume * globalScene.fieldVolume, 0, ); @@ -5317,7 +5365,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }); // Failsafe - globalScene.time.delayedCall(Utils.fixedInt(3000), () => { + globalScene.time.delayedCall(fixedInt(3000), () => { if (!faintCryTimer || !globalScene) { return; } @@ -5342,6 +5390,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ); } + queueImmuneMessage(quiet: boolean, effect?: StatusEffect): void { + if (!effect || quiet) { + return; + } + const message = effect && this.status?.effect === effect + ? getStatusEffectOverlapText(effect ?? StatusEffect.NONE, getPokemonNameWithAffix(this)) + : i18next.t("abilityTriggers:moveImmunity", { + pokemonNameWithAffix: getPokemonNameWithAffix(this), + }); + globalScene.queueMessage(message); + } + /** * Checks if a status effect can be applied to the Pokemon. * @@ -5360,6 +5420,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ): boolean { if (effect !== StatusEffect.FAINT) { if (overrideStatus ? this.status?.effect === effect : this.status) { + this.queueImmuneMessage(quiet, effect); return false; } if ( @@ -5367,18 +5428,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { !ignoreField && globalScene.arena.terrain?.terrainType === TerrainType.MISTY ) { + this.queueImmuneMessage(quiet, effect); return false; } } - if ( - sourcePokemon && - sourcePokemon !== this && - this.isSafeguarded(sourcePokemon) - ) { - return false; - } - const types = this.getTypes(true, true); switch (effect) { @@ -5392,7 +5446,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } // Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity - const cancelImmunity = new Utils.BooleanHolder(false); + const cancelImmunity = new BooleanHolder(false); if (sourcePokemon) { applyAbAttrs( IgnoreTypeStatusEffectImmunityAbAttr, @@ -5407,17 +5461,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } - return true; + return true; }); if (this.isOfType(PokemonType.POISON) || this.isOfType(PokemonType.STEEL)) { if (poisonImmunity.includes(true)) { + this.queueImmuneMessage(quiet, effect); return false; } } break; case StatusEffect.PARALYSIS: if (this.isOfType(PokemonType.ELECTRIC)) { + this.queueImmuneMessage(quiet, effect); return false; } break; @@ -5426,6 +5482,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.isGrounded() && globalScene.arena.terrain?.terrainType === TerrainType.ELECTRIC ) { + this.queueImmuneMessage(quiet, effect); return false; } break; @@ -5438,17 +5495,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { globalScene.arena.weather.weatherType, )) ) { + this.queueImmuneMessage(quiet, effect); return false; } break; case StatusEffect.BURN: if (this.isOfType(PokemonType.FIRE)) { + this.queueImmuneMessage(quiet, effect); return false; } break; } - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); applyPreSetStatusAbAttrs( StatusEffectImmunityAbAttr, this, @@ -5477,6 +5536,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return false; } + if ( + sourcePokemon && + sourcePokemon !== this && + this.isSafeguarded(sourcePokemon) + ) { + if(!quiet){ + globalScene.queueMessage( + i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(this) + })); + } + return false; + } + return true; } @@ -5486,8 +5558,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { sourcePokemon: Pokemon | null = null, turnsRemaining = 0, sourceText: string | null = null, + overrideStatus?: boolean, + quiet = true, ): boolean { - if (!this.canSetStatus(effect, asPhase, false, sourcePokemon)) { + if (!this.canSetStatus(effect, quiet, overrideStatus, sourcePokemon)) { return false; } if (this.isFainted() && effect !== StatusEffect.FAINT) { @@ -5499,10 +5573,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * cancel the attack's subsequent hits. */ if (effect === StatusEffect.SLEEP || effect === StatusEffect.FREEZE) { - this.stopMultiHit(); + const currentPhase = globalScene.getCurrentPhase(); + if (currentPhase instanceof MoveEffectPhase && currentPhase.getUserPokemon() === this) { + this.turnData.hitCount = 1; + this.turnData.hitsLeft = 1; + } } if (asPhase) { + if (overrideStatus) { + this.resetStatus(false); + } globalScene.unshiftPhase( new ObtainStatusEffectPhase( this.getBattlerIndex(), @@ -5515,10 +5596,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return true; } - let sleepTurnsRemaining: Utils.NumberHolder; + let sleepTurnsRemaining: NumberHolder; if (effect === StatusEffect.SLEEP) { - sleepTurnsRemaining = new Utils.NumberHolder(this.randSeedIntRange(2, 4)); + sleepTurnsRemaining = new NumberHolder(this.randSeedIntRange(2, 4)); this.setFrameRate(4); @@ -5542,20 +5623,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { effect = effect!; // If `effect` is undefined then `trySetStatus()` will have already returned early via the `canSetStatus()` call this.status = new Status(effect, 0, sleepTurnsRemaining?.value); - if (effect !== StatusEffect.FAINT) { - globalScene.triggerPokemonFormChange( - this, - SpeciesFormChangeStatusEffectTrigger, - true, - ); - applyPostSetStatusAbAttrs( - PostSetStatusAbAttr, - this, - effect, - sourcePokemon, - ); - } - return true; } @@ -5564,12 +5631,28 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param revive Whether revive should be cured; defaults to true. * @param confusion Whether resetStatus should include confusion or not; defaults to false. * @param reloadAssets Whether to reload the assets or not; defaults to false. + * @param asPhase Whether to reset the status in a phase or immediately */ - resetStatus(revive = true, confusion = false, reloadAssets = false): void { + resetStatus(revive = true, confusion = false, reloadAssets = false, asPhase = true): void { const lastStatus = this.status?.effect; if (!revive && lastStatus === StatusEffect.FAINT) { return; } + + if (asPhase) { + globalScene.unshiftPhase(new ResetStatusPhase(this, confusion, reloadAssets)); + } else { + this.clearStatus(confusion, reloadAssets); + } + } + + /** + * Performs the action of clearing a Pokemon's status + * + * This is a helper to {@linkcode resetStatus}, which should be called directly instead of this method + */ + public clearStatus(confusion: boolean, reloadAssets: boolean) { + const lastStatus = this.status?.effect; this.status = null; if (lastStatus === StatusEffect.SLEEP) { this.setFrameRate(10); @@ -5585,6 +5668,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (reloadAssets) { this.loadAssets(false).then(() => this.playAnim()); } + this.updateInfo(true); } /** @@ -5597,7 +5681,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; if (globalScene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, defendingSide)) { - const bypassed = new Utils.BooleanHolder(false); + const bypassed = new BooleanHolder(false); if (attacker) { applyAbAttrs(InfiltratorAbAttr, attacker, null, false, bypassed); } @@ -5606,58 +5690,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return false; } - primeSummonData(summonDataPrimer: PokemonSummonData): void { - this.summonDataPrimer = summonDataPrimer; - } - + /** + * Reset this Pokemon's {@linkcode PokemonSummonData | SummonData} and {@linkcode PokemonTempSummonData | TempSummonData} + * in preparation for switching pokemon, as well as removing any relevant on-switch tags. + */ resetSummonData(): void { - if (this.summonData?.speciesForm) { + const illusion: IllusionData | null = this.summonData.illusion; + if (this.summonData.speciesForm) { this.summonData.speciesForm = null; this.updateFusionPalette(); } this.summonData = new PokemonSummonData(); + this.tempSummonData = new PokemonTempSummonData(); this.setSwitchOutStatus(false); - if (!this.battleData) { - this.resetBattleData(); - } - this.resetBattleSummonData(); - if (this.summonDataPrimer) { - for (const k of Object.keys(this.summonDataPrimer)) { - if (this.summonDataPrimer[k]) { - this.summonData[k] = this.summonDataPrimer[k]; - } - } - // If this Pokemon has a Substitute when loading in, play an animation to add its sprite - if (this.getTag(SubstituteTag)) { - globalScene.triggerPokemonBattleAnim( - this, - PokemonAnimType.SUBSTITUTE_ADD, - ); - this.getTag(SubstituteTag)!.sourceInFocus = false; - } - - // If this Pokemon has Commander and Dondozo as an active ally, hide this Pokemon's sprite. - if ( - this.hasAbilityWithAttr(CommanderAbAttr) && - globalScene.currentBattle.double && - this.getAlly()?.species.speciesId === Species.DONDOZO - ) { - this.setVisible(false); - } - this.summonDataPrimer = null; - } - this.updateInfo(); - } - - resetBattleData(): void { - this.battleData = new PokemonBattleData(); - } - - resetBattleSummonData(): void { - this.battleSummonData = new PokemonBattleSummonData(); - if (this.getTag(BattlerTagType.SEEDED)) { - this.lapseTag(BattlerTagType.SEEDED); - } if (globalScene) { globalScene.triggerPokemonFormChange( this, @@ -5665,6 +5710,45 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { true, ); } + + // If this Pokemon has a Substitute when loading in, play an animation to add its sprite + if (this.getTag(SubstituteTag)) { + globalScene.triggerPokemonBattleAnim( + this, + PokemonAnimType.SUBSTITUTE_ADD, + ); + this.getTag(SubstituteTag)!.sourceInFocus = false; + } + + // If this Pokemon has Commander and Dondozo as an active ally, hide this Pokemon's sprite. + if ( + this.hasAbilityWithAttr(CommanderAbAttr) && + globalScene.currentBattle.double && + this.getAlly()?.species.speciesId === Species.DONDOZO + ) { + this.setVisible(false); + } + this.summonData.illusion = illusion + this.updateInfo(); + } + + /** + * Reset a {@linkcode Pokemon}'s per-battle {@linkcode PokemonBattleData | battleData}, + * as well as any transient {@linkcode PokemonWaveData | waveData} for the current wave. + * Should be called once per arena transition (new biome/trainer battle/Mystery Encounter). + */ + resetBattleAndWaveData(): void { + this.battleData = new PokemonBattleData(); + this.resetWaveData(); + } + + /** + * Reset a {@linkcode Pokemon}'s {@linkcode PokemonWaveData | waveData}. + * Should be called upon starting a new wave in addition to whenever an arena transition occurs. + * @see {@linkcode resetBattleAndWaveData()} + */ + resetWaveData(): void { + this.waveData = new PokemonWaveData(); } resetTera(): void { @@ -5785,10 +5869,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { .filter(s => !!s) .map(s => { s.pipelineData[ - `spriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}` + `spriteColors${ignoreOveride && this.summonData.speciesForm ? "Base" : ""}` ] = []; s.pipelineData[ - `fusionSpriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}` + `fusionSpriteColors${ignoreOveride && this.summonData.speciesForm ? "Base" : ""}` ] = []; }); return; @@ -5893,9 +5977,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (this.shiny && variantColors && variantColors[this.variant]) { Object.keys(variantColors[this.variant]).forEach(k => { variantColorSet.set( - Utils.rgbaToInt(Array.from(Object.values(Utils.rgbHexToRgba(k)))), + rgbaToInt(Array.from(Object.values(rgbHexToRgba(k)))), Array.from( - Object.values(Utils.rgbHexToRgba(variantColors[this.variant][k])), + Object.values(rgbHexToRgba(variantColors[this.variant][k])), ), ); }); @@ -5906,7 +5990,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const pixel = pixelData[f].slice(i, i + 4); let [r, g, b, a] = pixel; if (variantColors) { - const color = Utils.rgbaToInt([r, g, b, a]); + const color = rgbaToInt([r, g, b, a]); if (variantColorSet.has(color)) { const mappedPixel = variantColorSet.get(color); if (mappedPixel) { @@ -5955,10 +6039,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ) { for (const k of Object.keys(variantColors[this.fusionVariant])) { variantColorSet.set( - Utils.rgbaToInt(Array.from(Object.values(Utils.rgbHexToRgba(k)))), + rgbaToInt(Array.from(Object.values(rgbHexToRgba(k)))), Array.from( Object.values( - Utils.rgbHexToRgba(variantColors[this.fusionVariant][k]), + rgbHexToRgba(variantColors[this.fusionVariant][k]), ), ), ); @@ -5978,7 +6062,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { pixelData[2 + f][i + 3], ]; if (variantColors) { - const color = Utils.rgbaToInt([r, g, b, a]); + const color = rgbaToInt([r, g, b, a]); if (variantColorSet.has(color)) { const mappedPixel = variantColorSet.get(color); if (mappedPixel) { @@ -6036,7 +6120,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { hsvColors = Array.from(rgbaColors.keys()).reduce( (map: Map, k: number) => { const rgb = rgbaColors.get(k)!.slice(0, 3); - map.set(k, Utils.rgbToHsv(rgb[0], rgb[1], rgb[2])); + map.set(k, rgbToHsv(rgb[0], rgb[1], rgb[2])); return map; }, new Map(), @@ -6116,7 +6200,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { spriteColors.forEach((sc: number[], i: number) => { paletteDeltas.push([]); for (let p = 0; p < palette.length; p++) { - paletteDeltas[i].push(Utils.deltaRgb(sc, palette[p])); + paletteDeltas[i].push(deltaRgb(sc, palette[p])); } }); @@ -6145,10 +6229,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { .filter(s => !!s) .map(s => { s.pipelineData[ - `spriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}` + `spriteColors${ignoreOveride && this.summonData.speciesForm ? "Base" : ""}` ] = spriteColors; s.pipelineData[ - `fusionSpriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}` + `fusionSpriteColors${ignoreOveride && this.summonData.speciesForm ? "Base" : ""}` ] = fusionSpriteColors; }); @@ -6161,8 +6245,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * * This calls either {@linkcode BattleScene.randBattleSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle-scene.ts` * which calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts` - * which calls {@linkcode Utils.randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts`, - * or it directly calls {@linkcode Utils.randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts` if there is no current battle + * which calls {@linkcode randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts`, + * or it directly calls {@linkcode randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts` if there is no current battle * * @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min} * @param min The minimum integer to pick, default `0` @@ -6171,7 +6255,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { randSeedInt(range: number, min = 0): number { return globalScene.currentBattle ? globalScene.randBattleSeedInt(range, min) - : Utils.randSeedInt(range, min); + : randSeedInt(range, min); } /** @@ -6201,7 +6285,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (clearEffects) { this.destroySubstitute(); - this.resetSummonData(); // this also calls `resetBattleSummonData` + this.resetSummonData(); } if (hideInfo) { this.hideInfo(); @@ -6271,7 +6355,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { heldItem: PokemonHeldItemModifier, forBattle = true, ): boolean { - if (heldItem.pokemonId === -1 || heldItem.pokemonId === this.id) { + if (heldItem.pokemonId !== -1 && heldItem.pokemonId !== this.id) { + return false; + } + heldItem.stackCount--; if (heldItem.stackCount <= 0) { globalScene.removeModifier(heldItem, !this.isPlayer()); @@ -6279,10 +6366,23 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (forBattle) { applyPostItemLostAbAttrs(PostItemLostAbAttr, this, false); } + return true; - } else { - return false; + } + + /** + * Record a berry being eaten for ability and move triggers. + * Only tracks things that proc _every_ time a berry is eaten. + * @param berryType The type of berry being eaten. + * @param updateHarvest Whether to track the berry for harvest; default `true`. + */ + public recordEatenBerry(berryType: BerryType, updateHarvest: boolean = true) { + this.battleData.hasEatenBerry = true; + if (updateHarvest) { + // Only track for harvest if we actually consumed the berry + this.battleData.berriesEaten.push(berryType) } + this.turnData.berriesEaten.push(berryType); } } @@ -6429,7 +6529,7 @@ export class PlayerPokemon extends Pokemon { this.leaveField(switchType === SwitchType.SWITCH); globalScene.ui.setMode( - Mode.PARTY, + UiMode.PARTY, PartyUiMode.FAINT_SWITCH, this.getFieldIndex(), (slotIndex: number, option: PartyOption) => { @@ -6447,7 +6547,7 @@ export class PlayerPokemon extends Pokemon { MoveEndPhase, ); } - globalScene.ui.setMode(Mode.MESSAGE).then(resolve); + globalScene.ui.setMode(UiMode.MESSAGE).then(resolve); }, PartyUiHandler.FilterNonFainted, ); @@ -6467,7 +6567,7 @@ export class PlayerPokemon extends Pokemon { ? globalScene.gameData.starterData[fusionStarterSpeciesId] : null, ].filter(d => !!d); - const amount = new Utils.NumberHolder(friendship); + const amount = new NumberHolder(friendship); globalScene.applyModifier( PokemonFriendshipBoosterModifier, true, @@ -6482,7 +6582,7 @@ export class PlayerPokemon extends Pokemon { ? 1.5 // Divide candy gain for fusions by 1.5 during events : 2 // 2 for fusions outside events : 1; // 1 for non-fused mons - const starterAmount = new Utils.NumberHolder( + const starterAmount = new NumberHolder( Math.floor( (amount.value * candyFriendshipMultiplier) / fusionReduction, ), @@ -6851,6 +6951,8 @@ export class PlayerPokemon extends Pokemon { if (partyMemberIndex > fusedPartyMemberIndex) { partyMemberIndex--; } + + // combine the two mons' held items const fusedPartyMemberHeldModifiers = globalScene.findModifiers( m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id, true, @@ -6996,6 +7098,15 @@ export class EnemyPokemon extends Pokemon { } speciesId = prevolution; } + + if (this.hasTrainer() && globalScene.currentBattle) { + const { waveIndex } = globalScene.currentBattle; + const ivs: number[] = []; + while (ivs.length < 6) { + ivs.push(this.randSeedIntRange(Math.floor(waveIndex / 10), 31)); + } + this.ivs = ivs; + } } this.aiType = @@ -7005,8 +7116,8 @@ export class EnemyPokemon extends Pokemon { initBattleInfo(): void { if (!this.battleInfo) { this.battleInfo = new EnemyBattleInfo(); - this.battleInfo.updateBossSegments(this); this.battleInfo.initInfo(this); + this.battleInfo.updateBossSegments(this); } else { this.battleInfo.updateBossSegments(this); } @@ -7152,14 +7263,15 @@ export class EnemyPokemon extends Pokemon { ].includes(move.id); return ( doesNotFail && - p.getAttackDamage( - this, + p.getAttackDamage({ + source: this, move, - !p.battleData.abilityRevealed, - false, - !p.getAlly()?.battleData.abilityRevealed, - false, + ignoreAbility: !p.waveData.abilityRevealed, + ignoreSourceAbility: false, + ignoreAllyAbility: !p.getAlly()?.waveData.abilityRevealed, + ignoreSourceAllyAbility: false, isCritical, + } ).damage >= p.hp ); }) @@ -7221,12 +7333,15 @@ export class EnemyPokemon extends Pokemon { /** * Attack moves are given extra multipliers to their base benefit score based on * the move's type effectiveness against the target and whether the move is a STAB move. - */ + */ const effectiveness = target.getMoveEffectiveness( this, move, - !target.battleData?.abilityRevealed, - ); + !target.waveData.abilityRevealed, + undefined, + undefined, + true); + if (target.isPlayer() !== this.isPlayer()) { targetScore *= effectiveness; if (this.isOfType(move.type)) { @@ -7445,7 +7560,7 @@ export class EnemyPokemon extends Pokemon { //console.log('damage', damage, 'segment', segmentsBypassed + 1, 'segment size', segmentSize, 'damage needed', Math.round(segmentSize * Math.pow(2, segmentsBypassed + 1))); } - damage = Utils.toDmgValue( + damage = toDmgValue( this.hp - hpThreshold + segmentSize * segmentsBypassed, ); clearedBossSegmentIndex = s - segmentsBypassed; @@ -7523,7 +7638,7 @@ export class EnemyPokemon extends Pokemon { } // Pick a random stat from the leftover stats to increase its stages - const randInt = Utils.randSeedInt(totalWeight); + const randInt = randSeedInt(totalWeight); for (const i in statThresholds) { if (randInt < statThresholds[i]) { boostedStat = leftoverStats[i]; @@ -7594,7 +7709,7 @@ export class EnemyPokemon extends Pokemon { this, ); - if (Utils.isBetween(slotIndex, 0, PLAYER_PARTY_MAX_SIZE - 1)) { + if (isBetween(slotIndex, 0, PLAYER_PARTY_MAX_SIZE - 1)) { party.splice(slotIndex, 0, newPokemon); } else { party.push(newPokemon); @@ -7615,6 +7730,42 @@ export class EnemyPokemon extends Pokemon { } } +/** + * Illusion property + */ +interface IllusionData { + basePokemon: { + /** The actual name of the Pokemon */ + name: string; + /** The actual nickname of the Pokemon */ + nickname: string; + /** Whether the base pokemon is shiny or not */ + shiny: boolean; + /** The shiny variant of the base pokemon */ + variant: Variant; + /** Whether the fusion species of the base pokemon is shiny or not */ + fusionShiny: boolean; + /** The variant of the fusion species of the base pokemon */ + fusionVariant: Variant; + }; + /** The species of the illusion */ + species: Species; + /** The formIndex of the illusion */ + formIndex: number; + /** The gender of the illusion */ + gender: Gender; + /** The pokeball of the illusion */ + pokeball: PokeballType; + /** The fusion species of the illusion if it's a fusion */ + fusionSpecies?: PokemonSpecies; + /** The fusionFormIndex of the illusion */ + fusionFormIndex?: number; + /** The fusionGender of the illusion if it's a fusion */ + fusionGender?: Gender; + /** The level of the illusion (not used currently) */ + level?: number +} + export interface TurnMove { move: Moves; targets: BattlerIndex[]; @@ -7633,50 +7784,131 @@ export interface AttackMoveResult { sourceBattlerIndex: BattlerIndex; } +/** + * Persistent in-battle data for a {@linkcode Pokemon}. + * Resets on switch or new battle. + */ export class PokemonSummonData { /** [Atk, Def, SpAtk, SpDef, Spd, Acc, Eva] */ public statStages: number[] = [0, 0, 0, 0, 0, 0, 0]; public moveQueue: TurnMove[] = []; public tags: BattlerTag[] = []; public abilitySuppressed = false; - public abilitiesApplied: Abilities[] = []; - public speciesForm: PokemonSpeciesForm | null; - public fusionSpeciesForm: PokemonSpeciesForm; - public ability: Abilities = Abilities.NONE; - public passiveAbility: Abilities = Abilities.NONE; - public gender: Gender; - public fusionGender: Gender; + + // Overrides for transform. + // TODO: Move these into a separate class & add rage fist hit count + public speciesForm: PokemonSpeciesForm | null = null; + public fusionSpeciesForm: PokemonSpeciesForm | null = null; + public ability: Abilities | undefined; + public passiveAbility: Abilities | undefined; + public gender: Gender | undefined; + public fusionGender: Gender | undefined; public stats: number[] = [0, 0, 0, 0, 0, 0]; - public moveset: PokemonMove[]; + public moveset: PokemonMove[] | null; + // If not initialized this value will not be populated from save data. public types: PokemonType[] = []; public addedType: PokemonType | null = null; + + /** Data pertaining to this pokemon's illusion. */ + public illusion: IllusionData | null = null; + public illusionBroken: boolean = false; + + /** Array containing all berries eaten in the last turn; used by {@linkcode Abilities.CUD_CHEW} */ + public berriesEatenLast: BerryType[] = []; + + /** + * An array of all moves this pokemon has used since entering the battle. + * Used for most moves and abilities that check prior move usage or copy already-used moves. + */ + public moveHistory: TurnMove[] = []; + + constructor(source?: PokemonSummonData | Partial) { + if (isNullOrUndefined(source)) { + return; + } + + // TODO: Rework this into an actual generic function for use elsewhere + for (const [key, value] of Object.entries(source)) { + if (isNullOrUndefined(value) && this.hasOwnProperty(key)) { + continue; + } + + if (key === "tags") { + // load battler tags + this.tags = value.map((t: BattlerTag) => loadBattlerTag(t)); + continue; + } + this[key] = value; + } + } } + // TODO: Merge this inside `summmonData` but exclude from save if/when a save data serializer is added +export class PokemonTempSummonData { + /** + * The number of turns this pokemon has spent without switching out. + * Only currently used for positioning the battle cursor. + */ + turnCount: number = 1; + + /** + * The number of turns this pokemon has spent in the active position since the start of the wave + * without switching out. + * Reset on switch and new wave, but not stored in `SummonData` to avoid being written to the save file. + + * Used to evaluate "first turn only" conditions such as + * {@linkcode Moves.FAKE_OUT | Fake Out} and {@linkcode Moves.FIRST_IMPRESSION | First Impression}). + */ + waveTurnCount = 1; + +} + +/** + * Persistent data for a {@linkcode Pokemon}. + * Resets at the start of a new battle (but not on switch). + */ export class PokemonBattleData { - /** counts the hits the pokemon received */ + /** Counter tracking direct hits this Pokemon has received during this battle; used for {@linkcode Moves.RAGE_FIST} */ public hitCount = 0; - /** used for {@linkcode Moves.RAGE_FIST} in order to save hit Counts received before Rage Fist is applied */ - public prevHitCount = 0; - public endured = false; + /** Whether this Pokemon has eaten a berry this battle; used for {@linkcode Moves.BELCH} */ + public hasEatenBerry: boolean = false; + /** Array containing all berries eaten and not yet recovered during this current battle; used by {@linkcode Abilities.HARVEST} */ public berriesEaten: BerryType[] = []; - public abilitiesApplied: Abilities[] = []; + + constructor(source?: PokemonBattleData | Partial) { + if (!isNullOrUndefined(source)) { + this.hitCount = source.hitCount ?? 0; + this.hasEatenBerry = source.hasEatenBerry ?? false; + this.berriesEaten = source.berriesEaten ?? []; + } + } +} + +/** + * Temporary data for a {@linkcode Pokemon}. + * Resets on new wave/battle start (but not on switch). + */ +export class PokemonWaveData { + /** Whether the pokemon has endured due to a {@linkcode BattlerTagType.ENDURE_TOKEN} */ + public endured = false; + /** + * A set of all the abilities this {@linkcode Pokemon} has used in this wave. + * Used to track once per battle conditions, as well as (hopefully) by the updated AI for move effectiveness. + */ + public abilitiesApplied: Set = new Set; + /** Whether the pokemon's ability has been revealed or not */ public abilityRevealed = false; } -export class PokemonBattleSummonData { - /** The number of turns the pokemon has passed since entering the battle */ - public turnCount = 1; - /** The number of turns the pokemon has passed since the start of the wave */ - public waveTurnCount = 1; - /** The list of moves the pokemon has used since entering the battle */ - public moveHistory: TurnMove[] = []; -} - +/** + * Temporary data for a {@linkcode Pokemon}. + * Resets at the start of a new turn, as well as on switch. + */ export class PokemonTurnData { public flinched = false; public acted = false; - /** How many times the move should hit the target(s) */ + /** How many times the current move should hit the target(s) */ public hitCount = 0; /** * - `-1` = Calculate how many hits are left @@ -7700,6 +7932,12 @@ export class PokemonTurnData { * forced to act again in the same turn */ public extraTurns = 0; + /** + * All berries eaten by this pokemon in this turn. + * Saved into {@linkcode PokemonSummonData | SummonData} by {@linkcode Abilities.CUD_CHEW} on turn end. + * @see {@linkcode PokemonSummonData.berriesEatenLast} + */ + public berriesEaten: BerryType[] = [] } export enum AiType { @@ -7737,8 +7975,8 @@ export type DamageResult = | HitResult.SUPER_EFFECTIVE | HitResult.NOT_VERY_EFFECTIVE | HitResult.ONE_HIT_KO - | HitResult.CONFUSION - | HitResult.INDIRECT_KO + | HitResult.CONFUSION + | HitResult.INDIRECT_KO | HitResult.INDIRECT; /** Interface containing the results of a damage calculation for a given move */ @@ -7755,8 +7993,8 @@ export interface DamageCalculationResult { * Wrapper class for the {@linkcode Move} class for Pokemon to interact with. * These are the moves assigned to a {@linkcode Pokemon} object. * It links to {@linkcode Move} class via the move ID. - * Compared to {@linkcode Move}, this class also tracks if a move has received. - * PP Ups, amount of PP used, and things like that. + * Compared to {@linkcode Move}, this class also tracks things like + * PP Ups recieved, PP used, etc. * @see {@linkcode isUsable} - checks if move is restricted, out of PP, or not implemented. * @see {@linkcode getMove} - returns {@linkcode Move} object by looking it up via ID. * @see {@linkcode usePp} - removes a point of PP from the move. @@ -7827,16 +8065,16 @@ export class PokemonMove { /** * Sets {@link ppUsed} for this move and ensures the value does not exceed {@link getMovePp} - * @param {number} count Amount of PP to use + * @param count Amount of PP to use */ - usePp(count = 1) { + usePp(count: number = 1) { this.ppUsed = Math.min(this.ppUsed + count, this.getMovePp()); } getMovePp(): number { return ( this.maxPpOverride || - this.getMove().pp + this.ppUp * Utils.toDmgValue(this.getMove().pp / 5) + this.getMove().pp + this.ppUp * toDmgValue(this.getMove().pp / 5) ); } @@ -7849,9 +8087,9 @@ export class PokemonMove { } /** - * Copies an existing move or creates a valid PokemonMove object from json representing one - * @param {PokemonMove | any} source The data for the move to copy - * @return {PokemonMove} A valid pokemonmove object + * Copies an existing move or creates a valid {@linkcode PokemonMove} object from json representing one + * @param source The data for the move to copy; can be a {@linkcode PokemonMove} or JSON object representing one + * @returns A valid {@linkcode PokemonMove} object */ static loadMove(source: PokemonMove | any): PokemonMove { return new PokemonMove( diff --git a/src/field/trainer.ts b/src/field/trainer.ts index ccd8c83e684..6b0a54b2103 100644 --- a/src/field/trainer.ts +++ b/src/field/trainer.ts @@ -11,7 +11,7 @@ import { TrainerSlot } from "#enums/trainer-slot"; import { TrainerPoolTier } from "#enums/trainer-pool-tier"; import { TeraAIMode } from "#enums/tera-ai-mode"; import type { EnemyPokemon } from "#app/field/pokemon"; -import * as Utils from "#app/utils"; +import { randSeedWeightedItem, randSeedItem, randSeedInt } from "#app/utils/common"; import type { PersistentModifier } from "#app/modifier/modifier"; import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag"; import { getIsInitialized, initI18n } from "#app/plugins/i18n"; @@ -58,7 +58,7 @@ export default class Trainer extends Phaser.GameObjects.Container { this.partyTemplateIndex = Math.min( partyTemplateIndex !== undefined ? partyTemplateIndex - : Utils.randSeedWeightedItem(this.config.partyTemplates.map((_, i) => i)), + : randSeedWeightedItem(this.config.partyTemplates.map((_, i) => i)), this.config.partyTemplates.length - 1, ); const classKey = `trainersCommon:${TrainerType[trainerType]}`; @@ -71,9 +71,7 @@ export default class Trainer extends Phaser.GameObjects.Container { ? ".FEMALE" : ".MALE" : ""; - const trainerKey = Utils.randSeedItem( - Object.keys(i18next.t(`${classKey}${genderKey}`, { returnObjects: true })), - ); + const trainerKey = randSeedItem(Object.keys(i18next.t(`${classKey}${genderKey}`, { returnObjects: true }))); this.nameKey = `${classKey}${genderKey}.${trainerKey}`; } this.name = i18next.t(this.nameKey); @@ -87,7 +85,7 @@ export default class Trainer extends Phaser.GameObjects.Container { } } else { const partnerGenderKey = i18next.exists(`${classKey}.FEMALE`) ? ".FEMALE" : ""; - const partnerTrainerKey = Utils.randSeedItem( + const partnerTrainerKey = randSeedItem( Object.keys( i18next.t(`${classKey}${partnerGenderKey}`, { returnObjects: true, @@ -225,6 +223,13 @@ export default class Trainer extends Phaser.GameObjects.Container { return this.config.doubleOnly || this.variant === TrainerVariant.DOUBLE; } + /** + * Return whether the trainer is a duo, like Tate & Liza + */ + isPartner(): boolean { + return this.variant === TrainerVariant.DOUBLE; + } + getMixedBattleBgm(): string { return this.config.mixedBattleBgm; } @@ -420,7 +425,7 @@ export default class Trainer extends Phaser.GameObjects.Container { // If useNewSpeciesPool is true, we need to generate a new species from the new species pool, otherwise we generate a random species let species = useNewSpeciesPool - ? getPokemonSpecies(newSpeciesPool[Math.floor(Utils.randSeedInt(newSpeciesPool.length))]) + ? getPokemonSpecies(newSpeciesPool[Math.floor(randSeedInt(newSpeciesPool.length))]) : template.isSameSpecies(index) && index > offset ? getPokemonSpecies( battle.enemyParty[offset].species.getTrainerSpeciesForLevel( @@ -461,7 +466,7 @@ export default class Trainer extends Phaser.GameObjects.Container { let baseSpecies: PokemonSpecies; if (this.config.speciesPools) { - const tierValue = Utils.randSeedInt(512); + const tierValue = randSeedInt(512); let tier = tierValue >= 156 ? TrainerPoolTier.COMMON @@ -480,7 +485,7 @@ export default class Trainer extends Phaser.GameObjects.Container { tier--; } const tierPool = this.config.speciesPools[tier]; - baseSpecies = getPokemonSpecies(Utils.randSeedItem(tierPool)); + baseSpecies = getPokemonSpecies(randSeedItem(tierPool)); } else { baseSpecies = globalScene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter); } @@ -619,7 +624,7 @@ export default class Trainer extends Phaser.GameObjects.Container { if (maxScorePartyMemberIndexes.length > 1) { let rand: number; globalScene.executeWithSeedOffset( - () => (rand = Utils.randSeedInt(maxScorePartyMemberIndexes.length)), + () => (rand = randSeedInt(maxScorePartyMemberIndexes.length)), globalScene.currentBattle.turn << 2, ); return maxScorePartyMemberIndexes[rand!]; diff --git a/src/game-mode.ts b/src/game-mode.ts index c340768ef77..ec7171b0024 100644 --- a/src/game-mode.ts +++ b/src/game-mode.ts @@ -7,12 +7,13 @@ import type PokemonSpecies from "./data/pokemon-species"; import { allSpecies } from "./data/pokemon-species"; import type { Arena } from "./field/arena"; import Overrides from "#app/overrides"; -import * as Utils from "./utils"; +import { randSeedInt, randSeedItem } from "#app/utils/common"; import { Biome } from "#enums/biome"; import { Species } from "#enums/species"; import { Challenges } from "./enums/challenges"; import { globalScene } from "#app/global-scene"; import { getDailyStartingBiome } from "./data/daily-run"; +import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES, CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES } from "./constants"; export enum GameModes { CLASSIC, @@ -36,10 +37,6 @@ interface GameModeConfig { hasMysteryEncounters?: boolean; } -// Describes min and max waves for MEs in specific game modes -export const CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180]; -export const CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180]; - export class GameMode implements GameModeConfig { public modeId: GameModes; public isClassic: boolean; @@ -186,7 +183,7 @@ export class GameMode implements GameModeConfig { if (w < waveIndex) { globalScene.executeWithSeedOffset(() => { const waveTrainerChance = arena.getTrainerChance(); - if (!Utils.randSeedInt(waveTrainerChance)) { + if (!randSeedInt(waveTrainerChance)) { allowTrainerBattle = false; } }, w); @@ -196,7 +193,7 @@ export class GameMode implements GameModeConfig { } } } - return Boolean(allowTrainerBattle && trainerChance && !Utils.randSeedInt(trainerChance)); + return Boolean(allowTrainerBattle && trainerChance && !randSeedInt(trainerChance)); } return false; } @@ -222,7 +219,7 @@ export class GameMode implements GameModeConfig { s.speciesId !== Species.ETERNATUS && s.speciesId !== Species.ARCEUS, ); - return Utils.randSeedItem(allFinalBossSpecies); + return randSeedItem(allFinalBossSpecies); } return null; diff --git a/src/global-vars/bypass-login.ts b/src/global-vars/bypass-login.ts new file mode 100644 index 00000000000..3595a076101 --- /dev/null +++ b/src/global-vars/bypass-login.ts @@ -0,0 +1 @@ +export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; diff --git a/src/global-vars/starter-colors.ts b/src/global-vars/starter-colors.ts new file mode 100644 index 00000000000..6abe028be99 --- /dev/null +++ b/src/global-vars/starter-colors.ts @@ -0,0 +1,4 @@ +export const starterColors: StarterColors = {}; +interface StarterColors { + [key: string]: [string, string]; +} diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts index fb4555084ee..02a95f71ac4 100644 --- a/src/inputs-controller.ts +++ b/src/inputs-controller.ts @@ -1,12 +1,12 @@ import Phaser from "phaser"; -import * as Utils from "./utils"; -import { deepCopy } from "./utils"; +import { getEnumValues } from "#app/utils/common"; +import { deepCopy } from "#app/utils/data"; import pad_generic from "./configs/inputs/pad_generic"; import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES"; import pad_xbox360 from "./configs/inputs/pad_xbox360"; import pad_dualshock from "./configs/inputs/pad_dualshock"; import pad_procon from "./configs/inputs/pad_procon"; -import { Mode } from "./ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler"; import type SettingsKeyboardUiHandler from "./ui/settings/settings-keyboard-ui-handler"; import cfg_keyboard_qwerty from "./configs/inputs/cfg_keyboard_qwerty"; @@ -102,7 +102,7 @@ export class InputsController { [Device.KEYBOARD]: "default", }; - for (const b of Utils.getEnumValues(Button)) { + for (const b of getEnumValues(Button)) { this.interactions[b] = { pressTime: false, isPressed: false, @@ -236,7 +236,7 @@ export class InputsController { if (gamepadName) { this.selectedDevice[Device.GAMEPAD] = gamepadName.toLowerCase(); } - const handler = globalScene.ui?.handlers[Mode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler; + const handler = globalScene.ui?.handlers[UiMode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler; handler?.updateChosenGamepadDisplay(); } @@ -249,7 +249,7 @@ export class InputsController { if (layoutKeyboard) { this.selectedDevice[Device.KEYBOARD] = layoutKeyboard.toLowerCase(); } - const handler = globalScene.ui?.handlers[Mode.SETTINGS_KEYBOARD] as SettingsKeyboardUiHandler; + const handler = globalScene.ui?.handlers[UiMode.SETTINGS_KEYBOARD] as SettingsKeyboardUiHandler; handler?.updateChosenKeyboardDisplay(); } @@ -297,7 +297,7 @@ export class InputsController { globalScene.gameData?.saveMappingConfigs(gamepadID, this.configs[gamepadID]); } this.lastSource = "gamepad"; - const handler = globalScene.ui?.handlers[Mode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler; + const handler = globalScene.ui?.handlers[UiMode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler; handler?.updateChosenGamepadDisplay(); } @@ -407,7 +407,7 @@ export class InputsController { this.lastSource = "gamepad"; if ( !this.selectedDevice[Device.GAMEPAD] || - (globalScene.ui.getMode() !== Mode.GAMEPAD_BINDING && + (globalScene.ui.getMode() !== UiMode.GAMEPAD_BINDING && this.selectedDevice[Device.GAMEPAD] !== pad.id.toLowerCase()) ) { this.setChosenGamepad(pad.id); diff --git a/src/loading-scene.ts b/src/loading-scene.ts index f99831c53bc..914e6e961e2 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -4,14 +4,14 @@ import CacheBustedLoaderPlugin from "#app/plugins/cache-busted-loader-plugin"; import { SceneBase } from "#app/scene-base"; import { WindowVariant, getWindowVariantSuffix } from "#app/ui/ui-theme"; import { isMobile } from "#app/touch-controls"; -import * as Utils from "#app/utils"; +import { localPing, getEnumValues, hasAllLocalizedSprites, getEnumKeys } from "#app/utils/common"; import { initPokemonPrevolutions, initPokemonStarters } from "#app/data/balance/pokemon-evolutions"; import { initBiomes } from "#app/data/balance/biomes"; import { initEggMoves } from "#app/data/balance/egg-moves"; import { initPokemonForms } from "#app/data/pokemon-forms"; import { initSpecies } from "#app/data/pokemon-species"; import { initMoves } from "#app/data/moves/move"; -import { initAbilities } from "#app/data/ability"; +import { initAbilities } from "#app/data/abilities/ability"; import { initAchievements } from "#app/system/achv"; import { initTrainerTypeDialogue } from "#app/data/dialogue"; import { initChallenges } from "#app/data/challenge"; @@ -34,7 +34,7 @@ export class LoadingScene extends SceneBase { } preload() { - Utils.localPing(); + localPing(); this.load["manifest"] = this.game["manifest"]; this.loadImage("loading_bg", "arenas"); @@ -49,7 +49,7 @@ export class LoadingScene extends SceneBase { this.loadImage("friendship_overlay", "ui"); this.loadImage("cursor", "ui"); this.loadImage("cursor_reverse", "ui"); - for (const wv of Utils.getEnumValues(WindowVariant)) { + for (const wv of getEnumValues(WindowVariant)) { for (let w = 1; w <= 5; w++) { this.loadImage(`window_${w}${getWindowVariantSuffix(wv)}`, "ui/windows"); } @@ -177,7 +177,7 @@ export class LoadingScene extends SceneBase { this.loadImage("default_bg", "arenas"); // Load arena images - Utils.getEnumValues(Biome).map(bt => { + getEnumValues(Biome).map(bt => { const btKey = Biome[bt].toLowerCase(); const isBaseAnimated = btKey === "end"; const baseAKey = `${btKey}_a`; @@ -239,7 +239,7 @@ export class LoadingScene extends SceneBase { // Get current lang and load the types atlas for it. English will only load types while all other languages will load types and types_ const lang = i18next.resolvedLanguage; if (lang !== "en") { - if (Utils.hasAllLocalizedSprites(lang)) { + if (hasAllLocalizedSprites(lang)) { this.loadAtlas(`statuses_${lang}`, ""); this.loadAtlas(`types_${lang}`, ""); } else { @@ -268,7 +268,7 @@ export class LoadingScene extends SceneBase { this.loadAtlas("egg_icons", "egg"); this.loadAtlas("egg_shard", "egg"); this.loadAtlas("egg_lightrays", "egg"); - for (const gt of Utils.getEnumKeys(GachaType)) { + for (const gt of getEnumKeys(GachaType)) { const key = gt.toLowerCase(); this.loadImage(`gacha_${key}`, "egg"); this.loadAtlas(`gacha_underlay_${key}`, "egg"); diff --git a/src/main.ts b/src/main.ts index 3d3965cad08..7db663d14c7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -93,7 +93,7 @@ const startGame = async (manifest?: any) => { dom: { createContainer: true, }, - pixelArt: true, + antialias: false, pipeline: [InvertPostFX] as unknown as Phaser.Types.Core.PipelineConfig, scene: [LoadingScene, BattleScene], version: version, diff --git a/src/messages.ts b/src/messages.ts index e35b48f7226..c29151a98b3 100644 --- a/src/messages.ts +++ b/src/messages.ts @@ -6,9 +6,10 @@ import i18next from "i18next"; /** * Retrieves the Pokemon's name, potentially with an affix indicating its role (wild or foe) in the current battle context, translated * @param pokemon {@linkcode Pokemon} name and battle context will be retrieved from this instance + * @param {boolean} useIllusion - Whether we want the name of the illusion or not. Default value : true * @returns {string} ex: "Wild Gengar", "Ectoplasma sauvage" */ -export function getPokemonNameWithAffix(pokemon: Pokemon | undefined): string { +export function getPokemonNameWithAffix(pokemon: Pokemon | undefined, useIllusion = true): string { if (!pokemon) { return "Missigno"; } @@ -18,19 +19,17 @@ export function getPokemonNameWithAffix(pokemon: Pokemon | undefined): string { return !pokemon.isPlayer() ? pokemon.hasTrainer() ? i18next.t("battle:foePokemonWithAffix", { - pokemonName: pokemon.getNameToRender(), + pokemonName: pokemon.getNameToRender(useIllusion), }) : i18next.t("battle:wildPokemonWithAffix", { - pokemonName: pokemon.getNameToRender(), + pokemonName: pokemon.getNameToRender(useIllusion), }) - : pokemon.getNameToRender(); + : pokemon.getNameToRender(useIllusion); case BattleSpec.FINAL_BOSS: return !pokemon.isPlayer() - ? i18next.t("battle:foePokemonWithAffix", { - pokemonName: pokemon.getNameToRender(), - }) - : pokemon.getNameToRender(); + ? i18next.t("battle:foePokemonWithAffix", { pokemonName: pokemon.getNameToRender(useIllusion) }) + : pokemon.getNameToRender(useIllusion); default: - return pokemon.getNameToRender(); + return pokemon.getNameToRender(useIllusion); } } diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 8feb60c7778..8bd2dc8948a 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -114,7 +114,7 @@ import { NumberHolder, padInt, randSeedInt, -} from "#app/utils"; +} from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; @@ -128,6 +128,7 @@ import { getStatKey, Stat, TEMP_BATTLE_STATS } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; import i18next from "i18next"; import { timedEventManager } from "#app/global-event-manager"; +import { TYPE_BOOST_ITEM_BOOST_PERCENT } from "#app/constants"; const outputModifierData = false; const useMaxWeightForOutput = false; @@ -789,6 +790,7 @@ export class BerryModifierType extends PokemonHeldItemModifierType implements Ge ); this.berryType = berryType; + this.id = "BERRY"; // needed to prevent harvest item deletion; remove after modifier rework } get name(): string { @@ -1329,7 +1331,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator { constructor() { super((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in PokemonType) { - return new AttackTypeBoosterModifierType(pregenArgs[0] as PokemonType, 20); + return new AttackTypeBoosterModifierType(pregenArgs[0] as PokemonType, TYPE_BOOST_ITEM_BOOST_PERCENT); } const attackMoveTypes = party.flatMap(p => @@ -1377,7 +1379,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator { weight += typeWeight; } - return new AttackTypeBoosterModifierType(type!, 20); + return new AttackTypeBoosterModifierType(type!, TYPE_BOOST_ITEM_BOOST_PERCENT); }); } } diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 7c9207bbea5..9df7aa7813f 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -15,7 +15,7 @@ import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import type { VoucherType } from "#app/system/voucher"; import { Command } from "#app/ui/command-ui-handler"; import { addTextObject, TextStyle } from "#app/ui/text"; -import { BooleanHolder, hslToHex, isNullOrUndefined, NumberHolder, toDmgValue } from "#app/utils"; +import { BooleanHolder, hslToHex, isNullOrUndefined, NumberHolder, toDmgValue } from "#app/utils/common"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; import type { Moves } from "#enums/moves"; @@ -47,7 +47,12 @@ import { } from "./modifier-type"; import { Color, ShadowColor } from "#enums/color"; import { FRIENDSHIP_GAIN_FROM_RARE_CANDY } from "#app/data/balance/starters"; -import { applyAbAttrs, CommanderAbAttr } from "#app/data/ability"; +import { + applyAbAttrs, + applyPostItemLostAbAttrs, + CommanderAbAttr, + PostItemLostAbAttr, +} from "#app/data/abilities/ability"; import { globalScene } from "#app/global-scene"; export type ModifierPredicate = (modifier: Modifier) => boolean; @@ -232,6 +237,10 @@ export abstract class PersistentModifier extends Modifier { abstract getMaxStackCount(forThreshold?: boolean): number; + getCountUnderMax(): number { + return this.getMaxStackCount() - this.getStackCount(); + } + isIconVisible(): boolean { return true; } @@ -653,7 +662,9 @@ export class TerastallizeAccessModifier extends PersistentModifier { } export abstract class PokemonHeldItemModifier extends PersistentModifier { + /** The ID of the {@linkcode Pokemon} that this item belongs to. */ public pokemonId: number; + /** Whether this item can be transfered to or stolen by another Pokemon. */ public isTransferable = true; constructor(type: ModifierType, pokemonId: number, stackCount?: number) { @@ -1103,20 +1114,20 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier { * @returns always `true` */ override apply(_pokemon: Pokemon, stat: Stat, statHolder: NumberHolder): boolean { - // Modifies the passed in stat number holder by +1 per stack for HP, +2 per stack for other stats - // If the Macho Brace is at max stacks (50), adds additional 5% to total HP and 10% to other stats + // Modifies the passed in stat number holder by +2 per stack for HP, +1 per stack for other stats + // If the Macho Brace is at max stacks (50), adds additional 10% to total HP and 5% to other stats const isHp = stat === Stat.HP; if (isHp) { - statHolder.value += this.stackCount; - if (this.stackCount === this.getMaxHeldItemCount()) { - statHolder.value = Math.floor(statHolder.value * 1.05); - } - } else { statHolder.value += 2 * this.stackCount; if (this.stackCount === this.getMaxHeldItemCount()) { statHolder.value = Math.floor(statHolder.value * 1.1); } + } else { + statHolder.value += this.stackCount; + if (this.stackCount === this.getMaxHeldItemCount()) { + statHolder.value = Math.floor(statHolder.value * 1.05); + } } return true; @@ -1479,7 +1490,8 @@ export class AttackTypeBoosterModifier extends PokemonHeldItemModifier { return ( super.shouldApply(pokemon, moveType, movePower) && typeof moveType === "number" && - movePower instanceof NumberHolder + movePower instanceof NumberHolder && + this.moveType === moveType ); } @@ -1638,14 +1650,15 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier { } /** - * Applies {@linkcode FlinchChanceModifier} - * @param pokemon the {@linkcode Pokemon} that holds the item - * @param flinched {@linkcode BooleanHolder} that is `true` if the pokemon flinched - * @returns `true` if {@linkcode FlinchChanceModifier} has been applied + * Applies {@linkcode FlinchChanceModifier} to randomly flinch targets hit. + * @param pokemon - The {@linkcode Pokemon} that holds the item + * @param flinched - A {@linkcode BooleanHolder} holding whether the pokemon has flinched + * @returns `true` if {@linkcode FlinchChanceModifier} was applied successfully */ override apply(pokemon: Pokemon, flinched: BooleanHolder): boolean { - // The check for pokemon.battleSummonData is to ensure that a crash doesn't occur when a Pokemon with King's Rock procs a flinch - if (pokemon.battleSummonData && !flinched.value && pokemon.randSeedInt(100) < this.getStackCount() * this.chance) { + // The check for pokemon.summonData is to ensure that a crash doesn't occur when a Pokemon with King's Rock procs a flinch + // TODO: Since summonData is always defined now, we can probably remove this + if (pokemon.summonData && !flinched.value && pokemon.randSeedInt(100) < this.getStackCount() * this.chance) { flinched.value = true; return true; } @@ -1771,6 +1784,7 @@ export class HitHealModifier extends PokemonHeldItemModifier { */ override apply(pokemon: Pokemon): boolean { if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) { + // TODO: this shouldn't be undefined AFAIK globalScene.unshiftPhase( new PokemonHealPhase( pokemon.getBattlerIndex(), @@ -1866,11 +1880,15 @@ export class BerryModifier extends PokemonHeldItemModifier { override apply(pokemon: Pokemon): boolean { const preserve = new BooleanHolder(false); globalScene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), pokemon, preserve); + this.consumed = !preserve.value; + // munch the berry and trigger unburden-like effects getBerryEffectFunc(this.berryType)(pokemon); - if (!preserve.value) { - this.consumed = true; - } + applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, false); + + // Update berry eaten trackers for Belch, Harvest, Cud Chew, etc. + // Don't recover it if we proc berry pouch (no item duplication) + pokemon.recordEatenBerry(this.berryType, this.consumed); return true; } @@ -1909,9 +1927,7 @@ export class PreserveBerryModifier extends PersistentModifier { * @returns always `true` */ override apply(pokemon: Pokemon, doPreserve: BooleanHolder): boolean { - if (!doPreserve.value) { - doPreserve.value = pokemon.randSeedInt(10) < this.getStackCount() * 3; - } + doPreserve.value ||= pokemon.randSeedInt(10) < this.getStackCount() * 3; return true; } @@ -1952,7 +1968,7 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier { ); // Remove the Pokemon's FAINT status - pokemon.resetStatus(true, false, true); + pokemon.resetStatus(true, false, true, false); // Reapply Commander on the Pokemon's side of the field, if applicable const field = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField(); @@ -2160,7 +2176,7 @@ export class PokemonHpRestoreModifier extends ConsumablePokemonModifier { restorePoints = Math.floor(restorePoints * multiplier); } if (this.fainted || this.healStatus) { - pokemon.resetStatus(true, true); + pokemon.resetStatus(true, true, false, false); } pokemon.hp = Math.min( pokemon.hp + @@ -2180,7 +2196,7 @@ export class PokemonStatusHealModifier extends ConsumablePokemonModifier { * @returns always `true` */ override apply(playerPokemon: PlayerPokemon): boolean { - playerPokemon.resetStatus(true, true); + playerPokemon.resetStatus(true, true, false, false); return true; } } @@ -2734,7 +2750,7 @@ export class PokemonMoveAccuracyBoosterModifier extends PokemonHeldItemModifier * @returns always `true` */ override apply(_pokemon: Pokemon, moveAccuracy: NumberHolder): boolean { - moveAccuracy.value = Math.min(moveAccuracy.value + this.accuracyAmount * this.getStackCount(), 100); + moveAccuracy.value = moveAccuracy.value + this.accuracyAmount * this.getStackCount(); return true; } @@ -3608,7 +3624,7 @@ export class EnemyAttackStatusEffectChanceModifier extends EnemyPersistentModifi super(type, stackCount); this.effect = effect; - //Hardcode temporarily + // Hardcode temporarily this.chance = 0.025 * (this.effect === StatusEffect.BURN || this.effect === StatusEffect.POISON ? 2 : 1); } @@ -3715,13 +3731,13 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier { * @returns `true` if {@linkcode Pokemon} endured */ override apply(target: Pokemon): boolean { - if (target.battleData.endured || target.randSeedInt(100) >= this.chance * this.getStackCount()) { + if (target.waveData.endured || target.randSeedInt(100) >= this.chance * this.getStackCount()) { return false; } target.addTag(BattlerTagType.ENDURE_TOKEN, 1); - target.battleData.endured = true; + target.waveData.endured = true; return true; } diff --git a/src/overrides.ts b/src/overrides.ts index 3a9a54e740b..5bbd29b355f 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -2,10 +2,11 @@ import { type PokeballCounts } from "#app/battle-scene"; import { EvolutionItem } from "#app/data/balance/pokemon-evolutions"; import { Gender } from "#app/data/gender"; import { FormChangeItem } from "#app/data/pokemon-forms"; -import { Variant } from "#app/data/variant"; import { type ModifierOverride } from "#app/modifier/modifier-type"; +import { Variant } from "#app/sprites/variant"; import { Unlockables } from "#app/system/unlockables"; import { Abilities } from "#enums/abilities"; +import { BattleType } from "#enums/battle-type"; import { BerryType } from "#enums/berry-type"; import { Biome } from "#enums/biome"; import { EggTier } from "#enums/egg-type"; @@ -18,6 +19,7 @@ import { Species } from "#enums/species"; import { Stat } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; import { TimeOfDay } from "#enums/time-of-day"; +import { TrainerType } from "#enums/trainer-type"; import { VariantTier } from "#enums/variant-tier"; import { WeatherType } from "#enums/weather-type"; @@ -41,7 +43,7 @@ import { WeatherType } from "#enums/weather-type"; * } * ``` */ -const overrides = {} satisfies Partial>; +const overrides = {} satisfies Partial>; /** * If you need to add Overrides values for local testing do that inside {@linkcode overrides} @@ -69,7 +71,7 @@ class DefaultOverrides { * * If `"odd-doubles"`, follow the `"double"` rule on odd wave numbers, and follow the `"single"` rule on even wave numbers. */ - readonly BATTLE_TYPE_OVERRIDE: BattleStyle | null = null; + readonly BATTLE_STYLE_OVERRIDE: BattleStyle | null = null; readonly STARTING_WAVE_OVERRIDE: number = 0; readonly STARTING_BIOME_OVERRIDE: Biome = Biome.TOWN; readonly ARENA_TINT_OVERRIDE: TimeOfDay | null = null; @@ -102,8 +104,16 @@ class DefaultOverrides { readonly BYPASS_TUTORIAL_SKIP_OVERRIDE: boolean = false; /** Set to `true` to be able to re-earn already unlocked achievements */ readonly ACHIEVEMENTS_REUNLOCK_OVERRIDE: boolean = false; - /** Set to `true` to force Paralysis and Freeze to always activate, or `false` to force them to not activate */ + /** + * Set to `true` to force Paralysis and Freeze to always activate, + * or `false` to force them to not activate (or clear for freeze). + */ readonly STATUS_ACTIVATION_OVERRIDE: boolean | null = null; + /** + * Set to `true` to force confusion to always trigger, + * or `false` to force it to never trigger. + */ + readonly CONFUSION_ACTIVATION_OVERRIDE: boolean | null = null; // ---------------- // PLAYER OVERRIDES @@ -259,6 +269,16 @@ class DefaultOverrides { * If `true`, disable all non-scripted opponent trainer encounters. */ readonly DISABLE_STANDARD_TRAINERS_OVERRIDE: boolean = false; + + /** + * Set all non-scripted waves to use the selected battle type. + * + * Ignored if set to {@linkcode BattleType.TRAINER} and `DISABLE_STANDARD_TRAINERS_OVERRIDE` is `true`. + */ + readonly BATTLE_TYPE_OVERRIDE: Exclude | null = null; + + /** Force all random trainer types to be the provided type. */ + readonly RANDOM_TRAINER_OVERRIDE: RandomTrainerOverride | null = null; } export const defaultOverrides = new DefaultOverrides(); @@ -269,3 +289,13 @@ export default { } satisfies InstanceType; export type BattleStyle = "double" | "single" | "even-doubles" | "odd-doubles"; + +export type RandomTrainerOverride = { + /** The Type of trainer to force */ + trainerType: Exclude, + /* If the selected trainer type has a double version, it will always use its double version. */ + alwaysDouble?: boolean +} + +/** The type of the {@linkcode DefaultOverrides} class */ +export type OverridesType = typeof DefaultOverrides; \ No newline at end of file diff --git a/src/phases/add-enemy-buff-modifier-phase.ts b/src/phases/add-enemy-buff-modifier-phase.ts index 7d91e64382a..16ed78e6d0d 100644 --- a/src/phases/add-enemy-buff-modifier-phase.ts +++ b/src/phases/add-enemy-buff-modifier-phase.ts @@ -9,10 +9,6 @@ import { Phase } from "#app/phase"; import { globalScene } from "#app/global-scene"; export class AddEnemyBuffModifierPhase extends Phase { - constructor() { - super(); - } - start() { super.start(); diff --git a/src/phases/attempt-capture-phase.ts b/src/phases/attempt-capture-phase.ts index 78021da4066..795aa7010e1 100644 --- a/src/phases/attempt-capture-phase.ts +++ b/src/phases/attempt-capture-phase.ts @@ -19,7 +19,7 @@ import { achvs } from "#app/system/achv"; import type { PartyOption } from "#app/ui/party-ui-handler"; import { PartyUiMode } from "#app/ui/party-ui-handler"; import { SummaryUiMode } from "#app/ui/summary-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type { PokeballType } from "#enums/pokeball"; import { StatusEffect } from "#enums/status-effect"; import i18next from "i18next"; @@ -295,7 +295,7 @@ export class AttemptCapturePhase extends PokemonPhase { () => { globalScene.pokemonInfoContainer.makeRoomForConfirmUi(1, true); globalScene.ui.setMode( - Mode.CONFIRM, + UiMode.CONFIRM, () => { const newPokemon = globalScene.addPlayerPokemon( pokemon.species, @@ -310,12 +310,12 @@ export class AttemptCapturePhase extends PokemonPhase { pokemon, ); globalScene.ui.setMode( - Mode.SUMMARY, + UiMode.SUMMARY, newPokemon, 0, SummaryUiMode.DEFAULT, () => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { promptRelease(); }); }, @@ -329,19 +329,26 @@ export class AttemptCapturePhase extends PokemonPhase { form: pokemon.formIndex, female: pokemon.gender === Gender.FEMALE, }; - globalScene.ui.setOverlayMode(Mode.POKEDEX_PAGE, pokemon.species, attributes, null, null, () => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { - promptRelease(); - }); - }); + globalScene.ui.setOverlayMode( + UiMode.POKEDEX_PAGE, + pokemon.species, + attributes, + null, + null, + () => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { + promptRelease(); + }); + }, + ); }, () => { globalScene.ui.setMode( - Mode.PARTY, + UiMode.PARTY, PartyUiMode.RELEASE, this.fieldIndex, (slotIndex: number, _option: PartyOption) => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { if (slotIndex < 6) { addToParty(slotIndex); } else { @@ -352,7 +359,7 @@ export class AttemptCapturePhase extends PokemonPhase { ); }, () => { - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { removePokemon(); end(); }); diff --git a/src/phases/attempt-run-phase.ts b/src/phases/attempt-run-phase.ts index dab5b8789da..274d3c40576 100644 --- a/src/phases/attempt-run-phase.ts +++ b/src/phases/attempt-run-phase.ts @@ -1,14 +1,20 @@ -import { applyAbAttrs, applyPreLeaveFieldAbAttrs, PreLeaveFieldAbAttr, RunSuccessAbAttr } from "#app/data/ability"; -import { Stat } from "#app/enums/stat"; -import { StatusEffect } from "#app/enums/status-effect"; +import { + applyAbAttrs, + applyPreLeaveFieldAbAttrs, + PreLeaveFieldAbAttr, + RunSuccessAbAttr, +} from "#app/data/abilities/ability"; +import { Stat } from "#enums/stat"; +import { StatusEffect } from "#enums/status-effect"; import type { PlayerPokemon, EnemyPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import i18next from "i18next"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { BattleEndPhase } from "./battle-end-phase"; import { NewBattlePhase } from "./new-battle-phase"; import { PokemonPhase } from "./pokemon-phase"; import { globalScene } from "#app/global-scene"; +import { SelectBiomePhase } from "./select-biome-phase"; export class AttemptRunPhase extends PokemonPhase { /** For testing purposes: this is to force the pokemon to fail and escape */ @@ -22,7 +28,7 @@ export class AttemptRunPhase extends PokemonPhase { const playerPokemon = this.getPokemon(); - const escapeChance = new Utils.NumberHolder(0); + const escapeChance = new NumberHolder(0); this.attemptRunAway(playerField, enemyField, escapeChance); @@ -54,6 +60,11 @@ export class AttemptRunPhase extends PokemonPhase { }); globalScene.pushPhase(new BattleEndPhase(false)); + + if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { + globalScene.pushPhase(new SelectBiomePhase()); + } + globalScene.pushPhase(new NewBattlePhase()); } else { playerPokemon.turnData.failedRunAway = true; @@ -63,7 +74,7 @@ export class AttemptRunPhase extends PokemonPhase { this.end(); } - attemptRunAway(playerField: PlayerPokemon[], enemyField: EnemyPokemon[], escapeChance: Utils.NumberHolder) { + attemptRunAway(playerField: PlayerPokemon[], enemyField: EnemyPokemon[], escapeChance: NumberHolder) { /** Sum of the speed of all enemy pokemon on the field */ const enemySpeed = enemyField.reduce( (total: number, enemyPokemon: Pokemon) => total + enemyPokemon.getStat(Stat.SPD), diff --git a/src/phases/battle-end-phase.ts b/src/phases/battle-end-phase.ts index a7158264ab7..b4bb28fe55e 100644 --- a/src/phases/battle-end-phase.ts +++ b/src/phases/battle-end-phase.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { applyPostBattleAbAttrs, PostBattleAbAttr } from "#app/data/ability"; +import { applyPostBattleAbAttrs, PostBattleAbAttr } from "#app/data/abilities/ability"; import { LapsingPersistentModifier, LapsingPokemonHeldItemModifier } from "#app/modifier/modifier"; import { BattlePhase } from "./battle-phase"; import { GameOverPhase } from "./game-over-phase"; @@ -17,6 +17,25 @@ export class BattleEndPhase extends BattlePhase { start() { super.start(); + // cull any extra `BattleEnd` phases from the queue. + globalScene.phaseQueue = globalScene.phaseQueue.filter(phase => { + if (phase instanceof BattleEndPhase) { + this.isVictory ||= phase.isVictory; + return false; + } + return true; + }); + // `phaseQueuePrepend` is private, so we have to use this inefficient loop. + while ( + globalScene.tryRemoveUnshiftedPhase(phase => { + if (phase instanceof BattleEndPhase) { + this.isVictory ||= phase.isVictory; + return true; + } + return false; + }) + ) {} + globalScene.gameData.gameStats.battles++; if ( globalScene.gameMode.isEndless && @@ -40,8 +59,8 @@ export class BattleEndPhase extends BattlePhase { } for (const pokemon of globalScene.getField()) { - if (pokemon?.battleSummonData) { - pokemon.battleSummonData.waveTurnCount = 1; + if (pokemon) { + pokemon.tempSummonData.waveTurnCount = 1; } } @@ -54,6 +73,13 @@ export class BattleEndPhase extends BattlePhase { } globalScene.clearEnemyHeldItemModifiers(); + for (const p of globalScene.getEnemyParty()) { + try { + p.destroy(); + } catch { + console.warn("Unable to destroy stale pokemon object in BattleEndPhase:", p); + } + } const lapsingModifiers = globalScene.findModifiers( m => m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier, diff --git a/src/phases/battle-phase.ts b/src/phases/battle-phase.ts index 72bcc85bc62..d70b3909639 100644 --- a/src/phases/battle-phase.ts +++ b/src/phases/battle-phase.ts @@ -3,13 +3,13 @@ import { TrainerSlot } from "#enums/trainer-slot"; import { Phase } from "#app/phase"; export class BattlePhase extends Phase { - constructor() { - super(); - } - showEnemyTrainer(trainerSlot: TrainerSlot = TrainerSlot.NONE): void { - const sprites = globalScene.currentBattle.trainer?.getSprites()!; // TODO: is this bang correct? - const tintSprites = globalScene.currentBattle.trainer?.getTintSprites()!; // TODO: is this bang correct? + if (!globalScene.currentBattle.trainer) { + console.warn("Enemy trainer is missing!"); + return; + } + const sprites = globalScene.currentBattle.trainer.getSprites(); + const tintSprites = globalScene.currentBattle.trainer.getTintSprites(); for (let i = 0; i < sprites.length; i++) { const visible = !trainerSlot || !i === (trainerSlot === TrainerSlot.TRAINER) || sprites.length < 2; [sprites[i], tintSprites[i]].map(sprite => { diff --git a/src/phases/berry-phase.ts b/src/phases/berry-phase.ts index 0048f8cd2f2..b027469ea5e 100644 --- a/src/phases/berry-phase.ts +++ b/src/phases/berry-phase.ts @@ -1,54 +1,77 @@ -import { applyAbAttrs, PreventBerryUseAbAttr, HealFromBerryUseAbAttr } from "#app/data/ability"; +import { + applyAbAttrs, + PreventBerryUseAbAttr, + HealFromBerryUseAbAttr, + RepeatBerryNextTurnAbAttr, +} from "#app/data/abilities/ability"; import { CommonAnim } from "#app/data/battle-anims"; import { BerryUsedEvent } from "#app/events/battle-scene"; import { getPokemonNameWithAffix } from "#app/messages"; import { BerryModifier } from "#app/modifier/modifier"; import i18next from "i18next"; -import * as Utils from "#app/utils"; +import { BooleanHolder } from "#app/utils/common"; import { FieldPhase } from "./field-phase"; import { CommonAnimPhase } from "./common-anim-phase"; import { globalScene } from "#app/global-scene"; +import type Pokemon from "#app/field/pokemon"; -/** The phase after attacks where the pokemon eat berries */ +/** + * The phase after attacks where the pokemon eat berries. + * Also triggers Cud Chew's "repeat berry use" effects + */ export class BerryPhase extends FieldPhase { start() { super.start(); this.executeForAll(pokemon => { - const hasUsableBerry = !!globalScene.findModifier(m => { - return m instanceof BerryModifier && m.shouldApply(pokemon); - }, pokemon.isPlayer()); - - if (hasUsableBerry) { - const cancelled = new Utils.BooleanHolder(false); - pokemon.getOpponents().map(opp => applyAbAttrs(PreventBerryUseAbAttr, opp, cancelled)); - - if (cancelled.value) { - globalScene.queueMessage( - i18next.t("abilityTriggers:preventBerryUse", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - }), - ); - } else { - globalScene.unshiftPhase( - new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM), - ); - - for (const berryModifier of globalScene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon)) { - if (berryModifier.consumed) { - berryModifier.consumed = false; - pokemon.loseHeldItem(berryModifier); - } - globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(berryModifier)); // Announce a berry was used - } - - globalScene.updateModifiers(pokemon.isPlayer()); - - applyAbAttrs(HealFromBerryUseAbAttr, pokemon, new Utils.BooleanHolder(false)); - } - } + this.eatBerries(pokemon); + applyAbAttrs(RepeatBerryNextTurnAbAttr, pokemon, null); }); this.end(); } + + /** + * Attempt to eat all of a given {@linkcode Pokemon}'s berries once. + * @param pokemon - The {@linkcode Pokemon} to check + */ + eatBerries(pokemon: Pokemon): void { + const hasUsableBerry = !!globalScene.findModifier( + m => m instanceof BerryModifier && m.shouldApply(pokemon), + pokemon.isPlayer(), + ); + + if (!hasUsableBerry) { + return; + } + + // TODO: If both opponents on field have unnerve, which one displays its message? + const cancelled = new BooleanHolder(false); + pokemon.getOpponents().forEach(opp => applyAbAttrs(PreventBerryUseAbAttr, opp, cancelled)); + if (cancelled.value) { + globalScene.queueMessage( + i18next.t("abilityTriggers:preventBerryUse", { + pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), + }), + ); + return; + } + + globalScene.unshiftPhase( + new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM), + ); + + for (const berryModifier of globalScene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon)) { + // No need to track berries being eaten; already done inside applyModifiers + if (berryModifier.consumed) { + berryModifier.consumed = false; + pokemon.loseHeldItem(berryModifier); + } + globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(berryModifier)); + } + globalScene.updateModifiers(pokemon.isPlayer()); + + // Abilities.CHEEK_POUCH only works once per round of nom noms + applyAbAttrs(HealFromBerryUseAbAttr, pokemon, new BooleanHolder(false)); + } } diff --git a/src/phases/check-switch-phase.ts b/src/phases/check-switch-phase.ts index ba4837fd7cc..9d73411fd37 100644 --- a/src/phases/check-switch-phase.ts +++ b/src/phases/check-switch-phase.ts @@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene"; import { BattleStyle } from "#app/enums/battle-style"; import { BattlerTagType } from "#app/enums/battler-tag-type"; import { getPokemonNameWithAffix } from "#app/messages"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { BattlePhase } from "./battle-phase"; import { SummonMissingPhase } from "./summon-missing-phase"; @@ -64,14 +64,14 @@ export class CheckSwitchPhase extends BattlePhase { null, () => { globalScene.ui.setMode( - Mode.CONFIRM, + UiMode.CONFIRM, () => { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.unshiftPhase(new SwitchPhase(SwitchType.INITIAL_SWITCH, this.fieldIndex, false, true)); this.end(); }, () => { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); this.end(); }, ); diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index 8691ac453ca..c3e558e1d86 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import type { TurnCommand } from "#app/battle"; -import { BattleType } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import type { EncoreTag } from "#app/data/battler-tags"; import { TrappedTag } from "#app/data/battler-tags"; import type { MoveTargetSet } from "#app/data/moves/move"; @@ -15,12 +15,12 @@ import type { PlayerPokemon, TurnMove } from "#app/field/pokemon"; import { FieldPosition } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { FieldPhase } from "./field-phase"; import { SelectTargetPhase } from "./select-target-phase"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; import { ArenaTagSide } from "#app/data/arena-tag"; import { ArenaTagType } from "#app/enums/arena-tag-type"; @@ -38,7 +38,7 @@ export class CommandPhase extends FieldPhase { globalScene.updateGameInfo(); - const commandUiHandler = globalScene.ui.handlers[Mode.COMMAND]; + const commandUiHandler = globalScene.ui.handlers[UiMode.COMMAND]; // If one of these conditions is true, we always reset the cursor to Command.FIGHT const cursorResetEvent = @@ -127,7 +127,7 @@ export class CommandPhase extends FieldPhase { ) { this.handleCommand(Command.FIGHT, moveIndex, queuedMove.ignorePP, queuedMove); } else { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); } } } else { @@ -136,9 +136,9 @@ export class CommandPhase extends FieldPhase { globalScene.currentBattle.mysteryEncounter?.skipToFightInput ) { globalScene.ui.clearText(); - globalScene.ui.setMode(Mode.FIGHT, this.fieldIndex); + globalScene.ui.setMode(UiMode.FIGHT, this.fieldIndex); } else { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); } } } @@ -209,7 +209,7 @@ export class CommandPhase extends FieldPhase { success = true; } else if (cursor < playerPokemon.getMoveset().length) { const move = playerPokemon.getMoveset()[cursor]; - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); // Decides between a Disabled, Not Implemented, or No PP translation message const errorMessage = playerPokemon.isMoveRestricted(move.moveId, playerPokemon) @@ -226,7 +226,7 @@ export class CommandPhase extends FieldPhase { null, () => { globalScene.ui.clearText(); - globalScene.ui.setMode(Mode.FIGHT, this.fieldIndex); + globalScene.ui.setMode(UiMode.FIGHT, this.fieldIndex); }, null, true, @@ -244,27 +244,27 @@ export class CommandPhase extends FieldPhase { globalScene.arena.biomeType === Biome.END && (!globalScene.gameMode.isClassic || globalScene.gameMode.isFreshStartChallenge() || notInDex) ) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText( i18next.t("battle:noPokeballForce"), null, () => { globalScene.ui.showText("", 0); - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); }, null, true, ); } else if (globalScene.currentBattle.battleType === BattleType.TRAINER) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText( i18next.t("battle:noPokeballTrainer"), null, () => { globalScene.ui.showText("", 0); - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); }, null, true, @@ -273,14 +273,14 @@ export class CommandPhase extends FieldPhase { globalScene.currentBattle.isBattleMysteryEncounter() && !globalScene.currentBattle.mysteryEncounter!.catchAllowed ) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText( i18next.t("battle:noPokeballMysteryEncounter"), null, () => { globalScene.ui.showText("", 0); - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); }, null, true, @@ -291,14 +291,14 @@ export class CommandPhase extends FieldPhase { .filter(p => p.isActive(true)) .map(p => p.getBattlerIndex()); if (targets.length > 1) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText( i18next.t("battle:noPokeballMulti"), null, () => { globalScene.ui.showText("", 0); - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); }, null, true, @@ -311,14 +311,14 @@ export class CommandPhase extends FieldPhase { !targetPokemon?.hasAbility(Abilities.WONDER_GUARD, false, true) && cursor < PokeballType.MASTER_BALL ) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText( i18next.t("battle:noPokeballStrong"), null, () => { globalScene.ui.showText("", 0); - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); }, null, true, @@ -347,14 +347,14 @@ export class CommandPhase extends FieldPhase { (arena.biomeType === Biome.END || (!isNullOrUndefined(mysteryEncounterFleeAllowed) && !mysteryEncounterFleeAllowed)) ) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText( i18next.t("battle:noEscapeForce"), null, () => { globalScene.ui.showText("", 0); - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); }, null, true, @@ -364,14 +364,14 @@ export class CommandPhase extends FieldPhase { (currentBattle.battleType === BattleType.TRAINER || currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) ) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText( i18next.t("battle:noEscapeTrainer"), null, () => { globalScene.ui.showText("", 0); - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); }, null, true, @@ -389,7 +389,7 @@ export class CommandPhase extends FieldPhase { } } else if (trappedAbMessages.length > 0) { if (!isSwitch) { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); } globalScene.ui.showText( trappedAbMessages[0], @@ -397,7 +397,7 @@ export class CommandPhase extends FieldPhase { () => { globalScene.ui.showText("", 0); if (!isSwitch) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); } }, null, @@ -412,8 +412,8 @@ export class CommandPhase extends FieldPhase { break; } if (!isSwitch) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.MESSAGE); } const showNoEscapeText = (tag: any) => { globalScene.ui.showText( @@ -429,7 +429,7 @@ export class CommandPhase extends FieldPhase { () => { globalScene.ui.showText("", 0); if (!isSwitch) { - globalScene.ui.setMode(Mode.COMMAND, this.fieldIndex); + globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); } }, null, @@ -471,6 +471,6 @@ export class CommandPhase extends FieldPhase { } end() { - globalScene.ui.setMode(Mode.MESSAGE).then(() => super.end()); + globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end()); } } diff --git a/src/phases/common-anim-phase.ts b/src/phases/common-anim-phase.ts index d32e93ea6aa..5be5e112389 100644 --- a/src/phases/common-anim-phase.ts +++ b/src/phases/common-anim-phase.ts @@ -6,13 +6,18 @@ import { PokemonPhase } from "./pokemon-phase"; export class CommonAnimPhase extends PokemonPhase { private anim: CommonAnim | null; - private targetIndex: number | undefined; + private targetIndex?: BattlerIndex; private playOnEmptyField: boolean; - constructor(battlerIndex?: BattlerIndex, targetIndex?: BattlerIndex, anim?: CommonAnim, playOnEmptyField = false) { + constructor( + battlerIndex?: BattlerIndex, + targetIndex?: BattlerIndex, + anim: CommonAnim | null = null, + playOnEmptyField = false, + ) { super(battlerIndex); - this.anim = anim!; // TODO: is this bang correct? + this.anim = anim; this.targetIndex = targetIndex; this.playOnEmptyField = playOnEmptyField; } diff --git a/src/phases/damage-anim-phase.ts b/src/phases/damage-anim-phase.ts index 703cd3d160e..b9581573f2e 100644 --- a/src/phases/damage-anim-phase.ts +++ b/src/phases/damage-anim-phase.ts @@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene"; import type { BattlerIndex } from "#app/battle"; import { BattleSpec } from "#enums/battle-spec"; import { type DamageResult, HitResult } from "#app/field/pokemon"; -import { fixedInt } from "#app/utils"; +import { fixedInt } from "#app/utils/common"; import { PokemonPhase } from "#app/phases/pokemon-phase"; export class DamageAnimPhase extends PokemonPhase { @@ -10,11 +10,16 @@ export class DamageAnimPhase extends PokemonPhase { private damageResult: DamageResult; private critical: boolean; - constructor(battlerIndex: BattlerIndex, amount: number, damageResult?: DamageResult, critical = false) { + constructor( + battlerIndex: BattlerIndex, + amount: number, + damageResult: DamageResult = HitResult.EFFECTIVE, + critical = false, + ) { super(battlerIndex); this.amount = amount; - this.damageResult = damageResult || HitResult.EFFECTIVE; + this.damageResult = damageResult; this.critical = critical; } diff --git a/src/phases/egg-hatch-phase.ts b/src/phases/egg-hatch-phase.ts index 49a408e8699..69bcf741383 100644 --- a/src/phases/egg-hatch-phase.ts +++ b/src/phases/egg-hatch-phase.ts @@ -8,10 +8,10 @@ import { achvs } from "#app/system/achv"; import EggCounterContainer from "#app/ui/egg-counter-container"; import type EggHatchSceneHandler from "#app/ui/egg-hatch-scene-handler"; import PokemonInfoContainer from "#app/ui/pokemon-info-container"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; -import * as Utils from "#app/utils"; +import { fixedInt, getFrameMs, randInt } from "#app/utils/common"; import type { EggLapsePhase } from "./egg-lapse-phase"; import type { EggHatchData } from "#app/data/egg-hatch-data"; import { doShinySparkleAnim } from "#app/field/anims"; @@ -76,7 +76,7 @@ export class EggHatchPhase extends Phase { start() { super.start(); - globalScene.ui.setModeForceTransition(Mode.EGG_HATCH_SCENE).then(() => { + globalScene.ui.setModeForceTransition(UiMode.EGG_HATCH_SCENE).then(() => { if (!this.egg) { return this.end(); } @@ -306,17 +306,17 @@ export class EggHatchPhase extends Phase { this.canSkip = false; this.hatched = true; if (this.evolutionBgm) { - SoundFade.fadeOut(globalScene, this.evolutionBgm, Utils.fixedInt(100)); + SoundFade.fadeOut(globalScene, this.evolutionBgm, fixedInt(100)); } for (let e = 0; e < 5; e++) { - globalScene.time.delayedCall(Utils.fixedInt(375 * e), () => + globalScene.time.delayedCall(fixedInt(375 * e), () => globalScene.playSound("se/egg_hatch", { volume: 1 - e * 0.2 }), ); } this.eggLightraysOverlay.setVisible(true); this.eggLightraysOverlay.play("egg_lightrays"); globalScene.tweens.add({ - duration: Utils.fixedInt(125), + duration: fixedInt(125), targets: this.eggHatchOverlay, alpha: 1, ease: "Cubic.easeIn", @@ -325,7 +325,7 @@ export class EggHatchPhase extends Phase { this.canSkip = true; }, }); - globalScene.time.delayedCall(Utils.fixedInt(1500), () => { + globalScene.time.delayedCall(fixedInt(1500), () => { this.canSkip = false; if (!this.skipped) { this.doReveal(); @@ -363,46 +363,43 @@ export class EggHatchPhase extends Phase { this.pokemonSprite.setPipelineData("shiny", this.pokemon.shiny); this.pokemonSprite.setPipelineData("variant", this.pokemon.variant); this.pokemonSprite.setVisible(true); - globalScene.time.delayedCall(Utils.fixedInt(250), () => { + globalScene.time.delayedCall(fixedInt(250), () => { this.eggsToHatchCount--; this.eggHatchHandler.eventTarget.dispatchEvent(new EggCountChangedEvent(this.eggsToHatchCount)); this.pokemon.cry(); if (isShiny) { - globalScene.time.delayedCall(Utils.fixedInt(500), () => { + globalScene.time.delayedCall(fixedInt(500), () => { doShinySparkleAnim(this.pokemonShinySparkle, this.pokemon.variant); }); } - globalScene.time.delayedCall( - Utils.fixedInt(!this.skipped ? (!isShiny ? 1250 : 1750) : !isShiny ? 250 : 750), - () => { - this.infoContainer.show(this.pokemon, false, this.skipped ? 2 : 1); + globalScene.time.delayedCall(fixedInt(!this.skipped ? (!isShiny ? 1250 : 1750) : !isShiny ? 250 : 750), () => { + this.infoContainer.show(this.pokemon, false, this.skipped ? 2 : 1); - globalScene.playSoundWithoutBgm("evolution_fanfare"); + globalScene.playSoundWithoutBgm("evolution_fanfare"); - globalScene.ui.showText( - i18next.t("egg:hatchFromTheEgg", { - pokemonName: this.pokemon.species.getExpandedSpeciesName(), - }), - null, - () => { - globalScene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs); - globalScene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => { - globalScene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then(value => { - this.eggHatchData.setEggMoveUnlocked(value); - globalScene.ui.showText("", 0); - this.end(); - }); + globalScene.ui.showText( + i18next.t("egg:hatchFromTheEgg", { + pokemonName: this.pokemon.species.getExpandedSpeciesName(), + }), + null, + () => { + globalScene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs); + globalScene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => { + globalScene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then(value => { + this.eggHatchData.setEggMoveUnlocked(value); + globalScene.ui.showText("", 0); + this.end(); }); - }, - null, - true, - 3000, - ); - }, - ); + }); + }, + null, + true, + 3000, + ); + }); }); globalScene.tweens.add({ - duration: Utils.fixedInt(this.skipped ? 500 : 3000), + duration: fixedInt(this.skipped ? 500 : 3000), targets: this.eggHatchOverlay, alpha: 0, ease: "Cubic.easeOut", @@ -427,9 +424,9 @@ export class EggHatchPhase extends Phase { doSpray(intensity: number, offsetY?: number) { globalScene.tweens.addCounter({ repeat: intensity, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { - this.doSprayParticle(Utils.randInt(8), offsetY || 0); + this.doSprayParticle(randInt(8), offsetY || 0); }, }); } @@ -448,12 +445,12 @@ export class EggHatchPhase extends Phase { let f = 0; let yOffset = 0; - const speed = 3 - Utils.randInt(8); - const amp = 24 + Utils.randInt(32); + const speed = 3 - randInt(8); + const amp = 24 + randInt(32); const particleTimer = globalScene.tweens.addCounter({ repeat: -1, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { updateParticle(); }, diff --git a/src/phases/egg-lapse-phase.ts b/src/phases/egg-lapse-phase.ts index 397eb970fec..4632e264c1d 100644 --- a/src/phases/egg-lapse-phase.ts +++ b/src/phases/egg-lapse-phase.ts @@ -5,7 +5,7 @@ import { Phase } from "#app/phase"; import i18next from "i18next"; import Overrides from "#app/overrides"; import { EggHatchPhase } from "./egg-hatch-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { achvs } from "#app/system/achv"; import type { PlayerPokemon } from "#app/field/pokemon"; import { EggSummaryPhase } from "./egg-summary-phase"; @@ -41,7 +41,7 @@ export class EggLapsePhase extends Phase { 0, ); globalScene.ui.setModeWithoutClear( - Mode.CONFIRM, + UiMode.CONFIRM, () => { this.hatchEggsSkipped(eggsToHatch); this.showSummary(); diff --git a/src/phases/egg-summary-phase.ts b/src/phases/egg-summary-phase.ts index 9d9259d1e67..d16cafa7611 100644 --- a/src/phases/egg-summary-phase.ts +++ b/src/phases/egg-summary-phase.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import { Phase } from "#app/phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type { EggHatchData } from "#app/data/egg-hatch-data"; /** @@ -22,7 +22,7 @@ export class EggSummaryPhase extends Phase { // updates next pokemon once the current update has been completed const updateNextPokemon = (i: number) => { if (i >= this.eggHatchData.length) { - globalScene.ui.setModeForceTransition(Mode.EGG_HATCH_SUMMARY, this.eggHatchData).then(() => { + globalScene.ui.setModeForceTransition(UiMode.EGG_HATCH_SUMMARY, this.eggHatchData).then(() => { globalScene.fadeOutBgm(undefined, false); }); } else { @@ -39,7 +39,7 @@ export class EggSummaryPhase extends Phase { end() { globalScene.time.delayedCall(250, () => globalScene.setModifiersVisible(true)); - globalScene.ui.setModeForceTransition(Mode.MESSAGE).then(() => { + globalScene.ui.setModeForceTransition(UiMode.MESSAGE).then(() => { super.end(); }); } diff --git a/src/phases/encounter-phase.ts b/src/phases/encounter-phase.ts index ad2bf689e38..5b799bd9316 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -1,7 +1,13 @@ -import { BattlerIndex, BattleType } from "#app/battle"; +import { BattlerIndex } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import { globalScene } from "#app/global-scene"; import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; -import { applyAbAttrs, SyncEncounterNatureAbAttr } from "#app/data/ability"; +import { + applyAbAttrs, + SyncEncounterNatureAbAttr, + applyPreSummonAbAttrs, + PreSummonAbAttr, +} from "#app/data/abilities/ability"; import { initEncounterAnims, loadEncounterAnimAssets } from "#app/data/battle-anims"; import { getCharVariantFromDialogue } from "#app/data/dialogue"; import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; @@ -28,8 +34,8 @@ import { SummonPhase } from "#app/phases/summon-phase"; import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase"; import { achvs } from "#app/system/achv"; import { handleTutorial, Tutorial } from "#app/tutorial"; -import { Mode } from "#app/ui/ui"; -import { randSeedInt, randSeedItem } from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import { randSeedInt, randSeedItem } from "#app/utils/common"; import { BattleSpec } from "#enums/battle-spec"; import { Biome } from "#enums/biome"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; @@ -43,10 +49,10 @@ import { getNatureName } from "#app/data/nature"; export class EncounterPhase extends BattlePhase { private loaded: boolean; - constructor(loaded?: boolean) { + constructor(loaded = false) { super(); - this.loaded = !!loaded; + this.loaded = loaded; } start() { @@ -107,12 +113,6 @@ export class EncounterPhase extends BattlePhase { } if (!this.loaded) { if (battle.battleType === BattleType.TRAINER) { - //resets hitRecCount during Trainer ecnounter - for (const pokemon of globalScene.getPlayerParty()) { - if (pokemon) { - pokemon.customPokemonData.resetHitReceivedCount(); - } - } battle.enemyParty[e] = battle.trainer?.genPartyMember(e)!; // TODO:: is the bang correct here? } else { let enemySpecies = globalScene.randomSpecies(battle.waveIndex, level, true); @@ -134,7 +134,6 @@ export class EncounterPhase extends BattlePhase { if (globalScene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { battle.enemyParty[e].ivs = new Array(6).fill(31); } - // biome-ignore lint/complexity/noForEach: Improves readability globalScene .getPlayerParty() .slice(0, !battle.double ? 1 : 2) @@ -189,12 +188,13 @@ export class EncounterPhase extends BattlePhase { ]; const moveset: string[] = []; for (const move of enemyPokemon.getMoveset()) { - moveset.push(move!.getName()); // TODO: remove `!` after moveset-null removal PR + moveset.push(move.getName()); } console.log( `Pokemon: ${getPokemonNameWithAffix(enemyPokemon)}`, `| Species ID: ${enemyPokemon.species.speciesId}`, + `| Level: ${enemyPokemon.level}`, `| Nature: ${getNatureName(enemyPokemon.nature, true, true, true)}`, ); console.log(`Stats (IVs): ${stats}`); @@ -259,6 +259,9 @@ export class EncounterPhase extends BattlePhase { } if (e < (battle.double ? 2 : 1)) { if (battle.battleType === BattleType.WILD) { + for (const pokemon of globalScene.getField()) { + applyPreSummonAbAttrs(PreSummonAbAttr, pokemon, []); + } globalScene.field.add(enemyPokemon); battle.seenEnemyPartyMemberIds.add(enemyPokemon.id); const playerPokemon = globalScene.getPlayerPokemon(); @@ -278,6 +281,7 @@ export class EncounterPhase extends BattlePhase { }); if (!this.loaded && battle.battleType !== BattleType.MYSTERY_ENCOUNTER) { + // generate modifiers for MEs, overriding prior ones as applicable regenerateModifierPoolThresholds( globalScene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, @@ -290,11 +294,11 @@ export class EncounterPhase extends BattlePhase { } } - if (battle.battleType === BattleType.TRAINER) { - globalScene.currentBattle.trainer!.genAI(globalScene.getEnemyParty()); + if (battle.battleType === BattleType.TRAINER && globalScene.currentBattle.trainer) { + globalScene.currentBattle.trainer.genAI(globalScene.getEnemyParty()); } - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { if (!this.loaded) { this.trySetWeatherIfNewBiome(); // Set weather before session gets saved // Game syncs to server on waves X1 and X6 (As of 1.2.0) @@ -332,8 +336,10 @@ export class EncounterPhase extends BattlePhase { } for (const pokemon of globalScene.getPlayerParty()) { + // Currently, a new wave is not considered a new battle if there is no arena reset + // Therefore, we only reset wave data here if (pokemon) { - pokemon.resetBattleData(); + pokemon.resetWaveData(); } } @@ -545,10 +551,10 @@ export class EncounterPhase extends BattlePhase { const enemyField = globalScene.getEnemyField(); enemyField.forEach((enemyPokemon, e) => { - if (enemyPokemon.isShiny()) { + if (enemyPokemon.isShiny(true)) { globalScene.unshiftPhase(new ShinySparklePhase(BattlerIndex.ENEMY + e)); } - /** This sets Eternatus' held item to be untransferrable, preventing it from being stolen */ + /** This sets Eternatus' held item to be untransferrable, preventing it from being stolen */ if ( enemyPokemon.species.speciesId === Species.ETERNATUS && (globalScene.gameMode.isBattleClassicFinalBoss(globalScene.currentBattle.waveIndex) || diff --git a/src/phases/end-evolution-phase.ts b/src/phases/end-evolution-phase.ts index e0bdc7e0d68..579920dde90 100644 --- a/src/phases/end-evolution-phase.ts +++ b/src/phases/end-evolution-phase.ts @@ -1,11 +1,11 @@ import { globalScene } from "#app/global-scene"; import { Phase } from "#app/phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; export class EndEvolutionPhase extends Phase { start() { super.start(); - globalScene.ui.setModeForceTransition(Mode.MESSAGE).then(() => this.end()); + globalScene.ui.setModeForceTransition(UiMode.MESSAGE).then(() => this.end()); } } diff --git a/src/phases/evolution-phase.ts b/src/phases/evolution-phase.ts index bb283fa8139..8fc8a8be031 100644 --- a/src/phases/evolution-phase.ts +++ b/src/phases/evolution-phase.ts @@ -5,8 +5,8 @@ import { globalScene } from "#app/global-scene"; import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions"; import { FusionSpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions"; import type EvolutionSceneHandler from "#app/ui/evolution-scene-handler"; -import * as Utils from "#app/utils"; -import { Mode } from "#app/ui/ui"; +import { fixedInt, getFrameMs, randInt } from "#app/utils/common"; +import { UiMode } from "#enums/ui-mode"; import { cos, sin } from "#app/field/anims"; import type { PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; @@ -53,7 +53,7 @@ export class EvolutionPhase extends Phase { } setMode(): Promise { - return globalScene.ui.setModeForceTransition(Mode.EVOLUTION_SCENE); + return globalScene.ui.setModeForceTransition(UiMode.EVOLUTION_SCENE); } start() { @@ -146,7 +146,7 @@ export class EvolutionPhase extends Phase { sprite.setPipelineData("shiny", this.pokemon.shiny); sprite.setPipelineData("variant", this.pokemon.variant); ["spriteColors", "fusionSpriteColors"].map(k => { - if (this.pokemon.summonData?.speciesForm) { + if (this.pokemon.summonData.speciesForm) { k += "Base"; } sprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k]; @@ -178,7 +178,7 @@ export class EvolutionPhase extends Phase { sprite.setPipelineData("shiny", evolvedPokemon.shiny); sprite.setPipelineData("variant", evolvedPokemon.variant); ["spriteColors", "fusionSpriteColors"].map(k => { - if (evolvedPokemon.summonData?.speciesForm) { + if (evolvedPokemon.summonData.speciesForm) { k += "Base"; } sprite.pipelineData[k] = evolvedPokemon.getSprite().pipelineData[k]; @@ -280,7 +280,7 @@ export class EvolutionPhase extends Phase { this.end(); }; globalScene.ui.setOverlayMode( - Mode.CONFIRM, + UiMode.CONFIRM, () => { globalScene.ui.revertMode(); this.pokemon.pauseEvolutions = true; @@ -332,9 +332,9 @@ export class EvolutionPhase extends Phase { () => this.end(), null, true, - Utils.fixedInt(4000), + fixedInt(4000), ); - globalScene.time.delayedCall(Utils.fixedInt(4250), () => globalScene.playBgm()); + globalScene.time.delayedCall(fixedInt(4250), () => globalScene.playBgm()); }); }); }; @@ -392,7 +392,7 @@ export class EvolutionPhase extends Phase { globalScene.tweens.addCounter({ repeat: 64, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { if (f < 64) { if (!(f & 7)) { @@ -411,7 +411,7 @@ export class EvolutionPhase extends Phase { globalScene.tweens.addCounter({ repeat: 96, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { if (f < 96) { if (f < 6) { @@ -461,7 +461,7 @@ export class EvolutionPhase extends Phase { globalScene.tweens.addCounter({ repeat: 48, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { if (!f) { for (let i = 0; i < 16; i++) { @@ -482,14 +482,14 @@ export class EvolutionPhase extends Phase { globalScene.tweens.addCounter({ repeat: 48, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { if (!f) { for (let i = 0; i < 8; i++) { this.doSprayParticle(i); } } else if (f < 50) { - this.doSprayParticle(Utils.randInt(8)); + this.doSprayParticle(randInt(8)); } f++; }, @@ -506,7 +506,7 @@ export class EvolutionPhase extends Phase { const particleTimer = globalScene.tweens.addCounter({ repeat: -1, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { updateParticle(); }, @@ -543,7 +543,7 @@ export class EvolutionPhase extends Phase { const particleTimer = globalScene.tweens.addCounter({ repeat: -1, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { updateParticle(); }, @@ -575,7 +575,7 @@ export class EvolutionPhase extends Phase { const particleTimer = globalScene.tweens.addCounter({ repeat: -1, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { updateParticle(); }, @@ -605,12 +605,12 @@ export class EvolutionPhase extends Phase { let f = 0; let yOffset = 0; - const speed = 3 - Utils.randInt(8); - const amp = 48 + Utils.randInt(64); + const speed = 3 - randInt(8); + const amp = 48 + randInt(64); const particleTimer = globalScene.tweens.addCounter({ repeat: -1, - duration: Utils.getFrameMs(1), + duration: getFrameMs(1), onRepeat: () => { updateParticle(); }, diff --git a/src/phases/exp-phase.ts b/src/phases/exp-phase.ts index 092482d4c18..8841a90d5b1 100644 --- a/src/phases/exp-phase.ts +++ b/src/phases/exp-phase.ts @@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; import { ExpBoosterModifier } from "#app/modifier/modifier"; import i18next from "i18next"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase"; import { LevelUpPhase } from "./level-up-phase"; @@ -19,7 +19,7 @@ export class ExpPhase extends PlayerPartyMemberPokemonPhase { super.start(); const pokemon = this.getPokemon(); - const exp = new Utils.NumberHolder(this.expValue); + const exp = new NumberHolder(this.expValue); globalScene.applyModifiers(ExpBoosterModifier, true, exp); exp.value = Math.floor(exp.value); globalScene.ui.showText( diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts index 7e1ae4ec07b..1aa24d59fa0 100644 --- a/src/phases/faint-phase.ts +++ b/src/phases/faint-phase.ts @@ -1,5 +1,5 @@ import type { BattlerIndex } from "#app/battle"; -import { BattleType } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import { globalScene } from "#app/global-scene"; import { applyPostFaintAbAttrs, @@ -8,8 +8,7 @@ import { PostFaintAbAttr, PostKnockOutAbAttr, PostVictoryAbAttr, -} from "#app/data/ability"; -import type { DestinyBondTag, GrudgeTag } from "#app/data/battler-tags"; +} from "#app/data/abilities/ability"; import { BattlerTagLapseType } from "#app/data/battler-tags"; import { battleSpecDialogue } from "#app/data/dialogue"; import { allMoves, PostVictoryStatStageChangeAttr } from "#app/data/moves/move"; @@ -30,42 +29,25 @@ import { SwitchPhase } from "./switch-phase"; import { SwitchSummonPhase } from "./switch-summon-phase"; import { ToggleDoublePositionPhase } from "./toggle-double-position-phase"; import { VictoryPhase } from "./victory-phase"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; import { FRIENDSHIP_LOSS_FROM_FAINT } from "#app/data/balance/starters"; +import { BattlerTagType } from "#enums/battler-tag-type"; export class FaintPhase extends PokemonPhase { /** - * Whether or not enduring (for this phase's purposes, Reviver Seed) should be prevented + * Whether or not instant revive should be prevented */ - private preventEndure: boolean; - - /** - * Destiny Bond tag belonging to the currently fainting Pokemon, if applicable - */ - private destinyTag?: DestinyBondTag | null; - - /** - * Grudge tag belonging to the currently fainting Pokemon, if applicable - */ - private grudgeTag?: GrudgeTag | null; + private preventInstantRevive: boolean; /** * The source Pokemon that dealt fatal damage */ private source?: Pokemon; - constructor( - battlerIndex: BattlerIndex, - preventEndure = false, - destinyTag?: DestinyBondTag | null, - grudgeTag?: GrudgeTag | null, - source?: Pokemon, - ) { + constructor(battlerIndex: BattlerIndex, preventInstantRevive = false, source?: Pokemon) { super(battlerIndex); - this.preventEndure = preventEndure; - this.destinyTag = destinyTag; - this.grudgeTag = grudgeTag; + this.preventInstantRevive = preventInstantRevive; this.source = source; } @@ -74,15 +56,14 @@ export class FaintPhase extends PokemonPhase { const faintPokemon = this.getPokemon(); - if (!isNullOrUndefined(this.destinyTag) && !isNullOrUndefined(this.source)) { - this.destinyTag.lapse(this.source, BattlerTagLapseType.CUSTOM); + if (this.source) { + faintPokemon.getTag(BattlerTagType.DESTINY_BOND)?.lapse(this.source, BattlerTagLapseType.CUSTOM); + faintPokemon.getTag(BattlerTagType.GRUDGE)?.lapse(faintPokemon, BattlerTagLapseType.CUSTOM, this.source); } - if (!isNullOrUndefined(this.grudgeTag) && !isNullOrUndefined(this.source)) { - this.grudgeTag.lapse(faintPokemon, BattlerTagLapseType.CUSTOM, this.source); - } + faintPokemon.resetSummonData(); - if (!this.preventEndure) { + if (!this.preventInstantRevive) { const instantReviveModifier = globalScene.applyModifier( PokemonInstantReviveModifier, this.player, @@ -137,7 +118,7 @@ export class FaintPhase extends PokemonPhase { pokemon.resetTera(); - if (pokemon.turnData?.attacksReceived?.length) { + if (pokemon.turnData.attacksReceived?.length) { const lastAttack = pokemon.turnData.attacksReceived[0]; applyPostFaintAbAttrs( PostFaintAbAttr, @@ -155,7 +136,7 @@ export class FaintPhase extends PokemonPhase { for (const p of alivePlayField) { applyPostKnockOutAbAttrs(PostKnockOutAbAttr, p, pokemon); } - if (pokemon.turnData?.attacksReceived?.length) { + if (pokemon.turnData.attacksReceived?.length) { const defeatSource = this.source; if (defeatSource?.isOnField()) { diff --git a/src/phases/field-phase.ts b/src/phases/field-phase.ts index 98c1ced510f..c37f0e960e7 100644 --- a/src/phases/field-phase.ts +++ b/src/phases/field-phase.ts @@ -6,8 +6,7 @@ type PokemonFunc = (pokemon: Pokemon) => void; export abstract class FieldPhase extends BattlePhase { executeForAll(func: PokemonFunc): void { - const field = globalScene.getField(true).filter(p => p.summonData); - for (const pokemon of field) { + for (const pokemon of globalScene.getField(true)) { func(pokemon); } } diff --git a/src/phases/form-change-phase.ts b/src/phases/form-change-phase.ts index e0ec4e87600..5517fb0f402 100644 --- a/src/phases/form-change-phase.ts +++ b/src/phases/form-change-phase.ts @@ -1,15 +1,15 @@ import { globalScene } from "#app/global-scene"; -import * as Utils from "../utils"; +import { fixedInt } from "#app/utils/common"; import { achvs } from "../system/achv"; import type { SpeciesFormChange } from "../data/pokemon-forms"; import { getSpeciesFormChangeMessage } from "../data/pokemon-forms"; import type { PlayerPokemon } from "../field/pokemon"; -import { Mode } from "../ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type PartyUiHandler from "../ui/party-ui-handler"; import { getPokemonNameWithAffix } from "../messages"; import { EndEvolutionPhase } from "./end-evolution-phase"; import { EvolutionPhase } from "./evolution-phase"; -import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { BattlerTagType } from "#enums/battler-tag-type"; import { SpeciesFormKey } from "#enums/species-form-key"; export class FormChangePhase extends EvolutionPhase { @@ -31,7 +31,7 @@ export class FormChangePhase extends EvolutionPhase { if (!this.modal) { return super.setMode(); } - return globalScene.ui.setOverlayMode(Mode.EVOLUTION_SCENE); + return globalScene.ui.setOverlayMode(UiMode.EVOLUTION_SCENE); } doEvolution(): void { @@ -51,7 +51,7 @@ export class FormChangePhase extends EvolutionPhase { sprite.setPipelineData("shiny", transformedPokemon.shiny); sprite.setPipelineData("variant", transformedPokemon.variant); ["spriteColors", "fusionSpriteColors"].map(k => { - if (transformedPokemon.summonData?.speciesForm) { + if (transformedPokemon.summonData.speciesForm) { k += "Base"; } sprite.pipelineData[k] = transformedPokemon.getSprite().pipelineData[k]; @@ -151,9 +151,9 @@ export class FormChangePhase extends EvolutionPhase { () => this.end(), null, true, - Utils.fixedInt(delay), + fixedInt(delay), ); - globalScene.time.delayedCall(Utils.fixedInt(delay + 250), () => + globalScene.time.delayedCall(fixedInt(delay + 250), () => globalScene.playBgm(), ); }); @@ -181,7 +181,7 @@ export class FormChangePhase extends EvolutionPhase { this.pokemon.findAndRemoveTags(t => t.tagType === BattlerTagType.AUTOTOMIZED); if (this.modal) { globalScene.ui.revertMode().then(() => { - if (globalScene.ui.getMode() === Mode.PARTY) { + if (globalScene.ui.getMode() === UiMode.PARTY) { const partyUiHandler = globalScene.ui.getHandler() as PartyUiHandler; partyUiHandler.clearPartySlots(); partyUiHandler.populatePartySlots(); diff --git a/src/phases/game-over-modifier-reward-phase.ts b/src/phases/game-over-modifier-reward-phase.ts index d0a39a4031a..ab6f6554c99 100644 --- a/src/phases/game-over-modifier-reward-phase.ts +++ b/src/phases/game-over-modifier-reward-phase.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { ModifierRewardPhase } from "./modifier-reward-phase"; @@ -10,7 +10,7 @@ export class GameOverModifierRewardPhase extends ModifierRewardPhase { globalScene.addModifier(newModifier); // Sound loaded into game as is globalScene.playSound("level_up_fanfare"); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.fadeIn(250).then(() => { globalScene.ui.showText( i18next.t("battle:rewardGain", { diff --git a/src/phases/game-over-phase.ts b/src/phases/game-over-phase.ts index f105b625cc8..3a3305fd45e 100644 --- a/src/phases/game-over-phase.ts +++ b/src/phases/game-over-phase.ts @@ -1,5 +1,5 @@ import { clientSessionId } from "#app/account"; -import { BattleType } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import { globalScene } from "#app/global-scene"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { getCharVariantFromDialogue } from "#app/data/dialogue"; @@ -19,8 +19,8 @@ import { SummonPhase } from "#app/phases/summon-phase"; import { UnlockPhase } from "#app/phases/unlock-phase"; import { achvs, ChallengeAchv } from "#app/system/achv"; import { Unlockables } from "#app/system/unlockables"; -import { Mode } from "#app/ui/ui"; -import * as Utils from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import { isLocal, isLocalServerConnected } from "#app/utils/common"; import { PlayerGender } from "#enums/player-gender"; import { TrainerType } from "#enums/trainer-type"; import i18next from "i18next"; @@ -31,6 +31,7 @@ import ChallengeData from "#app/system/challenge-data"; import TrainerData from "#app/system/trainer-data"; import ArenaData from "#app/system/arena-data"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; +import { MessagePhase } from "./message-phase"; export class GameOverPhase extends BattlePhase { private isVictory: boolean; @@ -78,7 +79,7 @@ export class GameOverPhase extends BattlePhase { } else { globalScene.ui.showText(i18next.t("battle:retryBattle"), null, () => { globalScene.ui.setMode( - Mode.CONFIRM, + UiMode.CONFIRM, () => { globalScene.ui.fadeOut(1250).then(() => { globalScene.reset(); @@ -122,7 +123,7 @@ export class GameOverPhase extends BattlePhase { globalScene.disableMenu = true; globalScene.time.delayedCall(1000, () => { let firstClear = false; - if (this.isVictory && newClear) { + if (this.isVictory) { if (globalScene.gameMode.isClassic) { firstClear = globalScene.validateAchv(achvs.CLASSIC_VICTORY); globalScene.validateAchv(achvs.UNEVOLVED_CLASSIC_VICTORY); @@ -219,14 +220,24 @@ export class GameOverPhase extends BattlePhase { /* Added a local check to see if the game is running offline If Online, execute apiFetch as intended If Offline, execute offlineNewClear() only for victory, a localStorage implementation of newClear daily run checks */ - if (!Utils.isLocal || Utils.isLocalServerConnected) { + if (!isLocal || isLocalServerConnected) { pokerogueApi.savedata.session .newclear({ slot: globalScene.sessionSlotId, isVictory: this.isVictory, clientSessionId: clientSessionId, }) - .then(success => doGameOver(!!success)); + .then(success => doGameOver(!globalScene.gameMode.isDaily || !!success)) + .catch(_err => { + globalScene.clearPhaseQueue(); + globalScene.clearPhaseQueueSplice(); + globalScene.unshiftPhase(new MessagePhase(i18next.t("menu:serverCommunicationFailed"), 2500)); + // force the game to reload after 2 seconds. + setTimeout(() => { + window.location.reload(); + }, 2000); + this.end(); + }); } else if (this.isVictory) { globalScene.gameData.offlineNewClear().then(result => { doGameOver(result); diff --git a/src/phases/learn-move-phase.ts b/src/phases/learn-move-phase.ts index 4107a9cf087..515ce492b92 100644 --- a/src/phases/learn-move-phase.ts +++ b/src/phases/learn-move-phase.ts @@ -8,7 +8,7 @@ import { getPokemonNameWithAffix } from "#app/messages"; import Overrides from "#app/overrides"; import EvolutionSceneHandler from "#app/ui/evolution-scene-handler"; import { SummaryUiMode } from "#app/ui/summary-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { PlayerPartyMemberPokemonPhase } from "#app/phases/player-party-member-pokemon-phase"; import type Pokemon from "#app/field/pokemon"; @@ -25,7 +25,7 @@ export enum LearnMoveType { export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { private moveId: Moves; - private messageMode: Mode; + private messageMode: UiMode; private learnMoveType: LearnMoveType; private cost: number; @@ -55,7 +55,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { } this.messageMode = - globalScene.ui.getHandler() instanceof EvolutionSceneHandler ? Mode.EVOLUTION_SCENE : Mode.MESSAGE; + globalScene.ui.getHandler() instanceof EvolutionSceneHandler ? UiMode.EVOLUTION_SCENE : UiMode.MESSAGE; globalScene.ui.setMode(this.messageMode); // If the Pokemon has less than 4 moves, the new move is added to the largest empty moveset index // If it has 4 moves, the phase then checks if the player wants to replace the move itself. @@ -90,7 +90,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { await globalScene.ui.showTextPromise(preQText); await globalScene.ui.showTextPromise(shouldReplaceQ, undefined, false); await globalScene.ui.setModeWithoutClear( - Mode.CONFIRM, + UiMode.CONFIRM, () => this.forgetMoveProcess(move, pokemon), // Yes () => { // No @@ -115,7 +115,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { globalScene.ui.setMode(this.messageMode); await globalScene.ui.showTextPromise(i18next.t("battle:learnMoveForgetQuestion"), undefined, true); await globalScene.ui.setModeWithoutClear( - Mode.SUMMARY, + UiMode.SUMMARY, pokemon, SummaryUiMode.LEARN_MOVE, move, @@ -153,7 +153,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { false, ); globalScene.ui.setModeWithoutClear( - Mode.CONFIRM, + UiMode.CONFIRM, () => { globalScene.ui.setMode(this.messageMode); globalScene.ui @@ -228,7 +228,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true); this.end(); }, - this.messageMode === Mode.EVOLUTION_SCENE ? 1000 : undefined, + this.messageMode === UiMode.EVOLUTION_SCENE ? 1000 : undefined, true, ); } diff --git a/src/phases/level-cap-phase.ts b/src/phases/level-cap-phase.ts index 567ac922124..6f3fa6fdb39 100644 --- a/src/phases/level-cap-phase.ts +++ b/src/phases/level-cap-phase.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { FieldPhase } from "./field-phase"; @@ -7,7 +7,7 @@ export class LevelCapPhase extends FieldPhase { start(): void { super.start(); - globalScene.ui.setMode(Mode.MESSAGE).then(() => { + globalScene.ui.setMode(UiMode.MESSAGE).then(() => { // Sound loaded into game as is globalScene.playSound("level_up_fanfare"); globalScene.ui.showText( diff --git a/src/phases/level-up-phase.ts b/src/phases/level-up-phase.ts index 31c7fabf451..8c4f4f58095 100644 --- a/src/phases/level-up-phase.ts +++ b/src/phases/level-up-phase.ts @@ -6,7 +6,7 @@ import { EvolutionPhase } from "#app/phases/evolution-phase"; import { LearnMovePhase } from "#app/phases/learn-move-phase"; import { PlayerPartyMemberPokemonPhase } from "#app/phases/player-party-member-pokemon-phase"; import { LevelAchv } from "#app/system/achv"; -import { NumberHolder } from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import i18next from "i18next"; export class LevelUpPhase extends PlayerPartyMemberPokemonPhase { @@ -71,6 +71,7 @@ export class LevelUpPhase extends PlayerPartyMemberPokemonPhase { if (!this.pokemon.pauseEvolutions) { const evolution = this.pokemon.getEvolution(); if (evolution) { + this.pokemon.breakIllusion(); globalScene.unshiftPhase(new EvolutionPhase(this.pokemon, evolution, this.lastLevel)); } } diff --git a/src/phases/login-phase.ts b/src/phases/login-phase.ts index 5cce6ca0298..673b94b1148 100644 --- a/src/phases/login-phase.ts +++ b/src/phases/login-phase.ts @@ -1,30 +1,31 @@ import { updateUserInfo } from "#app/account"; -import { bypassLogin } from "#app/battle-scene"; +import { bypassLogin } from "#app/global-vars/bypass-login"; import { globalScene } from "#app/global-scene"; import { Phase } from "#app/phase"; import { handleTutorial, Tutorial } from "#app/tutorial"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next, { t } from "i18next"; -import * as Utils from "#app/utils"; +import { sessionIdKey, executeIf } from "#app/utils/common"; +import { getCookie, removeCookie } from "#app/utils/cookies"; import { SelectGenderPhase } from "./select-gender-phase"; import { UnavailablePhase } from "./unavailable-phase"; export class LoginPhase extends Phase { private showText: boolean; - constructor(showText?: boolean) { + constructor(showText = true) { super(); - this.showText = showText === undefined || !!showText; + this.showText = showText; } start(): void { super.start(); - const hasSession = !!Utils.getCookie(Utils.sessionIdKey); + const hasSession = !!getCookie(sessionIdKey); - globalScene.ui.setMode(Mode.LOADING, { buttonActions: [] }); - Utils.executeIf(bypassLogin || hasSession, updateUserInfo).then(response => { + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); + executeIf(bypassLogin || hasSession, updateUserInfo).then(response => { const success = response ? response[0] : false; const statusCode = response ? response[1] : null; if (!success) { @@ -38,7 +39,7 @@ export class LoginPhase extends Phase { const loadData = () => { updateUserInfo().then(success => { if (!success[0]) { - Utils.removeCookie(Utils.sessionIdKey); + removeCookie(sessionIdKey); globalScene.reset(true, true); return; } @@ -46,7 +47,7 @@ export class LoginPhase extends Phase { }); }; - globalScene.ui.setMode(Mode.LOGIN_FORM, { + globalScene.ui.setMode(UiMode.LOGIN_FORM, { buttonActions: [ () => { globalScene.ui.playSelect(); @@ -54,13 +55,13 @@ export class LoginPhase extends Phase { }, () => { globalScene.playSound("menu_open"); - globalScene.ui.setMode(Mode.REGISTRATION_FORM, { + globalScene.ui.setMode(UiMode.REGISTRATION_FORM, { buttonActions: [ () => { globalScene.ui.playSelect(); updateUserInfo().then(success => { if (!success[0]) { - Utils.removeCookie(Utils.sessionIdKey); + removeCookie(sessionIdKey); globalScene.reset(true, true); return; } @@ -89,7 +90,7 @@ export class LoginPhase extends Phase { ], }); } else if (statusCode === 401) { - Utils.removeCookie(Utils.sessionIdKey); + removeCookie(sessionIdKey); globalScene.reset(true, true); } else { globalScene.unshiftPhase(new UnavailablePhase()); @@ -101,7 +102,7 @@ export class LoginPhase extends Phase { if (success || bypassLogin) { this.end(); } else { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText(t("menu:failedToLoadSaveData")); } }); @@ -109,7 +110,7 @@ export class LoginPhase extends Phase { } end(): void { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); if (!globalScene.gameData.gender) { globalScene.unshiftPhase(new SelectGenderPhase()); diff --git a/src/phases/message-phase.ts b/src/phases/message-phase.ts index cff7249fcfa..f6777579857 100644 --- a/src/phases/message-phase.ts +++ b/src/phases/message-phase.ts @@ -3,9 +3,9 @@ import { Phase } from "#app/phase"; export class MessagePhase extends Phase { private text: string; - private callbackDelay: number | null; - private prompt: boolean | null; - private promptDelay: number | null; + private callbackDelay?: number | null; + private prompt?: boolean | null; + private promptDelay?: number | null; private speaker?: string; constructor( @@ -18,9 +18,9 @@ export class MessagePhase extends Phase { super(); this.text = text; - this.callbackDelay = callbackDelay!; // TODO: is this bang correct? - this.prompt = prompt!; // TODO: is this bang correct? - this.promptDelay = promptDelay!; // TODO: is this bang correct? + this.callbackDelay = callbackDelay; + this.prompt = prompt; + this.promptDelay = promptDelay; this.speaker = speaker; } diff --git a/src/phases/money-reward-phase.ts b/src/phases/money-reward-phase.ts index 56f46d25f77..708bb3a2fa8 100644 --- a/src/phases/money-reward-phase.ts +++ b/src/phases/money-reward-phase.ts @@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene"; import { ArenaTagType } from "#app/enums/arena-tag-type"; import { MoneyMultiplierModifier } from "#app/modifier/modifier"; import i18next from "i18next"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { BattlePhase } from "./battle-phase"; export class MoneyRewardPhase extends BattlePhase { @@ -15,7 +15,7 @@ export class MoneyRewardPhase extends BattlePhase { } start() { - const moneyAmount = new Utils.NumberHolder(globalScene.getWaveMoneyAmount(this.moneyMultiplier)); + const moneyAmount = new NumberHolder(globalScene.getWaveMoneyAmount(this.moneyMultiplier)); globalScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); diff --git a/src/phases/move-anim-test-phase.ts b/src/phases/move-anim-test-phase.ts deleted file mode 100644 index e8b7c0c8fa7..00000000000 --- a/src/phases/move-anim-test-phase.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { globalScene } from "#app/global-scene"; -import { initMoveAnim, loadMoveAnimAssets, MoveAnim } from "#app/data/battle-anims"; -import { allMoves, SelfStatusMove } from "#app/data/moves/move"; -import { Moves } from "#app/enums/moves"; -import * as Utils from "#app/utils"; -import { BattlePhase } from "./battle-phase"; - -export class MoveAnimTestPhase extends BattlePhase { - private moveQueue: Moves[]; - - constructor(moveQueue?: Moves[]) { - super(); - - this.moveQueue = moveQueue || Utils.getEnumValues(Moves).slice(1); - } - - start() { - const moveQueue = this.moveQueue.slice(0); - this.playMoveAnim(moveQueue, true); - } - - playMoveAnim(moveQueue: Moves[], player: boolean) { - const moveId = player ? moveQueue[0] : moveQueue.shift(); - if (moveId === undefined) { - this.playMoveAnim(this.moveQueue.slice(0), true); - return; - } - if (player) { - console.log(Moves[moveId]); - } - - initMoveAnim(moveId).then(() => { - loadMoveAnimAssets([moveId], true).then(() => { - const user = player ? globalScene.getPlayerPokemon()! : globalScene.getEnemyPokemon()!; - const target = - player !== allMoves[moveId] instanceof SelfStatusMove - ? globalScene.getEnemyPokemon()! - : globalScene.getPlayerPokemon()!; - new MoveAnim(moveId, user, target.getBattlerIndex()).play(allMoves[moveId].hitsSubstitute(user, target), () => { - // TODO: are the bangs correct here? - if (player) { - this.playMoveAnim(moveQueue, false); - } else { - this.playMoveAnim(moveQueue, true); - } - }); - }); - }); - } -} diff --git a/src/phases/move-charge-phase.ts b/src/phases/move-charge-phase.ts index 26ad85bbe03..ea43f1ddb88 100644 --- a/src/phases/move-charge-phase.ts +++ b/src/phases/move-charge-phase.ts @@ -5,7 +5,7 @@ import { applyMoveChargeAttrs, MoveEffectAttr, InstantChargeAttr } from "#app/da import type { PokemonMove } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon"; -import { BooleanHolder } from "#app/utils"; +import { BooleanHolder } from "#app/utils/common"; import { MovePhase } from "#app/phases/move-phase"; import { PokemonPhase } from "#app/phases/pokemon-phase"; import { BattlerTagType } from "#enums/battler-tag-type"; diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index bd1c9caad96..64cae923f07 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -13,8 +13,7 @@ import { PostDamageAbAttr, PostDefendAbAttr, ReflectStatusMoveAbAttr, - TypeImmunityAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; import { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag"; import { MoveAnim } from "#app/data/battle-anims"; import { @@ -23,6 +22,7 @@ import { ProtectedTag, SemiInvulnerableTag, SubstituteTag, + TypeBoostTag, } from "#app/data/battler-tags"; import type { MoveAttr } from "#app/data/moves/move"; import { @@ -39,8 +39,8 @@ import { NoEffectAttr, OneHitKOAttr, OverrideMoveEffectAttr, + StatChangeBeforeDmgCalcAttr, ToxicAccuracyAttr, - VariableTargetAttr, } from "#app/data/moves/move"; import { MoveEffectTrigger } from "#enums/MoveEffectTrigger"; import { MoveFlags } from "#enums/MoveFlags"; @@ -48,51 +48,199 @@ import { MoveTarget } from "#enums/MoveTarget"; import { MoveCategory } from "#enums/MoveCategory"; import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms"; import { PokemonType } from "#enums/pokemon-type"; -import { PokemonMove } from "#app/field/pokemon"; +import { DamageResult, PokemonMove, type TurnMove } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { HitResult, MoveResult } from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import { ContactHeldItemTransferChanceModifier, + DamageMoneyRewardModifier, EnemyAttackStatusEffectChanceModifier, + EnemyEndureChanceModifier, FlinchChanceModifier, HitHealModifier, PokemonMultiHitModifier, } from "#app/modifier/modifier"; import { PokemonPhase } from "#app/phases/pokemon-phase"; -import { BooleanHolder, isNullOrUndefined, NumberHolder } from "#app/utils"; -import type { nil } from "#app/utils"; +import { BooleanHolder, isNullOrUndefined, NumberHolder } from "#app/utils/common"; +import type { nil } from "#app/utils/common"; import { BattlerTagType } from "#enums/battler-tag-type"; -import type { Moves } from "#enums/moves"; +import { Moves } from "#enums/moves"; import i18next from "i18next"; import type { Phase } from "#app/phase"; import { ShowAbilityPhase } from "./show-ability-phase"; import { MovePhase } from "./move-phase"; import { MoveEndPhase } from "./move-end-phase"; import { HideAbilityPhase } from "#app/phases/hide-ability-phase"; +import { TypeDamageMultiplier } from "#app/data/type"; +import { HitCheckResult } from "#enums/hit-check-result"; +import type Move from "#app/data/moves/move"; +import { isFieldTargeted } from "#app/data/moves/move-utils"; +import { FaintPhase } from "./faint-phase"; +import { DamageAchv } from "#app/system/achv"; + +type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier]; export class MoveEffectPhase extends PokemonPhase { - public move: PokemonMove; + public move: Move; + private virtual = false; protected targets: BattlerIndex[]; protected reflected = false; + /** The result of the hit check against each target */ + private hitChecks: HitCheckEntry[]; + + /** The move history entry for the move */ + private moveHistoryEntry: TurnMove; + + /** Is this the first strike of a move? */ + private firstHit: boolean; + /** Is this the last strike of a move? */ + private lastHit: boolean; + + /** Phases queued during moves */ + private queuedPhases: Phase[] = []; + /** * @param reflected Indicates that the move was reflected by the user due to magic coat or magic bounce + * @param virtual Indicates that the move is a virtual move (i.e. called by metronome) */ - constructor(battlerIndex: BattlerIndex, targets: BattlerIndex[], move: PokemonMove, reflected = false) { + constructor(battlerIndex: BattlerIndex, targets: BattlerIndex[], move: Move, reflected = false, virtual = false) { super(battlerIndex); this.move = move; + this.virtual = virtual; + this.reflected = reflected; /** * In double battles, if the right Pokemon selects a spread move and the left Pokemon dies * with no party members available to switch in, then the right Pokemon takes the index * of the left Pokemon and gets hit unless this is checked. */ - if (targets.includes(battlerIndex) && this.move.getMove().moveTarget === MoveTarget.ALL_NEAR_OTHERS) { + if (targets.includes(battlerIndex) && this.move.moveTarget === MoveTarget.ALL_NEAR_OTHERS) { const i = targets.indexOf(battlerIndex); targets.splice(i, i + 1); } this.targets = targets; + + this.hitChecks = Array(this.targets.length).fill([HitCheckResult.PENDING, 0]); + } + + /** + * Compute targets and the results of hit checks of the invoked move against all targets, + * organized by battler index. + * + * **This is *not* a pure function**; it has the following side effects + * - `this.hitChecks` - The results of the hit checks against each target + * - `this.moveHistoryEntry` - Sets success or failure based on the hit check results + * - user.turnData.hitCount and user.turnData.hitsLeft - Both set to 1 if the + * move was unsuccessful against all targets + * + * @returns The targets of the invoked move + * @see {@linkcode hitCheck} + */ + private conductHitChecks(user: Pokemon, fieldMove: boolean): Pokemon[] { + /** All Pokemon targeted by this phase's invoked move */ + /** Whether any hit check ended in a success */ + let anySuccess = false; + /** Whether the attack missed all of its targets */ + let allMiss = true; + + let targets = this.getTargets(); + + // For field targeted moves, we only look for the first target that may magic bounce + + for (const [i, target] of targets.entries()) { + const hitCheck = this.hitCheck(target); + // If the move bounced and was a field targeted move, + // then immediately stop processing other targets + if (fieldMove && hitCheck[0] === HitCheckResult.REFLECTED) { + targets = [target]; + this.hitChecks = [hitCheck]; + break; + } + if (hitCheck[0] === HitCheckResult.HIT) { + anySuccess = true; + } else { + allMiss ||= hitCheck[0] === HitCheckResult.MISS; + } + this.hitChecks[i] = hitCheck; + } + + if (anySuccess) { + this.moveHistoryEntry.result = MoveResult.SUCCESS; + } else { + user.turnData.hitCount = 1; + user.turnData.hitsLeft = 1; + this.moveHistoryEntry.result = allMiss ? MoveResult.MISS : MoveResult.FAIL; + } + + return targets; + } + + /** + * Queue the phaes that should occur when the target reflects the move back to the user + * @param user - The {@linkcode Pokemon} using this phase's invoked move + * @param target - The {@linkcode Pokemon} that is reflecting the move + * + */ + private queueReflectedMove(user: Pokemon, target: Pokemon): void { + const newTargets = this.move.isMultiTarget() + ? getMoveTargets(target, this.move.id).targets + : [user.getBattlerIndex()]; + // TODO: ability displays should be handled by the ability + if (!target.getTag(BattlerTagType.MAGIC_COAT)) { + this.queuedPhases.push( + new ShowAbilityPhase(target.getBattlerIndex(), target.getPassiveAbility().hasAttr(ReflectStatusMoveAbAttr)), + ); + this.queuedPhases.push(new HideAbilityPhase()); + } + + this.queuedPhases.push( + new MovePhase(target, newTargets, new PokemonMove(this.move.id, 0, 0, true), true, true, true), + ); + } + + /** + * Apply the move to each of the resolved targets. + * @param targets - The resolved set of targets of the move + * @throws Error if there was an unexpected hit check result + */ + private applyToTargets(user: Pokemon, targets: Pokemon[]): void { + for (const [i, target] of targets.entries()) { + const [hitCheckResult, effectiveness] = this.hitChecks[i]; + switch (hitCheckResult) { + case HitCheckResult.HIT: + this.applyMoveEffects(target, effectiveness); + if (isFieldTargeted(this.move)) { + // Stop processing other targets if the move is a field move + return; + } + break; + case HitCheckResult.NO_EFFECT: + globalScene.queueMessage( + i18next.t(this.move.id === Moves.SHEER_COLD ? "battle:hitResultImmune" : "battle:hitResultNoEffect", { + pokemonName: getPokemonNameWithAffix(target), + }), + ); + case HitCheckResult.NO_EFFECT_NO_MESSAGE: + case HitCheckResult.PROTECTED: + case HitCheckResult.TARGET_NOT_ON_FIELD: + applyMoveAttrs(NoEffectAttr, user, target, this.move); + break; + case HitCheckResult.MISS: + globalScene.queueMessage( + i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(target) }), + ); + applyMoveAttrs(MissEffectAttr, user, target, this.move); + break; + case HitCheckResult.REFLECTED: + this.queueReflectedMove(user, target); + break; + case HitCheckResult.PENDING: + case HitCheckResult.ERROR: + throw new Error("Unexpected hit check result"); + } + } } public override start(): void { @@ -100,11 +248,10 @@ export class MoveEffectPhase extends PokemonPhase { /** The Pokemon using this phase's invoked move */ const user = this.getUserPokemon(); - /** All Pokemon targeted by this phase's invoked move */ - const targets = this.getTargets(); if (!user) { - return super.end(); + super.end(); + return; } /** If an enemy used this move, set this as last enemy that used move or ability */ @@ -114,23 +261,21 @@ export class MoveEffectPhase extends PokemonPhase { globalScene.currentBattle.lastPlayerInvolved = this.fieldIndex; } - const isDelayedAttack = this.move.getMove().hasAttr(DelayedAttackAttr); + const isDelayedAttack = this.move.hasAttr(DelayedAttackAttr); /** If the user was somehow removed from the field and it's not a delayed attack, end this phase */ if (!user.isOnField()) { if (!isDelayedAttack) { - return super.end(); - } else { - if (!user.scene) { - /** - * This happens if the Pokemon that used the delayed attack gets caught and released - * on the turn the attack would have triggered. Having access to the global scene - * in the future may solve this entirely, so for now we just cancel the hit - */ - return super.end(); - } - if (isNullOrUndefined(user.turnData)) { - user.resetTurnData(); - } + super.end(); + return; + } + if (!user.scene) { + /* + * This happens if the Pokemon that used the delayed attack gets caught and released + * on the turn the attack would have triggered. Having access to the global scene + * in the future may solve this entirely, so for now we just cancel the hit + */ + super.end(); + return; } } @@ -139,17 +284,17 @@ export class MoveEffectPhase extends PokemonPhase { * e.g. Charging moves (Fly, etc.) on their first turn of use. */ const overridden = new BooleanHolder(false); - /** The {@linkcode Move} object from {@linkcode allMoves} invoked by this phase */ - const move = this.move.getMove(); + const move = this.move; // Assume single target for override - applyMoveAttrs(OverrideMoveEffectAttr, user, this.getFirstTarget() ?? null, move, overridden, this.move.virtual); + applyMoveAttrs(OverrideMoveEffectAttr, user, this.getFirstTarget() ?? null, move, overridden, this.virtual); // If other effects were overriden, stop this phase before they can be applied if (overridden.value) { return this.end(); } + // Lapse `MOVE_EFFECT` effects (i.e. semi-invulnerability) when applicable user.lapseTags(BattlerTagLapseType.MOVE_EFFECT); // If the user is acting again (such as due to Instruct), reset hitsLeft/hitCount so that @@ -178,330 +323,75 @@ export class MoveEffectPhase extends PokemonPhase { user.turnData.hitsLeft = hitCount.value; } - /** + /* * Log to be entered into the user's move history once the move result is resolved. - * Note that `result` (a {@linkcode MoveResult}) logs whether the move was successfully + * Note that `result` logs whether the move was successfully * used in the sense of "Does it have an effect on the user?". */ - const moveHistoryEntry = { - move: this.move.moveId, + this.moveHistoryEntry = { + move: this.move.id, targets: this.targets, result: MoveResult.PENDING, - virtual: this.move.virtual, + virtual: this.virtual, }; - /** - * Stores results of hit checks of the invoked move against all targets, organized by battler index. - * @see {@linkcode hitCheck} - */ - const targetHitChecks = Object.fromEntries(targets.map(p => [p.getBattlerIndex(), this.hitCheck(p)])); - const hasActiveTargets = targets.some(t => t.isActive(true)); + const fieldMove = isFieldTargeted(move); - /** Check if the target is immune via ability to the attacking move, and NOT in semi invulnerable state */ - const isImmune = - targets[0]?.hasAbilityWithAttr(TypeImmunityAbAttr) && - targets[0]?.getAbility()?.getAttrs(TypeImmunityAbAttr)?.[0]?.getImmuneType() === user.getMoveType(move) && - !targets[0]?.getTag(SemiInvulnerableTag); + const targets = this.conductHitChecks(user, fieldMove); - const mayBounce = - move.hasFlag(MoveFlags.REFLECTABLE) && - !this.reflected && - targets.some(t => t.hasAbilityWithAttr(ReflectStatusMoveAbAttr) || !!t.getTag(BattlerTagType.MAGIC_COAT)); + this.firstHit = user.turnData.hitCount === user.turnData.hitsLeft; + this.lastHit = user.turnData.hitsLeft === 1 || !targets.some(t => t.isActive(true)); - /** - * If no targets are left for the move to hit (FAIL), or the invoked move is non-reflectable, single-target - * (and not random target) and failed the hit check against its target (MISS), log the move - * as FAILed or MISSed (depending on the conditions above) and end this phase. - */ + // Play the animation if the move was successful against any of its targets or it has a POST_TARGET effect (like self destruct) if ( - !hasActiveTargets || - (!mayBounce && - !move.hasAttr(VariableTargetAttr) && - !move.isMultiTarget() && - !targetHitChecks[this.targets[0]] && - !targets[0].getTag(ProtectedTag) && - !isImmune) + this.moveHistoryEntry.result === MoveResult.SUCCESS || + move.getAttrs(MoveEffectAttr).some(attr => attr.trigger === MoveEffectTrigger.POST_TARGET) ) { - this.stopMultiHit(); - if (hasActiveTargets) { - globalScene.queueMessage( - i18next.t("battle:attackMissed", { - pokemonNameWithAffix: this.getFirstTarget() ? getPokemonNameWithAffix(this.getFirstTarget()!) : "", - }), - ); - moveHistoryEntry.result = MoveResult.MISS; - applyMoveAttrs(MissEffectAttr, user, null, this.move.getMove()); - } else { - globalScene.queueMessage(i18next.t("battle:attackFailed")); - moveHistoryEntry.result = MoveResult.FAIL; - } - user.pushMoveHistory(moveHistoryEntry); - return this.end(); + const firstTarget = this.getFirstTarget(); + new MoveAnim( + move.id as Moves, + user, + firstTarget?.getBattlerIndex() ?? BattlerIndex.ATTACKER, + // Field moves and some moves used in mystery encounters should be played even on an empty field + fieldMove || (globalScene.currentBattle?.mysteryEncounter?.hasBattleAnimationsWithoutTargets ?? false), + ).play(move.hitsSubstitute(user, firstTarget), () => this.postAnimCallback(user, targets)); + + return; + } + this.postAnimCallback(user, targets); + } + + /** + * Callback to be called after the move animation is played + */ + private postAnimCallback(user: Pokemon, targets: Pokemon[]) { + // Add to the move history entry + if (this.firstHit) { + user.pushMoveHistory(this.moveHistoryEntry); } - const playOnEmptyField = globalScene.currentBattle?.mysteryEncounter?.hasBattleAnimationsWithoutTargets ?? false; - // Move animation only needs one target - new MoveAnim(move.id as Moves, user, this.getFirstTarget()!.getBattlerIndex(), playOnEmptyField).play( - move.hitsSubstitute(user, this.getFirstTarget()!), - () => { - /** Has the move successfully hit a target (for damage) yet? */ - let hasHit = false; + try { + this.applyToTargets(user, targets); + } catch (e) { + console.warn(e.message || "Unexpected error in move effect phase"); + this.end(); + return; + } - // Prevent ENEMY_SIDE targeted moves from occurring twice in double battles - // and check which target will magic bounce. - const trueTargets: Pokemon[] = - move.moveTarget !== MoveTarget.ENEMY_SIDE - ? targets - : (() => { - const magicCoatTargets = targets.filter( - t => t.getTag(BattlerTagType.MAGIC_COAT) || t.hasAbilityWithAttr(ReflectStatusMoveAbAttr), - ); + if (this.queuedPhases.length) { + globalScene.appendToPhase(this.queuedPhases, MoveEndPhase); + } + const moveType = user.getMoveType(this.move, true); + if (this.move.category !== MoveCategory.STATUS && !user.stellarTypesBoosted.includes(moveType)) { + user.stellarTypesBoosted.push(moveType); + } - // only magic coat effect cares about order - if (!mayBounce || magicCoatTargets.length === 0) { - return [targets[0]]; - } - return [magicCoatTargets[0]]; - })(); + if (this.lastHit) { + this.triggerMoveEffects(MoveEffectTrigger.POST_TARGET, user, null); + } - const queuedPhases: Phase[] = []; - for (const target of trueTargets) { - /** The {@linkcode ArenaTagSide} to which the target belongs */ - const targetSide = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; - /** Has the invoked move been cancelled by conditional protection (e.g Quick Guard)? */ - const hasConditionalProtectApplied = new BooleanHolder(false); - /** Does the applied conditional protection bypass Protect-ignoring effects? */ - const bypassIgnoreProtect = new BooleanHolder(false); - /** If the move is not targeting a Pokemon on the user's side, try to apply conditional protection effects */ - if (!this.move.getMove().isAllyTarget()) { - globalScene.arena.applyTagsForSide( - ConditionalProtectTag, - targetSide, - false, - hasConditionalProtectApplied, - user, - target, - move.id, - bypassIgnoreProtect, - ); - } - - /** Is the target protected by Protect, etc. or a relevant conditional protection effect? */ - const isProtected = - ![MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES].includes(this.move.getMove().moveTarget) && - (bypassIgnoreProtect.value || !this.move.getMove().checkFlag(MoveFlags.IGNORE_PROTECT, user, target)) && - (hasConditionalProtectApplied.value || - (!target.findTags(t => t instanceof DamageProtectedTag).length && - target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType))) || - (this.move.getMove().category !== MoveCategory.STATUS && - target.findTags(t => t instanceof DamageProtectedTag).find(t => target.lapseTag(t.tagType)))); - - /** Is the target hidden by the effects of its Commander ability? */ - const isCommanding = - globalScene.currentBattle.double && - target.getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon() === target; - - /** Is the target reflecting status moves from the magic coat move? */ - const isReflecting = !!target.getTag(BattlerTagType.MAGIC_COAT); - - /** Is the target's magic bounce ability not ignored and able to reflect this move? */ - const canMagicBounce = - !isReflecting && - !move.checkFlag(MoveFlags.IGNORE_ABILITIES, user, target) && - target.hasAbilityWithAttr(ReflectStatusMoveAbAttr); - - const semiInvulnerableTag = target.getTag(SemiInvulnerableTag); - - /** Is the target reflecting the effect, not protected, and not in an semi-invulnerable state?*/ - const willBounce = - !isProtected && - !this.reflected && - !isCommanding && - move.hasFlag(MoveFlags.REFLECTABLE) && - (isReflecting || canMagicBounce) && - !semiInvulnerableTag; - - // If the move will bounce, then queue the bounce and move on to the next target - if (!target.switchOutStatus && willBounce) { - const newTargets = move.isMultiTarget() - ? getMoveTargets(target, move.id).targets - : [user.getBattlerIndex()]; - if (!isReflecting) { - // TODO: Ability displays should be handled by the ability - queuedPhases.push( - new ShowAbilityPhase( - target.getBattlerIndex(), - target.getPassiveAbility().hasAttr(ReflectStatusMoveAbAttr), - ), - ); - queuedPhases.push(new HideAbilityPhase()); - } - - queuedPhases.push( - new MovePhase(target, newTargets, new PokemonMove(move.id, 0, 0, true), true, true, true), - ); - continue; - } - - /** Is the pokemon immune due to an ablility, and also not in a semi invulnerable state? */ - const isImmune = - target.hasAbilityWithAttr(TypeImmunityAbAttr) && - target.getAbility()?.getAttrs(TypeImmunityAbAttr)?.[0]?.getImmuneType() === user.getMoveType(move) && - !semiInvulnerableTag; - - /** - * If the move missed a target, stop all future hits against that target - * and move on to the next target (if there is one). - */ - if ( - target.switchOutStatus || - isCommanding || - (!isImmune && !isProtected && !targetHitChecks[target.getBattlerIndex()]) - ) { - this.stopMultiHit(target); - if (!target.switchOutStatus) { - globalScene.queueMessage( - i18next.t("battle:attackMissed", { - pokemonNameWithAffix: getPokemonNameWithAffix(target), - }), - ); - } - if (moveHistoryEntry.result === MoveResult.PENDING) { - moveHistoryEntry.result = MoveResult.MISS; - } - user.pushMoveHistory(moveHistoryEntry); - applyMoveAttrs(MissEffectAttr, user, null, move); - continue; - } - - /** Does this phase represent the invoked move's first strike? */ - const firstHit = user.turnData.hitsLeft === user.turnData.hitCount; - - // Only log the move's result on the first strike - if (firstHit) { - user.pushMoveHistory(moveHistoryEntry); - } - - /** - * Since all fail/miss checks have applied, the move is considered successfully applied. - * It's worth noting that if the move has no effect or is protected against, this assignment - * is overwritten and the move is logged as a FAIL. - */ - moveHistoryEntry.result = MoveResult.SUCCESS; - - /** - * Stores the result of applying the invoked move to the target. - * If the target is protected, the result is always `NO_EFFECT`. - * Otherwise, the hit result is based on type effectiveness, immunities, - * and other factors that may negate the attack or status application. - * - * Internally, the call to {@linkcode Pokemon.apply} is where damage is calculated - * (for attack moves) and the target's HP is updated. However, this isn't - * made visible to the user until the resulting {@linkcode DamagePhase} - * is invoked. - */ - const hitResult = !isProtected ? target.apply(user, move) : HitResult.NO_EFFECT; - - /** Does {@linkcode hitResult} indicate that damage was dealt to the target? */ - const dealsDamage = [ - HitResult.EFFECTIVE, - HitResult.SUPER_EFFECTIVE, - HitResult.NOT_VERY_EFFECTIVE, - HitResult.ONE_HIT_KO, - ].includes(hitResult); - - /** Is this target the first one hit by the move on its current strike? */ - const firstTarget = dealsDamage && !hasHit; - if (firstTarget) { - hasHit = true; - } - - /** - * If the move has no effect on the target (i.e. the target is protected or immune), - * change the logged move result to FAIL. - */ - if (hitResult === HitResult.NO_EFFECT) { - moveHistoryEntry.result = MoveResult.FAIL; - } - - /** Does this phase represent the invoked move's last strike? */ - const lastHit = user.turnData.hitsLeft === 1 || !this.getFirstTarget()?.isActive(); - - /** - * If the user can change forms by using the invoked move, - * it only changes forms after the move's last hit - * (see Relic Song's interaction with Parental Bond when used by Meloetta). - */ - if (lastHit) { - globalScene.triggerPokemonFormChange(user, SpeciesFormChangePostMoveTrigger); - /** - * Multi-Lens, Multi Hit move and Parental Bond check for PostDamageAbAttr - * other damage source are calculated in damageAndUpdate in pokemon.ts - */ - if (user.turnData.hitCount > 1) { - applyPostDamageAbAttrs(PostDamageAbAttr, target, 0, target.hasPassive(), false, [], user); - } - } - - applyFilteredMoveAttrs( - (attr: MoveAttr) => - attr instanceof MoveEffectAttr && - attr.trigger === MoveEffectTrigger.PRE_APPLY && - (!attr.firstHitOnly || firstHit) && - (!attr.lastHitOnly || lastHit) && - hitResult !== HitResult.NO_EFFECT, - user, - target, - move, - ); - - if (hitResult !== HitResult.FAIL) { - this.applySelfTargetEffects(user, target, firstHit, lastHit); - - if (hitResult !== HitResult.NO_EFFECT) { - this.applyPostApplyEffects(user, target, firstHit, lastHit); - this.applyHeldItemFlinchCheck(user, target, dealsDamage); - this.applySuccessfulAttackEffects(user, target, firstHit, lastHit, !!isProtected, hitResult, firstTarget); - } else { - applyMoveAttrs(NoEffectAttr, user, null, move); - } - } - } - - // Apply queued phases - if (queuedPhases.length) { - globalScene.appendToPhase(queuedPhases, MoveEndPhase); - } - // Apply the move's POST_TARGET effects on the move's last hit, after all targeted effects have resolved - if (user.turnData.hitsLeft === 1 || !this.getFirstTarget()?.isActive()) { - applyFilteredMoveAttrs( - (attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.POST_TARGET, - user, - null, - move, - ); - } - - /** - * Remove the target's substitute (if it exists and has expired) - * after all targeted effects have applied. - * This prevents blocked effects from applying until after this hit resolves. - */ - targets.forEach(target => { - const substitute = target.getTag(SubstituteTag); - if (substitute && substitute.hp <= 0) { - target.lapseTag(BattlerTagType.SUBSTITUTE); - } - }); - - const moveType = user.getMoveType(move, true); - if (move.category !== MoveCategory.STATUS && !user.stellarTypesBoosted.includes(moveType)) { - user.stellarTypesBoosted.push(moveType); - } - - this.end(); - }, - ); + this.updateSubstitutes(); + this.end(); } public override end(): void { @@ -525,7 +415,6 @@ export class MoveEffectPhase extends PokemonPhase { globalScene.queueMessage(i18next.t("battle:attackHitsCount", { count: hitsTotal })); } globalScene.applyModifiers(HitHealModifier, this.player, user); - // Clear all cached move effectiveness values among targets this.getTargets().forEach(target => (target.turnData.moveEffectiveness = null)); } } @@ -533,82 +422,6 @@ export class MoveEffectPhase extends PokemonPhase { super.end(); } - /** - * Apply self-targeted effects that trigger `POST_APPLY` - * - * @param user - The {@linkcode Pokemon} using this phase's invoked move - * @param target - {@linkcode Pokemon} the current target of this phase's invoked move - * @param firstHit - `true` if this is the first hit in a multi-hit attack - * @param lastHit - `true` if this is the last hit in a multi-hit attack - * @returns a function intended to be passed into a `then()` call. - */ - protected applySelfTargetEffects(user: Pokemon, target: Pokemon, firstHit: boolean, lastHit: boolean): void { - applyFilteredMoveAttrs( - (attr: MoveAttr) => - attr instanceof MoveEffectAttr && - attr.trigger === MoveEffectTrigger.POST_APPLY && - attr.selfTarget && - (!attr.firstHitOnly || firstHit) && - (!attr.lastHitOnly || lastHit), - user, - target, - this.move.getMove(), - ); - } - - /** - * Applies non-self-targeted effects that trigger `POST_APPLY` - * (i.e. Smelling Salts curing Paralysis, and the forced switch from U-Turn, Dragon Tail, etc) - * @param user - The {@linkcode Pokemon} using this phase's invoked move - * @param target - {@linkcode Pokemon} the current target of this phase's invoked move - * @param firstHit - `true` if this is the first hit in a multi-hit attack - * @param lastHit - `true` if this is the last hit in a multi-hit attack - * @returns a function intended to be passed into a `then()` call. - */ - protected applyPostApplyEffects(user: Pokemon, target: Pokemon, firstHit: boolean, lastHit: boolean): void { - applyFilteredMoveAttrs( - (attr: MoveAttr) => - attr instanceof MoveEffectAttr && - attr.trigger === MoveEffectTrigger.POST_APPLY && - !attr.selfTarget && - (!attr.firstHitOnly || firstHit) && - (!attr.lastHitOnly || lastHit), - user, - target, - this.move.getMove(), - ); - } - - /** - * Applies effects that trigger on HIT - * (i.e. Final Gambit, Power-Up Punch, Drain Punch) - * @param user - The {@linkcode Pokemon} using this phase's invoked move - * @param target - {@linkcode Pokemon} the current target of this phase's invoked move - * @param firstHit - `true` if this is the first hit in a multi-hit attack - * @param lastHit - `true` if this is the last hit in a multi-hit attack - * @param firstTarget - `true` if {@linkcode target} is the first target hit by this strike of {@linkcode move} - * @returns a function intended to be passed into a `then()` call. - */ - protected applyOnHitEffects( - user: Pokemon, - target: Pokemon, - firstHit: boolean, - lastHit: boolean, - firstTarget: boolean, - ): void { - applyFilteredMoveAttrs( - (attr: MoveAttr) => - attr instanceof MoveEffectAttr && - attr.trigger === MoveEffectTrigger.HIT && - (!attr.firstHitOnly || firstHit) && - (!attr.lastHitOnly || lastHit) && - (!attr.firstTargetOnly || firstTarget), - user, - target, - this.move.getMove(), - ); - } - /** * Applies reactive effects that occur when a Pokémon is hit. * (i.e. Effect Spore, Disguise, Liquid Ooze, Beak Blast) @@ -618,48 +431,8 @@ export class MoveEffectPhase extends PokemonPhase { * @returns a `Promise` intended to be passed into a `then()` call. */ protected applyOnGetHitAbEffects(user: Pokemon, target: Pokemon, hitResult: HitResult): void { - if (!target.isFainted() || target.canApplyAbility()) { - applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult); - - if (!this.move.getMove().hitsSubstitute(user, target)) { - if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) { - globalScene.applyShuffledModifiers(EnemyAttackStatusEffectChanceModifier, false, target); - } - - target.lapseTags(BattlerTagLapseType.AFTER_HIT); - } - } - } - - /** - * Applies all effects and attributes that require a move to connect with a target, - * namely reactive effects like Weak Armor, on-hit effects like that of Power-Up Punch, and item stealing effects - * @param user - The {@linkcode Pokemon} using this phase's invoked move - * @param target - {@linkcode Pokemon} the current target of this phase's invoked move - * @param firstHit - `true` if this is the first hit in a multi-hit attack - * @param lastHit - `true` if this is the last hit in a multi-hit attack - * @param isProtected - `true` if the target is protected by effects such as Protect - * @param hitResult - The {@linkcode HitResult} of the attempted move - * @param firstTarget - `true` if {@linkcode target} is the first target hit by this strike of {@linkcode move} - * @returns a function intended to be passed into a `then()` call. - */ - protected applySuccessfulAttackEffects( - user: Pokemon, - target: Pokemon, - firstHit: boolean, - lastHit: boolean, - isProtected: boolean, - hitResult: HitResult, - firstTarget: boolean, - ): void { - if (!isProtected) { - this.applyOnHitEffects(user, target, firstHit, lastHit, firstTarget); - this.applyOnGetHitAbEffects(user, target, hitResult); - applyPostAttackAbAttrs(PostAttackAbAttr, user, target, this.move.getMove(), hitResult); - if (this.move.getMove() instanceof AttackMove && hitResult !== HitResult.STATUS) { - globalScene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user, target); - } - } + applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move, hitResult); + target.lapseTags(BattlerTagLapseType.AFTER_HIT); } /** @@ -670,80 +443,162 @@ export class MoveEffectPhase extends PokemonPhase { * @returns a function intended to be passed into a `then()` call. */ protected applyHeldItemFlinchCheck(user: Pokemon, target: Pokemon, dealsDamage: boolean): void { - if (this.move.getMove().hasAttr(FlinchAttr)) { + if (this.move.hasAttr(FlinchAttr)) { return; } - if ( - dealsDamage && - !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && - !this.move.getMove().hitsSubstitute(user, target) - ) { + if (dealsDamage && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && !this.move.hitsSubstitute(user, target)) { const flinched = new BooleanHolder(false); globalScene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched); if (flinched.value) { - target.addTag(BattlerTagType.FLINCHED, undefined, this.move.moveId, user.id); + target.addTag(BattlerTagType.FLINCHED, undefined, this.move.id, user.id); } } } - /** - * Resolves whether this phase's invoked move hits the given target - * @param target - The {@linkcode Pokemon} targeted by the invoked move - * @returns `true` if the move hits the target + /** Return whether the target is protected by protect or a relevant conditional protection + * @param user - The {@linkcode Pokemon} using this phase's invoked move + * @param target - {@linkcode Pokemon} the target to check for protection + * @param move - The {@linkcode Move} being used */ - public hitCheck(target: Pokemon): boolean { - // Moves targeting the user and entry hazards can't miss - if ([MoveTarget.USER, MoveTarget.ENEMY_SIDE].includes(this.move.getMove().moveTarget)) { - return true; + private protectedCheck(user: Pokemon, target: Pokemon) { + /** The {@linkcode ArenaTagSide} to which the target belongs */ + const targetSide = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; + /** Has the invoked move been cancelled by conditional protection (e.g Quick Guard)? */ + const hasConditionalProtectApplied = new BooleanHolder(false); + /** Does the applied conditional protection bypass Protect-ignoring effects? */ + const bypassIgnoreProtect = new BooleanHolder(false); + /** If the move is not targeting a Pokemon on the user's side, try to apply conditional protection effects */ + if (!this.move.isAllyTarget()) { + globalScene.arena.applyTagsForSide( + ConditionalProtectTag, + targetSide, + false, + hasConditionalProtectApplied, + user, + target, + this.move.id, + bypassIgnoreProtect, + ); } + return ( + ![MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES].includes(this.move.moveTarget) && + (bypassIgnoreProtect.value || !this.move.doesFlagEffectApply({ flag: MoveFlags.IGNORE_PROTECT, user, target })) && + (hasConditionalProtectApplied.value || + (!target.findTags(t => t instanceof DamageProtectedTag).length && + target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType))) || + (this.move.category !== MoveCategory.STATUS && + target.findTags(t => t instanceof DamageProtectedTag).find(t => target.lapseTag(t.tagType)))) + ); + } + + /** + * Conduct the hit check and type effectiveness for this move against the target + * + * Checks occur in the following order: + * 1. if the move is self-target + * 2. if the target is on the field + * 3. if the target is hidden by the effects of its commander ability + * 4. if the target is in an applicable semi-invulnerable state + * 5. if the target has an applicable protection effect + * 6. if the move is reflected by magic coat or magic bounce + * 7. type effectiveness calculation, including immunities from abilities and typing + * 9. if accuracy is checked, whether the roll passes the accuracy check + * @param target - The {@linkcode Pokemon} targeted by the invoked move + * @returns a {@linkcode HitCheckEntry} containing the attack's {@linkcode HitCheckResult} + * and {@linkcode TypeDamageMultiplier | effectiveness} against the target. + */ + public hitCheck(target: Pokemon): HitCheckEntry { const user = this.getUserPokemon(); + const move = this.move; if (!user) { - return false; + return [HitCheckResult.ERROR, 0]; } - // Hit check only calculated on first hit for multi-hit moves unless flag is set to check all hits. - // However, if an ability with the MaxMultiHitAbAttr, namely Skill Link, is present, act as a normal - // multi-hit move and proceed with all hits + // Moves targeting the user bypass all checks + if (move.moveTarget === MoveTarget.USER) { + return [HitCheckResult.HIT, 1]; + } + + const fieldTargeted = isFieldTargeted(move); + + if (!target.isActive(true) && !fieldTargeted) { + return [HitCheckResult.TARGET_NOT_ON_FIELD, 0]; + } + + // Commander causes moves used against the target to miss + if ( + !fieldTargeted && + globalScene.currentBattle.double && + target.getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon() === target + ) { + return [HitCheckResult.MISS, 0]; + } + + /** Whether both accuracy and invulnerability checks can be skipped */ + const bypassAccAndInvuln = fieldTargeted || this.checkBypassAccAndInvuln(target); + const semiInvulnerableTag = target.getTag(SemiInvulnerableTag); + + if (semiInvulnerableTag && !bypassAccAndInvuln && !this.checkBypassSemiInvuln(semiInvulnerableTag)) { + return [HitCheckResult.MISS, 0]; + } + + if (!fieldTargeted && this.protectedCheck(user, target)) { + return [HitCheckResult.PROTECTED, 0]; + } + + if (!this.reflected && move.doesFlagEffectApply({ flag: MoveFlags.REFLECTABLE, user, target })) { + return [HitCheckResult.REFLECTED, 0]; + } + + // After the magic bounce check, field targeted moves are always successful + if (fieldTargeted) { + return [HitCheckResult.HIT, 1]; + } + + const cancelNoEffectMessage = new BooleanHolder(false); + + /** + * The effectiveness of the move against the given target. + * Accounts for type and move immunities from defensive typing, abilities, and other effects. + */ + const effectiveness = target.getMoveEffectiveness(user, move, false, false, cancelNoEffectMessage); + if (effectiveness === 0) { + return [ + cancelNoEffectMessage.value ? HitCheckResult.NO_EFFECT_NO_MESSAGE : HitCheckResult.NO_EFFECT, + effectiveness, + ]; + } + + const moveAccuracy = move.calculateBattleAccuracy(user, target); + + // Strikes after the first in a multi-strike move are guaranteed to hit, + // unless the move is flagged to check all hits and the user does not have Skill Link. if (user.turnData.hitsLeft < user.turnData.hitCount) { - if (!this.move.getMove().hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr(MaxMultiHitAbAttr)) { - return true; + if (!move.hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr(MaxMultiHitAbAttr)) { + return [HitCheckResult.HIT, effectiveness]; } } - if (this.checkBypassAccAndInvuln(target)) { - return true; + const bypassAccuracy = + bypassAccAndInvuln || + target.getTag(BattlerTagType.ALWAYS_GET_HIT) || + (target.getTag(BattlerTagType.TELEKINESIS) && !this.move.hasAttr(OneHitKOAttr)); + + if (moveAccuracy === -1 || bypassAccuracy) { + return [HitCheckResult.HIT, effectiveness]; } - if (target.getTag(BattlerTagType.ALWAYS_GET_HIT)) { - return true; - } - - const semiInvulnerableTag = target.getTag(SemiInvulnerableTag); - if ( - target.getTag(BattlerTagType.TELEKINESIS) && - !semiInvulnerableTag && - !this.move.getMove().hasAttr(OneHitKOAttr) - ) { - return true; - } - - if (semiInvulnerableTag && !this.checkBypassSemiInvuln(semiInvulnerableTag)) { - return false; - } - - const moveAccuracy = this.move.getMove().calculateBattleAccuracy(user, target); - - if (moveAccuracy === -1) { - return true; - } - - const accuracyMultiplier = user.getAccuracyMultiplier(target, this.move.getMove()); + const accuracyMultiplier = user.getAccuracyMultiplier(target, this.move); const rand = user.randSeedInt(100); - return rand < moveAccuracy * accuracyMultiplier; + if (rand < moveAccuracy * accuracyMultiplier) { + return [HitCheckResult.HIT, effectiveness]; + } + + return [HitCheckResult.MISS, 0]; } /** @@ -755,6 +610,7 @@ export class MoveEffectPhase extends PokemonPhase { * - An ability like {@linkcode Abilities.NO_GUARD | No Guard} * - A poison type using {@linkcode Moves.TOXIC | Toxic} * - A move like {@linkcode Moves.LOCK_ON | Lock-On} or {@linkcode Moves.MIND_READER | Mind Reader}. + * - A field-targeted move like spikes * * Does *not* check against effects {@linkcode Moves.GLAIVE_RUSH | Glaive Rush} status (which * should not bypass semi-invulnerability), or interactions like Earthquake hitting against Dig, @@ -770,7 +626,7 @@ export class MoveEffectPhase extends PokemonPhase { if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr)) { return true; } - if (this.move.getMove().hasAttr(ToxicAccuracyAttr) && user.isOfType(PokemonType.POISON)) { + if (this.move.hasAttr(ToxicAccuracyAttr) && user.isOfType(PokemonType.POISON)) { return true; } // TODO: Fix lock on / mind reader check. @@ -780,18 +636,21 @@ export class MoveEffectPhase extends PokemonPhase { ) { return true; } + if (isFieldTargeted(this.move)) { + return true; + } } /** * Check whether the move is able to ignore the given `semiInvulnerableTag` - * @param semiInvulnerableTag - The semiInvulnerbale tag to check against + * @param semiInvulnerableTag - The semiInvulnerable tag to check against * @returns `true` if the move can ignore the semi-invulnerable state */ public checkBypassSemiInvuln(semiInvulnerableTag: SemiInvulnerableTag | nil): boolean { if (!semiInvulnerableTag) { return false; } - const move = this.move.getMove(); + const move = this.move; return move.getAttrs(HitsTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType); } @@ -850,6 +709,282 @@ export class MoveEffectPhase extends PokemonPhase { /** @returns A new `MoveEffectPhase` with the same properties as this phase */ protected getNewHitPhase(): MoveEffectPhase { - return new MoveEffectPhase(this.battlerIndex, this.targets, this.move); + return new MoveEffectPhase(this.battlerIndex, this.targets, this.move, this.reflected, this.virtual); + } + + /** Removes all substitutes that were broken by this phase's invoked move */ + protected updateSubstitutes(): void { + const targets = this.getTargets(); + for (const target of targets) { + const substitute = target.getTag(SubstituteTag); + if (substitute && substitute.hp <= 0) { + target.lapseTag(BattlerTagType.SUBSTITUTE); + } + } + } + + /** + * Triggers move effects of the given move effect trigger. + * @param triggerType The {@linkcode MoveEffectTrigger} being applied + * @param user The {@linkcode Pokemon} using the move + * @param target The {@linkcode Pokemon} targeted by the move + * @param firstTarget Whether the target is the first to be hit by the current strike + * @param selfTarget If defined, limits the effects triggered to either self-targeted + * effects (if set to `true`) or targeted effects (if set to `false`). + * @returns a `Promise` applying the relevant move effects. + */ + protected triggerMoveEffects( + triggerType: MoveEffectTrigger, + user: Pokemon, + target: Pokemon | null, + firstTarget?: boolean | null, + selfTarget?: boolean, + ): void { + return applyFilteredMoveAttrs( + (attr: MoveAttr) => + attr instanceof MoveEffectAttr && + attr.trigger === triggerType && + (isNullOrUndefined(selfTarget) || attr.selfTarget === selfTarget) && + (!attr.firstHitOnly || this.firstHit) && + (!attr.lastHitOnly || this.lastHit) && + (!attr.firstTargetOnly || (firstTarget ?? true)), + user, + target, + this.move, + ); + } + + /** + * Applies all move effects that trigger in the event of a successful hit: + * + * - {@linkcode MoveEffectTrigger.PRE_APPLY | PRE_APPLY} effects` + * - Applying damage to the target + * - {@linkcode MoveEffectTrigger.POST_APPLY | POST_APPLY} effects + * - Invoking {@linkcode applyOnTargetEffects} if the move does not hit a substitute + * - Triggering form changes and emergency exit / wimp out if this is the last hit + * + * @param target the {@linkcode Pokemon} hit by this phase's move. + * @param effectiveness the effectiveness of the move (as previously evaluated in {@linkcode hitCheck}) + */ + protected applyMoveEffects(target: Pokemon, effectiveness: TypeDamageMultiplier): void { + const user = this.getUserPokemon(); + + /** The first target hit by the move */ + const firstTarget = target === this.getTargets().find((_, i) => this.hitChecks[i][1] > 0); + + if (isNullOrUndefined(user)) { + return; + } + + this.triggerMoveEffects(MoveEffectTrigger.PRE_APPLY, user, target); + + const hitResult = this.applyMove(user, target, effectiveness); + + this.triggerMoveEffects(MoveEffectTrigger.POST_APPLY, user, target, firstTarget, true); + if (!this.move.hitsSubstitute(user, target)) { + this.applyOnTargetEffects(user, target, hitResult, firstTarget); + } + if (this.lastHit) { + globalScene.triggerPokemonFormChange(user, SpeciesFormChangePostMoveTrigger); + + // Multi-hit check for Wimp Out/Emergency Exit + if (user.turnData.hitCount > 1) { + applyPostDamageAbAttrs(PostDamageAbAttr, target, 0, target.hasPassive(), false, [], user); + } + } + } + + /** + * Sub-method of for {@linkcode applyMoveEffects} that applies damage to the target. + * + * @param user - The {@linkcode Pokemon} using this phase's invoked move + * @param target - The {@linkcode Pokemon} targeted by the move + * @param effectiveness - The effectiveness of the move against the target + */ + protected applyMoveDamage(user: Pokemon, target: Pokemon, effectiveness: TypeDamageMultiplier): HitResult { + const isCritical = target.getCriticalHitResult(user, this.move, false); + + /* + * Apply stat changes from {@linkcode move} and gives it to {@linkcode source} + * before damage calculation + */ + applyMoveAttrs(StatChangeBeforeDmgCalcAttr, user, target, this.move); + + const { result: result, damage: dmg } = target.getAttackDamage({ + source: user, + move: this.move, + ignoreAbility: false, + ignoreSourceAbility: false, + ignoreAllyAbility: false, + ignoreSourceAllyAbility: false, + simulated: false, + effectiveness, + isCritical, + }); + + const typeBoost = user.findTag( + t => t instanceof TypeBoostTag && t.boostedType === user.getMoveType(this.move), + ) as TypeBoostTag; + if (typeBoost?.oneUse) { + user.removeTag(typeBoost.tagType); + } + + const isOneHitKo = result === HitResult.ONE_HIT_KO; + + if (!dmg) { + return result; + } + + target.lapseTags(BattlerTagLapseType.HIT); + + const substitute = target.getTag(SubstituteTag); + const isBlockedBySubstitute = substitute && this.move.hitsSubstitute(user, target); + if (isBlockedBySubstitute) { + substitute.hp -= dmg; + } else if (!target.isPlayer() && dmg >= target.hp) { + globalScene.applyModifiers(EnemyEndureChanceModifier, false, target); + } + + const damage = isBlockedBySubstitute + ? 0 + : target.damageAndUpdate(dmg, { + result: result as DamageResult, + ignoreFaintPhase: true, + ignoreSegments: isOneHitKo, + isCritical, + source: user, + }); + + if (isCritical) { + globalScene.queueMessage(i18next.t("battle:hitResultCriticalHit")); + } + + if (damage <= 0) { + return result; + } + + if (user.isPlayer()) { + globalScene.validateAchvs(DamageAchv, new NumberHolder(damage)); + + if (damage > globalScene.gameData.gameStats.highestDamage) { + globalScene.gameData.gameStats.highestDamage = damage; + } + } + + user.turnData.totalDamageDealt += damage; + user.turnData.singleHitDamageDealt = damage; + target.battleData.hitCount++; + target.turnData.damageTaken += damage; + + target.turnData.attacksReceived.unshift({ + move: this.move.id, + result: result as DamageResult, + damage: damage, + critical: isCritical, + sourceId: user.id, + sourceBattlerIndex: user.getBattlerIndex(), + }); + + if (user.isPlayer() && !target.isPlayer()) { + globalScene.applyModifiers(DamageMoneyRewardModifier, true, user, new NumberHolder(damage)); + } + + return result; + } + + /** + * Sub-method of {@linkcode applyMove} that handles the event of a target fainting. + * @param user - The {@linkcode Pokemon} using this phase's invoked move + * @param target - The {@linkcode Pokemon} that fainted + */ + protected onFaintTarget(user: Pokemon, target: Pokemon): void { + // set splice index here, so future scene queues happen before FaintedPhase + globalScene.setPhaseQueueSplice(); + + globalScene.unshiftPhase(new FaintPhase(target.getBattlerIndex(), false, user)); + + target.destroySubstitute(); + target.lapseTag(BattlerTagType.COMMANDED); + } + + /** + * Sub-method of {@linkcode applyMove} that queues the hit-result message + * on the final strike of the move against a target + * @param result - The {@linkcode HitResult} of the move + */ + protected queueHitResultMessage(result: HitResult) { + let msg: string | undefined; + switch (result) { + case HitResult.SUPER_EFFECTIVE: + msg = i18next.t("battle:hitResultSuperEffective"); + break; + case HitResult.NOT_VERY_EFFECTIVE: + msg = i18next.t("battle:hitResultNotVeryEffective"); + break; + case HitResult.ONE_HIT_KO: + msg = i18next.t("battle:hitResultOneHitKO"); + break; + } + if (msg) { + globalScene.queueMessage(msg); + } + } + + /** Apply the result of this phase's move to the given target + * @param user - The {@linkcode Pokemon} using this phase's invoked move + * @param target - The {@linkcode Pokemon} struck by the move + * @param effectiveness - The effectiveness of the move against the target + */ + protected applyMove(user: Pokemon, target: Pokemon, effectiveness: TypeDamageMultiplier): HitResult { + const moveCategory = user.getMoveCategory(target, this.move); + + if (moveCategory === MoveCategory.STATUS) { + return HitResult.STATUS; + } + + const result = this.applyMoveDamage(user, target, effectiveness); + + if (user.turnData.hitsLeft === 1 && target.isFainted()) { + this.queueHitResultMessage(result); + } + + if (target.isFainted()) { + this.onFaintTarget(user, target); + } + + return result; + } + + /** + * Applies all effects aimed at the move's target. + * To be used when the target is successfully and directly hit by the move. + * @param user - The {@linkcode Pokemon} using the move + * @param target - The {@linkcode Pokemon} targeted by the move + * @param hitResult - The {@linkcode HitResult} obtained from applying the move + * @param firstTarget - `true` if the target is the first Pokemon hit by the attack + */ + protected applyOnTargetEffects(user: Pokemon, target: Pokemon, hitResult: HitResult, firstTarget: boolean): void { + /** Does {@linkcode hitResult} indicate that damage was dealt to the target? */ + const dealsDamage = [ + HitResult.EFFECTIVE, + HitResult.SUPER_EFFECTIVE, + HitResult.NOT_VERY_EFFECTIVE, + HitResult.ONE_HIT_KO, + ].includes(hitResult); + + this.triggerMoveEffects(MoveEffectTrigger.POST_APPLY, user, target, firstTarget, false); + this.applyHeldItemFlinchCheck(user, target, dealsDamage); + this.applyOnGetHitAbEffects(user, target, hitResult); + applyPostAttackAbAttrs(PostAttackAbAttr, user, target, this.move, hitResult); + + // We assume only enemy Pokemon are able to have the EnemyAttackStatusEffectChanceModifier from tokens + if (!user.isPlayer() && this.move instanceof AttackMove) { + globalScene.applyShuffledModifiers(EnemyAttackStatusEffectChanceModifier, false, target); + } + + // Apply Grip Claw's chance to steal an item from the target + if (this.move instanceof AttackMove) { + globalScene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user, target); + } } } diff --git a/src/phases/move-end-phase.ts b/src/phases/move-end-phase.ts index 46e266a32b7..037596dca59 100644 --- a/src/phases/move-end-phase.ts +++ b/src/phases/move-end-phase.ts @@ -1,18 +1,38 @@ import { globalScene } from "#app/global-scene"; import { BattlerTagLapseType } from "#app/data/battler-tags"; import { PokemonPhase } from "./pokemon-phase"; +import type { BattlerIndex } from "#app/battle"; +import { applyPostSummonAbAttrs, PostSummonRemoveEffectAbAttr } from "#app/data/abilities/ability"; +import type Pokemon from "#app/field/pokemon"; export class MoveEndPhase extends PokemonPhase { + private wasFollowUp: boolean; + + /** Targets from the preceding MovePhase */ + private targets: Pokemon[]; + constructor(battlerIndex: BattlerIndex, targets: Pokemon[], wasFollowUp = false) { + super(battlerIndex); + + this.targets = targets; + this.wasFollowUp = wasFollowUp; + } + start() { super.start(); const pokemon = this.getPokemon(); - if (pokemon.isActive(true)) { + if (!this.wasFollowUp && pokemon?.isActive(true)) { pokemon.lapseTags(BattlerTagLapseType.AFTER_MOVE); } - globalScene.arena.setIgnoreAbilities(false); + // Remove effects which were set on a Pokemon which removes them on summon (i.e. via Mold Breaker) + for (const target of this.targets) { + if (target) { + applyPostSummonAbAttrs(PostSummonRemoveEffectAbAttr, target); + } + } + this.end(); } } diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index e04f48c2880..e704b040d20 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -10,11 +10,12 @@ import { PostMoveUsedAbAttr, RedirectMoveAbAttr, ReduceStatusEffectDurationAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; import type { DelayedAttackTag } from "#app/data/arena-tag"; import { CommonAnim } from "#app/data/battle-anims"; import { BattlerTagLapseType, CenterOfAttentionTag } from "#app/data/battler-tags"; import { + AddArenaTrapTagAttr, allMoves, applyMoveAttrs, BypassRedirectAttr, @@ -42,7 +43,7 @@ import { CommonAnimPhase } from "#app/phases/common-anim-phase"; import { MoveChargePhase } from "#app/phases/move-charge-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; -import { NumberHolder } from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; @@ -168,7 +169,11 @@ export class MovePhase extends BattlePhase { // Check move to see if arena.ignoreAbilities should be true. if (!this.followUp || this.reflected) { - if (this.move.getMove().checkFlag(MoveFlags.IGNORE_ABILITIES, this.pokemon, null)) { + if ( + this.move + .getMove() + .doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user: this.pokemon, isFollowUp: this.followUp }) + ) { globalScene.arena.setIgnoreAbilities(true, this.pokemon.getBattlerIndex()); } } @@ -201,7 +206,10 @@ export class MovePhase extends BattlePhase { const targets = this.getActiveTargetPokemon(); const moveQueue = this.pokemon.getMoveQueue(); - if (targets.length === 0 || (moveQueue.length && moveQueue[0].move === Moves.NONE)) { + if ( + (targets.length === 0 && !this.move.getMove().hasAttr(AddArenaTrapTagAttr)) || + (moveQueue.length && moveQueue[0].move === Moves.NONE) + ) { this.showMoveText(); this.showFailedText(); this.cancel(); @@ -227,7 +235,7 @@ export class MovePhase extends BattlePhase { (!this.pokemon.randSeedInt(4) || Overrides.STATUS_ACTIVATION_OVERRIDE === true) && Overrides.STATUS_ACTIVATION_OVERRIDE !== false; break; - case StatusEffect.SLEEP: + case StatusEffect.SLEEP: { applyMoveAttrs(BypassSleepAttr, this.pokemon, null, this.move.getMove()); const turnsRemaining = new NumberHolder(this.pokemon.status.sleepTurnsRemaining ?? 0); applyAbAttrs( @@ -242,6 +250,7 @@ export class MovePhase extends BattlePhase { healed = this.pokemon.status.sleepTurnsRemaining <= 0; activated = !healed && !this.pokemon.getTag(BattlerTagType.BYPASS_SLEEP); break; + } case StatusEffect.FREEZE: healed = !!this.move @@ -395,9 +404,10 @@ export class MovePhase extends BattlePhase { * if the move fails. */ if (success) { - applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove()); + const move = this.move.getMove(); + applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, move); globalScene.unshiftPhase( - new MoveEffectPhase(this.pokemon.getBattlerIndex(), this.targets, this.move, this.reflected), + new MoveEffectPhase(this.pokemon.getBattlerIndex(), this.targets, move, this.reflected, this.move.virtual), ); } else { if ([Moves.ROAR, Moves.WHIRLWIND, Moves.TRICK_OR_TREAT, Moves.FORESTS_CURSE].includes(this.move.moveId)) { @@ -465,13 +475,12 @@ export class MovePhase extends BattlePhase { } /** - * Queues a {@linkcode MoveEndPhase} if the move wasn't a {@linkcode followUp} and {@linkcode canMove()} returns `true`, - * then ends the phase. + * Queues a {@linkcode MoveEndPhase} and then ends the phase */ public end(): void { - if (!this.followUp && this.canMove()) { - globalScene.unshiftPhase(new MoveEndPhase(this.pokemon.getBattlerIndex())); - } + globalScene.unshiftPhase( + new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon(), this.followUp), + ); super.end(); } @@ -609,7 +618,7 @@ export class MovePhase extends BattlePhase { globalScene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), ppUsed)); } - if (this.cancelled && this.pokemon.summonData?.tags?.find(t => t.tagType === BattlerTagType.FRENZY)) { + if (this.cancelled && this.pokemon.summonData.tags?.find(t => t.tagType === BattlerTagType.FRENZY)) { frenzyMissFunc(this.pokemon, this.move.getMove()); } @@ -646,7 +655,7 @@ export class MovePhase extends BattlePhase { }), 500, ); - applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents()[0], this.move.getMove()); + applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents(false)[0], this.move.getMove()); } public showFailedText(failedText: string = i18next.t("battle:attackFailed")): void { diff --git a/src/phases/mystery-encounter-phases.ts b/src/phases/mystery-encounter-phases.ts index eb187617e69..fd0c4ef7949 100644 --- a/src/phases/mystery-encounter-phases.ts +++ b/src/phases/mystery-encounter-phases.ts @@ -25,9 +25,9 @@ import { transitionMysteryEncounterIntroVisuals } from "../data/mystery-encounte import { TrainerSlot } from "#enums/trainer-slot"; import { IvScannerModifier } from "../modifier/modifier"; import { Phase } from "../phase"; -import { Mode } from "../ui/ui"; -import * as Utils from "../utils"; -import { isNullOrUndefined } from "../utils"; +import { UiMode } from "#enums/ui-mode"; +import { isNullOrUndefined, randSeedItem } from "#app/utils/common"; +import { SelectBiomePhase } from "./select-biome-phase"; /** * Will handle (in order): @@ -73,7 +73,7 @@ export class MysteryEncounterPhase extends Phase { } // Initiates encounter dialogue window and option select - globalScene.ui.setMode(Mode.MYSTERY_ENCOUNTER, this.optionSelectSettings); + globalScene.ui.setMode(UiMode.MYSTERY_ENCOUNTER, this.optionSelectSettings); } /** @@ -131,7 +131,7 @@ export class MysteryEncounterPhase extends Phase { const optionSelectDialogue = globalScene.currentBattle?.mysteryEncounter?.selectedOption?.dialogue; if (optionSelectDialogue?.selected && optionSelectDialogue.selected.length > 0) { // Handle intermediate dialogue (between player selection event and the onOptionSelect logic) - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); const selectedDialogue = optionSelectDialogue.selected; let i = 0; const showNextDialogue = () => { @@ -168,7 +168,7 @@ export class MysteryEncounterPhase extends Phase { * Ends phase */ end() { - globalScene.ui.setMode(Mode.MESSAGE).then(() => super.end()); + globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end()); } } @@ -229,8 +229,7 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase { // Lapse any residual flinches/endures but ignore all other turn-end battle tags const includedLapseTags = [BattlerTagType.FLINCHED, BattlerTagType.ENDURING]; - const field = globalScene.getField(true).filter(p => p.summonData); - field.forEach(pokemon => { + globalScene.getField(true).forEach(pokemon => { const tags = pokemon.summonData.tags; tags .filter( @@ -387,7 +386,7 @@ export class MysteryEncounterBattlePhase extends Phase { const trainer = globalScene.currentBattle.trainer; let message: string; globalScene.executeWithSeedOffset( - () => (message = Utils.randSeedItem(encounterMessages)), + () => (message = randSeedItem(encounterMessages)), globalScene.currentBattle.mysteryEncounter?.getSeedOffset(), ); message = message!; // tell TS compiler it's defined now @@ -613,6 +612,10 @@ export class PostMysteryEncounterPhase extends Phase { */ continueEncounter() { const endPhase = () => { + if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { + globalScene.pushPhase(new SelectBiomePhase()); + } + globalScene.pushPhase(new NewBattlePhase()); this.end(); }; @@ -630,7 +633,7 @@ export class PostMysteryEncounterPhase extends Phase { } i++; - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); if (title) { globalScene.ui.showDialogue( text ?? "", diff --git a/src/phases/new-battle-phase.ts b/src/phases/new-battle-phase.ts index 8cdbdc5891a..09b8ab1d335 100644 --- a/src/phases/new-battle-phase.ts +++ b/src/phases/new-battle-phase.ts @@ -5,6 +5,11 @@ export class NewBattlePhase extends BattlePhase { start() { super.start(); + // cull any extra `NewBattle` phases from the queue. + globalScene.phaseQueue = globalScene.phaseQueue.filter(phase => !(phase instanceof NewBattlePhase)); + // `phaseQueuePrepend` is private, so we have to use this inefficient loop. + while (globalScene.tryRemoveUnshiftedPhase(phase => phase instanceof NewBattlePhase)) {} + globalScene.newBattle(); this.end(); diff --git a/src/phases/new-biome-encounter-phase.ts b/src/phases/new-biome-encounter-phase.ts index bb1fe54fe9f..ef027bfd77a 100644 --- a/src/phases/new-biome-encounter-phase.ts +++ b/src/phases/new-biome-encounter-phase.ts @@ -1,27 +1,23 @@ import { globalScene } from "#app/global-scene"; -import { applyAbAttrs, PostBiomeChangeAbAttr } from "#app/data/ability"; +import { applyAbAttrs, PostBiomeChangeAbAttr } from "#app/data/abilities/ability"; import { getRandomWeatherType } from "#app/data/weather"; import { NextEncounterPhase } from "./next-encounter-phase"; export class NewBiomeEncounterPhase extends NextEncounterPhase { - constructor() { - super(); - } - doEncounter(): void { globalScene.playBgm(undefined, true); + // Reset all battle and wave data, perform form changes, etc. + // We do this because new biomes are considered "arena transitions" akin to MEs and trainer battles for (const pokemon of globalScene.getPlayerParty()) { if (pokemon) { - pokemon.resetBattleData(); - pokemon.customPokemonData.resetHitReceivedCount(); + pokemon.resetBattleAndWaveData(); + if (pokemon.isOnField()) { + applyAbAttrs(PostBiomeChangeAbAttr, pokemon, null); + } } } - for (const pokemon of globalScene.getPlayerParty().filter(p => p.isOnField())) { - applyAbAttrs(PostBiomeChangeAbAttr, pokemon, null); - } - const enemyField = globalScene.getEnemyField(); const moveTargets: any[] = [globalScene.arenaEnemy, enemyField]; const mysteryEncounter = globalScene.currentBattle?.mysteryEncounter?.introVisuals; diff --git a/src/phases/next-encounter-phase.ts b/src/phases/next-encounter-phase.ts index e53f775f083..30b4004363c 100644 --- a/src/phases/next-encounter-phase.ts +++ b/src/phases/next-encounter-phase.ts @@ -1,11 +1,11 @@ import { globalScene } from "#app/global-scene"; import { EncounterPhase } from "./encounter-phase"; +/** + * The phase between defeating an encounter and starting another wild wave. + * Handles generating, loading and preparing for it. + */ export class NextEncounterPhase extends EncounterPhase { - constructor() { - super(); - } - start() { super.start(); } @@ -13,9 +13,12 @@ export class NextEncounterPhase extends EncounterPhase { doEncounter(): void { globalScene.playBgm(undefined, true); + // Reset all player transient wave data/intel before starting a new wild encounter. + // We exclusively reset wave data here as wild waves are considered one continuous "battle" + // for lack of an arena transition. for (const pokemon of globalScene.getPlayerParty()) { if (pokemon) { - pokemon.resetBattleData(); + pokemon.resetWaveData(); } } diff --git a/src/phases/obtain-status-effect-phase.ts b/src/phases/obtain-status-effect-phase.ts index a0c0c14e93f..47cae2dcbf6 100644 --- a/src/phases/obtain-status-effect-phase.ts +++ b/src/phases/obtain-status-effect-phase.ts @@ -6,6 +6,9 @@ import { StatusEffect } from "#app/enums/status-effect"; import type Pokemon from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import { PokemonPhase } from "./pokemon-phase"; +import { SpeciesFormChangeStatusEffectTrigger } from "#app/data/pokemon-forms"; +import { applyPostSetStatusAbAttrs, PostSetStatusAbAttr } from "#app/data/abilities/ability"; +import { isNullOrUndefined } from "#app/utils/common"; export class ObtainStatusEffectPhase extends PokemonPhase { private statusEffect?: StatusEffect; @@ -44,6 +47,12 @@ export class ObtainStatusEffectPhase extends PokemonPhase { this.sourceText ?? undefined, ), ); + if (!isNullOrUndefined(this.statusEffect) && this.statusEffect !== StatusEffect.FAINT) { + globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeStatusEffectTrigger, true); + // If mold breaker etc was used to set this status, it shouldn't apply to abilities activated afterwards + globalScene.arena.setIgnoreAbilities(false); + applyPostSetStatusAbAttrs(PostSetStatusAbAttr, pokemon, this.statusEffect, this.sourcePokemon); + } this.end(); }); return; diff --git a/src/phases/party-heal-phase.ts b/src/phases/party-heal-phase.ts index a9b24309e24..4a9f8a0c888 100644 --- a/src/phases/party-heal-phase.ts +++ b/src/phases/party-heal-phase.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import * as Utils from "#app/utils"; +import { fixedInt } from "#app/utils/common"; import { BattlePhase } from "./battle-phase"; export class PartyHealPhase extends BattlePhase { @@ -21,14 +21,14 @@ export class PartyHealPhase extends BattlePhase { globalScene.ui.fadeOut(1000).then(() => { for (const pokemon of globalScene.getPlayerParty()) { pokemon.hp = pokemon.getMaxHp(); - pokemon.resetStatus(); + pokemon.resetStatus(true, false, false, true); for (const move of pokemon.moveset) { move.ppUsed = 0; } pokemon.updateInfo(true); } const healSong = globalScene.playSoundWithoutBgm("heal"); - globalScene.time.delayedCall(Utils.fixedInt(healSong.totalDuration * 1000), () => { + globalScene.time.delayedCall(fixedInt(healSong.totalDuration * 1000), () => { healSong.destroy(); if (this.resumeBgm && bgmPlaying) { globalScene.playBgm(); diff --git a/src/phases/pokemon-anim-phase.ts b/src/phases/pokemon-anim-phase.ts index b9c91508b5a..1889b238f05 100644 --- a/src/phases/pokemon-anim-phase.ts +++ b/src/phases/pokemon-anim-phase.ts @@ -2,24 +2,24 @@ import { globalScene } from "#app/global-scene"; import { SubstituteTag } from "#app/data/battler-tags"; import type Pokemon from "#app/field/pokemon"; import { BattlePhase } from "#app/phases/battle-phase"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; import { PokemonAnimType } from "#enums/pokemon-anim-type"; import { Species } from "#enums/species"; export class PokemonAnimPhase extends BattlePhase { /** The type of animation to play in this phase */ - private key: PokemonAnimType; + protected key: PokemonAnimType; /** The Pokemon to which this animation applies */ - private pokemon: Pokemon; + protected pokemon: Pokemon; /** Any other field sprites affected by this animation */ - private fieldAssets: Phaser.GameObjects.Sprite[]; + protected fieldAssets: Phaser.GameObjects.Sprite[]; - constructor(key: PokemonAnimType, pokemon: Pokemon, fieldAssets?: Phaser.GameObjects.Sprite[]) { + constructor(key: PokemonAnimType, pokemon: Pokemon, fieldAssets: Phaser.GameObjects.Sprite[] = []) { super(); this.key = key; this.pokemon = pokemon; - this.fieldAssets = fieldAssets ?? []; + this.fieldAssets = fieldAssets; } start(): void { diff --git a/src/phases/pokemon-heal-phase.ts b/src/phases/pokemon-heal-phase.ts index ecfe99389eb..7cb013251f6 100644 --- a/src/phases/pokemon-heal-phase.ts +++ b/src/phases/pokemon-heal-phase.ts @@ -8,7 +8,7 @@ import { getPokemonNameWithAffix } from "#app/messages"; import { HealingBoosterModifier } from "#app/modifier/modifier"; import { HealAchv } from "#app/system/achv"; import i18next from "i18next"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { CommonAnimPhase } from "./common-anim-phase"; import { BattlerTagType } from "#app/enums/battler-tag-type"; import type { HealBlockTag } from "#app/data/battler-tags"; @@ -72,11 +72,11 @@ export class PokemonHealPhase extends CommonAnimPhase { return super.end(); } if (healOrDamage) { - const hpRestoreMultiplier = new Utils.NumberHolder(1); + const hpRestoreMultiplier = new NumberHolder(1); if (!this.revive) { globalScene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier); } - const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value)); + const healAmount = new NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value)); if (healAmount.value < 0) { pokemon.damageAndUpdate(healAmount.value * -1, { result: HitResult.INDIRECT }); healAmount.value = 0; diff --git a/src/phases/pokemon-phase.ts b/src/phases/pokemon-phase.ts index 3ca5f09f953..8c30512cdc4 100644 --- a/src/phases/pokemon-phase.ts +++ b/src/phases/pokemon-phase.ts @@ -11,11 +11,14 @@ export abstract class PokemonPhase extends FieldPhase { constructor(battlerIndex?: BattlerIndex | number) { super(); - if (battlerIndex === undefined) { - battlerIndex = globalScene + battlerIndex = + battlerIndex ?? + globalScene .getField() - .find(p => p?.isActive())! - .getBattlerIndex(); // TODO: is the bang correct here? + .find(p => p?.isActive())! // TODO: is the bang correct here? + .getBattlerIndex(); + if (battlerIndex === undefined) { + console.warn("There are no Pokemon on the field!"); // TODO: figure out a suitable fallback behavior } this.battlerIndex = battlerIndex; diff --git a/src/phases/post-game-over-phase.ts b/src/phases/post-game-over-phase.ts index f86ec8496e0..753251e992f 100644 --- a/src/phases/post-game-over-phase.ts +++ b/src/phases/post-game-over-phase.ts @@ -4,12 +4,12 @@ import type { EndCardPhase } from "./end-card-phase"; import { TitlePhase } from "./title-phase"; export class PostGameOverPhase extends Phase { - private endCardPhase: EndCardPhase | null; + private endCardPhase?: EndCardPhase; constructor(endCardPhase?: EndCardPhase) { super(); - this.endCardPhase = endCardPhase!; // TODO: is this bang correct? + this.endCardPhase = endCardPhase; } start() { diff --git a/src/phases/post-summon-phase.ts b/src/phases/post-summon-phase.ts index 45b0a0f65ce..446d45bb2fa 100644 --- a/src/phases/post-summon-phase.ts +++ b/src/phases/post-summon-phase.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { applyAbAttrs, applyPostSummonAbAttrs, CommanderAbAttr, PostSummonAbAttr } from "#app/data/ability"; +import { applyAbAttrs, applyPostSummonAbAttrs, CommanderAbAttr, PostSummonAbAttr } from "#app/data/abilities/ability"; import { ArenaTrapTag } from "#app/data/arena-tag"; import { StatusEffect } from "#app/enums/status-effect"; import { PokemonPhase } from "./pokemon-phase"; diff --git a/src/phases/post-turn-status-effect-phase.ts b/src/phases/post-turn-status-effect-phase.ts index f6341666e7e..9b530d48196 100644 --- a/src/phases/post-turn-status-effect-phase.ts +++ b/src/phases/post-turn-status-effect-phase.ts @@ -7,13 +7,13 @@ import { BlockStatusDamageAbAttr, PostDamageAbAttr, ReduceBurnDamageAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; import { CommonBattleAnim, CommonAnim } from "#app/data/battle-anims"; import { getStatusEffectActivationText } from "#app/data/status-effect"; import { BattleSpec } from "#app/enums/battle-spec"; import { StatusEffect } from "#app/enums/status-effect"; import { getPokemonNameWithAffix } from "#app/messages"; -import * as Utils from "#app/utils"; +import { BooleanHolder, NumberHolder } from "#app/utils/common"; import { PokemonPhase } from "./pokemon-phase"; export class PostTurnStatusEffectPhase extends PokemonPhase { @@ -26,7 +26,7 @@ export class PostTurnStatusEffectPhase extends PokemonPhase { const pokemon = this.getPokemon(); if (pokemon?.isActive(true) && pokemon.status && pokemon.status.isPostTurn() && !pokemon.switchOutStatus) { pokemon.status.incrementTurn(); - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); applyAbAttrs(BlockStatusDamageAbAttr, pokemon, cancelled); @@ -34,7 +34,7 @@ export class PostTurnStatusEffectPhase extends PokemonPhase { globalScene.queueMessage( getStatusEffectActivationText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)), ); - const damage = new Utils.NumberHolder(0); + const damage = new NumberHolder(0); switch (pokemon.status.effect) { case StatusEffect.POISON: damage.value = Math.max(pokemon.getMaxHp() >> 3, 1); diff --git a/src/phases/quiet-form-change-phase.ts b/src/phases/quiet-form-change-phase.ts index 1512609abf9..76411f62f77 100644 --- a/src/phases/quiet-form-change-phase.ts +++ b/src/phases/quiet-form-change-phase.ts @@ -16,7 +16,7 @@ import { ClearTerrainAbAttr, ClearWeatherAbAttr, PostTeraFormChangeStatChangeAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; export class QuietFormChangePhase extends BattlePhase { protected pokemon: Pokemon; @@ -74,7 +74,7 @@ export class QuietFormChangePhase extends BattlePhase { isTerastallized: this.pokemon.isTerastallized, }); ["spriteColors", "fusionSpriteColors"].map(k => { - if (this.pokemon.summonData?.speciesForm) { + if (this.pokemon.summonData.speciesForm) { k += "Base"; } sprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k]; diff --git a/src/phases/reload-session-phase.ts b/src/phases/reload-session-phase.ts index 3a4a4e0e3a5..8cd5f67b43a 100644 --- a/src/phases/reload-session-phase.ts +++ b/src/phases/reload-session-phase.ts @@ -1,24 +1,24 @@ import { globalScene } from "#app/global-scene"; import { Phase } from "#app/phase"; -import { Mode } from "#app/ui/ui"; -import * as Utils from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import { fixedInt } from "#app/utils/common"; export class ReloadSessionPhase extends Phase { - private systemDataStr: string | null; + private systemDataStr?: string; constructor(systemDataStr?: string) { super(); - this.systemDataStr = systemDataStr ?? null; + this.systemDataStr = systemDataStr; } start(): void { - globalScene.ui.setMode(Mode.SESSION_RELOAD); + globalScene.ui.setMode(UiMode.SESSION_RELOAD); let delayElapsed = false; let loaded = false; - globalScene.time.delayedCall(Utils.fixedInt(1500), () => { + globalScene.time.delayedCall(fixedInt(1500), () => { if (loaded) { this.end(); } else { diff --git a/src/phases/reset-status-phase.ts b/src/phases/reset-status-phase.ts new file mode 100644 index 00000000000..19bfc3027e2 --- /dev/null +++ b/src/phases/reset-status-phase.ts @@ -0,0 +1,26 @@ +import type Pokemon from "#app/field/pokemon"; +import { BattlePhase } from "#app/phases/battle-phase"; + +/** + * Phase which handles resetting a Pokemon's status to none + * + * This is necessary to perform in a phase primarly to ensure that the status icon disappears at the correct time in the battle + */ +export class ResetStatusPhase extends BattlePhase { + private readonly pokemon: Pokemon; + private readonly affectConfusion: boolean; + private readonly reloadAssets: boolean; + + constructor(pokemon: Pokemon, affectConfusion: boolean, reloadAssets: boolean) { + super(); + + this.pokemon = pokemon; + this.affectConfusion = affectConfusion; + this.reloadAssets = reloadAssets; + } + + public override start() { + this.pokemon.clearStatus(this.affectConfusion, this.reloadAssets); + this.end(); + } +} diff --git a/src/phases/revival-blessing-phase.ts b/src/phases/revival-blessing-phase.ts index e650d714abc..598d9109abc 100644 --- a/src/phases/revival-blessing-phase.ts +++ b/src/phases/revival-blessing-phase.ts @@ -2,9 +2,9 @@ import { SwitchType } from "#enums/switch-type"; import { globalScene } from "#app/global-scene"; import type { PartyOption } from "#app/ui/party-ui-handler"; import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; -import * as Utils from "#app/utils"; +import { toDmgValue, isNullOrUndefined } from "#app/utils/common"; import { BattlePhase } from "#app/phases/battle-phase"; import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase"; @@ -21,7 +21,7 @@ export class RevivalBlessingPhase extends BattlePhase { public override start(): void { globalScene.ui.setMode( - Mode.PARTY, + UiMode.PARTY, PartyUiMode.REVIVAL_BLESSING, this.user.getFieldIndex(), (slotIndex: integer, _option: PartyOption) => { @@ -32,8 +32,8 @@ export class RevivalBlessingPhase extends BattlePhase { } pokemon.resetTurnData(); - pokemon.resetStatus(); - pokemon.heal(Math.min(Utils.toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); + pokemon.resetStatus(true, false, false, false); + pokemon.heal(Math.min(toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); globalScene.queueMessage( i18next.t("moveTriggers:revivalBlessing", { pokemonName: pokemon.name, @@ -46,7 +46,7 @@ export class RevivalBlessingPhase extends BattlePhase { if ( globalScene.currentBattle.double && globalScene.getPlayerParty().length > 1 && - !Utils.isNullOrUndefined(allyPokemon) + !isNullOrUndefined(allyPokemon) ) { if (slotIndex <= 1) { // Revived ally pokemon @@ -63,7 +63,7 @@ export class RevivalBlessingPhase extends BattlePhase { } } } - globalScene.ui.setMode(Mode.MESSAGE).then(() => this.end()); + globalScene.ui.setMode(UiMode.MESSAGE).then(() => this.end()); }, PartyUiHandler.FilterFainted, ); diff --git a/src/phases/ribbon-modifier-reward-phase.ts b/src/phases/ribbon-modifier-reward-phase.ts index 0ee38250ce1..21114ab3de9 100644 --- a/src/phases/ribbon-modifier-reward-phase.ts +++ b/src/phases/ribbon-modifier-reward-phase.ts @@ -1,7 +1,7 @@ import { globalScene } from "#app/global-scene"; import type PokemonSpecies from "#app/data/pokemon-species"; import type { ModifierTypeFunc } from "#app/modifier/modifier-type"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { ModifierRewardPhase } from "./modifier-reward-phase"; @@ -19,7 +19,7 @@ export class RibbonModifierRewardPhase extends ModifierRewardPhase { const newModifier = this.modifierType.newModifier(); globalScene.addModifier(newModifier); globalScene.playSound("level_up_fanfare"); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText( i18next.t("battle:beatModeFirstTime", { speciesName: this.species.name, diff --git a/src/phases/scan-ivs-phase.ts b/src/phases/scan-ivs-phase.ts index 2a2d68591ca..d79a32bd47e 100644 --- a/src/phases/scan-ivs-phase.ts +++ b/src/phases/scan-ivs-phase.ts @@ -3,11 +3,12 @@ import type { BattlerIndex } from "#app/battle"; import { PERMANENT_STATS, Stat } from "#app/enums/stat"; import { getPokemonNameWithAffix } from "#app/messages"; import { getTextColor, TextStyle } from "#app/ui/text"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { PokemonPhase } from "./pokemon-phase"; export class ScanIvsPhase extends PokemonPhase { + // biome-ignore lint/complexity/noUselessConstructor: This changes `battlerIndex` to be required constructor(battlerIndex: BattlerIndex) { super(battlerIndex); } @@ -24,7 +25,8 @@ export class ScanIvsPhase extends PokemonPhase { const uiTheme = globalScene.uiTheme; // Assuming uiTheme is accessible for (let e = 0; e < enemyField.length; e++) { enemyIvs = enemyField[e].ivs; - const currentIvs = globalScene.gameData.dexData[enemyField[e].species.getRootSpeciesId()].ivs; // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists + // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists + const currentIvs = globalScene.gameData.dexData[enemyField[e].species.getRootSpeciesId()].ivs; statsContainer = enemyField[e].getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[]; statsContainerLabels = statsContainer.filter(m => m.name.indexOf("icon_stat_label") >= 0); for (let s = 0; s < statsContainerLabels.length; s++) { @@ -49,9 +51,9 @@ export class ScanIvsPhase extends PokemonPhase { null, () => { globalScene.ui.setMode( - Mode.CONFIRM, + UiMode.CONFIRM, () => { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.clearText(); globalScene.ui .getMessageHandler() @@ -59,7 +61,7 @@ export class ScanIvsPhase extends PokemonPhase { .then(() => this.end()); }, () => { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.clearText(); this.end(); }, diff --git a/src/phases/select-biome-phase.ts b/src/phases/select-biome-phase.ts index 6a11967832a..4811c4e6b8f 100644 --- a/src/phases/select-biome-phase.ts +++ b/src/phases/select-biome-phase.ts @@ -3,24 +3,21 @@ import { biomeLinks, getBiomeName } from "#app/data/balance/biomes"; import { Biome } from "#app/enums/biome"; import { MoneyInterestModifier, MapModifier } from "#app/modifier/modifier"; import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { BattlePhase } from "./battle-phase"; -import * as Utils from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import { PartyHealPhase } from "./party-heal-phase"; import { SwitchBiomePhase } from "./switch-biome-phase"; export class SelectBiomePhase extends BattlePhase { - constructor() { - super(); - } - start() { super.start(); const currentBiome = globalScene.arena.biomeType; + const nextWaveIndex = globalScene.currentBattle.waveIndex + 1; const setNextBiome = (nextBiome: Biome) => { - if (globalScene.currentBattle.waveIndex % 10 === 1) { + if (nextWaveIndex % 10 === 1) { globalScene.applyModifiers(MoneyInterestModifier, true); globalScene.unshiftPhase(new PartyHealPhase(false)); } @@ -29,60 +26,48 @@ export class SelectBiomePhase extends BattlePhase { }; if ( - (globalScene.gameMode.isClassic && globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex + 9)) || - (globalScene.gameMode.isDaily && globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) || - (globalScene.gameMode.hasShortBiomes && !(globalScene.currentBattle.waveIndex % 50)) + (globalScene.gameMode.isClassic && globalScene.gameMode.isWaveFinal(nextWaveIndex + 9)) || + (globalScene.gameMode.isDaily && globalScene.gameMode.isWaveFinal(nextWaveIndex)) || + (globalScene.gameMode.hasShortBiomes && !(nextWaveIndex % 50)) ) { setNextBiome(Biome.END); } else if (globalScene.gameMode.hasRandomBiomes) { - setNextBiome(this.generateNextBiome()); + setNextBiome(this.generateNextBiome(nextWaveIndex)); } else if (Array.isArray(biomeLinks[currentBiome])) { - let biomes: Biome[] = []; - globalScene.executeWithSeedOffset(() => { - biomes = (biomeLinks[currentBiome] as (Biome | [Biome, number])[]) - .filter(b => !Array.isArray(b) || !Utils.randSeedInt(b[1])) - .map(b => (!Array.isArray(b) ? b : b[0])); - }, globalScene.currentBattle.waveIndex); + const biomes: Biome[] = (biomeLinks[currentBiome] as (Biome | [Biome, number])[]) + .filter(b => !Array.isArray(b) || !randSeedInt(b[1])) + .map(b => (!Array.isArray(b) ? b : b[0])); + if (biomes.length > 1 && globalScene.findModifier(m => m instanceof MapModifier)) { - let biomeChoices: Biome[] = []; - globalScene.executeWithSeedOffset(() => { - biomeChoices = ( - !Array.isArray(biomeLinks[currentBiome]) - ? [biomeLinks[currentBiome] as Biome] - : (biomeLinks[currentBiome] as (Biome | [Biome, number])[]) - ) - .filter((b, _i) => !Array.isArray(b) || !Utils.randSeedInt(b[1])) - .map(b => (Array.isArray(b) ? b[0] : b)); - }, globalScene.currentBattle.waveIndex); - const biomeSelectItems = biomeChoices.map(b => { + const biomeSelectItems = biomes.map(b => { const ret: OptionSelectItem = { label: getBiomeName(b), handler: () => { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); setNextBiome(b); return true; }, }; return ret; }); - globalScene.ui.setMode(Mode.OPTION_SELECT, { + globalScene.ui.setMode(UiMode.OPTION_SELECT, { options: biomeSelectItems, delay: 1000, }); } else { - setNextBiome(biomes[Utils.randSeedInt(biomes.length)]); + setNextBiome(biomes[randSeedInt(biomes.length)]); } } else if (biomeLinks.hasOwnProperty(currentBiome)) { setNextBiome(biomeLinks[currentBiome] as Biome); } else { - setNextBiome(this.generateNextBiome()); + setNextBiome(this.generateNextBiome(nextWaveIndex)); } } - generateNextBiome(): Biome { - if (!(globalScene.currentBattle.waveIndex % 50)) { + generateNextBiome(waveIndex: number): Biome { + if (!(waveIndex % 50)) { return Biome.END; } - return globalScene.generateRandomBiome(globalScene.currentBattle.waveIndex); + return globalScene.generateRandomBiome(waveIndex); } } diff --git a/src/phases/select-challenge-phase.ts b/src/phases/select-challenge-phase.ts index 2a6797d3556..76ac8a60c4f 100644 --- a/src/phases/select-challenge-phase.ts +++ b/src/phases/select-challenge-phase.ts @@ -1,17 +1,13 @@ import { globalScene } from "#app/global-scene"; import { Phase } from "#app/phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; export class SelectChallengePhase extends Phase { - constructor() { - super(); - } - start() { super.start(); globalScene.playBgm("menu"); - globalScene.ui.setMode(Mode.CHALLENGE_SELECT); + globalScene.ui.setMode(UiMode.CHALLENGE_SELECT); } } diff --git a/src/phases/select-gender-phase.ts b/src/phases/select-gender-phase.ts index 1c86536de53..a1171c1a5db 100644 --- a/src/phases/select-gender-phase.ts +++ b/src/phases/select-gender-phase.ts @@ -2,19 +2,15 @@ import { globalScene } from "#app/global-scene"; import { PlayerGender } from "#app/enums/player-gender"; import { Phase } from "#app/phase"; import { SettingKeys } from "#app/system/settings/settings"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; export class SelectGenderPhase extends Phase { - constructor() { - super(); - } - start(): void { super.start(); globalScene.ui.showText(i18next.t("menu:boyOrGirl"), null, () => { - globalScene.ui.setMode(Mode.OPTION_SELECT, { + globalScene.ui.setMode(UiMode.OPTION_SELECT, { options: [ { label: i18next.t("settings:boy"), @@ -40,7 +36,7 @@ export class SelectGenderPhase extends Phase { } end(): void { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); super.end(); } } diff --git a/src/phases/select-modifier-phase.ts b/src/phases/select-modifier-phase.ts index 11d448876d3..5f11441333b 100644 --- a/src/phases/select-modifier-phase.ts +++ b/src/phases/select-modifier-phase.ts @@ -24,13 +24,12 @@ import { import type ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler"; import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; -import * as Utils from "#app/utils"; import { BattlePhase } from "./battle-phase"; import Overrides from "#app/overrides"; import type { CustomModifierSettings } from "#app/modifier/modifier-type"; -import { isNullOrUndefined, NumberHolder } from "#app/utils"; +import { isNullOrUndefined, NumberHolder } from "#app/utils/common"; export class SelectModifierPhase extends BattlePhase { private rerollCount: number; @@ -67,7 +66,7 @@ export class SelectModifierPhase extends BattlePhase { if (!this.isCopy) { regenerateModifierPoolThresholds(party, this.getPoolType(), this.rerollCount); } - const modifierCount = new Utils.NumberHolder(3); + const modifierCount = new NumberHolder(3); if (this.isPlayer()) { globalScene.applyModifiers(ExtraModifierModifier, true, modifierCount); globalScene.applyModifiers(TempExtraModifierModifier, true, modifierCount); @@ -93,15 +92,15 @@ export class SelectModifierPhase extends BattlePhase { if (rowCursor < 0 || cursor < 0) { globalScene.ui.showText(i18next.t("battle:skipItemQuestion"), null, () => { globalScene.ui.setOverlayMode( - Mode.CONFIRM, + UiMode.CONFIRM, () => { globalScene.ui.revertMode(); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); super.end(); }, () => globalScene.ui.setMode( - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, @@ -130,7 +129,7 @@ export class SelectModifierPhase extends BattlePhase { ), ); globalScene.ui.clearText(); - globalScene.ui.setMode(Mode.MESSAGE).then(() => super.end()); + globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end()); if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) { globalScene.money -= rerollCost; globalScene.updateMoneyText(); @@ -140,7 +139,7 @@ export class SelectModifierPhase extends BattlePhase { break; case 1: globalScene.ui.setModeWithoutClear( - Mode.PARTY, + UiMode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: number, itemIndex: number, itemQuantity: number, toSlotIndex: number) => { @@ -169,7 +168,7 @@ export class SelectModifierPhase extends BattlePhase { ); } else { globalScene.ui.setMode( - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, @@ -181,9 +180,9 @@ export class SelectModifierPhase extends BattlePhase { ); break; case 2: - globalScene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.CHECK, -1, () => { + globalScene.ui.setModeWithoutClear(UiMode.PARTY, PartyUiMode.CHECK, -1, () => { globalScene.ui.setMode( - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, @@ -208,7 +207,7 @@ export class SelectModifierPhase extends BattlePhase { case 1: if (this.typeOptions.length === 0) { globalScene.ui.clearText(); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); super.end(); return true; } @@ -264,7 +263,7 @@ export class SelectModifierPhase extends BattlePhase { } } else { globalScene.ui.clearText(); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); super.end(); } }; @@ -273,7 +272,7 @@ export class SelectModifierPhase extends BattlePhase { //TODO: is the bang correct? if (modifierType instanceof FusePokemonModifierType) { globalScene.ui.setModeWithoutClear( - Mode.PARTY, + UiMode.PARTY, PartyUiMode.SPLICE, -1, (fromSlotIndex: number, spliceSlotIndex: number) => { @@ -283,13 +282,13 @@ export class SelectModifierPhase extends BattlePhase { spliceSlotIndex < 6 && fromSlotIndex !== spliceSlotIndex ) { - globalScene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { + globalScene.ui.setMode(UiMode.MODIFIER_SELECT, this.isPlayer()).then(() => { const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex])!; //TODO: is the bang correct? applyModifier(modifier, true); }); } else { globalScene.ui.setMode( - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, @@ -315,12 +314,12 @@ export class SelectModifierPhase extends BattlePhase { : PartyUiMode.MODIFIER; const tmMoveId = isTmModifier ? (modifierType as TmModifierType).moveId : undefined; globalScene.ui.setModeWithoutClear( - Mode.PARTY, + UiMode.PARTY, partyUiMode, -1, (slotIndex: number, option: PartyOption) => { if (slotIndex < 6) { - globalScene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { + globalScene.ui.setMode(UiMode.MODIFIER_SELECT, this.isPlayer()).then(() => { const modifier = !isMoveModifier ? !isRememberMoveModifier ? modifierType.newModifier(party[slotIndex]) @@ -330,7 +329,7 @@ export class SelectModifierPhase extends BattlePhase { }); } else { globalScene.ui.setMode( - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, @@ -353,7 +352,7 @@ export class SelectModifierPhase extends BattlePhase { return !cost!; // TODO: is the bang correct? }; globalScene.ui.setMode( - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, diff --git a/src/phases/select-starter-phase.ts b/src/phases/select-starter-phase.ts index b3ebe6731c9..0a76df31a2c 100644 --- a/src/phases/select-starter-phase.ts +++ b/src/phases/select-starter-phase.ts @@ -9,24 +9,20 @@ import { Phase } from "#app/phase"; import { TitlePhase } from "#app/phases/title-phase"; import { SaveSlotUiMode } from "#app/ui/save-slot-select-ui-handler"; import type { Starter } from "#app/ui/starter-select-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type { Species } from "#enums/species"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; -import * as Utils from "../utils"; +import { isNullOrUndefined } from "#app/utils/common"; export class SelectStarterPhase extends Phase { - constructor() { - super(); - } - start() { super.start(); globalScene.playBgm("menu"); - globalScene.ui.setMode(Mode.STARTER_SELECT, (starters: Starter[]) => { + globalScene.ui.setMode(UiMode.STARTER_SELECT, (starters: Starter[]) => { globalScene.ui.clearText(); - globalScene.ui.setMode(Mode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => { + globalScene.ui.setMode(UiMode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => { if (slotId === -1) { globalScene.clearPhaseQueue(); globalScene.pushPhase(new TitlePhase()); @@ -53,7 +49,7 @@ export class SelectStarterPhase extends Phase { let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0)); if ( starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES && - !Utils.isNullOrUndefined(Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]) && + !isNullOrUndefined(Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]) && starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!] ) { starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!; @@ -91,7 +87,7 @@ export class SelectStarterPhase extends Phase { starterPokemon.nickname = starter.nickname; } - if (!Utils.isNullOrUndefined(starter.teraType)) { + if (!isNullOrUndefined(starter.teraType)) { starterPokemon.teraType = starter.teraType; } else { starterPokemon.teraType = starterPokemon.species.type1; diff --git a/src/phases/select-target-phase.ts b/src/phases/select-target-phase.ts index 2042d0a3fcf..c969b9ca421 100644 --- a/src/phases/select-target-phase.ts +++ b/src/phases/select-target-phase.ts @@ -1,13 +1,14 @@ import { globalScene } from "#app/global-scene"; import type { BattlerIndex } from "#app/battle"; import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { CommandPhase } from "./command-phase"; import { PokemonPhase } from "./pokemon-phase"; import i18next from "#app/plugins/i18n"; import { allMoves } from "#app/data/moves/move"; export class SelectTargetPhase extends PokemonPhase { + // biome-ignore lint/complexity/noUselessConstructor: This makes `fieldIndex` required constructor(fieldIndex: number) { super(fieldIndex); } @@ -17,8 +18,8 @@ export class SelectTargetPhase extends PokemonPhase { const turnCommand = globalScene.currentBattle.turnCommands[this.fieldIndex]; const move = turnCommand?.move?.move; - globalScene.ui.setMode(Mode.TARGET_SELECT, this.fieldIndex, move, (targets: BattlerIndex[]) => { - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.TARGET_SELECT, this.fieldIndex, move, (targets: BattlerIndex[]) => { + globalScene.ui.setMode(UiMode.MESSAGE); const fieldSide = globalScene.getField(); const user = fieldSide[this.fieldIndex]; const moveObject = allMoves[move!]; diff --git a/src/phases/shiny-sparkle-phase.ts b/src/phases/shiny-sparkle-phase.ts index 2540d98fb79..87a7db29cf6 100644 --- a/src/phases/shiny-sparkle-phase.ts +++ b/src/phases/shiny-sparkle-phase.ts @@ -3,6 +3,7 @@ import type { BattlerIndex } from "#app/battle"; import { PokemonPhase } from "./pokemon-phase"; export class ShinySparklePhase extends PokemonPhase { + // biome-ignore lint/complexity/noUselessConstructor: This makes `battlerIndex` required constructor(battlerIndex: BattlerIndex) { super(battlerIndex); } diff --git a/src/phases/show-ability-phase.ts b/src/phases/show-ability-phase.ts index 8097af33fe0..d6193ac3946 100644 --- a/src/phases/show-ability-phase.ts +++ b/src/phases/show-ability-phase.ts @@ -50,9 +50,7 @@ export class ShowAbilityPhase extends PokemonPhase { } globalScene.abilityBar.showAbility(this.pokemonName, this.abilityName, this.passive, this.player).then(() => { - if (pokemon?.battleData) { - pokemon.battleData.abilityRevealed = true; - } + pokemon.waveData.abilityRevealed = true; this.end(); }); diff --git a/src/phases/show-party-exp-bar-phase.ts b/src/phases/show-party-exp-bar-phase.ts index 568b8b615c8..89bec6d8fdd 100644 --- a/src/phases/show-party-exp-bar-phase.ts +++ b/src/phases/show-party-exp-bar-phase.ts @@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene"; import { ExpGainsSpeed } from "#app/enums/exp-gains-speed"; import { ExpNotification } from "#app/enums/exp-notification"; import { ExpBoosterModifier } from "#app/modifier/modifier"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { HidePartyExpBarPhase } from "./hide-party-exp-bar-phase"; import { LevelUpPhase } from "./level-up-phase"; import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase"; @@ -20,7 +20,7 @@ export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase { super.start(); const pokemon = this.getPokemon(); - const exp = new Utils.NumberHolder(this.expValue); + const exp = new NumberHolder(this.expValue); globalScene.applyModifiers(ExpBoosterModifier, true, exp); exp.value = Math.floor(exp.value); diff --git a/src/phases/show-trainer-phase.ts b/src/phases/show-trainer-phase.ts index 740c11f5c5d..b6c1e345c70 100644 --- a/src/phases/show-trainer-phase.ts +++ b/src/phases/show-trainer-phase.ts @@ -3,10 +3,6 @@ import { PlayerGender } from "#app/enums/player-gender"; import { BattlePhase } from "./battle-phase"; export class ShowTrainerPhase extends BattlePhase { - constructor() { - super(); - } - start() { super.start(); diff --git a/src/phases/stat-stage-change-phase.ts b/src/phases/stat-stage-change-phase.ts index 4c82661a3bb..6731e45025c 100644 --- a/src/phases/stat-stage-change-phase.ts +++ b/src/phases/stat-stage-change-phase.ts @@ -10,14 +10,14 @@ import { ReflectStatStageChangeAbAttr, StatStageChangeCopyAbAttr, StatStageChangeMultiplierAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; import { ArenaTagSide, MistTag } from "#app/data/arena-tag"; import type { ArenaTag } from "#app/data/arena-tag"; import type Pokemon from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import { ResetNegativeStatStageModifier } from "#app/modifier/modifier"; import { handleTutorial, Tutorial } from "#app/tutorial"; -import { NumberHolder, BooleanHolder, isNullOrUndefined } from "#app/utils"; +import { NumberHolder, BooleanHolder, isNullOrUndefined } from "#app/utils/common"; import i18next from "i18next"; import { PokemonPhase } from "./pokemon-phase"; import { Stat, type BattleStat, getStatKey, getStatStageChangeDescriptionKey } from "#enums/stat"; @@ -217,16 +217,8 @@ export class StatStageChangePhase extends PokemonPhase { for (const s of filteredStats) { if (stages.value > 0 && pokemon.getStatStage(s) < 6) { - if (!pokemon.turnData) { - // Temporary fix for missing turn data struct on turn 1 - pokemon.resetTurnData(); - } pokemon.turnData.statStagesIncreased = true; } else if (stages.value < 0 && pokemon.getStatStage(s) > -6) { - if (!pokemon.turnData) { - // Temporary fix for missing turn data struct on turn 1 - pokemon.resetTurnData(); - } pokemon.turnData.statStagesDecreased = true; } diff --git a/src/phases/summon-missing-phase.ts b/src/phases/summon-missing-phase.ts index 32bc7495dce..a692455ce47 100644 --- a/src/phases/summon-missing-phase.ts +++ b/src/phases/summon-missing-phase.ts @@ -4,10 +4,6 @@ import { SummonPhase } from "./summon-phase"; import { globalScene } from "#app/global-scene"; export class SummonMissingPhase extends SummonPhase { - constructor(fieldIndex: number) { - super(fieldIndex); - } - preSummon(): void { globalScene.ui.showText( i18next.t("battle:sendOutPokemon", { diff --git a/src/phases/summon-phase.ts b/src/phases/summon-phase.ts index 621c8c8c2a9..fef9b356348 100644 --- a/src/phases/summon-phase.ts +++ b/src/phases/summon-phase.ts @@ -1,4 +1,4 @@ -import { BattleType } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; import { TrainerSlot } from "#enums/trainer-slot"; @@ -13,6 +13,7 @@ import { PostSummonPhase } from "./post-summon-phase"; import { GameOverPhase } from "./game-over-phase"; import { ShinySparklePhase } from "./shiny-sparkle-phase"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; +import { applyPreSummonAbAttrs, PreSummonAbAttr } from "#app/data/abilities/ability"; import { globalScene } from "#app/global-scene"; export class SummonPhase extends PartyMemberPokemonPhase { @@ -27,6 +28,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { start() { super.start(); + applyPreSummonAbAttrs(PreSummonAbAttr, this.getPokemon()); this.preSummon(); } @@ -126,7 +128,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { this.player ? 36 : 248, this.player ? 80 : 44, "pb", - getPokeballAtlasKey(pokemon.pokeball), + getPokeballAtlasKey(pokemon.getPokeball(true)), ); pokeball.setVisible(false); pokeball.setOrigin(0.5, 0.625); @@ -175,7 +177,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { } globalScene.currentBattle.seenEnemyPartyMemberIds.add(pokemon.id); } - addPokeballOpenParticles(pokemon.x, pokemon.y - 16, pokemon.pokeball); + addPokeballOpenParticles(pokemon.x, pokemon.y - 16, pokemon.getPokeball(true)); globalScene.updateModifiers(this.player); globalScene.updateFieldScale(); pokemon.showInfo(); @@ -183,7 +185,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { pokemon.setVisible(true); pokemon.getSprite().setVisible(true); pokemon.setScale(0.5); - pokemon.tint(getPokeballTintColor(pokemon.pokeball)); + pokemon.tint(getPokeballTintColor(pokemon.getPokeball(true))); pokemon.untint(250, "Sine.easeIn"); globalScene.updateFieldScale(); globalScene.tweens.add({ @@ -194,9 +196,8 @@ export class SummonPhase extends PartyMemberPokemonPhase { onComplete: () => { pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); pokemon.getSprite().clearTint(); - pokemon.resetSummonData(); // necessary to stay transformed during wild waves - if (pokemon.summonData?.speciesForm) { + if (pokemon.summonData.speciesForm) { pokemon.loadAssets(false); } globalScene.time.delayedCall(1000, () => this.end()); @@ -260,7 +261,6 @@ export class SummonPhase extends PartyMemberPokemonPhase { onComplete: () => { pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); pokemon.getSprite().clearTint(); - pokemon.resetSummonData(); globalScene.updateFieldScale(); globalScene.time.delayedCall(1000, () => this.end()); }, @@ -270,7 +270,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { onEnd(): void { const pokemon = this.getPokemon(); - if (pokemon.isShiny()) { + if (pokemon.isShiny(true)) { globalScene.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex())); } diff --git a/src/phases/switch-biome-phase.ts b/src/phases/switch-biome-phase.ts index 2dd2a642f43..f708830318e 100644 --- a/src/phases/switch-biome-phase.ts +++ b/src/phases/switch-biome-phase.ts @@ -19,6 +19,10 @@ export class SwitchBiomePhase extends BattlePhase { return this.end(); } + // Before switching biomes, make sure to set the last encounter for other phases that need it too. + globalScene.lastEnemyTrainer = globalScene.currentBattle?.trainer ?? null; + globalScene.lastMysteryEncounter = globalScene.currentBattle?.mysteryEncounter; + globalScene.tweens.add({ targets: [globalScene.arenaEnemy, globalScene.lastEnemyTrainer], x: "+=300", diff --git a/src/phases/switch-phase.ts b/src/phases/switch-phase.ts index 8562309ede5..c056b186021 100644 --- a/src/phases/switch-phase.ts +++ b/src/phases/switch-phase.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import PartyUiHandler, { PartyOption, PartyUiMode } from "#app/ui/party-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { SwitchType } from "#enums/switch-type"; import { BattlePhase } from "./battle-phase"; import { PostSummonPhase } from "./post-summon-phase"; @@ -69,7 +69,7 @@ export class SwitchPhase extends BattlePhase { : 0; globalScene.ui.setMode( - Mode.PARTY, + UiMode.PARTY, this.isModal ? PartyUiMode.FAINT_SWITCH : PartyUiMode.POST_BATTLE_SWITCH, fieldIndex, (slotIndex: number, option: PartyOption) => { @@ -80,7 +80,7 @@ export class SwitchPhase extends BattlePhase { const switchType = option === PartyOption.PASS_BATON ? SwitchType.BATON_PASS : this.switchType; globalScene.unshiftPhase(new SwitchSummonPhase(switchType, fieldIndex, slotIndex, this.doReturn)); } - globalScene.ui.setMode(Mode.MESSAGE).then(() => super.end()); + globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end()); }, PartyUiHandler.FilterNonFainted, ); diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index 16868bf9bc0..bb31f87cc3d 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -1,5 +1,11 @@ import { globalScene } from "#app/global-scene"; -import { applyPreSwitchOutAbAttrs, PostDamageForceSwitchAbAttr, PreSwitchOutAbAttr } from "#app/data/ability"; +import { + applyPreSummonAbAttrs, + applyPreSwitchOutAbAttrs, + PostDamageForceSwitchAbAttr, + PreSummonAbAttr, + PreSwitchOutAbAttr, +} from "#app/data/abilities/ability"; import { allMoves, ForceSwitchOutAttr } from "#app/data/moves/move"; import { getPokeballTintColor } from "#app/data/pokeball"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; @@ -23,14 +29,14 @@ export class SwitchSummonPhase extends SummonPhase { /** * Constructor for creating a new SwitchSummonPhase - * @param switchType the type of switch behavior - * @param fieldIndex integer representing position on the battle field - * @param slotIndex integer for the index of pokemon (in party of 6) to switch into - * @param doReturn boolean whether to render "comeback" dialogue - * @param player boolean if the switch is from the player + * @param switchType - The type of switch behavior + * @param fieldIndex - Position on the battle field + * @param slotIndex - The index of pokemon (in party of 6) to switch into + * @param doReturn - Whether to render "comeback" dialogue + * @param player - Whether the switch came from the player or enemy; default `true` */ - constructor(switchType: SwitchType, fieldIndex: number, slotIndex: number, doReturn: boolean, player?: boolean) { - super(fieldIndex, player !== undefined ? player : true); + constructor(switchType: SwitchType, fieldIndex: number, slotIndex: number, doReturn: boolean, player = true) { + super(fieldIndex, player); this.switchType = switchType; this.slotIndex = slotIndex; @@ -61,7 +67,8 @@ export class SwitchSummonPhase extends SummonPhase { !(this.player ? globalScene.getPlayerParty() : globalScene.getEnemyParty())[this.slotIndex]) ) { if (this.player) { - return this.switchAndSummon(); + this.switchAndSummon(); + return; } globalScene.time.delayedCall(750, () => this.switchAndSummon()); return; @@ -99,7 +106,7 @@ export class SwitchSummonPhase extends SummonPhase { ); globalScene.playSound("se/pb_rel"); pokemon.hideInfo(); - pokemon.tint(getPokeballTintColor(pokemon.pokeball), 1, 250, "Sine.easeIn"); + pokemon.tint(getPokeballTintColor(pokemon.getPokeball(true)), 1, 250, "Sine.easeIn"); globalScene.tweens.add({ targets: pokemon, duration: 250, @@ -114,13 +121,23 @@ export class SwitchSummonPhase extends SummonPhase { switchAndSummon() { const party = this.player ? this.getParty() : globalScene.getEnemyParty(); - const switchedInPokemon = party[this.slotIndex]; + const switchedInPokemon: Pokemon | undefined = party[this.slotIndex]; this.lastPokemon = this.getPokemon(); + + applyPreSummonAbAttrs(PreSummonAbAttr, switchedInPokemon); applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, this.lastPokemon); - if (this.switchType === SwitchType.BATON_PASS && switchedInPokemon) { - (this.player ? globalScene.getEnemyField() : globalScene.getPlayerField()).forEach(enemyPokemon => + if (!switchedInPokemon) { + this.end(); + return; + } + + if (this.switchType === SwitchType.BATON_PASS) { + // If switching via baton pass, update opposing tags coming from the prior pokemon + (this.player ? globalScene.getEnemyField() : globalScene.getPlayerField()).forEach((enemyPokemon: Pokemon) => enemyPokemon.transferTagsBySourceId(this.lastPokemon.id, switchedInPokemon.id), ); + + // If the recipient pokemon lacks a baton, give our baton to it during the swap if ( !globalScene.findModifier( m => @@ -133,14 +150,8 @@ export class SwitchSummonPhase extends SummonPhase { m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id, ) as SwitchEffectTransferModifier; - if ( - batonPassModifier && - !globalScene.findModifier( - m => - m instanceof SwitchEffectTransferModifier && - (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id, - ) - ) { + + if (batonPassModifier) { globalScene.tryTransferHeldItemModifier( batonPassModifier, switchedInPokemon, @@ -153,49 +164,48 @@ export class SwitchSummonPhase extends SummonPhase { } } } - if (switchedInPokemon) { - party[this.slotIndex] = this.lastPokemon; - party[this.fieldIndex] = switchedInPokemon; - const showTextAndSummon = () => { - globalScene.ui.showText( - this.player - ? i18next.t("battle:playerGo", { - pokemonName: getPokemonNameWithAffix(switchedInPokemon), - }) - : i18next.t("battle:trainerGo", { - trainerName: globalScene.currentBattle.trainer?.getName( - !(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER, - ), - pokemonName: this.getPokemon().getNameToRender(), - }), - ); - /** - * If this switch is passing a Substitute, make the switched Pokemon match the returned Pokemon's state as it left. - * Otherwise, clear any persisting tags on the returned Pokemon. - */ - if (this.switchType === SwitchType.BATON_PASS || this.switchType === SwitchType.SHED_TAIL) { - const substitute = this.lastPokemon.getTag(SubstituteTag); - if (substitute) { - switchedInPokemon.x += this.lastPokemon.getSubstituteOffset()[0]; - switchedInPokemon.y += this.lastPokemon.getSubstituteOffset()[1]; - switchedInPokemon.setAlpha(0.5); - } - } else { - switchedInPokemon.resetSummonData(); + + party[this.slotIndex] = this.lastPokemon; + party[this.fieldIndex] = switchedInPokemon; + const showTextAndSummon = () => { + globalScene.ui.showText( + this.player + ? i18next.t("battle:playerGo", { + pokemonName: getPokemonNameWithAffix(switchedInPokemon), + }) + : i18next.t("battle:trainerGo", { + trainerName: globalScene.currentBattle.trainer?.getName( + !(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER, + ), + pokemonName: this.getPokemon().getNameToRender(), + }), + ); + + /** + * If this switch is passing a Substitute, make the switched Pokemon matches the returned Pokemon's state as it left. + * Otherwise, clear any persisting tags on the returned Pokemon. + */ + if (this.switchType === SwitchType.BATON_PASS || this.switchType === SwitchType.SHED_TAIL) { + const substitute = this.lastPokemon.getTag(SubstituteTag); + if (substitute) { + switchedInPokemon.x += this.lastPokemon.getSubstituteOffset()[0]; + switchedInPokemon.y += this.lastPokemon.getSubstituteOffset()[1]; + switchedInPokemon.setAlpha(0.5); } - this.summon(); - }; - if (this.player) { - showTextAndSummon(); } else { - globalScene.time.delayedCall(1500, () => { - this.hideEnemyTrainer(); - globalScene.pbTrayEnemy.hide(); - showTextAndSummon(); - }); + switchedInPokemon.resetSummonData(); } + this.summon(); + }; + + if (this.player) { + showTextAndSummon(); } else { - this.end(); + globalScene.time.delayedCall(1500, () => { + this.hideEnemyTrainer(); + globalScene.pbTrayEnemy.hide(); + showTextAndSummon(); + }); } } @@ -213,15 +223,15 @@ export class SwitchSummonPhase extends SummonPhase { const lastPokemonHasForceSwitchAbAttr = this.lastPokemon.hasAbilityWithAttr(PostDamageForceSwitchAbAttr) && !this.lastPokemon.isFainted(); - // Compensate for turn spent summoning - // Or compensate for force switch move if switched out pokemon is not fainted + // Compensate for turn spent summoning/forced switch if switched out pokemon is not fainted. + // Needed as we increment turn counters in `TurnEndPhase`. if ( currentCommand === Command.POKEMON || lastPokemonIsForceSwitchedAndNotFainted || lastPokemonHasForceSwitchAbAttr ) { - pokemon.battleSummonData.turnCount--; - pokemon.battleSummonData.waveTurnCount--; + pokemon.tempSummonData.turnCount--; + pokemon.tempSummonData.waveTurnCount--; } if (this.switchType === SwitchType.BATON_PASS && pokemon) { @@ -233,12 +243,13 @@ export class SwitchSummonPhase extends SummonPhase { } } + // Reset turn data if not initial switch (since it gets initialized to an empty object on turn start) if (this.switchType !== SwitchType.INITIAL_SWITCH) { pokemon.resetTurnData(); pokemon.turnData.switchedInThisTurn = true; } - this.lastPokemon?.resetSummonData(); + this.lastPokemon.resetSummonData(); globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); // Reverts to weather-based forms when weather suppressors (Cloud Nine/Air Lock) are switched out diff --git a/src/phases/test-message-phase.ts b/src/phases/test-message-phase.ts deleted file mode 100644 index d5e74efd490..00000000000 --- a/src/phases/test-message-phase.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { MessagePhase } from "./message-phase"; - -export class TestMessagePhase extends MessagePhase { - constructor(message: string) { - super(message, null, true); - } -} diff --git a/src/phases/title-phase.ts b/src/phases/title-phase.ts index dc455a0a62a..56057c23372 100644 --- a/src/phases/title-phase.ts +++ b/src/phases/title-phase.ts @@ -1,5 +1,5 @@ import { loggedInUser } from "#app/account"; -import { BattleType } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import { fetchDailyRunSeed, getDailyRunStarters } from "#app/data/daily-run"; import { Gender } from "#app/data/gender"; import { getBiomeKey } from "#app/field/arena"; @@ -17,8 +17,8 @@ import { Unlockables } from "#app/system/unlockables"; import { vouchers } from "#app/system/voucher"; import type { OptionSelectConfig, OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import { SaveSlotUiMode } from "#app/ui/save-slot-select-ui-handler"; -import { Mode } from "#app/ui/ui"; -import * as Utils from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import { isLocal, isLocalServerConnected, isNullOrUndefined } from "#app/utils/common"; import i18next from "i18next"; import { CheckSwitchPhase } from "./check-switch-phase"; import { EncounterPhase } from "./encounter-phase"; @@ -29,16 +29,10 @@ import { globalScene } from "#app/global-scene"; import Overrides from "#app/overrides"; export class TitlePhase extends Phase { - private loaded: boolean; + private loaded = false; private lastSessionData: SessionSaveData; public gameMode: GameModes; - constructor() { - super(); - - this.loaded = false; - } - start(): void { super.start(); @@ -81,7 +75,7 @@ export class TitlePhase extends Phase { handler: () => { const setModeAndEnd = (gameMode: GameModes) => { this.gameMode = gameMode; - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.clearText(); this.end(); }; @@ -136,7 +130,7 @@ export class TitlePhase extends Phase { }, }); globalScene.ui.showText(i18next.t("menu:selectGameMode"), null, () => - globalScene.ui.setOverlayMode(Mode.OPTION_SELECT, { + globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, { options: options, }), ); @@ -146,7 +140,7 @@ export class TitlePhase extends Phase { { label: i18next.t("menu:loadGame"), handler: () => { - globalScene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD, (slotId: number) => { + globalScene.ui.setOverlayMode(UiMode.SAVE_SLOT, SaveSlotUiMode.LOAD, (slotId: number) => { if (slotId === -1) { return this.showOptions(); } @@ -158,7 +152,7 @@ export class TitlePhase extends Phase { { label: i18next.t("menu:runHistory"), handler: () => { - globalScene.ui.setOverlayMode(Mode.RUN_HISTORY); + globalScene.ui.setOverlayMode(UiMode.RUN_HISTORY); return true; }, keepOpen: true, @@ -166,7 +160,7 @@ export class TitlePhase extends Phase { { label: i18next.t("menu:settings"), handler: () => { - globalScene.ui.setOverlayMode(Mode.SETTINGS); + globalScene.ui.setOverlayMode(UiMode.SETTINGS); return true; }, keepOpen: true, @@ -177,12 +171,12 @@ export class TitlePhase extends Phase { noCancel: true, yOffset: 47, }; - globalScene.ui.setMode(Mode.TITLE, config); + globalScene.ui.setMode(UiMode.TITLE, config); } loadSaveSlot(slotId: number): void { globalScene.sessionSlotId = slotId > -1 || !loggedInUser ? slotId : loggedInUser.lastSessionSlot; - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.resetModeChain(); globalScene.gameData .loadSession(slotId, slotId === -1 ? this.lastSessionData : undefined) @@ -202,7 +196,7 @@ export class TitlePhase extends Phase { initDailyRun(): void { globalScene.ui.clearText(); - globalScene.ui.setMode(Mode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => { + globalScene.ui.setMode(UiMode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => { globalScene.clearPhaseQueue(); if (slotId === -1) { globalScene.pushPhase(new TitlePhase()); @@ -282,7 +276,7 @@ export class TitlePhase extends Phase { }; // If Online, calls seed fetch from db to generate daily run. If Offline, generates a daily run based on current date. - if (!Utils.isLocal || Utils.isLocalServerConnected) { + if (!isLocal || isLocalServerConnected) { fetchDailyRunSeed() .then(seed => { if (seed) { @@ -296,7 +290,7 @@ export class TitlePhase extends Phase { }); } else { let seed: string = btoa(new Date().toISOString().substring(0, 10)); - if (!Utils.isNullOrUndefined(Overrides.DAILY_RUN_SEED_OVERRIDE)) { + if (!isNullOrUndefined(Overrides.DAILY_RUN_SEED_OVERRIDE)) { seed = Overrides.DAILY_RUN_SEED_OVERRIDE; } generateDaily(seed); diff --git a/src/phases/trainer-message-test-phase.ts b/src/phases/trainer-message-test-phase.ts deleted file mode 100644 index 23c2c86361c..00000000000 --- a/src/phases/trainer-message-test-phase.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { globalScene } from "#app/global-scene"; -import { trainerConfigs } from "#app/data/trainers/trainer-config"; -import type { TrainerType } from "#app/enums/trainer-type"; -import { BattlePhase } from "./battle-phase"; -import { TestMessagePhase } from "./test-message-phase"; - -export class TrainerMessageTestPhase extends BattlePhase { - private trainerTypes: TrainerType[]; - - constructor(...trainerTypes: TrainerType[]) { - super(); - - this.trainerTypes = trainerTypes; - } - - start() { - super.start(); - - const testMessages: string[] = []; - - for (const t of Object.keys(trainerConfigs)) { - const type = Number.parseInt(t); - if (this.trainerTypes.length && !this.trainerTypes.find(tt => tt === (type as TrainerType))) { - continue; - } - const config = trainerConfigs[type]; - [ - config.encounterMessages, - config.femaleEncounterMessages, - config.victoryMessages, - config.femaleVictoryMessages, - config.defeatMessages, - config.femaleDefeatMessages, - ].map(messages => { - if (messages?.length) { - testMessages.push(...messages); - } - }); - } - - for (const message of testMessages) { - globalScene.pushPhase(new TestMessagePhase(message)); - } - - this.end(); - } -} diff --git a/src/phases/trainer-victory-phase.ts b/src/phases/trainer-victory-phase.ts index a024885121f..f7005b1300d 100644 --- a/src/phases/trainer-victory-phase.ts +++ b/src/phases/trainer-victory-phase.ts @@ -3,7 +3,7 @@ import { TrainerType } from "#app/enums/trainer-type"; import { modifierTypes } from "#app/modifier/modifier-type"; import { vouchers } from "#app/system/voucher"; import i18next from "i18next"; -import * as Utils from "#app/utils"; +import { randSeedItem } from "#app/utils/common"; import { BattlePhase } from "./battle-phase"; import { ModifierRewardPhase } from "./modifier-reward-phase"; import { MoneyRewardPhase } from "./money-reward-phase"; @@ -14,10 +14,6 @@ import { achvs } from "#app/system/achv"; import { timedEventManager } from "#app/global-event-manager"; export class TrainerVictoryPhase extends BattlePhase { - constructor() { - super(); - } - start() { globalScene.disableMenu = true; @@ -30,12 +26,6 @@ export class TrainerVictoryPhase extends BattlePhase { globalScene.unshiftPhase(new ModifierRewardPhase(modifierRewardFunc)); } - if (timedEventManager.isEventActive()) { - for (const rewardFunc of globalScene.currentBattle.trainer?.config.eventRewardFuncs!) { - globalScene.unshiftPhase(new ModifierRewardPhase(rewardFunc)); - } - } - const trainerType = globalScene.currentBattle.trainer?.config.trainerType!; // TODO: is this bang correct? // Validate Voucher for boss trainers if (vouchers.hasOwnProperty(TrainerType[trainerType])) { @@ -82,7 +72,7 @@ export class TrainerVictoryPhase extends BattlePhase { const victoryMessages = globalScene.currentBattle.trainer?.getVictoryMessages()!; // TODO: is this bang correct? let message: string; globalScene.executeWithSeedOffset( - () => (message = Utils.randSeedItem(victoryMessages)), + () => (message = randSeedItem(victoryMessages)), globalScene.currentBattle.waveIndex, ); message = message!; // tell TS compiler it's defined now diff --git a/src/phases/turn-end-phase.ts b/src/phases/turn-end-phase.ts index ddfc0955508..756c497802b 100644 --- a/src/phases/turn-end-phase.ts +++ b/src/phases/turn-end-phase.ts @@ -1,4 +1,4 @@ -import { applyPostTurnAbAttrs, PostTurnAbAttr } from "#app/data/ability"; +import { applyPostTurnAbAttrs, PostTurnAbAttr } from "#app/data/abilities/ability"; import { BattlerTagLapseType } from "#app/data/battler-tags"; import { TerrainType } from "#app/data/terrain"; import { WeatherType } from "#app/enums/weather-type"; @@ -18,10 +18,6 @@ import { PokemonHealPhase } from "./pokemon-heal-phase"; import { globalScene } from "#app/global-scene"; export class TurnEndPhase extends FieldPhase { - constructor() { - super(); - } - start() { super.start(); @@ -58,11 +54,10 @@ export class TurnEndPhase extends FieldPhase { } globalScene.applyModifiers(TurnStatusEffectModifier, pokemon.isPlayer(), pokemon); - globalScene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon); - pokemon.battleSummonData.turnCount++; - pokemon.battleSummonData.waveTurnCount++; + pokemon.tempSummonData.turnCount++; + pokemon.tempSummonData.waveTurnCount++; }; this.executeForAll(handlePokemon); diff --git a/src/phases/turn-init-phase.ts b/src/phases/turn-init-phase.ts index 3104b65eb3f..0c110024af7 100644 --- a/src/phases/turn-init-phase.ts +++ b/src/phases/turn-init-phase.ts @@ -15,10 +15,6 @@ import { TurnStartPhase } from "./turn-start-phase"; import { globalScene } from "#app/global-scene"; export class TurnInitPhase extends FieldPhase { - constructor() { - super(); - } - start() { super.start(); diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index 34dd7df3e89..b802780bbb8 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -1,4 +1,4 @@ -import { applyAbAttrs, BypassSpeedChanceAbAttr, PreventBypassSpeedChanceAbAttr } from "#app/data/ability"; +import { applyAbAttrs, BypassSpeedChanceAbAttr, PreventBypassSpeedChanceAbAttr } from "#app/data/abilities/ability"; import { allMoves, MoveHeaderAttr } from "#app/data/moves/move"; import { Abilities } from "#app/enums/abilities"; import { Stat } from "#app/enums/stat"; @@ -6,7 +6,7 @@ import type Pokemon from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon"; import { BypassSpeedChanceModifier } from "#app/modifier/modifier"; import { Command } from "#app/ui/command-ui-handler"; -import * as Utils from "#app/utils"; +import { randSeedShuffle, BooleanHolder } from "#app/utils/common"; import { AttemptCapturePhase } from "./attempt-capture-phase"; import { AttemptRunPhase } from "./attempt-run-phase"; import { BerryPhase } from "./berry-phase"; @@ -24,10 +24,6 @@ import { globalScene } from "#app/global-scene"; import { TeraPhase } from "./tera-phase"; export class TurnStartPhase extends FieldPhase { - constructor() { - super(); - } - /** * This orders the active Pokemon on the field by speed into an BattlerIndex array and returns that array. * It also checks for Trick Room and reverses the array if it is present. @@ -43,14 +39,14 @@ export class TurnStartPhase extends FieldPhase { // was varying based on how long since you last reloaded globalScene.executeWithSeedOffset( () => { - orderedTargets = Utils.randSeedShuffle(orderedTargets); + orderedTargets = randSeedShuffle(orderedTargets); }, globalScene.currentBattle.turn, globalScene.waveSeed, ); // Next, a check for Trick Room is applied to determine sort order. - const speedReversed = new Utils.BooleanHolder(false); + const speedReversed = new BooleanHolder(false); globalScene.arena.applyTags(TrickRoomTag, false, speedReversed); // Adjust the sort function based on whether Trick Room is active. @@ -76,19 +72,16 @@ export class TurnStartPhase extends FieldPhase { // This occurs before the main loop because of battles with more than two Pokemon const battlerBypassSpeed = {}; - globalScene - .getField(true) - .filter(p => p.summonData) - .map(p => { - const bypassSpeed = new Utils.BooleanHolder(false); - const canCheckHeldItems = new Utils.BooleanHolder(true); - applyAbAttrs(BypassSpeedChanceAbAttr, p, null, false, bypassSpeed); - applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, false, bypassSpeed, canCheckHeldItems); - if (canCheckHeldItems.value) { - globalScene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed); - } - battlerBypassSpeed[p.getBattlerIndex()] = bypassSpeed; - }); + globalScene.getField(true).map(p => { + const bypassSpeed = new BooleanHolder(false); + const canCheckHeldItems = new BooleanHolder(true); + applyAbAttrs(BypassSpeedChanceAbAttr, p, null, false, bypassSpeed); + applyAbAttrs(PreventBypassSpeedChanceAbAttr, p, null, false, bypassSpeed, canCheckHeldItems); + if (canCheckHeldItems.value) { + globalScene.applyModifiers(BypassSpeedChanceModifier, p.isPlayer(), p, bypassSpeed); + } + battlerBypassSpeed[p.getBattlerIndex()] = bypassSpeed; + }); // The function begins sorting orderedTargets based on command priority, move priority, and possible speed bypasses. // Non-FIGHT commands (SWITCH, BALL, RUN) have a higher command priority and will always occur before any FIGHT commands. diff --git a/src/phases/unavailable-phase.ts b/src/phases/unavailable-phase.ts index c0b5d4224c5..e5f1d899191 100644 --- a/src/phases/unavailable-phase.ts +++ b/src/phases/unavailable-phase.ts @@ -1,15 +1,11 @@ import { globalScene } from "#app/global-scene"; import { Phase } from "#app/phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { LoginPhase } from "./login-phase"; export class UnavailablePhase extends Phase { - constructor() { - super(); - } - start(): void { - globalScene.ui.setMode(Mode.UNAVAILABLE, () => { + globalScene.ui.setMode(UiMode.UNAVAILABLE, () => { globalScene.unshiftPhase(new LoginPhase(true)); this.end(); }); diff --git a/src/phases/unlock-phase.ts b/src/phases/unlock-phase.ts index b420a4b3a61..7a69fc207bb 100644 --- a/src/phases/unlock-phase.ts +++ b/src/phases/unlock-phase.ts @@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene"; import { Phase } from "#app/phase"; import type { Unlockables } from "#app/system/unlockables"; import { getUnlockableName } from "#app/system/unlockables"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; export class UnlockPhase extends Phase { @@ -19,7 +19,7 @@ export class UnlockPhase extends Phase { globalScene.gameData.unlocks[this.unlockable] = true; // Sound loaded into game as is globalScene.playSound("level_up_fanfare"); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.showText( i18next.t("battle:unlockedSomething", { unlockedThing: getUnlockableName(this.unlockable), diff --git a/src/phases/victory-phase.ts b/src/phases/victory-phase.ts index 78bf72195e8..1204877fec2 100644 --- a/src/phases/victory-phase.ts +++ b/src/phases/victory-phase.ts @@ -1,5 +1,6 @@ import type { BattlerIndex } from "#app/battle"; -import { BattleType, ClassicFixedBossWaves } from "#app/battle"; +import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves"; +import { BattleType } from "#enums/battle-type"; import type { CustomModifierSettings } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type"; import { BattleEndPhase } from "./battle-end-phase"; @@ -13,6 +14,8 @@ import { SelectModifierPhase } from "./select-modifier-phase"; import { TrainerVictoryPhase } from "./trainer-victory-phase"; import { handleMysteryEncounterVictory } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { globalScene } from "#app/global-scene"; +import { timedEventManager } from "#app/global-event-manager"; +import { SelectBiomePhase } from "./select-biome-phase"; export class VictoryPhase extends PokemonPhase { /** If true, indicates that the phase is intended for EXP purposes only, and not to continue a battle to next phase */ @@ -53,12 +56,20 @@ export class VictoryPhase extends PokemonPhase { } if (globalScene.gameMode.isEndless || !globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) { globalScene.pushPhase(new EggLapsePhase()); - if ( - globalScene.gameMode.isClassic && - globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_BOSS_2 - ) { - // Should get Lock Capsule on 165 before shop phase so it can be used in the rewards shop - globalScene.pushPhase(new ModifierRewardPhase(modifierTypes.LOCK_CAPSULE)); + if (globalScene.gameMode.isClassic) { + switch (globalScene.currentBattle.waveIndex) { + case ClassicFixedBossWaves.RIVAL_1: + case ClassicFixedBossWaves.RIVAL_2: + // Get event modifiers for this wave + timedEventManager + .getFixedBattleEventRewards(globalScene.currentBattle.waveIndex) + .map(r => globalScene.pushPhase(new ModifierRewardPhase(modifierTypes[r]))); + break; + case ClassicFixedBossWaves.EVIL_BOSS_2: + // Should get Lock Capsule on 165 before shop phase so it can be used in the rewards shop + globalScene.pushPhase(new ModifierRewardPhase(modifierTypes.LOCK_CAPSULE)); + break; + } } if (globalScene.currentBattle.waveIndex % 10) { globalScene.pushPhase(new SelectModifierPhase(undefined, undefined, this.getFixedBattleCustomModifiers())); @@ -101,6 +112,11 @@ export class VictoryPhase extends PokemonPhase { globalScene.pushPhase(new AddEnemyBuffModifierPhase()); } } + + if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { + globalScene.pushPhase(new SelectBiomePhase()); + } + globalScene.pushPhase(new NewBattlePhase()); } else { globalScene.currentBattle.battleType = BattleType.CLEAR; diff --git a/src/phases/weather-effect-phase.ts b/src/phases/weather-effect-phase.ts index d7a1f193029..d89c78e96c7 100644 --- a/src/phases/weather-effect-phase.ts +++ b/src/phases/weather-effect-phase.ts @@ -7,7 +7,7 @@ import { BlockNonDirectDamageAbAttr, applyPostWeatherLapseAbAttrs, PostWeatherLapseAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; import { CommonAnim } from "#app/data/battle-anims"; import type { Weather } from "#app/data/weather"; import { getWeatherDamageMessage, getWeatherLapseMessage } from "#app/data/weather"; @@ -15,7 +15,7 @@ import { BattlerTagType } from "#app/enums/battler-tag-type"; import { WeatherType } from "#app/enums/weather-type"; import type Pokemon from "#app/field/pokemon"; import { HitResult } from "#app/field/pokemon"; -import * as Utils from "#app/utils"; +import { BooleanHolder, toDmgValue } from "#app/utils/common"; import { CommonAnimPhase } from "./common-anim-phase"; export class WeatherEffectPhase extends CommonAnimPhase { @@ -35,14 +35,13 @@ export class WeatherEffectPhase extends CommonAnimPhase { this.weather = globalScene?.arena?.weather; if (!this.weather) { - this.end(); - return; + return this.end(); } this.setAnimation(CommonAnim.SUNNY + (this.weather.weatherType - 1)); if (this.weather.isDamaging()) { - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); this.executeForAll((pokemon: Pokemon) => applyPreWeatherEffectAbAttrs(SuppressWeatherEffectAbAttr, pokemon, this.weather, cancelled), @@ -50,7 +49,7 @@ export class WeatherEffectPhase extends CommonAnimPhase { if (!cancelled.value) { const inflictDamage = (pokemon: Pokemon) => { - const cancelled = new Utils.BooleanHolder(false); + const cancelled = new BooleanHolder(false); applyPreWeatherEffectAbAttrs(PreWeatherDamageAbAttr, pokemon, this.weather, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); @@ -63,9 +62,9 @@ export class WeatherEffectPhase extends CommonAnimPhase { return; } - const damage = Utils.toDmgValue(pokemon.getMaxHp() / 16); + const damage = toDmgValue(pokemon.getMaxHp() / 16); - globalScene.queueMessage(getWeatherDamageMessage(this.weather?.weatherType!, pokemon)!); // TODO: are those bangs correct? + globalScene.queueMessage(getWeatherDamageMessage(this.weather!.weatherType, pokemon) ?? ""); pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT, ignoreSegments: true }); }; diff --git a/src/pipelines/field-sprite.ts b/src/pipelines/field-sprite.ts index 547281d7dee..a6e248c9998 100644 --- a/src/pipelines/field-sprite.ts +++ b/src/pipelines/field-sprite.ts @@ -1,210 +1,8 @@ import { globalScene } from "#app/global-scene"; import { TerrainType, getTerrainColor } from "../data/terrain"; -import * as Utils from "../utils"; - -const spriteFragShader = ` -#ifdef GL_FRAGMENT_PRECISION_HIGH -precision highp float; -#else -precision mediump float; -#endif - -uniform sampler2D uMainSampler[%count%]; - -varying vec2 outTexCoord; -varying float outTexId; -varying float outTintEffect; -varying vec4 outTint; - -uniform float time; -uniform int ignoreTimeTint; -uniform int isOutside; -uniform vec3 dayTint; -uniform vec3 duskTint; -uniform vec3 nightTint; -uniform vec3 terrainColor; -uniform float terrainColorRatio; - -float blendOverlay(float base, float blend) { - return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend)); -} - -vec3 blendOverlay(vec3 base, vec3 blend) { - return vec3(blendOverlay(base.r,blend.r),blendOverlay(base.g,blend.g),blendOverlay(base.b,blend.b)); -} - -vec3 blendHardLight(vec3 base, vec3 blend) { - return blendOverlay(blend, base); -} - -float hue2rgb(float f1, float f2, float hue) { - if (hue < 0.0) - hue += 1.0; - else if (hue > 1.0) - hue -= 1.0; - float res; - if ((6.0 * hue) < 1.0) - res = f1 + (f2 - f1) * 6.0 * hue; - else if ((2.0 * hue) < 1.0) - res = f2; - else if ((3.0 * hue) < 2.0) - res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0; - else - res = f1; - return res; -} - -vec3 rgb2hsl(vec3 color) { - vec3 hsl; - - float fmin = min(min(color.r, color.g), color.b); - float fmax = max(max(color.r, color.g), color.b); - float delta = fmax - fmin; - - hsl.z = (fmax + fmin) / 2.0; - - if (delta == 0.0) { - hsl.x = 0.0; - hsl.y = 0.0; - } else { - if (hsl.z < 0.5) - hsl.y = delta / (fmax + fmin); - else - hsl.y = delta / (2.0 - fmax - fmin); - - float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta; - float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta; - float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta; - - if (color.r == fmax ) - hsl.x = deltaB - deltaG; - else if (color.g == fmax) - hsl.x = (1.0 / 3.0) + deltaR - deltaB; - else if (color.b == fmax) - hsl.x = (2.0 / 3.0) + deltaG - deltaR; - - if (hsl.x < 0.0) - hsl.x += 1.0; - else if (hsl.x > 1.0) - hsl.x -= 1.0; - } - - return hsl; -} - -vec3 hsl2rgb(vec3 hsl) { - vec3 rgb; - - if (hsl.y == 0.0) - rgb = vec3(hsl.z); - else { - float f2; - - if (hsl.z < 0.5) - f2 = hsl.z * (1.0 + hsl.y); - else - f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z); - - float f1 = 2.0 * hsl.z - f2; - - rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0)); - rgb.g = hue2rgb(f1, f2, hsl.x); - rgb.b = hue2rgb(f1, f2, hsl.x - (1.0/3.0)); - } - - return rgb; -} - -vec3 blendHue(vec3 base, vec3 blend) { - vec3 baseHSL = rgb2hsl(base); - return hsl2rgb(vec3(rgb2hsl(blend).r, baseHSL.g, baseHSL.b)); -} - -void main() { - vec4 texture; - - %forloop% - - vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a); - - // Multiply texture tint - vec4 color = texture * texel; - - if (outTintEffect == 1.0) { - // Solid color + texture alpha - color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a); - } else if (outTintEffect == 2.0) { - // Solid color, no texture - color = texel; - } - - /* Apply day/night tint */ - if (color.a > 0.0 && ignoreTimeTint == 0) { - vec3 dayNightTint; - - if (time < 0.25) { - dayNightTint = dayTint; - } else if (isOutside == 0 && time < 0.5) { - dayNightTint = mix(dayTint, nightTint, (time - 0.25) / 0.25); - } else if (time < 0.375) { - dayNightTint = mix(dayTint, duskTint, (time - 0.25) / 0.125); - } else if (time < 0.5) { - dayNightTint = mix(duskTint, nightTint, (time - 0.375) / 0.125); - } else if (time < 0.75) { - dayNightTint = nightTint; - } else if (isOutside == 0) { - dayNightTint = mix(nightTint, dayTint, (time - 0.75) / 0.25); - } else if (time < 0.875) { - dayNightTint = mix(nightTint, duskTint, (time - 0.75) / 0.125); - } else { - dayNightTint = mix(duskTint, dayTint, (time - 0.875) / 0.125); - } - - color = vec4(blendHardLight(color.rgb, dayNightTint), color.a); - } - - if (terrainColorRatio > 0.0 && (1.0 - terrainColorRatio) < outTexCoord.y) { - if (color.a > 0.0 && (terrainColor.r > 0.0 || terrainColor.g > 0.0 || terrainColor.b > 0.0)) { - color.rgb = mix(color.rgb, blendHue(color.rgb, terrainColor), 1.0); - } - } - - gl_FragColor = color; -} -`; - -const spriteVertShader = ` -precision mediump float; - -uniform mat4 uProjectionMatrix; -uniform int uRoundPixels; -uniform vec2 uResolution; - -attribute vec2 inPosition; -attribute vec2 inTexCoord; -attribute float inTexId; -attribute float inTintEffect; -attribute vec4 inTint; - -varying vec2 outTexCoord; -varying float outTexId; -varying vec2 outPosition; -varying float outTintEffect; -varying vec4 outTint; - -void main() { - gl_Position = uProjectionMatrix * vec4(inPosition, 1.0, 1.0); - if (uRoundPixels == 1) - { - gl_Position.xy = floor(((gl_Position.xy + 1.0) * 0.5 * uResolution) + 0.5) / uResolution * 2.0 - 1.0; - } - outTexCoord = inTexCoord; - outTexId = inTexId; - outPosition = inPosition; - outTint = inTint; - outTintEffect = inTintEffect; -} -`; +import { getCurrentTime } from "#app/utils/common"; +import fieldSpriteFragShader from "./glsl/fieldSpriteFragShader.frag?raw"; +import spriteVertShader from "./glsl/spriteShader.vert?raw"; export default class FieldSpritePipeline extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline { constructor(game: Phaser.Game, config?: Phaser.Types.Renderer.WebGL.WebGLPipelineConfig) { @@ -212,7 +10,7 @@ export default class FieldSpritePipeline extends Phaser.Renderer.WebGL.Pipelines config || { game: game, name: "field-sprite", - fragShader: spriteFragShader, + fragShader: fieldSpriteFragShader, vertShader: spriteVertShader, }, ); @@ -236,7 +34,7 @@ export default class FieldSpritePipeline extends Phaser.Renderer.WebGL.Pipelines const time = globalScene.currentBattle?.waveIndex ? ((globalScene.currentBattle.waveIndex + globalScene.waveCycleOffset) % 40) / 40 // ((new Date().getSeconds() * 1000 + new Date().getMilliseconds()) % 10000) / 10000 - : Utils.getCurrentTime(); + : getCurrentTime(); this.set1f("time", time); this.set1i("ignoreTimeTint", ignoreTimeTint ? 1 : 0); this.set1i("isOutside", globalScene.arena.isOutside() ? 1 : 0); diff --git a/src/pipelines/glsl/fieldSpriteFragShader.frag b/src/pipelines/glsl/fieldSpriteFragShader.frag new file mode 100644 index 00000000000..e79dea86fe9 --- /dev/null +++ b/src/pipelines/glsl/fieldSpriteFragShader.frag @@ -0,0 +1,168 @@ +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif + +uniform sampler2D uMainSampler[%count%]; + +varying vec2 outTexCoord; +varying float outTexId; +varying float outTintEffect; +varying vec4 outTint; + +uniform float time; +uniform int ignoreTimeTint; +uniform int isOutside; +uniform vec3 dayTint; +uniform vec3 duskTint; +uniform vec3 nightTint; +uniform vec3 terrainColor; +uniform float terrainColorRatio; + +float blendOverlay(float base, float blend) { + return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend)); +} + +vec3 blendOverlay(vec3 base, vec3 blend) { + return vec3(blendOverlay(base.r,blend.r),blendOverlay(base.g,blend.g),blendOverlay(base.b,blend.b)); +} + +vec3 blendHardLight(vec3 base, vec3 blend) { + return blendOverlay(blend, base); +} + +float hue2rgb(float f1, float f2, float hue) { + if (hue < 0.0) + hue += 1.0; + else if (hue > 1.0) + hue -= 1.0; + float res; + if ((6.0 * hue) < 1.0) + res = f1 + (f2 - f1) * 6.0 * hue; + else if ((2.0 * hue) < 1.0) + res = f2; + else if ((3.0 * hue) < 2.0) + res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0; + else + res = f1; + return res; +} + +vec3 rgb2hsl(vec3 color) { + vec3 hsl; + + float fmin = min(min(color.r, color.g), color.b); + float fmax = max(max(color.r, color.g), color.b); + float delta = fmax - fmin; + + hsl.z = (fmax + fmin) / 2.0; + + if (delta == 0.0) { + hsl.x = 0.0; + hsl.y = 0.0; + } else { + if (hsl.z < 0.5) + hsl.y = delta / (fmax + fmin); + else + hsl.y = delta / (2.0 - fmax - fmin); + + float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta; + float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta; + float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta; + + if (color.r == fmax ) + hsl.x = deltaB - deltaG; + else if (color.g == fmax) + hsl.x = (1.0 / 3.0) + deltaR - deltaB; + else if (color.b == fmax) + hsl.x = (2.0 / 3.0) + deltaG - deltaR; + + if (hsl.x < 0.0) + hsl.x += 1.0; + else if (hsl.x > 1.0) + hsl.x -= 1.0; + } + + return hsl; +} + +vec3 hsl2rgb(vec3 hsl) { + vec3 rgb; + + if (hsl.y == 0.0) + rgb = vec3(hsl.z); + else { + float f2; + + if (hsl.z < 0.5) + f2 = hsl.z * (1.0 + hsl.y); + else + f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z); + + float f1 = 2.0 * hsl.z - f2; + + rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0)); + rgb.g = hue2rgb(f1, f2, hsl.x); + rgb.b = hue2rgb(f1, f2, hsl.x - (1.0/3.0)); + } + + return rgb; +} + +vec3 blendHue(vec3 base, vec3 blend) { + vec3 baseHSL = rgb2hsl(base); + return hsl2rgb(vec3(rgb2hsl(blend).r, baseHSL.g, baseHSL.b)); +} + +void main() { + vec4 texture; + + %forloop% + + vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a); + + // Multiply texture tint + vec4 color = texture * texel; + + if (outTintEffect == 1.0) { + // Solid color + texture alpha + color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a); + } else if (outTintEffect == 2.0) { + // Solid color, no texture + color = texel; + } + + /* Apply day/night tint */ + if (color.a > 0.0 && ignoreTimeTint == 0) { + vec3 dayNightTint; + + if (time < 0.25) { + dayNightTint = dayTint; + } else if (isOutside == 0 && time < 0.5) { + dayNightTint = mix(dayTint, nightTint, (time - 0.25) / 0.25); + } else if (time < 0.375) { + dayNightTint = mix(dayTint, duskTint, (time - 0.25) / 0.125); + } else if (time < 0.5) { + dayNightTint = mix(duskTint, nightTint, (time - 0.375) / 0.125); + } else if (time < 0.75) { + dayNightTint = nightTint; + } else if (isOutside == 0) { + dayNightTint = mix(nightTint, dayTint, (time - 0.75) / 0.25); + } else if (time < 0.875) { + dayNightTint = mix(nightTint, duskTint, (time - 0.75) / 0.125); + } else { + dayNightTint = mix(duskTint, dayTint, (time - 0.875) / 0.125); + } + + color = vec4(blendHardLight(color.rgb, dayNightTint), color.a); + } + + if (terrainColorRatio > 0.0 && (1.0 - terrainColorRatio) < outTexCoord.y) { + if (color.a > 0.0 && (terrainColor.r > 0.0 || terrainColor.g > 0.0 || terrainColor.b > 0.0)) { + color.rgb = mix(color.rgb, blendHue(color.rgb, terrainColor), 1.0); + } + } + + gl_FragColor = color; +} \ No newline at end of file diff --git a/src/pipelines/glsl/invert.frag b/src/pipelines/glsl/invert.frag new file mode 100644 index 00000000000..24d9ee83a55 --- /dev/null +++ b/src/pipelines/glsl/invert.frag @@ -0,0 +1,10 @@ +precision mediump float; + +uniform sampler2D uMainSampler; + +varying vec2 outTexCoord; + +void main() +{ + gl_FragColor = 1.0 - texture2D(uMainSampler, outTexCoord); +} \ No newline at end of file diff --git a/src/pipelines/glsl/spriteFragShader.frag b/src/pipelines/glsl/spriteFragShader.frag new file mode 100644 index 00000000000..03f8c8c27bc --- /dev/null +++ b/src/pipelines/glsl/spriteFragShader.frag @@ -0,0 +1,267 @@ +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif + +uniform sampler2D uMainSampler[%count%]; + +varying vec2 outTexCoord; +varying float outTexId; +varying vec2 outPosition; +varying float outTintEffect; +varying vec4 outTint; + +uniform float time; +uniform int ignoreTimeTint; +uniform int isOutside; +uniform vec3 dayTint; +uniform vec3 duskTint; +uniform vec3 nightTint; +uniform float teraTime; +uniform vec3 teraColor; +uniform int hasShadow; +uniform int yCenter; +uniform float fieldScale; +uniform float vCutoff; +uniform vec2 relPosition; +uniform vec2 texFrameUv; +uniform vec2 size; +uniform vec2 texSize; +uniform float yOffset; +uniform float yShadowOffset; +uniform vec4 tone; +uniform vec4 baseVariantColors[32]; +uniform vec4 variantColors[32]; +uniform vec4 spriteColors[32]; +uniform ivec4 fusionSpriteColors[32]; + +const vec3 lumaF = vec3(.299, .587, .114); + +float blendOverlay(float base, float blend) { + return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend)); +} + +vec3 blendOverlay(vec3 base, vec3 blend) { + return vec3(blendOverlay(base.r,blend.r),blendOverlay(base.g,blend.g),blendOverlay(base.b,blend.b)); +} + +vec3 blendHardLight(vec3 base, vec3 blend) { + return blendOverlay(blend, base); +} + +float hue2rgb(float f1, float f2, float hue) { + if (hue < 0.0) + hue += 1.0; + else if (hue > 1.0) + hue -= 1.0; + float res; + if ((6.0 * hue) < 1.0) + res = f1 + (f2 - f1) * 6.0 * hue; + else if ((2.0 * hue) < 1.0) + res = f2; + else if ((3.0 * hue) < 2.0) + res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0; + else + res = f1; + return res; +} + +vec3 rgb2hsl(vec3 color) { + vec3 hsl; + float fmin = min(min(color.r, color.g), color.b); + float fmax = max(max(color.r, color.g), color.b); + float delta = fmax - fmin; + + hsl.z = (fmax + fmin) / 2.0; + + if (delta == 0.0) { + hsl.x = 0.0; + hsl.y = 0.0; + } else { + if (hsl.z < 0.5) + hsl.y = delta / (fmax + fmin); + else + hsl.y = delta / (2.0 - fmax - fmin); + + float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta; + float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta; + float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta; + + if (color.r == fmax ) + hsl.x = deltaB - deltaG; + else if (color.g == fmax) + hsl.x = (1.0 / 3.0) + deltaR - deltaB; + else if (color.b == fmax) + hsl.x = (2.0 / 3.0) + deltaG - deltaR; + + if (hsl.x < 0.0) + hsl.x += 1.0; + else if (hsl.x > 1.0) + hsl.x -= 1.0; + } + + return hsl; +} + +vec3 hsl2rgb(vec3 hsl) { + vec3 rgb; + + if (hsl.y == 0.0) + rgb = vec3(hsl.z); + else { + float f2; + + if (hsl.z < 0.5) + f2 = hsl.z * (1.0 + hsl.y); + else + f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z); + + float f1 = 2.0 * hsl.z - f2; + + rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0)); + rgb.g = hue2rgb(f1, f2, hsl.x); + rgb.b= hue2rgb(f1, f2, hsl.x - (1.0/3.0)); + } + + return rgb; +} + +vec3 blendHue(vec3 base, vec3 blend) { + vec3 baseHSL = rgb2hsl(base); + return hsl2rgb(vec3(rgb2hsl(blend).r, baseHSL.g, baseHSL.b)); +} + +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +void main() { + vec4 texture = texture2D(uMainSampler[0], outTexCoord); + + for (int i = 0; i < 32; i++) { + if (baseVariantColors[i].a == 0.0) + break; + if (texture.a > 0.0 && all(lessThan(abs(texture.rgb - baseVariantColors[i].rgb), vec3(1.0/255.0)))) { + texture.rgb = variantColors[i].rgb; + break; + } + } + + for (int i = 0; i < 32; i++) { + if (spriteColors[i][3] == 0.0) + break; + if (texture.a > 0.0 && all(lessThan(abs(texture.rgb - spriteColors[i].rgb), vec3(1.0/255.0)))) { + vec3 fusionColor = vec3(fusionSpriteColors[i].rgb) / 255.0; + vec3 bg = spriteColors[i].rgb; + float gray = (bg.r + bg.g + bg.b) / 3.0; + bg = vec3(gray); + vec3 fg = fusionColor; + texture.rgb = mix(1.0 - 2.0 * (1.0 - bg) * (1.0 - fg), 2.0 * bg * fg, step(bg, vec3(0.5))); + break; + } + } + + vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a); + + // Multiply texture tint + vec4 color = texture * texel; + + if (color.a > 0.0 && teraColor.r > 0.0 && teraColor.g > 0.0 && teraColor.b > 0.0) { + vec2 relUv = (outTexCoord.xy - texFrameUv.xy) / (size.xy / texSize.xy); + vec2 teraTexCoord = vec2(relUv.x * (size.x / 200.0), relUv.y * (size.y / 120.0)); + vec4 teraCol = texture2D(uMainSampler[1], teraTexCoord); + float floorValue = 86.0 / 255.0; + vec3 teraPatternHsv = rgb2hsv(teraCol.rgb); + teraCol.rgb = hsv2rgb(vec3((teraPatternHsv.b - floorValue) * 4.0 + teraTexCoord.x * fieldScale / 2.0 + teraTexCoord.y * fieldScale / 2.0 + teraTime * 255.0, teraPatternHsv.b, teraPatternHsv.b)); + + color.rgb = mix(color.rgb, blendHue(color.rgb, teraColor), 0.625); + teraCol.rgb = mix(teraCol.rgb, teraColor, 0.5); + color.rgb = blendOverlay(color.rgb, teraCol.rgb); + + if (any(lessThan(teraCol.rgb, vec3(1.0)))) { + vec3 teraColHsv = rgb2hsv(teraColor); + color.rgb = mix(color.rgb, teraColor, (1.0 - teraColHsv.g) / 2.0); + } + } + + if (outTintEffect == 1.0) { + // Solid color + texture alpha + color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a); + } else if (outTintEffect == 2.0) { + // Solid color, no texture + color = texel; + } + + /* Apply gray */ + float luma = dot(color.rgb, lumaF); + color.rgb = mix(color.rgb, vec3(luma), tone.w); + + /* Apply tone */ + color.rgb += tone.rgb * (color.a / 255.0); + + /* Apply day/night tint */ + if (color.a > 0.0 && ignoreTimeTint == 0) { + vec3 dayNightTint; + + if (time < 0.25) { + dayNightTint = dayTint; + } else if (isOutside == 0 && time < 0.5) { + dayNightTint = mix(dayTint, nightTint, (time - 0.25) / 0.25); + } else if (time < 0.375) { + dayNightTint = mix(dayTint, duskTint, (time - 0.25) / 0.125); + } else if (time < 0.5) { + dayNightTint = mix(duskTint, nightTint, (time - 0.375) / 0.125); + } else if (time < 0.75) { + dayNightTint = nightTint; + } else if (isOutside == 0) { + dayNightTint = mix(nightTint, dayTint, (time - 0.75) / 0.25); + } else if (time < 0.875) { + dayNightTint = mix(nightTint, duskTint, (time - 0.75) / 0.125); + } else { + dayNightTint = mix(duskTint, dayTint, (time - 0.875) / 0.125); + } + + color.rgb = blendHardLight(color.rgb, dayNightTint); + } + + if (hasShadow == 1) { + float width = size.x - (yOffset / 2.0); + + float spriteX = ((floor(outPosition.x / fieldScale) - relPosition.x) / width) + 0.5; + float spriteY = ((floor(outPosition.y / fieldScale) - relPosition.y - yShadowOffset) / size.y); + + if (yCenter == 1) { + spriteY += 0.5; + } else { + spriteY += 1.0; + } + + bool yOverflow = outTexCoord.y >= vCutoff; + + if ((spriteY >= 0.9 && (color.a == 0.0 || yOverflow))) { + float shadowSpriteY = (spriteY - 0.9) * (1.0 / 0.15); + if (distance(vec2(spriteX, shadowSpriteY), vec2(0.5)) < 0.5) { + color = vec4(vec3(0.0), 0.5); + } else if (yOverflow) { + discard; + } + } else if (yOverflow) { + discard; + } + } + + gl_FragColor = color; +} \ No newline at end of file diff --git a/src/pipelines/glsl/spriteShader.vert b/src/pipelines/glsl/spriteShader.vert new file mode 100644 index 00000000000..84e73834f49 --- /dev/null +++ b/src/pipelines/glsl/spriteShader.vert @@ -0,0 +1,31 @@ +precision mediump float; + +uniform mat4 uProjectionMatrix; +uniform int uRoundPixels; +uniform vec2 uResolution; + +attribute vec2 inPosition; +attribute vec2 inTexCoord; +attribute float inTexId; +attribute float inTintEffect; +attribute vec4 inTint; + +varying vec2 outTexCoord; +varying float outTexId; +varying vec2 outPosition; +varying float outTintEffect; +varying vec4 outTint; + +void main() +{ + gl_Position = uProjectionMatrix * vec4(inPosition, 1.0, 1.0); + if (uRoundPixels == 1) + { + gl_Position.xy = floor(((gl_Position.xy + 1.0) * 0.5 * uResolution) + 0.5) / uResolution * 2.0 - 1.0; + } + outTexCoord = inTexCoord; + outTexId = inTexId; + outPosition = inPosition; + outTint = inTint; + outTintEffect = inTintEffect; +} \ No newline at end of file diff --git a/src/pipelines/invert.ts b/src/pipelines/invert.ts index a945d0c95aa..0ebc3ad865f 100644 --- a/src/pipelines/invert.ts +++ b/src/pipelines/invert.ts @@ -1,17 +1,5 @@ import type { Game } from "phaser"; - -const fragShader = ` -precision mediump float; - -uniform sampler2D uMainSampler; - -varying vec2 outTexCoord; - -void main() -{ - gl_FragColor = 1.0 - texture2D(uMainSampler, outTexCoord); -} -`; +import fragShader from "./glsl/invert.frag?raw"; export default class InvertPostFX extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline { constructor(game: Game) { diff --git a/src/pipelines/sprite.ts b/src/pipelines/sprite.ts index 439e35f711f..307c2cee4cc 100644 --- a/src/pipelines/sprite.ts +++ b/src/pipelines/sprite.ts @@ -1,318 +1,12 @@ -import { variantColorCache } from "#app/data/variant"; +import { variantColorCache } from "#app/sprites/variant"; import MysteryEncounterIntroVisuals from "#app/field/mystery-encounter-intro"; import Pokemon from "#app/field/pokemon"; import Trainer from "#app/field/trainer"; import { globalScene } from "#app/global-scene"; -import * as Utils from "#app/utils"; +import { rgbHexToRgba } from "#app/utils/common"; import FieldSpritePipeline from "./field-sprite"; - -const spriteFragShader = ` -#ifdef GL_FRAGMENT_PRECISION_HIGH -precision highp float; -#else -precision mediump float; -#endif - -uniform sampler2D uMainSampler[%count%]; - -varying vec2 outTexCoord; -varying float outTexId; -varying vec2 outPosition; -varying float outTintEffect; -varying vec4 outTint; - -uniform float time; -uniform int ignoreTimeTint; -uniform int isOutside; -uniform vec3 dayTint; -uniform vec3 duskTint; -uniform vec3 nightTint; -uniform float teraTime; -uniform vec3 teraColor; -uniform int hasShadow; -uniform int yCenter; -uniform float fieldScale; -uniform float vCutoff; -uniform vec2 relPosition; -uniform vec2 texFrameUv; -uniform vec2 size; -uniform vec2 texSize; -uniform float yOffset; -uniform float yShadowOffset; -uniform vec4 tone; -uniform ivec4 baseVariantColors[32]; -uniform vec4 variantColors[32]; -uniform ivec4 spriteColors[32]; -uniform ivec4 fusionSpriteColors[32]; - -const vec3 lumaF = vec3(.299, .587, .114); - -float blendOverlay(float base, float blend) { - return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend)); -} - -vec3 blendOverlay(vec3 base, vec3 blend) { - return vec3(blendOverlay(base.r,blend.r),blendOverlay(base.g,blend.g),blendOverlay(base.b,blend.b)); -} - -vec3 blendHardLight(vec3 base, vec3 blend) { - return blendOverlay(blend, base); -} - -float hue2rgb(float f1, float f2, float hue) { - if (hue < 0.0) - hue += 1.0; - else if (hue > 1.0) - hue -= 1.0; - float res; - if ((6.0 * hue) < 1.0) - res = f1 + (f2 - f1) * 6.0 * hue; - else if ((2.0 * hue) < 1.0) - res = f2; - else if ((3.0 * hue) < 2.0) - res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0; - else - res = f1; - return res; -} - -vec3 rgb2hsl(vec3 color) { - vec3 hsl; - - float fmin = min(min(color.r, color.g), color.b); - float fmax = max(max(color.r, color.g), color.b); - float delta = fmax - fmin; - - hsl.z = (fmax + fmin) / 2.0; - - if (delta == 0.0) { - hsl.x = 0.0; - hsl.y = 0.0; - } else { - if (hsl.z < 0.5) - hsl.y = delta / (fmax + fmin); - else - hsl.y = delta / (2.0 - fmax - fmin); - - float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta; - float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta; - float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta; - - if (color.r == fmax ) - hsl.x = deltaB - deltaG; - else if (color.g == fmax) - hsl.x = (1.0 / 3.0) + deltaR - deltaB; - else if (color.b == fmax) - hsl.x = (2.0 / 3.0) + deltaG - deltaR; - - if (hsl.x < 0.0) - hsl.x += 1.0; - else if (hsl.x > 1.0) - hsl.x -= 1.0; - } - - return hsl; -} - -vec3 hsl2rgb(vec3 hsl) { - vec3 rgb; - - if (hsl.y == 0.0) - rgb = vec3(hsl.z); - else { - float f2; - - if (hsl.z < 0.5) - f2 = hsl.z * (1.0 + hsl.y); - else - f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z); - - float f1 = 2.0 * hsl.z - f2; - - rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0)); - rgb.g = hue2rgb(f1, f2, hsl.x); - rgb.b= hue2rgb(f1, f2, hsl.x - (1.0/3.0)); - } - - return rgb; -} - -vec3 blendHue(vec3 base, vec3 blend) { - vec3 baseHSL = rgb2hsl(base); - return hsl2rgb(vec3(rgb2hsl(blend).r, baseHSL.g, baseHSL.b)); -} - -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} - -void main() { - vec4 texture = texture2D(uMainSampler[0], outTexCoord); - - ivec4 colorInt = ivec4(int(texture.r * 255.0), int(texture.g * 255.0), int(texture.b * 255.0), int(texture.a * 255.0)); - - for (int i = 0; i < 32; i++) { - if (baseVariantColors[i][3] == 0) - break; - if (texture.a > 0.0 && colorInt.r == baseVariantColors[i].r && colorInt.g == baseVariantColors[i].g && colorInt.b == baseVariantColors[i].b) { - texture.rgb = variantColors[i].rgb; - break; - } - } - - for (int i = 0; i < 32; i++) { - if (spriteColors[i][3] == 0) - break; - if (texture.a > 0.0 && colorInt.r == spriteColors[i].r && colorInt.g == spriteColors[i].g && colorInt.b == spriteColors[i].b) { - vec3 fusionColor = vec3(float(fusionSpriteColors[i].r) / 255.0, float(fusionSpriteColors[i].g) / 255.0, float(fusionSpriteColors[i].b) / 255.0); - vec3 bg = vec3(float(spriteColors[i].r) / 255.0, float(spriteColors[i].g) / 255.0, float(spriteColors[i].b) / 255.0); - float gray = (bg.r + bg.g + bg.b) / 3.0; - bg = vec3(gray, gray, gray); - vec3 fg = fusionColor; - texture.rgb = mix(1.0 - 2.0 * (1.0 - bg) * (1.0 - fg), 2.0 * bg * fg, step(bg, vec3(0.5))); - break; - } - } - - vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a); - - // Multiply texture tint - vec4 color = texture * texel; - - if (color.a > 0.0 && teraColor.r > 0.0 && teraColor.g > 0.0 && teraColor.b > 0.0) { - vec2 relUv = vec2((outTexCoord.x - texFrameUv.x) / (size.x / texSize.x), (outTexCoord.y - texFrameUv.y) / (size.y / texSize.y)); - vec2 teraTexCoord = vec2(relUv.x * (size.x / 200.0), relUv.y * (size.y / 120.0)); - vec4 teraCol = texture2D(uMainSampler[1], teraTexCoord); - float floorValue = 86.0 / 255.0; - vec3 teraPatternHsv = rgb2hsv(teraCol.rgb); - teraCol.rgb = hsv2rgb(vec3((teraPatternHsv.b - floorValue) * 4.0 + teraTexCoord.x * fieldScale / 2.0 + teraTexCoord.y * fieldScale / 2.0 + teraTime * 255.0, teraPatternHsv.b, teraPatternHsv.b)); - - color.rgb = mix(color.rgb, blendHue(color.rgb, teraColor), 0.625); - teraCol.rgb = mix(teraCol.rgb, teraColor, 0.5); - color.rgb = blendOverlay(color.rgb, teraCol.rgb); - - if (teraColor.r < 1.0 || teraColor.g < 1.0 || teraColor.b < 1.0) { - vec3 teraColHsv = rgb2hsv(teraColor); - color.rgb = mix(color.rgb, teraColor, (1.0 - teraColHsv.g) / 2.0); - } - } - - if (outTintEffect == 1.0) { - // Solid color + texture alpha - color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a); - } else if (outTintEffect == 2.0) { - // Solid color, no texture - color = texel; - } - - /* Apply gray */ - float luma = dot(color.rgb, lumaF); - color.rgb = mix(color.rgb, vec3(luma), tone.w); - - /* Apply tone */ - color.rgb += tone.rgb * (color.a / 255.0); - - /* Apply day/night tint */ - if (color.a > 0.0 && ignoreTimeTint == 0) { - vec3 dayNightTint; - - if (time < 0.25) { - dayNightTint = dayTint; - } else if (isOutside == 0 && time < 0.5) { - dayNightTint = mix(dayTint, nightTint, (time - 0.25) / 0.25); - } else if (time < 0.375) { - dayNightTint = mix(dayTint, duskTint, (time - 0.25) / 0.125); - } else if (time < 0.5) { - dayNightTint = mix(duskTint, nightTint, (time - 0.375) / 0.125); - } else if (time < 0.75) { - dayNightTint = nightTint; - } else if (isOutside == 0) { - dayNightTint = mix(nightTint, dayTint, (time - 0.75) / 0.25); - } else if (time < 0.875) { - dayNightTint = mix(nightTint, duskTint, (time - 0.75) / 0.125); - } else { - dayNightTint = mix(duskTint, dayTint, (time - 0.875) / 0.125); - } - - color.rgb = blendHardLight(color.rgb, dayNightTint); - } - - if (hasShadow == 1) { - float width = size.x - (yOffset / 2.0); - - float spriteX = ((floor(outPosition.x / fieldScale) - relPosition.x) / width) + 0.5; - float spriteY = ((floor(outPosition.y / fieldScale) - relPosition.y - yShadowOffset) / size.y); - - if (yCenter == 1) { - spriteY += 0.5; - } else { - spriteY += 1.0; - } - - bool yOverflow = outTexCoord.y >= vCutoff; - - if ((spriteY >= 0.9 && (color.a == 0.0 || yOverflow))) { - float shadowSpriteY = (spriteY - 0.9) * (1.0 / 0.15); - if (distance(vec2(spriteX, shadowSpriteY), vec2(0.5, 0.5)) < 0.5) { - color = vec4(vec3(0.0, 0.0, 0.0), 0.5); - } else if (yOverflow) { - discard; - } - } else if (yOverflow) { - discard; - } - } - - gl_FragColor = color; -} -`; - -const spriteVertShader = ` -precision mediump float; - -uniform mat4 uProjectionMatrix; -uniform int uRoundPixels; -uniform vec2 uResolution; - -attribute vec2 inPosition; -attribute vec2 inTexCoord; -attribute float inTexId; -attribute float inTintEffect; -attribute vec4 inTint; - -varying vec2 outTexCoord; -varying vec2 outtexFrameUv; -varying float outTexId; -varying vec2 outPosition; -varying float outTintEffect; -varying vec4 outTint; - -void main() -{ - gl_Position = uProjectionMatrix * vec4(inPosition, 1.0, 1.0); - if (uRoundPixels == 1) - { - gl_Position.xy = floor(((gl_Position.xy + 1.0) * 0.5 * uResolution) + 0.5) / uResolution * 2.0 - 1.0; - } - outTexCoord = inTexCoord; - outTexId = inTexId; - outPosition = inPosition; - outTint = inTint; - outTintEffect = inTintEffect; -} -`; +import spriteFragShader from "./glsl/spriteFragShader.frag?raw"; +import spriteVertShader from "./glsl/spriteShader.vert?raw"; export default class SpritePipeline extends FieldSpritePipeline { private _tone: number[]; @@ -407,7 +101,7 @@ export default class SpritePipeline extends FieldSpritePipeline { flatSpriteColors.splice( flatSpriteColors.length, 0, - ...(c < spriteColors.length ? spriteColors[c] : emptyColors), + ...(c < spriteColors.length ? spriteColors[c].map(x => x / 255.0) : emptyColors), ); flatFusionSpriteColors.splice( flatFusionSpriteColors.length, @@ -416,7 +110,7 @@ export default class SpritePipeline extends FieldSpritePipeline { ); } - this.set4iv("spriteColors", flatSpriteColors.flat()); + this.set4fv("spriteColors", flatSpriteColors.flat()); this.set4iv("fusionSpriteColors", flatFusionSpriteColors.flat()); } } @@ -450,9 +144,9 @@ export default class SpritePipeline extends FieldSpritePipeline { const baseColors = Object.keys(variantColors[variant]); for (let c = 0; c < 32; c++) { if (c < baseColors.length) { - const baseColor = Array.from(Object.values(Utils.rgbHexToRgba(baseColors[c]))); - const variantColor = Array.from(Object.values(Utils.rgbHexToRgba(variantColors[variant][baseColors[c]]))); - flatBaseColors.splice(flatBaseColors.length, 0, ...baseColor); + const baseColor = Array.from(Object.values(rgbHexToRgba(baseColors[c]))); + const variantColor = Array.from(Object.values(rgbHexToRgba(variantColors[variant][baseColors[c]]))); + flatBaseColors.splice(flatBaseColors.length, 0, ...baseColor.map(c => c / 255.0)); flatVariantColors.splice(flatVariantColors.length, 0, ...variantColor.map(c => c / 255.0)); } else { flatBaseColors.splice(flatBaseColors.length, 0, ...emptyColors); @@ -466,7 +160,7 @@ export default class SpritePipeline extends FieldSpritePipeline { } } - this.set4iv("baseVariantColors", flatBaseColors.flat()); + this.set4fv("baseVariantColors", flatBaseColors.flat()); this.set4fv("variantColors", flatVariantColors.flat()); } diff --git a/src/plugins/api/api-base.ts b/src/plugins/api/api-base.ts index 6a0eca56eaa..f55ffe2d3fd 100644 --- a/src/plugins/api/api-base.ts +++ b/src/plugins/api/api-base.ts @@ -1,5 +1,5 @@ import { SESSION_ID_COOKIE_NAME } from "#app/constants"; -import { getCookie } from "#app/utils"; +import { getCookie } from "#app/utils/cookies"; type DataType = "json" | "form-urlencoded"; diff --git a/src/plugins/api/pokerogue-account-api.ts b/src/plugins/api/pokerogue-account-api.ts index bab74799677..9cd82c24430 100644 --- a/src/plugins/api/pokerogue-account-api.ts +++ b/src/plugins/api/pokerogue-account-api.ts @@ -6,7 +6,7 @@ import type { } from "#app/@types/PokerogueAccountApi"; import { SESSION_ID_COOKIE_NAME } from "#app/constants"; import { ApiBase } from "#app/plugins/api/api-base"; -import { removeCookie, setCookie } from "#app/utils"; +import { removeCookie, setCookie } from "#app/utils/cookies"; /** * A wrapper for PokéRogue account API requests. diff --git a/src/plugins/api/pokerogue-session-savedata-api.ts b/src/plugins/api/pokerogue-session-savedata-api.ts index e703d55a242..aac8b9b93ad 100644 --- a/src/plugins/api/pokerogue-session-savedata-api.ts +++ b/src/plugins/api/pokerogue-session-savedata-api.ts @@ -20,17 +20,20 @@ export class PokerogueSessionSavedataApi extends ApiBase { * *This is **NOT** the same as {@linkcode clear | clear()}.* * @param params The {@linkcode NewClearSessionSavedataRequest} to send * @returns The raw savedata as `string`. + * @throws Error if the request fails */ public async newclear(params: NewClearSessionSavedataRequest) { try { const urlSearchParams = this.toUrlSearchParams(params); const response = await this.doGet(`/savedata/session/newclear?${urlSearchParams}`); const json = await response.json(); - - return Boolean(json); + if (response.ok) { + return Boolean(json); + } + throw new Error("Could not newclear session!"); } catch (err) { console.warn("Could not newclear session!", err); - return false; + throw new Error("Could not newclear session!"); } } diff --git a/src/plugins/api/pokerogue-system-savedata-api.ts b/src/plugins/api/pokerogue-system-savedata-api.ts index 659584776c4..d6fbb39ae0a 100644 --- a/src/plugins/api/pokerogue-system-savedata-api.ts +++ b/src/plugins/api/pokerogue-system-savedata-api.ts @@ -15,14 +15,17 @@ export class PokerogueSystemSavedataApi extends ApiBase { /** * Get a system savedata. * @param params The {@linkcode GetSystemSavedataRequest} to send - * @returns The system savedata as `string` or `null` on error + * @returns The system savedata as `string` or either the status code or `null` on error */ - public async get(params: GetSystemSavedataRequest) { + public async get(params: GetSystemSavedataRequest): Promise { try { const urlSearchParams = this.toUrlSearchParams(params); const response = await this.doGet(`/savedata/system/get?${urlSearchParams}`); const rawSavedata = await response.text(); - + if (!response.ok) { + console.warn("Could not get system savedata!", response.status, rawSavedata); + return response.status; + } return rawSavedata; } catch (err) { console.warn("Could not get system savedata!", err); diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 5e145d08e28..ff9e54fcf50 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -1,4 +1,4 @@ -import { camelCaseToKebabCase } from "#app/utils"; +import { camelCaseToKebabCase } from "#app/utils/common"; import i18next from "i18next"; import LanguageDetector from "i18next-browser-languagedetector"; import HttpBackend from "i18next-http-backend"; diff --git a/src/sprites/pokemon-asset-loader.ts b/src/sprites/pokemon-asset-loader.ts new file mode 100644 index 00000000000..4ce88f4f1fb --- /dev/null +++ b/src/sprites/pokemon-asset-loader.ts @@ -0,0 +1,11 @@ +import type { Moves } from "#enums/moves"; +import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims"; + +/** + * Asynchronously load the animations and assets for the provided moves. + * @param moveIds - An array of move IDs to load assets for. + */ +export async function loadMoveAnimations(moveIds: Moves[]): Promise { + await Promise.allSettled(moveIds.map(m => initMoveAnim(m))); + await loadMoveAnimAssets(moveIds); +} diff --git a/src/sprites/pokemon-sprite.ts b/src/sprites/pokemon-sprite.ts new file mode 100644 index 00000000000..66432f5a4ea --- /dev/null +++ b/src/sprites/pokemon-sprite.ts @@ -0,0 +1,79 @@ +import { globalScene } from "#app/global-scene"; +import { variantColorCache, variantData } from "#app/sprites/variant"; +import { Gender } from "#app/data/gender"; +import { hasExpSprite } from "./sprite-utils"; +import type { Variant, VariantSet } from "#app/sprites/variant"; +import type Pokemon from "#app/field/pokemon"; +import type BattleScene from "#app/battle-scene"; + +// Regex patterns + +/** Regex matching double underscores */ +const DUNDER_REGEX = /\_{2}/g; + +/** + * Calculate the sprite ID from a pokemon form. + */ +export function getSpriteId(pokemon: Pokemon, ignoreOverride?: boolean): string { + return pokemon + .getSpeciesForm(ignoreOverride) + .getSpriteId( + pokemon.getGender(ignoreOverride) === Gender.FEMALE, + pokemon.formIndex, + pokemon.shiny, + pokemon.variant, + ); +} + +export function getBattleSpriteId(pokemon: Pokemon, back?: boolean, ignoreOverride = false): string { + if (back === undefined) { + back = pokemon.isPlayer(); + } + return pokemon + .getSpeciesForm(ignoreOverride) + .getSpriteId( + pokemon.getGender(ignoreOverride) === Gender.FEMALE, + pokemon.formIndex, + pokemon.shiny, + pokemon.variant, + back, + ); +} + +/** Compute the path to the sprite atlas by converting double underscores to path components (/) + */ +export function getSpriteAtlasPath(pokemon: Pokemon, ignoreOverride = false): string { + const spriteId = getSpriteId(pokemon, ignoreOverride).replace(DUNDER_REGEX, "/"); + return `${/_[1-3]$/.test(spriteId) ? "variant/" : ""}${spriteId}`; +} + +/** + * Load the variant assets for the given sprite and store it in {@linkcode variantColorCache}. + * @param spriteKey - The key of the sprite to load + * @param fileRoot - The root path of the sprite file + * @param variant - The variant to load + * @param scene - The scene to load the assets in (defaults to the global scene) + */ +export async function loadPokemonVariantAssets( + spriteKey: string, + fileRoot: string, + variant: Variant, + scene: BattleScene = globalScene, +): Promise { + if (variantColorCache.hasOwnProperty(spriteKey)) { + return; + } + const useExpSprite = scene.experimentalSprites && hasExpSprite(spriteKey); + if (useExpSprite) { + fileRoot = `exp/${fileRoot}`; + } + let variantConfig = variantData; + fileRoot.split("/").map(p => (variantConfig ? (variantConfig = variantConfig[p]) : null)); + const variantSet = variantConfig as VariantSet; + if (!variantConfig || variantSet[variant] !== 1) { + return; + } + variantColorCache[spriteKey] = await scene + .cachedFetch(`./images/pokemon/variant/${fileRoot}.json`) + .then(res => res.json()); +} diff --git a/src/sprites/sprite-keys.ts b/src/sprites/sprite-keys.ts new file mode 100644 index 00000000000..f023df089f6 --- /dev/null +++ b/src/sprites/sprite-keys.ts @@ -0,0 +1 @@ +export const expSpriteKeys: Set = new Set(); diff --git a/src/sprites/sprite-utils.ts b/src/sprites/sprite-utils.ts new file mode 100644 index 00000000000..8a352de3d55 --- /dev/null +++ b/src/sprites/sprite-utils.ts @@ -0,0 +1,28 @@ +import { expSpriteKeys } from "#app/sprites/sprite-keys"; + +const expKeyRegex = /^pkmn__?(back__)?(shiny__)?(female__)?(\d+)(\-.*?)?(?:_[1-3])?$/; + +export function hasExpSprite(key: string): boolean { + const keyMatch = expKeyRegex.exec(key); + if (!keyMatch) { + return false; + } + + let k = keyMatch[4]!; + if (keyMatch[2]) { + k += "s"; + } + if (keyMatch[1]) { + k += "b"; + } + if (keyMatch[3]) { + k += "f"; + } + if (keyMatch[5]) { + k += keyMatch[5]; + } + if (!expSpriteKeys.has(k)) { + return false; + } + return true; +} diff --git a/src/sprites/variant.ts b/src/sprites/variant.ts new file mode 100644 index 00000000000..985068015c6 --- /dev/null +++ b/src/sprites/variant.ts @@ -0,0 +1,145 @@ +import { VariantTier } from "#app/enums/variant-tier"; +import { hasExpSprite } from "#app/sprites/sprite-utils"; +import { globalScene } from "#app/global-scene"; +import type Pokemon from "#app/field/pokemon"; +import { isNullOrUndefined } from "#app/utils/common"; + +export type Variant = 0 | 1 | 2; + +export type VariantSet = [Variant, Variant, Variant]; + +export const variantData: any = {}; + +/** Caches variant colors that have been generated */ +export const variantColorCache = {}; + +export function getVariantTint(variant: Variant): number { + switch (variant) { + case 0: + return 0xf8c020; + case 1: + return 0x20f8f0; + case 2: + return 0xe81048; + } +} + +export function getVariantIcon(variant: Variant): number { + switch (variant) { + case 0: + return VariantTier.STANDARD; + case 1: + return VariantTier.RARE; + case 2: + return VariantTier.EPIC; + } +} + +/** Delete all of the keys in variantData */ +export function clearVariantData(): void { + for (const key in variantData) { + delete variantData[key]; + } +} + +/** Update the variant data to use experiment sprite files for variants that have experimental sprites. */ +export async function mergeExperimentalData(mainData: any, expData: any): Promise { + if (!expData) { + return; + } + + for (const key of Object.keys(expData)) { + if (typeof expData[key] === "object" && !Array.isArray(expData[key])) { + // If the value is an object, recursively merge. + if (!mainData[key]) { + mainData[key] = {}; + } + mergeExperimentalData(mainData[key], expData[key]); + } else { + // Otherwise, replace the value + mainData[key] = expData[key]; + } + } +} + +/** + * Populate the variant color cache with the variant colors for this pokemon. + * The global scene must be initialized before this function is called. + */ +export async function populateVariantColors( + pokemon: Pokemon, + isBackSprite = false, + ignoreOverride = true, +): Promise { + const battleSpritePath = pokemon + .getBattleSpriteAtlasPath(isBackSprite, ignoreOverride) + .replace("variant/", "") + .replace(/_[1-3]$/, ""); + let config = variantData; + const useExpSprite = + globalScene.experimentalSprites && hasExpSprite(pokemon.getBattleSpriteKey(isBackSprite, ignoreOverride)); + battleSpritePath.split("/").map(p => (config ? (config = config[p]) : null)); + const variantSet: VariantSet = config as VariantSet; + if (!variantSet || variantSet[pokemon.variant] !== 1) { + return; + } + const cacheKey = pokemon.getBattleSpriteKey(isBackSprite); + if (!variantColorCache.hasOwnProperty(cacheKey)) { + await populateVariantColorCache(cacheKey, useExpSprite, battleSpritePath); + } +} + +/** + * Gracefully handle errors loading a variant sprite. Log if it fails and attempt to fall back on + * non-experimental sprites before giving up. + * + * @param cacheKey - The cache key for the variant color sprite + * @param attemptedSpritePath - The sprite path that failed to load + * @param useExpSprite - Was the attempted sprite experimental + * @param battleSpritePath - The filename of the sprite + * @param optionalParams - Any additional params to log + */ +async function fallbackVariantColor( + cacheKey: string, + attemptedSpritePath: string, + useExpSprite: boolean, + battleSpritePath: string, + ...optionalParams: any[] +): Promise { + console.warn(`Could not load ${attemptedSpritePath}!`, ...optionalParams); + if (useExpSprite) { + await populateVariantColorCache(cacheKey, false, battleSpritePath); + } +} + +/** + * Fetch a variant color sprite from the key and store it in the variant color cache. + * + * @param cacheKey - The cache key for the variant color sprite + * @param useExpSprite - Should the experimental sprite be used + * @param battleSpritePath - The filename of the sprite + */ +export async function populateVariantColorCache( + cacheKey: string, + useExpSprite: boolean, + battleSpritePath: string, +): Promise { + const spritePath = `./images/pokemon/variant/${useExpSprite ? "exp/" : ""}${battleSpritePath}.json`; + return globalScene + .cachedFetch(spritePath) + .then(res => { + // Prevent the JSON from processing if it failed to load + if (!res.ok) { + return fallbackVariantColor(cacheKey, res.url, useExpSprite, battleSpritePath, res.status, res.statusText); + } + return res.json(); + }) + .catch(error => { + return fallbackVariantColor(cacheKey, spritePath, useExpSprite, battleSpritePath, error); + }) + .then(c => { + if (!isNullOrUndefined(c)) { + variantColorCache[cacheKey] = c; + } + }); +} diff --git a/src/starter-colors.ts b/src/starter-colors.ts new file mode 100644 index 00000000000..6abe028be99 --- /dev/null +++ b/src/starter-colors.ts @@ -0,0 +1,4 @@ +export const starterColors: StarterColors = {}; +interface StarterColors { + [key: string]: [string, string]; +} diff --git a/src/starting-wave.ts b/src/starting-wave.ts new file mode 100644 index 00000000000..3d36dabe652 --- /dev/null +++ b/src/starting-wave.ts @@ -0,0 +1,3 @@ +import Overrides from "./overrides"; + +export const startingWave = Overrides.STARTING_WAVE_OVERRIDE || 1; diff --git a/src/system/achv.ts b/src/system/achv.ts index bd8595b2f94..90816ff65c3 100644 --- a/src/system/achv.ts +++ b/src/system/achv.ts @@ -2,7 +2,7 @@ import type { Modifier } from "typescript"; import { TurnHeldItemTransferModifier } from "../modifier/modifier"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import i18next from "i18next"; -import * as Utils from "../utils"; +import { NumberHolder } from "#app/utils/common"; import { PlayerGender } from "#enums/player-gender"; import type { Challenge } from "#app/data/challenge"; import { @@ -138,7 +138,7 @@ export class DamageAchv extends Achv { "", iconImage, score, - (args: any[]) => (args[0] instanceof Utils.NumberHolder ? args[0].value : args[0]) >= this.damageAmount, + (args: any[]) => (args[0] instanceof NumberHolder ? args[0].value : args[0]) >= this.damageAmount, ); this.damageAmount = damageAmount; } @@ -154,7 +154,7 @@ export class HealAchv extends Achv { "", iconImage, score, - (args: any[]) => (args[0] instanceof Utils.NumberHolder ? args[0].value : args[0]) >= this.healAmount, + (args: any[]) => (args[0] instanceof NumberHolder ? args[0].value : args[0]) >= this.healAmount, ); this.healAmount = healAmount; } @@ -170,7 +170,7 @@ export class LevelAchv extends Achv { "", iconImage, score, - (args: any[]) => (args[0] instanceof Utils.NumberHolder ? args[0].value : args[0]) >= this.level, + (args: any[]) => (args[0] instanceof NumberHolder ? args[0].value : args[0]) >= this.level, ); this.level = level; } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 391ceec503d..e200fa6b3c7 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1,6 +1,6 @@ import i18next from "i18next"; import type { PokeballCounts } from "#app/battle-scene"; -import { bypassLogin } from "#app/battle-scene"; +import { bypassLogin } from "#app/global-vars/bypass-login"; import { globalScene } from "#app/global-scene"; import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; @@ -8,14 +8,14 @@ import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; import type PokemonSpecies from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import { speciesStarterCosts } from "#app/data/balance/starters"; -import * as Utils from "#app/utils"; +import { randInt, getEnumKeys, isLocal, executeIf, fixedInt, randSeedItem, NumberHolder } from "#app/utils/common"; import Overrides from "#app/overrides"; import PokemonData from "#app/system/pokemon-data"; import PersistentModifierData from "#app/system/modifier-data"; import ArenaData from "#app/system/arena-data"; import { Unlockables } from "#app/system/unlockables"; import { GameModes, getGameMode } from "#app/game-mode"; -import { BattleType } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import TrainerData from "#app/system/trainer-data"; import { trainerConfigs } from "#app/data/trainers/trainer-config"; import { resetSettings, setSetting, SettingKeys } from "#app/system/settings/settings"; @@ -24,7 +24,7 @@ import EggData from "#app/system/egg-data"; import type { Egg } from "#app/data/egg"; import { vouchers, VoucherType } from "#app/system/voucher"; import { AES, enc } from "crypto-js"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { clientSessionId, loggedInUser, updateUserInfo } from "#app/account"; import { Nature } from "#enums/nature"; import { GameStats } from "#app/system/game-stats"; @@ -32,11 +32,12 @@ import { Tutorial } from "#app/tutorial"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { allMoves } from "#app/data/moves/move"; import { TrainerVariant } from "#app/field/trainer"; -import type { Variant } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; import { setSettingGamepad, SettingGamepad, settingGamepadDefaults } from "#app/system/settings/settings-gamepad"; import type { SettingKeyboard } from "#app/system/settings/settings-keyboard"; import { setSettingKeyboard } from "#app/system/settings/settings-keyboard"; import { TagAddedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena"; +// biome-ignore lint/style/noNamespaceImport: Something weird is going on here and I don't want to touch it import * as Modifier from "#app/modifier/modifier"; import { StatusEffect } from "#enums/status-effect"; import ChallengeData from "#app/system/challenge-data"; @@ -360,8 +361,8 @@ export class GameData { this.loadSettings(); this.loadGamepadSettings(); this.loadMappingConfigs(); - this.trainerId = Utils.randInt(65536); - this.secretId = Utils.randInt(65536); + this.trainerId = randInt(65536); + this.secretId = randInt(65536); this.starterData = {}; this.gameStats = new GameStats(); this.runHistory = {}; @@ -461,8 +462,13 @@ export class GameData { if (!bypassLogin) { pokerogueApi.savedata.system.get({ clientSessionId }).then(saveDataOrErr => { - if (!saveDataOrErr || saveDataOrErr.length === 0 || saveDataOrErr[0] !== "{") { - if (saveDataOrErr?.startsWith("sql: no rows in result set")) { + if ( + typeof saveDataOrErr === "number" || + !saveDataOrErr || + saveDataOrErr.length === 0 || + saveDataOrErr[0] !== "{" + ) { + if (saveDataOrErr === 404) { globalScene.queueMessage( "Save data could not be found. If this is a new account, you can safely ignore this message.", null, @@ -470,7 +476,7 @@ export class GameData { ); return resolve(true); } - if (saveDataOrErr?.includes("Too many connections")) { + if (typeof saveDataOrErr === "string" && saveDataOrErr?.includes("Too many connections")) { globalScene.queueMessage( "Too many people are trying to connect and the server is overloaded. Please try again later.", null, @@ -478,7 +484,6 @@ export class GameData { ); return resolve(false); } - console.error(saveDataOrErr); return resolve(false); } @@ -589,7 +594,7 @@ export class GameData { } if (systemData.voucherCounts) { - Utils.getEnumKeys(VoucherType).forEach(key => { + getEnumKeys(VoucherType).forEach(key => { const index = VoucherType[key]; this.voucherCounts[index] = systemData.voucherCounts[index] || 0; }); @@ -617,7 +622,7 @@ export class GameData { * At the moment, only retrievable from locale cache */ async getRunHistoryData(): Promise { - if (!Utils.isLocal) { + if (!isLocal) { /** * Networking Code DO NOT DELETE! * Note: Might have to be migrated to `pokerogue-api.ts` @@ -1035,6 +1040,7 @@ export class GameData { } getSession(slotId: number): Promise { + // biome-ignore lint/suspicious/noAsyncPromiseExecutor: return new Promise(async (resolve, reject) => { if (slotId < 0) { return resolve(null); @@ -1075,6 +1081,7 @@ export class GameData { } loadSession(slotId: number, sessionData?: SessionSaveData): Promise { + // biome-ignore lint/suspicious/noAsyncPromiseExecutor: return new Promise(async (resolve, reject) => { try { const initSessionFromData = async (sessionData: SessionSaveData) => { @@ -1138,7 +1145,7 @@ export class GameData { ? trainerConfig?.doubleOnly || sessionData.trainer?.variant === TrainerVariant.DOUBLE : sessionData.enemyParty.length > 1, mysteryEncounterType, - )!; // TODO: is this bang correct? + ); battle.enemyLevels = sessionData.enemyParty.map(p => p.level); globalScene.arena.init(); @@ -1191,13 +1198,16 @@ export class GameData { } } + if (globalScene.modifiers.length) { + console.warn("Existing modifiers not cleared on session load, deleting..."); + globalScene.modifiers = []; + } for (const modifierData of sessionData.modifiers) { const modifier = modifierData.toModifier(Modifier[modifierData.className]); if (modifier) { globalScene.addModifier(modifier, true); } } - globalScene.updateModifiers(true); for (const enemyModifierData of sessionData.enemyModifiers) { @@ -1335,68 +1345,67 @@ export class GameData { } parseSessionData(dataStr: string): SessionSaveData { + // TODO: Add `null`/`undefined` to the corresponding type signatures for this + // (or prevent them from being null) + // If the value is able to *not exist*, it should say so in the code const sessionData = JSON.parse(dataStr, (k: string, v: any) => { - if (k === "party" || k === "enemyParty") { - const ret: PokemonData[] = []; - if (v === null) { - v = []; - } - for (const pd of v) { - ret.push(new PokemonData(pd)); - } - return ret; - } - - if (k === "trainer") { - return v ? new TrainerData(v) : null; - } - - if (k === "modifiers" || k === "enemyModifiers") { - const player = k === "modifiers"; - const ret: PersistentModifierData[] = []; - if (v === null) { - v = []; - } - for (const md of v) { - if (md?.className === "ExpBalanceModifier") { - // Temporarily limit EXP Balance until it gets reworked - md.stackCount = Math.min(md.stackCount, 4); + // TODO: Add pre-parse migrate scripts + switch (k) { + case "party": + case "enemyParty": { + const ret: PokemonData[] = []; + for (const pd of v ?? []) { + ret.push(new PokemonData(pd)); } - if ( - (md instanceof Modifier.EnemyAttackStatusEffectChanceModifier && md.effect === StatusEffect.FREEZE) || - md.effect === StatusEffect.SLEEP - ) { - continue; + return ret; + } + + case "trainer": + return v ? new TrainerData(v) : null; + + case "modifiers": + case "enemyModifiers": { + const ret: PersistentModifierData[] = []; + for (const md of v ?? []) { + if (md?.className === "ExpBalanceModifier") { + // Temporarily limit EXP Balance until it gets reworked + md.stackCount = Math.min(md.stackCount, 4); + } + + if ( + md instanceof Modifier.EnemyAttackStatusEffectChanceModifier && + (md.effect === StatusEffect.FREEZE || md.effect === StatusEffect.SLEEP) + ) { + // Discard any old "sleep/freeze chance tokens". + // TODO: make this migrate script + continue; + } + + ret.push(new PersistentModifierData(md, k === "modifiers")); } - ret.push(new PersistentModifierData(md, player)); + return ret; } - return ret; - } - if (k === "arena") { - return new ArenaData(v); - } + case "arena": + return new ArenaData(v); - if (k === "challenges") { - const ret: ChallengeData[] = []; - if (v === null) { - v = []; + case "challenges": { + const ret: ChallengeData[] = []; + for (const c of v ?? []) { + ret.push(new ChallengeData(c)); + } + return ret; } - for (const c of v) { - ret.push(new ChallengeData(c)); - } - return ret; - } - if (k === "mysteryEncounterType") { - return v as MysteryEncounterType; - } + case "mysteryEncounterType": + return v as MysteryEncounterType; - if (k === "mysteryEncounterSaveData") { - return new MysteryEncounterSaveData(v); - } + case "mysteryEncounterSaveData": + return new MysteryEncounterSaveData(v); - return v; + default: + return v; + } }) as SessionSaveData; applySessionVersionMigration(sessionData); @@ -1406,7 +1415,7 @@ export class GameData { saveAll(skipVerification = false, sync = false, useCachedSession = false, useCachedSystem = false): Promise { return new Promise(resolve => { - Utils.executeIf(!skipVerification, updateUserInfo).then(success => { + executeIf(!skipVerification, updateUserInfo).then(success => { if (success !== null && !success) { return resolve(false); } @@ -1423,7 +1432,6 @@ export class GameData { ), ) // TODO: is this bang correct? : this.getSessionSaveData(); - const maxIntAttrValue = 0x80000000; const systemData = useCachedSystem ? this.parseSystemData(decrypt(localStorage.getItem(`data_${loggedInUser?.username}`)!, bypassLogin)) @@ -1445,13 +1453,12 @@ export class GameData { bypassLogin, ), ); - localStorage.setItem( `sessionData${globalScene.sessionSlotId ? globalScene.sessionSlotId : ""}_${loggedInUser?.username}`, encrypt(JSON.stringify(sessionData), bypassLogin), ); - console.debug("Session data saved"); + console.debug("Session data saved!"); if (!bypassLogin && sync) { pokerogueApi.savedata.updateAll(request).then(error => { @@ -1499,7 +1506,7 @@ export class GameData { link.remove(); }; if (!bypassLogin && dataType < GameDataType.SETTINGS) { - let promise: Promise = Promise.resolve(null); + let promise: Promise = Promise.resolve(null); if (dataType === GameDataType.SYSTEM) { promise = pokerogueApi.savedata.system.get({ clientSessionId }); @@ -1511,7 +1518,7 @@ export class GameData { } promise.then(response => { - if (!response?.length || response[0] !== "{") { + if (typeof response === "number" || !response?.length || response[0] !== "{") { console.error(response); resolve(false); return; @@ -1586,7 +1593,7 @@ export class GameData { } const displayError = (error: string) => - globalScene.ui.showText(error, null, () => globalScene.ui.showText("", 0), Utils.fixedInt(1500)); + globalScene.ui.showText(error, null, () => globalScene.ui.showText("", 0), fixedInt(1500)); dataName = dataName!; // tell TS compiler that dataName is defined! if (!valid) { @@ -1594,7 +1601,7 @@ export class GameData { `Your ${dataName} data could not be loaded. It may be corrupted.`, null, () => globalScene.ui.showText("", 0), - Utils.fixedInt(1500), + fixedInt(1500), ); } @@ -1603,7 +1610,7 @@ export class GameData { null, () => { globalScene.ui.setOverlayMode( - Mode.CONFIRM, + UiMode.CONFIRM, () => { localStorage.setItem(dataKey, encrypt(dataStr, bypassLogin)); @@ -1687,7 +1694,7 @@ export class GameData { () => { const neutralNatures = [Nature.HARDY, Nature.DOCILE, Nature.SERIOUS, Nature.BASHFUL, Nature.QUIRKY]; for (let s = 0; s < defaultStarterSpecies.length; s++) { - defaultStarterNatures.push(Utils.randSeedItem(neutralNatures)); + defaultStarterNatures.push(randSeedItem(neutralNatures)); } }, 0, @@ -2188,7 +2195,7 @@ export class GameData { value = decrementValue(value); } - const cost = new Utils.NumberHolder(value); + const cost = new NumberHolder(value); applyChallenges(ChallengeType.STARTER_COST, speciesId, cost); return cost.value; @@ -2216,7 +2223,7 @@ export class GameData { entry.hatchedCount = 0; } if (!entry.hasOwnProperty("natureAttr") || (entry.caughtAttr && !entry.natureAttr)) { - entry.natureAttr = this.defaultDexData?.[k].natureAttr || 1 << Utils.randInt(25, 1); + entry.natureAttr = this.defaultDexData?.[k].natureAttr || 1 << randInt(25, 1); } } } diff --git a/src/system/game-speed.ts b/src/system/game-speed.ts index d9c48664f80..712870dfaf1 100644 --- a/src/system/game-speed.ts +++ b/src/system/game-speed.ts @@ -3,7 +3,7 @@ import type FadeIn from "phaser3-rex-plugins/plugins/audio/fade/FadeIn"; import type FadeOut from "phaser3-rex-plugins/plugins/audio/fade/FadeOut"; import type BattleScene from "#app/battle-scene"; import { globalScene } from "#app/global-scene"; -import * as Utils from "../utils"; +import { FixedInt } from "#app/utils/common"; type FadeInType = typeof FadeIn; type FadeOutType = typeof FadeOut; @@ -11,9 +11,9 @@ type FadeOutType = typeof FadeOut; export function initGameSpeed() { const thisArg = this as BattleScene; - const transformValue = (value: number | Utils.FixedInt): number => { - if (value instanceof Utils.FixedInt) { - return (value as Utils.FixedInt).value; + const transformValue = (value: number | FixedInt): number => { + if (value instanceof FixedInt) { + return (value as FixedInt).value; } return thisArg.gameSpeed === 1 ? value : Math.ceil((value /= thisArg.gameSpeed)); }; diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index 957d43797a1..ef1f30830f0 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -1,16 +1,15 @@ -import { BattleType } from "../battle"; +import { BattleType } from "#enums/battle-type"; import { globalScene } from "#app/global-scene"; import type { Gender } from "../data/gender"; -import type { Nature } from "#enums/nature"; -import type { PokeballType } from "#enums/pokeball"; +import { Nature } from "#enums/nature"; +import { PokeballType } from "#enums/pokeball"; import { getPokemonSpecies, getPokemonSpeciesForm } from "../data/pokemon-species"; import { Status } from "../data/status-effect"; -import Pokemon, { EnemyPokemon, PokemonMove, PokemonSummonData } from "../field/pokemon"; +import Pokemon, { EnemyPokemon, PokemonBattleData, PokemonMove, PokemonSummonData } from "../field/pokemon"; import { TrainerSlot } from "#enums/trainer-slot"; -import type { Variant } from "#app/data/variant"; -import { loadBattlerTag } from "../data/battler-tags"; +import type { Variant } from "#app/sprites/variant"; import type { Biome } from "#enums/biome"; -import { Moves } from "#enums/moves"; +import type { Moves } from "#enums/moves"; import type { Species } from "#enums/species"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import type { PokemonType } from "#enums/pokemon-type"; @@ -60,73 +59,68 @@ export default class PokemonData { public fusionTeraType: PokemonType; public boss: boolean; - public bossSegments?: number; + public bossSegments: number; + // Effects that need to be preserved between waves public summonData: PokemonSummonData; + public battleData: PokemonBattleData; public summonDataSpeciesFormIndex: number; - /** Data that can customize a Pokemon in non-standard ways from its Species */ public customPokemonData: CustomPokemonData; public fusionCustomPokemonData: CustomPokemonData; // Deprecated attributes, needed for now to allow SessionData migration (see PR#4619 comments) + // TODO: Remove these once pre-session migration is implemented public natureOverride: Nature | -1; public mysteryEncounterPokemonData: CustomPokemonData | null; public fusionMysteryEncounterPokemonData: CustomPokemonData | null; - constructor(source: Pokemon | any, forHistory = false) { - const sourcePokemon = source instanceof Pokemon ? source : null; + /** + * Construct a new {@linkcode PokemonData} instance out of a {@linkcode Pokemon} + * or JSON representation thereof. + * @param source The {@linkcode Pokemon} to convert into data (or a JSON object representing one) + */ + // TODO: Remove any from type signature in favor of 2 separate method funcs + constructor(source: Pokemon | any) { + const sourcePokemon = source instanceof Pokemon ? source : undefined; + this.id = source.id; - this.player = sourcePokemon ? sourcePokemon.isPlayer() : source.player; - this.species = sourcePokemon ? sourcePokemon.species.speciesId : source.species; - this.nickname = sourcePokemon ? sourcePokemon.nickname : source.nickname; + this.player = sourcePokemon?.isPlayer() ?? source.player; + this.species = sourcePokemon?.species.speciesId ?? source.species; + this.nickname = sourcePokemon?.summonData.illusion?.basePokemon.nickname ?? source.nickname; this.formIndex = Math.max(Math.min(source.formIndex, getPokemonSpecies(this.species).forms.length - 1), 0); this.abilityIndex = source.abilityIndex; this.passive = source.passive; - this.shiny = source.shiny; - this.variant = source.variant; - this.pokeball = source.pokeball; + this.shiny = sourcePokemon?.isShiny() ?? source.shiny; + this.variant = sourcePokemon?.getVariant() ?? source.variant; + this.pokeball = source.pokeball ?? PokeballType.POKEBALL; this.level = source.level; this.exp = source.exp; - if (!forHistory) { - this.levelExp = source.levelExp; - } + this.levelExp = source.levelExp; this.gender = source.gender; - if (!forHistory) { - this.hp = source.hp; - } + this.hp = source.hp; this.stats = source.stats; this.ivs = source.ivs; - this.nature = source.nature !== undefined ? source.nature : (0 as Nature); - this.friendship = - source.friendship !== undefined ? source.friendship : getPokemonSpecies(this.species).baseFriendship; + + // TODO: Can't we move some of this verification stuff to an upgrade script? + this.nature = source.nature ?? Nature.HARDY; + this.moveset = source.moveset.map((m: any) => PokemonMove.loadMove(m)); + this.status = source.status + ? new Status(source.status.effect, source.status.toxicTurnCount, source.status.sleepTurnsRemaining) + : null; + this.friendship = source.friendship ?? getPokemonSpecies(this.species).baseFriendship; this.metLevel = source.metLevel || 5; - this.metBiome = source.metBiome !== undefined ? source.metBiome : -1; + this.metBiome = source.metBiome ?? -1; this.metSpecies = source.metSpecies; this.metWave = source.metWave ?? (this.metBiome === -1 ? -1 : 0); - this.luck = source.luck !== undefined ? source.luck : source.shiny ? source.variant + 1 : 0; - if (!forHistory) { - this.pauseEvolutions = !!source.pauseEvolutions; - this.evoCounter = source.evoCounter ?? 0; - } + this.luck = source.luck ?? (source.shiny ? source.variant + 1 : 0); + this.pauseEvolutions = !!source.pauseEvolutions; this.pokerus = !!source.pokerus; - this.teraType = source.teraType as PokemonType; - this.isTerastallized = source.isTerastallized || false; - this.stellarTypesBoosted = source.stellarTypesBoosted || []; - - this.fusionSpecies = sourcePokemon ? sourcePokemon.fusionSpecies?.speciesId : source.fusionSpecies; - this.fusionFormIndex = source.fusionFormIndex; - this.fusionAbilityIndex = source.fusionAbilityIndex; - this.fusionShiny = source.fusionShiny; - this.fusionVariant = source.fusionVariant; - this.fusionGender = source.fusionGender; - this.fusionLuck = - source.fusionLuck !== undefined ? source.fusionLuck : source.fusionShiny ? source.fusionVariant + 1 : 0; - this.fusionCustomPokemonData = new CustomPokemonData(source.fusionCustomPokemonData); - this.fusionTeraType = (source.fusionTeraType ?? 0) as PokemonType; this.usedTMs = source.usedTMs ?? []; - - this.customPokemonData = new CustomPokemonData(source.customPokemonData); + this.evoCounter = source.evoCounter ?? 0; + this.teraType = source.teraType as PokemonType; + this.isTerastallized = !!source.isTerastallized; + this.stellarTypesBoosted = source.stellarTypesBoosted ?? []; // Deprecated, but needed for session data migration this.natureOverride = source.natureOverride; @@ -137,51 +131,25 @@ export default class PokemonData { ? new CustomPokemonData(source.fusionMysteryEncounterPokemonData) : null; - if (!forHistory) { - this.boss = (source instanceof EnemyPokemon && !!source.bossSegments) || (!this.player && !!source.boss); - this.bossSegments = source.bossSegments; - } + this.fusionSpecies = sourcePokemon?.fusionSpecies?.speciesId ?? source.fusionSpecies; + this.fusionFormIndex = source.fusionFormIndex; + this.fusionAbilityIndex = source.fusionAbilityIndex; + this.fusionShiny = sourcePokemon?.summonData.illusion?.basePokemon.fusionShiny ?? source.fusionShiny; + this.fusionVariant = sourcePokemon?.summonData.illusion?.basePokemon.fusionVariant ?? source.fusionVariant; + this.fusionGender = source.fusionGender; + this.fusionLuck = source.fusionLuck ?? (source.fusionShiny ? source.fusionVariant + 1 : 0); + this.fusionTeraType = (source.fusionTeraType ?? 0) as PokemonType; - if (sourcePokemon) { - this.moveset = sourcePokemon.moveset; - if (!forHistory) { - this.status = sourcePokemon.status; - if (this.player && sourcePokemon.summonData) { - this.summonData = sourcePokemon.summonData; - this.summonDataSpeciesFormIndex = this.getSummonDataSpeciesFormIndex(); - } - } - } else { - this.moveset = (source.moveset || [new PokemonMove(Moves.TACKLE), new PokemonMove(Moves.GROWL)]) - .filter(m => m) - .map((m: any) => new PokemonMove(m.moveId, m.ppUsed, m.ppUp, m.virtual, m.maxPpOverride)); - if (!forHistory) { - this.status = source.status - ? new Status(source.status.effect, source.status.toxicTurnCount, source.status.sleepTurnsRemaining) - : null; - } + this.boss = (source instanceof EnemyPokemon && !!source.bossSegments) || (!this.player && !!source.boss); + this.bossSegments = source.bossSegments ?? 0; - this.summonData = new PokemonSummonData(); - if (!forHistory && source.summonData) { - this.summonData.stats = source.summonData.stats; - this.summonData.statStages = source.summonData.statStages; - this.summonData.moveQueue = source.summonData.moveQueue; - this.summonData.abilitySuppressed = source.summonData.abilitySuppressed; - this.summonData.abilitiesApplied = source.summonData.abilitiesApplied; + this.summonData = new PokemonSummonData(source.summonData); + this.battleData = new PokemonBattleData(source.battleData); + this.summonDataSpeciesFormIndex = + sourcePokemon?.summonData.speciesForm?.formIndex ?? source.summonDataSpeciesFormIndex; - this.summonData.ability = source.summonData.ability; - this.summonData.moveset = source.summonData.moveset?.map(m => PokemonMove.loadMove(m)); - this.summonData.types = source.summonData.types; - this.summonData.speciesForm = source.summonData.speciesForm; - this.summonDataSpeciesFormIndex = source.summonDataSpeciesFormIndex; - - if (source.summonData.tags) { - this.summonData.tags = source.summonData.tags?.map(t => loadBattlerTag(t)); - } else { - this.summonData.tags = []; - } - } - } + this.customPokemonData = new CustomPokemonData(source.customPokemonData); + this.fusionCustomPokemonData = new CustomPokemonData(source.fusionCustomPokemonData); } toPokemon(battleType?: BattleType, partyMemberIndex = 0, double = false): Pokemon { @@ -216,29 +184,15 @@ export default class PokemonData { false, this, ); - if (this.summonData) { - // when loading from saved session, recover summonData.speciesFrom and form index species object - // used to stay transformed on reload session - if (this.summonData.speciesForm) { - this.summonData.speciesForm = getPokemonSpeciesForm( - this.summonData.speciesForm.speciesId, - this.summonDataSpeciesFormIndex, - ); - } - ret.primeSummonData(this.summonData); + + // when loading from saved session, recover summonData.speciesFrom and form index species object + // used to stay transformed on reload session + if (this.summonData.speciesForm) { + this.summonData.speciesForm = getPokemonSpeciesForm( + this.summonData.speciesForm.speciesId, + this.summonDataSpeciesFormIndex, + ); } return ret; } - - /** - * Method to save summon data species form index - * Necessary in case the pokemon is transformed - * to reload the correct form - */ - getSummonDataSpeciesFormIndex(): number { - if (this.summonData.speciesForm) { - return this.summonData.speciesForm.formIndex; - } - return 0; - } } diff --git a/src/system/settings/settings-gamepad.ts b/src/system/settings/settings-gamepad.ts index f4a6bd465af..12add905096 100644 --- a/src/system/settings/settings-gamepad.ts +++ b/src/system/settings/settings-gamepad.ts @@ -1,6 +1,6 @@ import type SettingsGamepadUiHandler from "../../ui/settings/settings-gamepad-ui-handler"; -import { Mode } from "../../ui/ui"; -import { truncateString } from "../../utils"; +import { UiMode } from "#enums/ui-mode"; +import { truncateString } from "../../utils/common"; import { Button } from "#enums/buttons"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; import { globalScene } from "#app/global-scene"; @@ -107,7 +107,7 @@ export function setSettingGamepad(setting: SettingGamepad, value: number): boole (globalScene.ui.getHandler() as SettingsGamepadUiHandler).updateBindings(); return success; }; - globalScene.ui.setOverlayMode(Mode.GAMEPAD_BINDING, { + globalScene.ui.setOverlayMode(UiMode.GAMEPAD_BINDING, { target: setting, cancelHandler: cancelHandler, }); @@ -133,7 +133,7 @@ export function setSettingGamepad(setting: SettingGamepad, value: number): boole cancelHandler(); return true; }; - globalScene.ui.setOverlayMode(Mode.OPTION_SELECT, { + globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, { options: [ ...gp.map((g: string) => ({ label: truncateString(g, 30), // Truncate the gamepad name for display diff --git a/src/system/settings/settings-keyboard.ts b/src/system/settings/settings-keyboard.ts index ffe8811e5d9..ec5c9ad6b0e 100644 --- a/src/system/settings/settings-keyboard.ts +++ b/src/system/settings/settings-keyboard.ts @@ -1,5 +1,5 @@ import { Button } from "#enums/buttons"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler"; import i18next from "i18next"; import { globalScene } from "#app/global-scene"; @@ -174,7 +174,7 @@ export function setSettingKeyboard(setting: SettingKeyboard, value: number): boo (globalScene.ui.getHandler() as SettingsKeyboardUiHandler).updateBindings(); return success; }; - globalScene.ui.setOverlayMode(Mode.KEYBOARD_BINDING, { + globalScene.ui.setOverlayMode(UiMode.KEYBOARD_BINDING, { target: setting, cancelHandler: cancelHandler, }); diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index 377216291e2..8bbba267bd6 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -1,4 +1,4 @@ -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { globalScene } from "#app/global-scene"; import { hasTouchscreen } from "#app/touch-controls"; @@ -9,7 +9,7 @@ import { EaseType } from "#enums/ease-type"; import { MoneyFormat } from "#enums/money-format"; import { PlayerGender } from "#enums/player-gender"; import { ShopCursorTarget } from "#enums/shop-cursor-target"; -import { isLocal } from "#app/utils"; +import { isLocal } from "#app/utils/common"; const VOLUME_OPTIONS: SettingOption[] = new Array(11).fill(null).map((_, i) => i @@ -804,6 +804,7 @@ export function setSetting(setting: string, value: number): boolean { break; case SettingKeys.Candy_Upgrade_Display: globalScene.candyUpgradeDisplay = value; + break; case SettingKeys.Money_Format: switch (Setting[index].options[value].value) { case "Normal": @@ -906,7 +907,7 @@ export function setSetting(setting: string, value: number): boolean { return false; } }; - globalScene.ui.setOverlayMode(Mode.OPTION_SELECT, { + globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, { options: [ { label: "English", diff --git a/src/system/version_migration/version_converter.ts b/src/system/version_migration/version_converter.ts index 074f60c2c5d..798115e0395 100644 --- a/src/system/version_migration/version_converter.ts +++ b/src/system/version_migration/version_converter.ts @@ -1,19 +1,112 @@ -import type { SessionSaveData, SystemSaveData } from "../game-data"; +import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator"; +import type { SettingsSaveMigrator } from "#app/@types/SettingsSaveMigrator"; +import type { SystemSaveMigrator } from "#app/@types/SystemSaveMigrator"; +import type { SessionSaveData, SystemSaveData } from "#app/system/game-data"; +import { compareVersions } from "compare-versions"; import { version } from "../../../package.json"; +/* +// template for save migrator creation +// versions/vA_B_C.ts + +// The version for each migrator should match the filename, ie: `vA_B_C.ts` -> `version: "A.B.C" +// This is the target version (aka the version we're ending up on after the migrators are run) + +// The name for each migrator should match its purpose. For example, if you're fixing +// the ability index of a pokemon, it might be called `migratePokemonAbilityIndex` + +const systemMigratorA: SystemSaveMigrator = { + version: "A.B.C", + migrate: (data: SystemSaveData): void => { + // migration code goes here + }, +}; + +export const systemMigrators: Readonly = [systemMigratorA] as const; + +const sessionMigratorA: SessionSaveMigrator = { + version: "A.B.C", + migrate: (data: SessionSaveData): void => { + // migration code goes here + }, +}; + +export const sessionMigrators: Readonly = [sessionMigratorA] as const; + +const settingsMigratorA: SettingsSaveMigrator = { + version: "A.B.C", + // biome-ignore lint/complexity/noBannedTypes: TODO - refactor settings + migrate: (data: Object): void => { + // migration code goes here + }, +}; + +export const settingsMigrators: Readonly = [settingsMigratorA] as const; +*/ + +// --- vA.B.C PATCHES --- // +// import * as vA_B_C from "./versions/vA_B_C"; + // --- v1.0.4 (and below) PATCHES --- // +// biome-ignore lint/style/noNamespaceImport: Convenience (TODO: make this a file-wide ignore when Biome supports those) import * as v1_0_4 from "./versions/v1_0_4"; -// --- v1.1.0 PATCHES --- // -import * as v1_1_0 from "./versions/v1_1_0"; - // --- v1.7.0 PATCHES --- // +// biome-ignore lint/style/noNamespaceImport: Convenience import * as v1_7_0 from "./versions/v1_7_0"; // --- v1.8.3 PATCHES --- // +// biome-ignore lint/style/noNamespaceImport: Convenience import * as v1_8_3 from "./versions/v1_8_3"; -const LATEST_VERSION = version.split(".").map(value => Number.parseInt(value)); +// --- v1.9.0 PATCHES --- // +// biome-ignore lint/style/noNamespaceImport: Convenience +import * as v1_9_0 from "./versions/v1_9_0"; + +/** Current game version */ +const LATEST_VERSION = version; + +type SaveMigrator = SystemSaveMigrator | SessionSaveMigrator | SettingsSaveMigrator; + +// biome-ignore lint/complexity/noBannedTypes: TODO - refactor settings +type SaveData = SystemSaveData | SessionSaveData | Object; + +// To add a new set of migrators, create a new `.push()` line like so: +// `systemMigrators.push(...vA_B_C.systemMigrators);` + +/** All system save migrators */ +const systemMigrators: SystemSaveMigrator[] = []; +systemMigrators.push(...v1_0_4.systemMigrators); +systemMigrators.push(...v1_7_0.systemMigrators); +systemMigrators.push(...v1_8_3.systemMigrators); + +/** All session save migrators */ +const sessionMigrators: SessionSaveMigrator[] = []; +sessionMigrators.push(...v1_0_4.sessionMigrators); +sessionMigrators.push(...v1_7_0.sessionMigrators); +sessionMigrators.push(...v1_9_0.sessionMigrators); + +/** All settings migrators */ +const settingsMigrators: SettingsSaveMigrator[] = []; +settingsMigrators.push(...v1_0_4.settingsMigrators); + +/** Sorts migrators by their stated version, ensuring they are applied in order from oldest to newest */ +const sortMigrators = (migrators: SaveMigrator[]): void => { + migrators.sort((a, b) => compareVersions(a.version, b.version)); +}; + +sortMigrators(systemMigrators); +sortMigrators(sessionMigrators); +sortMigrators(settingsMigrators); + +const applyMigrators = (migrators: readonly SaveMigrator[], data: SaveData, saveVersion: string) => { + for (const migrator of migrators) { + const isMigratorVersionHigher = compareVersions(saveVersion, migrator.version) === -1; + if (isMigratorVersionHigher) { + migrator.migrate(data as any); + } + } +}; /** * Converts incoming {@linkcode SystemSaveData} that has a version below the @@ -26,12 +119,12 @@ const LATEST_VERSION = version.split(".").map(value => Number.parseInt(value)); * @see {@link SystemVersionConverter} */ export function applySystemVersionMigration(data: SystemSaveData) { - const curVersion = data.gameVersion.split(".").map(value => Number.parseInt(value)); + const prevVersion = data.gameVersion; + const isCurrentVersionHigher = compareVersions(prevVersion, LATEST_VERSION) === -1; - if (!curVersion.every((value, index) => value === LATEST_VERSION[index])) { - const converter = new SystemVersionConverter(); - converter.applyStaticPreprocessors(data); - converter.applyMigration(data, curVersion); + if (isCurrentVersionHigher) { + applyMigrators(systemMigrators, data, prevVersion); + console.log(`System data successfully migrated to v${LATEST_VERSION}!`); } } @@ -46,12 +139,15 @@ export function applySystemVersionMigration(data: SystemSaveData) { * @see {@link SessionVersionConverter} */ export function applySessionVersionMigration(data: SessionSaveData) { - const curVersion = data.gameVersion.split(".").map(value => Number.parseInt(value)); + const prevVersion = data.gameVersion; + const isCurrentVersionHigher = compareVersions(prevVersion, LATEST_VERSION) === -1; - if (!curVersion.every((value, index) => value === LATEST_VERSION[index])) { - const converter = new SessionVersionConverter(); - converter.applyStaticPreprocessors(data); - converter.applyMigration(data, curVersion); + if (isCurrentVersionHigher) { + // Always sanitize money as a safeguard + data.money = Math.floor(data.money); + + applyMigrators(sessionMigrators, data, prevVersion); + console.log(`Session data successfully migrated to v${LATEST_VERSION}!`); } } @@ -65,156 +161,13 @@ export function applySessionVersionMigration(data: SessionSaveData) { * @param data Settings data object * @see {@link SettingsVersionConverter} */ +// biome-ignore lint/complexity/noBannedTypes: TODO - refactor settings export function applySettingsVersionMigration(data: Object) { - const gameVersion: string = data.hasOwnProperty("gameVersion") ? data["gameVersion"] : "1.0.0"; - const curVersion = gameVersion.split(".").map(value => Number.parseInt(value)); + const prevVersion: string = data.hasOwnProperty("gameVersion") ? data["gameVersion"] : "1.0.0"; + const isCurrentVersionHigher = compareVersions(prevVersion, LATEST_VERSION) === -1; - if (!curVersion.every((value, index) => value === LATEST_VERSION[index])) { - const converter = new SettingsVersionConverter(); - converter.applyStaticPreprocessors(data); - converter.applyMigration(data, curVersion); - } -} - -/** - * Abstract class encapsulating the logic for migrating data from a given version up to - * the current version listed in `package.json`. - * - * Note that, for any version converter, the corresponding `applyMigration` - * function would only need to be changed once when the first migration for a - * given version is introduced. Similarly, a version file (within the `versions` - * folder) would only need to be created for a version once with the appropriate - * array nomenclature. - */ -abstract class VersionConverter { - /** - * Iterates through an array of designated migration functions that are each - * called one by one to transform the data. - * @param data The data to be operated on - * @param migrationArr An array of functions that will transform the incoming data - */ - callMigrators(data: any, migrationArr: readonly any[]) { - for (const migrate of migrationArr) { - migrate(data); - } - } - - /** - * Applies any version-agnostic data sanitation as defined within the function - * body. - * @param data The data to be operated on - */ - applyStaticPreprocessors(_data: any): void {} - - /** - * Uses the current version the incoming data to determine the starting point - * of the migration which will cascade up to the latest version, calling the - * necessary migration functions in the process. - * @param data The data to be operated on - * @param curVersion [0] Current major version - * [1] Current minor version - * [2] Current patch version - */ - abstract applyMigration(data: any, curVersion: number[]): void; -} - -/** - * Class encapsulating the logic for migrating {@linkcode SessionSaveData} from - * a given version up to the current version listed in `package.json`. - * @extends VersionConverter - */ -class SessionVersionConverter extends VersionConverter { - override applyStaticPreprocessors(data: SessionSaveData): void { - // Always sanitize money as a safeguard - data.money = Math.floor(data.money); - } - - override applyMigration(data: SessionSaveData, curVersion: number[]): void { - const [curMajor, curMinor, curPatch] = curVersion; - - if (curMajor === 1) { - if (curMinor === 0) { - if (curPatch <= 5) { - console.log("Applying v1.0.4 session data migration!"); - this.callMigrators(data, v1_0_4.sessionMigrators); - } - } - if (curMinor <= 1) { - console.log("Applying v1.1.0 session data migration!"); - this.callMigrators(data, v1_1_0.sessionMigrators); - } - if (curMinor < 7) { - console.log("Applying v1.7.0 session data migration!"); - this.callMigrators(data, v1_7_0.sessionMigrators); - } - } - - console.log(`Session data successfully migrated to v${version}!`); - } -} - -/** - * Class encapsulating the logic for migrating {@linkcode SystemSaveData} from - * a given version up to the current version listed in `package.json`. - * @extends VersionConverter - */ -class SystemVersionConverter extends VersionConverter { - override applyMigration(data: SystemSaveData, curVersion: number[]): void { - const [curMajor, curMinor, curPatch] = curVersion; - - if (curMajor === 1) { - if (curMinor === 0) { - if (curPatch <= 4) { - console.log("Applying v1.0.4 system data migraton!"); - this.callMigrators(data, v1_0_4.systemMigrators); - } - } - if (curMinor <= 1) { - console.log("Applying v1.1.0 system data migraton!"); - this.callMigrators(data, v1_1_0.systemMigrators); - } - if (curMinor < 7) { - console.log("Applying v1.7.0 system data migration!"); - this.callMigrators(data, v1_7_0.systemMigrators); - } - if (curMinor === 8) { - if (curPatch <= 2) { - console.log("Applying v1.8.3 system data migration!"); - this.callMigrators(data, v1_8_3.systemMigrators); - } - } - } - - console.log(`System data successfully migrated to v${version}!`); - } -} - -/** - * Class encapsulating the logic for migrating settings data from - * a given version up to the current version listed in `package.json`. - * @extends VersionConverter - */ -class SettingsVersionConverter extends VersionConverter { - override applyMigration(data: Object, curVersion: number[]): void { - const [curMajor, curMinor, curPatch] = curVersion; - - if (curMajor === 1) { - if (curMinor === 0) { - if (curPatch <= 4) { - console.log("Applying v1.0.4 settings data migraton!"); - this.callMigrators(data, v1_0_4.settingsMigrators); - } - } - if (curMinor <= 1) { - console.log("Applying v1.1.0 settings data migraton!"); - this.callMigrators(data, v1_1_0.settingsMigrators); - } - if (curMinor < 7) { - console.log("Applying v1.7.0 settings data migration!"); - this.callMigrators(data, v1_7_0.settingsMigrators); - } - } - - console.log(`Settings data successfully migrated to v${version}!`); + if (isCurrentVersionHigher) { + applyMigrators(settingsMigrators, data, prevVersion); + console.log(`Settings successfully migrated to v${LATEST_VERSION}!`); } } diff --git a/src/system/version_migration/versions/v1_0_4.ts b/src/system/version_migration/versions/v1_0_4.ts index 16bd9db9915..9e30ccdc2a7 100644 --- a/src/system/version_migration/versions/v1_0_4.ts +++ b/src/system/version_migration/versions/v1_0_4.ts @@ -3,16 +3,19 @@ import type { SystemSaveData, SessionSaveData } from "#app/system/game-data"; import { AbilityAttr, defaultStarterSpecies, DexAttr } from "#app/system/game-data"; import { allSpecies } from "#app/data/pokemon-species"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; +import type { SystemSaveMigrator } from "#app/@types/SystemSaveMigrator"; +import type { SettingsSaveMigrator } from "#app/@types/SettingsSaveMigrator"; +import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator"; -export const systemMigrators = [ - /** - * Migrate ability starter data if empty for caught species. - * @param data {@linkcode SystemSaveData} - */ - function migrateAbilityData(data: SystemSaveData) { +/** + * Migrate ability starter data if empty for caught species. + * @param data - {@linkcode SystemSaveData} + */ +const migrateAbilityData: SystemSaveMigrator = { + version: "1.0.4", + migrate: (data: SystemSaveData): void => { if (data.starterData && data.dexData) { - // biome-ignore lint/complexity/noForEach: Object.keys(data.starterData).forEach(sd => { if (data.dexData[sd]?.caughtAttr && data.starterData[sd] && !data.starterData[sd].abilityAttr) { data.starterData[sd].abilityAttr = 1; @@ -20,12 +23,15 @@ export const systemMigrators = [ }); } }, +}; - /** - * Populate legendary Pokémon statistics if they are missing. - * @param data {@linkcode SystemSaveData} - */ - function fixLegendaryStats(data: SystemSaveData) { +/** + * Populate legendary Pokémon statistics if they are missing. + * @param data - {@linkcode SystemSaveData} + */ +const fixLegendaryStats: SystemSaveMigrator = { + version: "1.0.4", + migrate: (data: SystemSaveData): void => { if ( data.gameStats && data.gameStats.legendaryPokemonCaught !== undefined && @@ -34,7 +40,6 @@ export const systemMigrators = [ data.gameStats.subLegendaryPokemonSeen = 0; data.gameStats.subLegendaryPokemonCaught = 0; data.gameStats.subLegendaryPokemonHatched = 0; - // biome-ignore lint/complexity/noForEach: allSpecies .filter(s => s.subLegendary) .forEach(s => { @@ -66,12 +71,15 @@ export const systemMigrators = [ ); } }, +}; - /** - * Unlock all starters' first ability and female gender option. - * @param data {@linkcode SystemSaveData} - */ - function fixStarterData(data: SystemSaveData) { +/** + * Unlock all starters' first ability and female gender option. + * @param data - {@linkcode SystemSaveData} + */ +const fixStarterData: SystemSaveMigrator = { + version: "1.0.4", + migrate: (data: SystemSaveData): void => { if (!isNullOrUndefined(data.starterData)) { for (const starterId of defaultStarterSpecies) { if (data.starterData[starterId]?.abilityAttr) { @@ -83,17 +91,22 @@ export const systemMigrators = [ } } }, +}; + +export const systemMigrators: Readonly = [ + migrateAbilityData, + fixLegendaryStats, + fixStarterData, ] as const; -export const settingsMigrators = [ - /** - * Migrate from "REROLL_TARGET" property to {@linkcode - * SettingKeys.Shop_Cursor_Target}. - * @param data the `settings` object - */ - - // biome-ignore lint/complexity/noBannedTypes: TODO: fix the type to not be object... - function fixRerollTarget(data: Object) { +/** + * Migrate from `REROLL_TARGET` property to {@linkcode SettingKeys.Shop_Cursor_Target} + * @param data - The `settings` object + */ +const fixRerollTarget: SettingsSaveMigrator = { + version: "1.0.4", + // biome-ignore lint/complexity/noBannedTypes: TODO - refactor settings + migrate: (data: Object): void => { if (data.hasOwnProperty("REROLL_TARGET") && !data.hasOwnProperty(SettingKeys.Shop_Cursor_Target)) { data[SettingKeys.Shop_Cursor_Target] = data["REROLL_TARGET"]; // biome-ignore lint/performance/noDelete: intentional @@ -101,16 +114,20 @@ export const settingsMigrators = [ localStorage.setItem("settings", JSON.stringify(data)); } }, -] as const; +}; -export const sessionMigrators = [ - /** - * Converts old lapsing modifiers (battle items, lures, and Dire Hit) and - * other miscellaneous modifiers (vitamins, White Herb) to any new class - * names and/or change in reload arguments. - * @param data {@linkcode SessionSaveData} - */ - function migrateModifiers(data: SessionSaveData) { +export const settingsMigrators: Readonly = [fixRerollTarget] as const; + +/** + * Converts old lapsing modifiers (battle items, lures, and Dire Hit) and + * other miscellaneous modifiers (vitamins, White Herb) to any new class + * names and/or change in reload arguments. + * @param data - {@linkcode SessionSaveData} + */ +const migrateModifiers: SessionSaveMigrator = { + version: "1.0.4", + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: necessary? + migrate: (data: SessionSaveData): void => { for (const m of data.modifiers) { if (m.className === "PokemonBaseStatModifier") { m.className = "BaseStatModifier"; @@ -163,12 +180,11 @@ export const sessionMigrators = [ } } }, - /** - * Converts old Pokemon natureOverride and mysteryEncounterData - * to use the new conjoined {@linkcode Pokemon.customPokemonData} structure instead. - * @param data {@linkcode SessionSaveData} - */ - function migrateCustomPokemonDataAndNatureOverrides(data: SessionSaveData) { +}; + +const migrateCustomPokemonData: SessionSaveMigrator = { + version: "1.0.4", + migrate: (data: SessionSaveData): void => { // Fix Pokemon nature overrides and custom data migration for (const pokemon of data.party) { if (pokemon["mysteryEncounterPokemonData"]) { @@ -186,4 +202,6 @@ export const sessionMigrators = [ } } }, -] as const; +}; + +export const sessionMigrators: Readonly = [migrateModifiers, migrateCustomPokemonData] as const; diff --git a/src/system/version_migration/versions/v1_1_0.ts b/src/system/version_migration/versions/v1_1_0.ts deleted file mode 100644 index 5d6247aeaa2..00000000000 --- a/src/system/version_migration/versions/v1_1_0.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const systemMigrators = [] as const; - -export const settingsMigrators = [] as const; - -export const sessionMigrators = [] as const; diff --git a/src/system/version_migration/versions/v1_7_0.ts b/src/system/version_migration/versions/v1_7_0.ts index 167cd974e56..dc7c0f48640 100644 --- a/src/system/version_migration/versions/v1_7_0.ts +++ b/src/system/version_migration/versions/v1_7_0.ts @@ -1,15 +1,18 @@ +import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator"; +import type { SystemSaveMigrator } from "#app/@types/SystemSaveMigrator"; import { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species"; import { globalScene } from "#app/global-scene"; import { DexAttr, type SessionSaveData, type SystemSaveData } from "#app/system/game-data"; -import * as Utils from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; -export const systemMigrators = [ - /** - * If a starter is caught, but the only forms registered as caught are not starterSelectable, - * unlock the default form. - * @param data {@linkcode SystemSaveData} - */ - function migrateUnselectableForms(data: SystemSaveData) { +/** + * If a starter is caught, but the only forms registered as caught are not starterSelectable, + * unlock the default form. + * @param data - {@linkcode SystemSaveData} + */ +const migrateUnselectableForms: SystemSaveMigrator = { + version: "1.7.0", + migrate: (data: SystemSaveData): void => { if (data.starterData && data.dexData) { Object.keys(data.starterData).forEach(sd => { const caughtAttr = data.dexData[sd]?.caughtAttr; @@ -30,12 +33,13 @@ export const systemMigrators = [ }); } }, -] as const; +}; -export const settingsMigrators = [] as const; +export const systemMigrators: Readonly = [migrateUnselectableForms] as const; -export const sessionMigrators = [ - function migrateTera(data: SessionSaveData) { +const migrateTera: SessionSaveMigrator = { + version: "1.7.0", + migrate: (data: SessionSaveData): void => { for (let i = 0; i < data.modifiers.length; ) { if (data.modifiers[i].className === "TerastallizeModifier") { data.party.forEach(p => { @@ -63,15 +67,17 @@ export const sessionMigrators = [ } data.party.forEach(p => { - if (Utils.isNullOrUndefined(p.teraType)) { + if (isNullOrUndefined(p.teraType)) { p.teraType = getPokemonSpeciesForm(p.species, p.formIndex).type1; } }); data.enemyParty.forEach(p => { - if (Utils.isNullOrUndefined(p.teraType)) { + if (isNullOrUndefined(p.teraType)) { p.teraType = getPokemonSpeciesForm(p.species, p.formIndex).type1; } }); }, -] as const; +}; + +export const sessionMigrators: Readonly = [migrateTera] as const; diff --git a/src/system/version_migration/versions/v1_8_3.ts b/src/system/version_migration/versions/v1_8_3.ts index d35530c28e9..6e2d96d3673 100644 --- a/src/system/version_migration/versions/v1_8_3.ts +++ b/src/system/version_migration/versions/v1_8_3.ts @@ -1,14 +1,16 @@ +import type { SystemSaveMigrator } from "#app/@types/SystemSaveMigrator"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { DexAttr, type SystemSaveData } from "#app/system/game-data"; import { Species } from "#enums/species"; -export const systemMigrators = [ - /** - * If a starter is caught, but the only forms registered as caught are not starterSelectable, - * unlock the default form. - * @param data {@linkcode SystemSaveData} - */ - function migratePichuForms(data: SystemSaveData) { +/** + * If a starter is caught, but the only forms registered as caught are not starterSelectable, + * unlock the default form. + * @param data - {@linkcode SystemSaveData} + */ +const migratePichuForms: SystemSaveMigrator = { + version: "1.8.3", + migrate: (data: SystemSaveData): void => { if (data.starterData && data.dexData) { // This is Pichu's Pokédex number const sd = 172; @@ -23,8 +25,6 @@ export const systemMigrators = [ } } }, -] as const; +}; -export const settingsMigrators = [] as const; - -export const sessionMigrators = [] as const; +export const systemMigrators: Readonly = [migratePichuForms] as const; diff --git a/src/system/version_migration/versions/v1_9_0.ts b/src/system/version_migration/versions/v1_9_0.ts new file mode 100644 index 00000000000..9505a7138f8 --- /dev/null +++ b/src/system/version_migration/versions/v1_9_0.ts @@ -0,0 +1,47 @@ +import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator"; +import { Status } from "#app/data/status-effect"; +import { PokemonMove } from "#app/field/pokemon"; +import type { SessionSaveData } from "#app/system/game-data"; +import type PokemonData from "#app/system/pokemon-data"; +import { Moves } from "#enums/moves"; + +/** + * Migrate all lingering rage fist data inside `CustomPokemonData`, + * as well as enforcing default values across the board. + * @param data - {@linkcode SystemSaveData} + */ +const migratePartyData: SessionSaveMigrator = { + version: "1.9.0", + migrate: (data: SessionSaveData): void => { + // this stuff is copied straight from the constructor fwiw + const mapParty = (pkmnData: PokemonData) => { + pkmnData.status &&= new Status( + pkmnData.status.effect, + pkmnData.status.toxicTurnCount, + pkmnData.status.sleepTurnsRemaining, + ); + // remove empty moves from moveset + pkmnData.moveset = (pkmnData.moveset ?? [new PokemonMove(Moves.TACKLE), new PokemonMove(Moves.GROWL)]) + .filter(m => !!m) + .map(m => PokemonMove.loadMove(m)); + // only edit summondata moveset if exists + pkmnData.summonData.moveset &&= pkmnData.summonData.moveset.filter(m => !!m).map(m => PokemonMove.loadMove(m)); + + if ( + pkmnData.customPokemonData && + "hitsRecCount" in pkmnData.customPokemonData && + typeof pkmnData.customPokemonData["hitsRecCount"] === "number" + ) { + // transfer old hit count stat to battleData. + pkmnData.battleData.hitCount = pkmnData.customPokemonData["hitsRecCount"]; + pkmnData.customPokemonData["hitsRecCount"] = null; + } + return pkmnData; + }; + + data.party = data.party.map(mapParty); + data.enemyParty = data.enemyParty.map(mapParty); + }, +}; + +export const sessionMigrators: Readonly = [migratePartyData] as const; diff --git a/src/timed-event-manager.ts b/src/timed-event-manager.ts index 7bbd157948b..163afdc098b 100644 --- a/src/timed-event-manager.ts +++ b/src/timed-event-manager.ts @@ -1,7 +1,7 @@ import { globalScene } from "#app/global-scene"; import { TextStyle, addTextObject } from "#app/ui/text"; -import type { nil } from "#app/utils"; -import { isNullOrUndefined } from "#app/utils"; +import type { nil } from "#app/utils/common"; +import { isNullOrUndefined } from "#app/utils/common"; import i18next from "i18next"; import { Species } from "#enums/species"; import type { WeatherPoolEntry } from "#app/data/weather"; @@ -310,6 +310,47 @@ const timedEvents: TimedEvent[] = [ }, ], }, + { + name: "Shining Spring", + eventType: EventType.SHINY, + startDate: new Date(Date.UTC(2025, 4, 3)), + endDate: new Date(Date.UTC(2025, 4, 13)), + bannerKey: "spr25event", + scale: 0.21, + availableLangs: ["en", "de", "it", "fr", "ja", "ko", "es-ES", "es-MX", "pt-BR", "zh-CN"], + shinyMultiplier: 2, + upgradeUnlockedVouchers: true, + eventEncounters: [ + { species: Species.HOPPIP }, + { species: Species.CELEBI }, + { species: Species.VOLBEAT }, + { species: Species.ILLUMISE }, + { species: Species.SPOINK }, + { species: Species.LILEEP }, + { species: Species.SHINX }, + { species: Species.PACHIRISU }, + { species: Species.CHERUBI }, + { species: Species.MUNCHLAX }, + { species: Species.TEPIG }, + { species: Species.PANSAGE }, + { species: Species.PANSEAR }, + { species: Species.PANPOUR }, + { species: Species.DARUMAKA }, + { species: Species.ARCHEN }, + { species: Species.DEERLING, formIndex: 0 }, // Spring Deerling + { species: Species.CLAUNCHER }, + { species: Species.WISHIWASHI }, + { species: Species.DRAMPA }, + { species: Species.JANGMO_O }, + { species: Species.APPLIN }, + ], + classicWaveRewards: [ + { wave: 8, type: "SHINY_CHARM" }, + { wave: 8, type: "ABILITY_CHARM" }, + { wave: 8, type: "CATCHING_CHARM" }, + { wave: 25, type: "SHINY_CHARM" }, + ], + }, ]; export class TimedEventManager { diff --git a/src/tutorial.ts b/src/tutorial.ts index 82912f73979..d9ae3a03290 100644 --- a/src/tutorial.ts +++ b/src/tutorial.ts @@ -1,7 +1,7 @@ import { globalScene } from "#app/global-scene"; import AwaitableUiHandler from "./ui/awaitable-ui-handler"; import type UiHandler from "./ui/ui-handler"; -import { Mode } from "./ui/ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import Overrides from "#app/overrides"; @@ -92,13 +92,13 @@ const tutorialHandlers = { }, [Tutorial.Select_Item]: () => { return new Promise(resolve => { - globalScene.ui.setModeWithoutClear(Mode.MESSAGE).then(() => { + globalScene.ui.setModeWithoutClear(UiMode.MESSAGE).then(() => { globalScene.ui.showText( i18next.t("tutorial:selectItem"), null, () => globalScene.ui.showText("", null, () => - globalScene.ui.setModeWithoutClear(Mode.MODIFIER_SELECT).then(() => resolve()), + globalScene.ui.setModeWithoutClear(UiMode.MODIFIER_SELECT).then(() => resolve()), ), null, true, diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index c9898f9b71e..0c13cdb9512 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -1,5 +1,5 @@ import type Phaser from "phaser"; -import { Mode } from "./ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type { InputsController } from "./inputs-controller"; import type MessageUiHandler from "./ui/message-ui-handler"; import StarterSelectUiHandler from "./ui/starter-select-ui-handler"; @@ -176,22 +176,24 @@ export class UiInputs { return; } switch (globalScene.ui?.getMode()) { - case Mode.MESSAGE: + case UiMode.MESSAGE: { const messageHandler = globalScene.ui.getHandler(); if (!messageHandler.pendingPrompt || messageHandler.isTextAnimationInProgress()) { return; } - case Mode.TITLE: - case Mode.COMMAND: - case Mode.MODIFIER_SELECT: - case Mode.MYSTERY_ENCOUNTER: - globalScene.ui.setOverlayMode(Mode.MENU); + // biome-ignore lint/suspicious/noFallthroughSwitchClause: falls through to show menu overlay + } + case UiMode.TITLE: + case UiMode.COMMAND: + case UiMode.MODIFIER_SELECT: + case UiMode.MYSTERY_ENCOUNTER: + globalScene.ui.setOverlayMode(UiMode.MENU); break; - case Mode.STARTER_SELECT: - case Mode.POKEDEX_PAGE: + case UiMode.STARTER_SELECT: + case UiMode.POKEDEX_PAGE: this.buttonTouch(); break; - case Mode.MENU: + case UiMode.MENU: globalScene.ui.revertMode(); globalScene.playSound("ui/select"); break; @@ -227,7 +229,7 @@ export class UiInputs { SettingKeys.Game_Speed, Setting[settingGameSpeed].options.findIndex(item => item.label === `${globalScene.gameSpeed}x`) + 1, ); - if (globalScene.ui?.getMode() === Mode.SETTINGS) { + if (globalScene.ui?.getMode() === UiMode.SETTINGS) { (globalScene.ui.getHandler() as SettingsUiHandler).show([]); } } else if (!up && globalScene.gameSpeed > 1) { @@ -238,7 +240,7 @@ export class UiInputs { 0, ), ); - if (globalScene.ui?.getMode() === Mode.SETTINGS) { + if (globalScene.ui?.getMode() === UiMode.SETTINGS) { (globalScene.ui.getHandler() as SettingsUiHandler).show([]); } } diff --git a/src/ui/abstact-option-select-ui-handler.ts b/src/ui/abstact-option-select-ui-handler.ts index f605f73e171..07609648a4e 100644 --- a/src/ui/abstact-option-select-ui-handler.ts +++ b/src/ui/abstact-option-select-ui-handler.ts @@ -1,9 +1,9 @@ import { globalScene } from "#app/global-scene"; import { TextStyle, addBBCodeTextObject, getTextColor, getTextStyleOptions } from "./text"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; -import * as Utils from "../utils"; +import { rgbHexToRgba, fixedInt } from "#app/utils/common"; import { argbFromRgba } from "@material/material-color-utilities"; import { Button } from "#enums/buttons"; import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodetext/BBCodeText"; @@ -56,7 +56,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { protected defaultTextStyle: TextStyle = TextStyle.WINDOW; protected textContent: string; - constructor(mode: Mode | null) { + constructor(mode: UiMode | null) { super(mode); } @@ -70,7 +70,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { const ui = this.getUi(); this.optionSelectContainer = globalScene.add.container(globalScene.game.canvas.width / 6 - 1, -48); - this.optionSelectContainer.setName(`option-select-${this.mode ? Mode[this.mode] : "UNKNOWN"}`); + this.optionSelectContainer.setName(`option-select-${this.mode ? UiMode[this.mode] : "UNKNOWN"}`); this.optionSelectContainer.setVisible(false); ui.add(this.optionSelectContainer); @@ -120,7 +120,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { // Setting the initial text to establish the width of the select object. We consider all options, even ones that are not displayed, // Except in the case of autocomplete, where we don't want to set up a text element with potentially hundreds of lines. - const optionsForWidth = globalScene.ui.getMode() === Mode.AUTO_COMPLETE ? optionsWithScroll : options; + const optionsForWidth = globalScene.ui.getMode() === UiMode.AUTO_COMPLETE ? optionsWithScroll : options; this.optionSelectText = addBBCodeTextObject( 0, 0, @@ -178,8 +178,8 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { itemOverlayIcon.setPositionRelative(this.optionSelectText, 36 * this.scale, 7 + i * (114 * this.scale - 3)); if (option.itemArgs) { - itemIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[0]))); - itemOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[1]))); + itemIcon.setTint(argbFromRgba(rgbHexToRgba(option.itemArgs[0]))); + itemOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(option.itemArgs[1]))); } } } @@ -207,7 +207,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { this.blockInput = true; this.optionSelectTextContainer.setAlpha(0.5); this.cursorObj?.setAlpha(0.8); - globalScene.time.delayedCall(Utils.fixedInt(this.config.delay), () => this.unblockInput()); + globalScene.time.delayedCall(fixedInt(this.config.delay), () => this.unblockInput()); } if (this.config?.supportHover) { @@ -250,7 +250,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { } else { ui.playError(); } - } else if (button === Button.SUBMIT && ui.getMode() === Mode.AUTO_COMPLETE) { + } else if (button === Button.SUBMIT && ui.getMode() === UiMode.AUTO_COMPLETE) { // this is here to differentiate between a Button.SUBMIT vs Button.ACTION within the autocomplete handler // this is here because Button.ACTION is picked up as z on the keyboard, meaning if you're typing and hit z, it'll select the option you've chosen success = true; diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/achvs-ui-handler.ts index 8b5a4dbd395..d0c8b716c7a 100644 --- a/src/ui/achvs-ui-handler.ts +++ b/src/ui/achvs-ui-handler.ts @@ -6,7 +6,7 @@ import type { Voucher } from "#app/system/voucher"; import { getVoucherTypeIcon, getVoucherTypeName, vouchers } from "#app/system/voucher"; import MessageUiHandler from "#app/ui/message-ui-handler"; import { addTextObject, TextStyle } from "#app/ui/text"; -import type { Mode } from "#app/ui/ui"; +import type { UiMode } from "#enums/ui-mode"; import { addWindow } from "#app/ui/ui-theme"; import { ScrollBar } from "#app/ui/scroll-bar"; import { PlayerGender } from "#enums/player-gender"; @@ -59,7 +59,7 @@ export default class AchvsUiHandler extends MessageUiHandler { private cursorObj: Phaser.GameObjects.NineSlice | null; private currentPage: Page; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.achvsTotal = Object.keys(achvs).length; diff --git a/src/ui/admin-ui-handler.ts b/src/ui/admin-ui-handler.ts index 34b6e59145f..67ae3118863 100644 --- a/src/ui/admin-ui-handler.ts +++ b/src/ui/admin-ui-handler.ts @@ -1,11 +1,11 @@ import { Button } from "#app/enums/buttons"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; -import { formatText } from "#app/utils"; +import { formatText } from "#app/utils/common"; import type { InputFieldConfig } from "./form-modal-ui-handler"; import { FormModalUiHandler } from "./form-modal-ui-handler"; import type { ModalConfig } from "./modal-ui-handler"; import { TextStyle } from "./text"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import { globalScene } from "#app/global-scene"; type AdminUiHandlerService = "discord" | "google"; @@ -30,7 +30,7 @@ export default class AdminUiHandler extends FormModalUiHandler { return `Username and ${service} successfully ${mode.toLowerCase()}ed`; }; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); } @@ -143,10 +143,10 @@ export default class AdminUiHandler extends FormModalUiHandler { const adminSearchResult: AdminSearchInfo = this.convertInputsToAdmin(); // this converts the input texts into a single object for use later const validFields = this.areFieldsValid(this.adminMode); if (validFields.error) { - globalScene.ui.setMode(Mode.LOADING, { buttonActions: [] }); // this is here to force a loading screen to allow the admin tool to reopen again if there's an error + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); // this is here to force a loading screen to allow the admin tool to reopen again if there's an error return this.showMessage(validFields.errorMessage ?? "", adminSearchResult, true); } - globalScene.ui.setMode(Mode.LOADING, { buttonActions: [] }); + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); if (this.adminMode === AdminMode.LINK) { this.adminLinkUnlink(adminSearchResult, "discord", "Link") // calls server to link discord .then(response => { @@ -174,7 +174,7 @@ export default class AdminUiHandler extends FormModalUiHandler { showMessage(message: string, adminResult: AdminSearchInfo, isError: boolean) { globalScene.ui.setMode( - Mode.ADMIN, + UiMode.ADMIN, Object.assign(this.config, { errorMessage: message?.trim() }), this.adminMode, adminResult, @@ -221,18 +221,18 @@ export default class AdminUiHandler extends FormModalUiHandler { const mode = adminResult[aR] === "" ? "Link" : "Unlink"; // this figures out if we're linking or unlinking a service const validFields = this.areFieldsValid(this.adminMode, service); if (validFields.error) { - globalScene.ui.setMode(Mode.LOADING, { buttonActions: [] }); // this is here to force a loading screen to allow the admin tool to reopen again if there's an error + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); // this is here to force a loading screen to allow the admin tool to reopen again if there's an error return this.showMessage(validFields.errorMessage ?? "", adminResult, true); } this.adminLinkUnlink(this.convertInputsToAdmin(), service as AdminUiHandlerService, mode).then( response => { // attempts to link/unlink depending on the service if (response.error) { - globalScene.ui.setMode(Mode.LOADING, { buttonActions: [] }); + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); return this.showMessage(response.errorType, adminResult, true); // fail } // success, reload panel with new results - globalScene.ui.setMode(Mode.LOADING, { buttonActions: [] }); + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); this.adminSearch(adminResult).then(response => { if (response.error) { return this.showMessage(response.errorType, adminResult, true); @@ -385,7 +385,7 @@ export default class AdminUiHandler extends FormModalUiHandler { private updateAdminPanelInfo(adminSearchResult: AdminSearchInfo, mode?: AdminMode) { mode = mode ?? AdminMode.ADMIN; globalScene.ui.setMode( - Mode.ADMIN, + UiMode.ADMIN, { buttonActions: [ // we double revert here and below to go back 2 layers of menus diff --git a/src/ui/arena-flyout.ts b/src/ui/arena-flyout.ts index 36a44eb5aa0..ab3bd13b47a 100644 --- a/src/ui/arena-flyout.ts +++ b/src/ui/arena-flyout.ts @@ -16,7 +16,7 @@ import type { TurnEndEvent } from "../events/battle-scene"; import { BattleSceneEventType } from "../events/battle-scene"; import { ArenaTagType } from "#enums/arena-tag-type"; import TimeOfDayWidget from "./time-of-day-widget"; -import * as Utils from "../utils"; +import { toCamelCaseString, formatText, fixedInt } from "#app/utils/common"; import type { ParseKeys } from "i18next"; import i18next from "i18next"; @@ -47,10 +47,10 @@ export function getFieldEffectText(arenaTagType: string): string { if (!arenaTagType || arenaTagType === ArenaTagType.NONE) { return arenaTagType; } - const effectName = Utils.toCamelCaseString(arenaTagType); + const effectName = toCamelCaseString(arenaTagType); const i18nKey = `arenaFlyout:${effectName}` as ParseKeys; const resultName = i18next.t(i18nKey); - return !resultName || resultName === i18nKey ? Utils.formatText(arenaTagType) : resultName; + return !resultName || resultName === i18nKey ? formatText(arenaTagType) : resultName; } export class ArenaFlyout extends Phaser.GameObjects.Container { @@ -411,7 +411,7 @@ export class ArenaFlyout extends Phaser.GameObjects.Container { globalScene.tweens.add({ targets: this.flyoutParent, x: visible ? this.anchorX : this.anchorX - this.translationX, - duration: Utils.fixedInt(125), + duration: fixedInt(125), ease: "Sine.easeInOut", alpha: visible ? 1 : 0, onComplete: () => (this.timeOfDayWidget.parentVisible = visible), diff --git a/src/ui/autocomplete-ui-handler.ts b/src/ui/autocomplete-ui-handler.ts index a170ae43f23..ba1802c8582 100644 --- a/src/ui/autocomplete-ui-handler.ts +++ b/src/ui/autocomplete-ui-handler.ts @@ -1,10 +1,10 @@ import { Button } from "#enums/buttons"; import AbstractOptionSelectUiHandler from "./abstact-option-select-ui-handler"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; export default class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler { modalContainer: Phaser.GameObjects.Container; - constructor(mode: Mode = Mode.OPTION_SELECT) { + constructor(mode: UiMode = UiMode.OPTION_SELECT) { super(mode); } diff --git a/src/ui/awaitable-ui-handler.ts b/src/ui/awaitable-ui-handler.ts index 890e2884fd5..3c577fd4411 100644 --- a/src/ui/awaitable-ui-handler.ts +++ b/src/ui/awaitable-ui-handler.ts @@ -1,4 +1,4 @@ -import type { Mode } from "./ui"; +import type { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; import { Button } from "#enums/buttons"; import { globalScene } from "#app/global-scene"; @@ -9,7 +9,7 @@ export default abstract class AwaitableUiHandler extends UiHandler { public tutorialActive = false; public tutorialOverlay: Phaser.GameObjects.Rectangle; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); } diff --git a/src/ui/ball-ui-handler.ts b/src/ui/ball-ui-handler.ts index cfa44832824..abb106a6553 100644 --- a/src/ui/ball-ui-handler.ts +++ b/src/ui/ball-ui-handler.ts @@ -1,7 +1,7 @@ import { getPokeballName } from "../data/pokeball"; import { addTextObject, getTextStyleOptions, TextStyle } from "./text"; import { Command } from "./command-ui-handler"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; import { Button } from "#enums/buttons"; @@ -18,7 +18,7 @@ export default class BallUiHandler extends UiHandler { private scale = 0.1666666667; constructor() { - super(Mode.BALL); + super(UiMode.BALL); } setup() { @@ -82,15 +82,15 @@ export default class BallUiHandler extends UiHandler { if (button === Button.ACTION && this.cursor < pokeballTypeCount) { if (globalScene.pokeballCounts[this.cursor]) { if (commandPhase.handleCommand(Command.BALL, this.cursor)) { - globalScene.ui.setMode(Mode.COMMAND, commandPhase.getFieldIndex()); - globalScene.ui.setMode(Mode.MESSAGE); + globalScene.ui.setMode(UiMode.COMMAND, commandPhase.getFieldIndex()); + globalScene.ui.setMode(UiMode.MESSAGE); success = true; } } else { ui.playError(); } } else { - ui.setMode(Mode.COMMAND, commandPhase.getFieldIndex()); + ui.setMode(UiMode.COMMAND, commandPhase.getFieldIndex()); success = true; } } else { diff --git a/src/ui/base-stats-overlay.ts b/src/ui/base-stats-overlay.ts index 5a6c67cae7b..0541ae766e5 100644 --- a/src/ui/base-stats-overlay.ts +++ b/src/ui/base-stats-overlay.ts @@ -1,7 +1,7 @@ import type { InfoToggle } from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { addWindow } from "./ui-theme"; -import * as Utils from "../utils"; +import { fixedInt } from "#app/utils/common"; import i18next from "i18next"; import { globalScene } from "#app/global-scene"; @@ -93,7 +93,7 @@ export class BaseStatsOverlay extends Phaser.GameObjects.Container implements In } globalScene.tweens.add({ targets: this.statsLabels, - duration: Utils.fixedInt(125), + duration: fixedInt(125), ease: "Sine.easeInOut", alpha: visible ? 1 : 0, }); diff --git a/src/ui/battle-flyout.ts b/src/ui/battle-flyout.ts index 206546ad9cb..e590bebcf5a 100644 --- a/src/ui/battle-flyout.ts +++ b/src/ui/battle-flyout.ts @@ -1,6 +1,6 @@ import type { default as Pokemon } from "../field/pokemon"; import { addTextObject, TextStyle } from "./text"; -import * as Utils from "../utils"; +import { fixedInt } from "#app/utils/common"; import { globalScene } from "#app/global-scene"; import type Move from "#app/data/moves/move"; import type { BerryUsedEvent, MoveUsedEvent } from "../events/battle-scene"; @@ -201,7 +201,7 @@ export default class BattleFlyout extends Phaser.GameObjects.Container { globalScene.tweens.add({ targets: this.flyoutParent, x: visible ? this.anchorX : this.anchorX - this.translationX, - duration: Utils.fixedInt(125), + duration: fixedInt(125), ease: "Sine.easeInOut", alpha: visible ? 1 : 0, }); diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 355ab9167a1..cabe897d7b6 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -1,13 +1,13 @@ import type { EnemyPokemon, default as Pokemon } from "../field/pokemon"; import { getLevelTotalExp, getLevelRelExp } from "../data/exp"; -import * as Utils from "../utils"; +import { getLocalizedSpriteKey, fixedInt } from "#app/utils/common"; import { addTextObject, TextStyle } from "./text"; import { getGenderSymbol, getGenderColor, Gender } from "../data/gender"; import { StatusEffect } from "#enums/status-effect"; import { globalScene } from "#app/global-scene"; import { getTypeRgb } from "#app/data/type"; import { PokemonType } from "#enums/pokemon-type"; -import { getVariantTint } from "#app/data/variant"; +import { getVariantTint } from "#app/sprites/variant"; import { Stat } from "#enums/stat"; import BattleFlyout from "./battle-flyout"; import { WindowVariant, addWindow } from "./ui-theme"; @@ -163,7 +163,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.splicedIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains); this.add(this.splicedIcon); - this.statusIndicator = globalScene.add.sprite(0, 0, Utils.getLocalizedSpriteKey("statuses")); + this.statusIndicator = globalScene.add.sprite(0, 0, getLocalizedSpriteKey("statuses")); this.statusIndicator.setName("icon_status"); this.statusIndicator.setVisible(false); this.statusIndicator.setOrigin(0, 0); @@ -356,7 +356,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { }); this.teraIcon.on("pointerout", () => globalScene.ui.hideTooltip()); - const isFusion = pokemon.isFusion(); + const isFusion = pokemon.isFusion(true); this.splicedIcon.setPositionRelative( this.nameText, @@ -375,7 +375,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { } const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; - const baseVariant = !doubleShiny ? pokemon.getVariant() : pokemon.variant; + const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; this.shinyIcon.setPositionRelative( this.nameText, @@ -536,7 +536,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { toggleStats(visible: boolean): void { globalScene.tweens.add({ targets: this.statsContainer, - duration: Utils.fixedInt(125), + duration: fixedInt(125), ease: "Sine.easeInOut", alpha: visible ? 1 : 0, }); @@ -557,11 +557,11 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.ownedIcon, this.championRibbon, this.statusIndicator, - this.levelContainer, this.statValuesContainer, ].map(e => (e.x += 48 * (boss ? -1 : 1))); this.hpBar.x += 38 * (boss ? -1 : 1); this.hpBar.y += 2 * (this.boss ? -1 : 1); + this.levelContainer.x += 2 * (boss ? -1 : 1); this.hpBar.setTexture(`overlay_hp${boss ? "_boss" : ""}`); this.box.setTexture(this.getTextureName()); this.statsBox.setTexture(`${this.getTextureName()}_stats`); @@ -617,6 +617,11 @@ export default class BattleInfo extends Phaser.GameObjects.Container { return resolve(); } + const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; + + this.genderText.setText(getGenderSymbol(gender)); + this.genderText.setColor(getGenderColor(gender)); + const nameUpdated = this.lastName !== pokemon.getNameToRender(); if (nameUpdated) { @@ -638,8 +643,10 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.lastTeraType = teraType; } + const isFusion = pokemon.isFusion(true); + if (nameUpdated || teraTypeUpdated) { - this.splicedIcon.setVisible(!!pokemon.fusionSpecies); + this.splicedIcon.setVisible(isFusion); this.teraIcon.setPositionRelative( this.nameText, @@ -764,7 +771,17 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.lastStats = statsStr; } - this.shinyIcon.setVisible(pokemon.isShiny()); + this.shinyIcon.setVisible(pokemon.isShiny(true)); + + const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; + const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; + this.shinyIcon.setTint(getVariantTint(baseVariant)); + + this.fusionShinyIcon.setVisible(doubleShiny); + if (isFusion) { + this.fusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); + } + this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); resolve(); }); @@ -777,10 +794,11 @@ export default class BattleInfo extends Phaser.GameObjects.Container { const nameSizeTest = addTextObject(0, 0, displayName, TextStyle.BATTLE_INFO); nameTextWidth = nameSizeTest.displayWidth; + const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; while ( nameTextWidth > (this.player || !this.boss ? 60 : 98) - - ((pokemon.gender !== Gender.GENDERLESS ? 6 : 0) + + ((gender !== Gender.GENDERLESS ? 6 : 0) + (pokemon.fusionSpecies ? 8 : 0) + (pokemon.isShiny() ? 8 : 0) + (Math.min(pokemon.level.toString().length, 3) - 3) * 8) diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index ccb9378c688..d1102bbe53e 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "./text"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import MessageUiHandler from "./message-ui-handler"; import { addWindow } from "./ui-theme"; import type BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; @@ -23,7 +23,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { public readonly wordWrapWidth: number = 1780; constructor() { - super(Mode.MESSAGE); + super(UiMode.MESSAGE); } setup(): void { diff --git a/src/ui/bgm-bar.ts b/src/ui/bgm-bar.ts index 45ed766c7fa..e331d82f6d9 100644 --- a/src/ui/bgm-bar.ts +++ b/src/ui/bgm-bar.ts @@ -1,6 +1,6 @@ import { addTextObject, TextStyle } from "./text"; import i18next from "i18next"; -import * as Utils from "#app/utils"; +import { formatText } from "#app/utils/common"; import { globalScene } from "#app/global-scene"; const hiddenX = -150; @@ -100,7 +100,7 @@ export default class BgmBar extends Phaser.GameObjects.Container { getRealBgmName(bgmName: string): string { return i18next.t([`bgmName:${bgmName}`, "bgmName:missing_entries"], { - name: Utils.formatText(bgmName), + name: formatText(bgmName), }); } } diff --git a/src/ui/candy-bar.ts b/src/ui/candy-bar.ts index ba85ed7fef3..f7a01b83093 100644 --- a/src/ui/candy-bar.ts +++ b/src/ui/candy-bar.ts @@ -1,8 +1,8 @@ -import { starterColors } from "#app/battle-scene"; +import { starterColors } from "#app/global-vars/starter-colors"; import { globalScene } from "#app/global-scene"; import { TextStyle, addTextObject } from "./text"; import { argbFromRgba } from "@material/material-color-utilities"; -import * as Utils from "../utils"; +import { rgbHexToRgba } from "#app/utils/common"; import type { Species } from "#enums/species"; export default class CandyBar extends Phaser.GameObjects.Container { @@ -60,8 +60,8 @@ export default class CandyBar extends Phaser.GameObjects.Container { const colorScheme = starterColors[starterSpeciesId]; - this.candyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0]))); - this.candyOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1]))); + this.candyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0]))); + this.candyOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1]))); this.countText.setText( `${globalScene.gameData.starterData[starterSpeciesId].candyCount + count} (+${count.toString()})`, diff --git a/src/ui/challenges-select-ui-handler.ts b/src/ui/challenges-select-ui-handler.ts index 61989cd594e..d1df16a457b 100644 --- a/src/ui/challenges-select-ui-handler.ts +++ b/src/ui/challenges-select-ui-handler.ts @@ -1,11 +1,11 @@ import { TextStyle, addTextObject } from "./text"; -import type { Mode } from "./ui"; +import type { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; import { Button } from "#enums/buttons"; import i18next from "i18next"; import type { Challenge } from "#app/data/challenge"; -import * as Utils from "../utils"; +import { getLocalizedSpriteKey } from "#app/utils/common"; import { Challenges } from "#app/enums/challenges"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import { Color, ShadowColor } from "#app/enums/color"; @@ -50,7 +50,7 @@ export default class GameChallengesUiHandler extends UiHandler { private readonly leftArrowGap: number = 90; // distance from the label to the left arrow private readonly arrowSpacing: number = 3; // distance between the arrows and the value area - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); } @@ -193,7 +193,7 @@ export default class GameChallengesUiHandler extends UiHandler { }; } - this.monoTypeValue = globalScene.add.sprite(8, 98, Utils.getLocalizedSpriteKey("types")); + this.monoTypeValue = globalScene.add.sprite(8, 98, getLocalizedSpriteKey("types")); this.monoTypeValue.setName("challenge-value-monotype-sprite"); this.monoTypeValue.setScale(0.86); this.monoTypeValue.setVisible(false); diff --git a/src/ui/char-sprite.ts b/src/ui/char-sprite.ts index 74c021a65b8..a8451f4bb9c 100644 --- a/src/ui/char-sprite.ts +++ b/src/ui/char-sprite.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import * as Utils from "../utils"; +import { MissingTextureKey } from "#app/utils/common"; export default class CharSprite extends Phaser.GameObjects.Container { private sprite: Phaser.GameObjects.Sprite; @@ -57,7 +57,7 @@ export default class CharSprite extends Phaser.GameObjects.Container { }, }); - this.setVisible(globalScene.textures.get(key).key !== Utils.MissingTextureKey); + this.setVisible(globalScene.textures.get(key).key !== MissingTextureKey); this.shown = true; this.key = key; diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index 55937bb8b00..ff27e9c41c0 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -1,6 +1,6 @@ import { addTextObject, TextStyle } from "./text"; import PartyUiHandler, { PartyUiMode } from "./party-ui-handler"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; import i18next from "i18next"; import { Button } from "#enums/buttons"; @@ -30,7 +30,7 @@ export default class CommandUiHandler extends UiHandler { protected cursor2 = 0; constructor() { - super(Mode.COMMAND); + super(UiMode.COMMAND); } setup() { @@ -86,7 +86,7 @@ export default class CommandUiHandler extends UiHandler { this.teraButton.setFrame(PokemonType[globalScene.getField()[this.fieldIndex].getTeraType()].toLowerCase()); } else { this.teraButton.setVisible(false); - if (this.cursor === Command.TERA) { + if (this.getCursor() === Command.TERA) { this.setCursor(Command.FIGHT); } } @@ -124,18 +124,18 @@ export default class CommandUiHandler extends UiHandler { switch (cursor) { // Fight case Command.FIGHT: - ui.setMode(Mode.FIGHT, (globalScene.getCurrentPhase() as CommandPhase).getFieldIndex()); + ui.setMode(UiMode.FIGHT, (globalScene.getCurrentPhase() as CommandPhase).getFieldIndex()); success = true; break; // Ball case Command.BALL: - ui.setModeWithoutClear(Mode.BALL); + ui.setModeWithoutClear(UiMode.BALL); success = true; break; // Pokemon case Command.POKEMON: ui.setMode( - Mode.PARTY, + UiMode.PARTY, PartyUiMode.SWITCH, (globalScene.getCurrentPhase() as CommandPhase).getPokemon().getFieldIndex(), null, @@ -149,7 +149,7 @@ export default class CommandUiHandler extends UiHandler { success = true; break; case Command.TERA: - ui.setMode(Mode.FIGHT, (globalScene.getCurrentPhase() as CommandPhase).getFieldIndex(), Command.TERA); + ui.setMode(UiMode.FIGHT, (globalScene.getCurrentPhase() as CommandPhase).getFieldIndex(), Command.TERA); success = true; break; } diff --git a/src/ui/confirm-ui-handler.ts b/src/ui/confirm-ui-handler.ts index eb7018051b7..7b5ca3d7e63 100644 --- a/src/ui/confirm-ui-handler.ts +++ b/src/ui/confirm-ui-handler.ts @@ -1,6 +1,6 @@ import type { OptionSelectConfig } from "./abstact-option-select-ui-handler"; import AbstractOptionSelectUiHandler from "./abstact-option-select-ui-handler"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { Button } from "#enums/buttons"; import { globalScene } from "#app/global-scene"; @@ -12,7 +12,7 @@ export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler { private switchCheckCursor: number; constructor() { - super(Mode.CONFIRM); + super(UiMode.CONFIRM); } getWindowWidth(): number { diff --git a/src/ui/daily-run-scoreboard.ts b/src/ui/daily-run-scoreboard.ts index 53c737898e7..076a782908b 100644 --- a/src/ui/daily-run-scoreboard.ts +++ b/src/ui/daily-run-scoreboard.ts @@ -1,6 +1,6 @@ import i18next from "i18next"; import { globalScene } from "#app/global-scene"; -import * as Utils from "../utils"; +import { getEnumKeys, executeIf } from "#app/utils/common"; import { TextStyle, addTextObject } from "./text"; import { WindowVariant, addWindow } from "./ui-theme"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; @@ -89,7 +89,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container { this.prevCategoryButton.setInteractive(new Phaser.Geom.Rectangle(0, 0, 6, 10), Phaser.Geom.Rectangle.Contains); this.prevCategoryButton.on("pointerup", () => { - this.update(this.category ? this.category - 1 : Utils.getEnumKeys(ScoreboardCategory).length - 1); + this.update(this.category ? this.category - 1 : getEnumKeys(ScoreboardCategory).length - 1); }); this.nextCategoryButton = globalScene.add.sprite(window.displayWidth - 4, 4, "cursor"); @@ -98,7 +98,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container { this.nextCategoryButton.setInteractive(new Phaser.Geom.Rectangle(0, 0, 6, 10), Phaser.Geom.Rectangle.Contains); this.nextCategoryButton.on("pointerup", () => { - this.update(this.category < Utils.getEnumKeys(ScoreboardCategory).length - 1 ? this.category + 1 : 0); + this.update(this.category < getEnumKeys(ScoreboardCategory).length - 1 ? this.category + 1 : 0); }); this.prevPageButton = globalScene.add.sprite( @@ -226,7 +226,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container { this.page = page = 1; } - Utils.executeIf(category !== this.category || this.pageCount === undefined, () => + executeIf(category !== this.category || this.pageCount === undefined, () => pokerogueApi.daily.getRankingsPageCount({ category }).then(count => (this.pageCount = count)), ) .then(() => { diff --git a/src/ui/egg-gacha-ui-handler.ts b/src/ui/egg-gacha-ui-handler.ts index 6853ff73632..22004404e51 100644 --- a/src/ui/egg-gacha-ui-handler.ts +++ b/src/ui/egg-gacha-ui-handler.ts @@ -1,7 +1,7 @@ -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import { TextStyle, addTextObject, getEggTierTextTint, getTextStyleOptions } from "./text"; import MessageUiHandler from "./message-ui-handler"; -import * as Utils from "../utils"; +import { getEnumValues, getEnumKeys, fixedInt, randSeedShuffle } from "#app/utils/common"; import type { IEggOptions } from "../data/egg"; import { Egg, getLegendaryGachaSpeciesForTimestamp } from "../data/egg"; import { VoucherType, getVoucherTypeIcon } from "../system/voucher"; @@ -41,7 +41,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { private scale = 0.1666666667; constructor() { - super(Mode.EGG_GACHA); + super(UiMode.EGG_GACHA); this.gachaContainers = []; this.gachaKnobs = []; @@ -83,7 +83,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { }); } - Utils.getEnumValues(GachaType).forEach((gachaType, g) => { + getEnumValues(GachaType).forEach((gachaType, g) => { const gachaTypeKey = GachaType[gachaType].toString().toLowerCase(); const gachaContainer = globalScene.add.container(180 * g, 18); @@ -276,7 +276,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { this.eggGachaContainer.add(this.eggGachaOptionsContainer); - new Array(Utils.getEnumKeys(VoucherType).length).fill(null).map((_, i) => { + new Array(getEnumKeys(VoucherType).length).fill(null).map((_, i) => { const container = globalScene.add.container(globalScene.game.canvas.width / 6 - 56 * i, 0); const bg = addWindow(0, 0, 56, 22); @@ -359,7 +359,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { if (this.transitioning && this.transitionCancelled) { delay = Math.ceil(delay / 5); } - return Utils.fixedInt(delay); + return fixedInt(delay); } pull(pullCount = 0, count = 0, eggs?: Egg[]): void { @@ -480,7 +480,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { eggs.push(egg); } // Shuffle the eggs in case the guaranteed one got added as last egg - eggs = Utils.randSeedShuffle(eggs); + eggs = randSeedShuffle(eggs); (globalScene.currentBattle ? globalScene.gameData.saveAll(true, true, true) @@ -647,7 +647,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { } showError(text: string): void { - this.showText(text, undefined, () => this.showText(this.defaultText), Utils.fixedInt(1500)); + this.showText(text, undefined, () => this.showText(this.defaultText), fixedInt(1500)); } setTransitioning(transitioning: boolean): void { @@ -826,7 +826,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { } break; case Button.RIGHT: - if (this.gachaCursor < Utils.getEnumKeys(GachaType).length - 1) { + if (this.gachaCursor < getEnumKeys(GachaType).length - 1) { success = this.setGachaCursor(this.gachaCursor + 1); } break; diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/egg-hatch-scene-handler.ts index 6ede68b7ae6..76e2c54f4b6 100644 --- a/src/ui/egg-hatch-scene-handler.ts +++ b/src/ui/egg-hatch-scene-handler.ts @@ -1,4 +1,4 @@ -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; import { Button } from "#enums/buttons"; import { EggHatchPhase } from "#app/phases/egg-hatch-phase"; @@ -16,7 +16,7 @@ export default class EggHatchSceneHandler extends UiHandler { public readonly eventTarget: EventTarget = new EventTarget(); constructor() { - super(Mode.EGG_HATCH_SCENE); + super(UiMode.EGG_HATCH_SCENE); } setup() { diff --git a/src/ui/egg-list-ui-handler.ts b/src/ui/egg-list-ui-handler.ts index cf3326bec13..9f41feea8ab 100644 --- a/src/ui/egg-list-ui-handler.ts +++ b/src/ui/egg-list-ui-handler.ts @@ -1,4 +1,4 @@ -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "#app/ui/pokemon-icon-anim-handler"; import { TextStyle, addTextObject } from "#app/ui/text"; import MessageUiHandler from "#app/ui/message-ui-handler"; @@ -29,7 +29,7 @@ export default class EggListUiHandler extends MessageUiHandler { private iconAnimHandler: PokemonIconAnimHandler; constructor() { - super(Mode.EGG_LIST); + super(UiMode.EGG_LIST); } setup() { diff --git a/src/ui/egg-summary-ui-handler.ts b/src/ui/egg-summary-ui-handler.ts index f335f83d8bf..ddc536fe1ad 100644 --- a/src/ui/egg-summary-ui-handler.ts +++ b/src/ui/egg-summary-ui-handler.ts @@ -1,4 +1,4 @@ -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler"; import MessageUiHandler from "./message-ui-handler"; import { getEggTierForSpecies } from "../data/egg"; @@ -54,7 +54,7 @@ export default class EggSummaryUiHandler extends MessageUiHandler { public readonly eventTarget: EventTarget = new EventTarget(); constructor() { - super(Mode.EGG_HATCH_SUMMARY); + super(UiMode.EGG_HATCH_SUMMARY); } setup() { diff --git a/src/ui/evolution-scene-handler.ts b/src/ui/evolution-scene-handler.ts index 91f3360a3d4..cea91ce4e2c 100644 --- a/src/ui/evolution-scene-handler.ts +++ b/src/ui/evolution-scene-handler.ts @@ -1,6 +1,6 @@ import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import { Button } from "#enums/buttons"; import { globalScene } from "#app/global-scene"; @@ -12,7 +12,7 @@ export default class EvolutionSceneHandler extends MessageUiHandler { public cancelled: boolean; constructor() { - super(Mode.EVOLUTION_SCENE); + super(UiMode.EVOLUTION_SCENE); } setup() { diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index 9f76e85f228..5a0978a934d 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -4,9 +4,9 @@ import { addTextObject, TextStyle } from "./text"; import { getTypeDamageMultiplierColor } from "#app/data/type"; import { PokemonType } from "#enums/pokemon-type"; import { Command } from "./command-ui-handler"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; -import * as Utils from "../utils"; +import { getLocalizedSpriteKey, fixedInt, padInt } from "#app/utils/common"; import { MoveCategory } from "#enums/MoveCategory"; import i18next from "i18next"; import { Button } from "#enums/buttons"; @@ -14,7 +14,7 @@ import type { PokemonMove } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import type { CommandPhase } from "#app/phases/command-phase"; import MoveInfoOverlay from "./move-info-overlay"; -import { BattleType } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; export default class FightUiHandler extends UiHandler implements InfoToggle { public static readonly MOVES_CONTAINER_NAME = "moves"; @@ -37,7 +37,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { protected cursor2 = 0; constructor() { - super(Mode.FIGHT); + super(UiMode.FIGHT); } setup() { @@ -54,7 +54,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { this.typeIcon = globalScene.add.sprite( globalScene.scaledCanvas.width - 57, -36, - Utils.getLocalizedSpriteKey("types"), + getLocalizedSpriteKey("types"), "unknown", ); this.typeIcon.setVisible(false); @@ -127,7 +127,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { messageHandler.commandWindow.setVisible(false); messageHandler.movesWindowContainer.setVisible(true); const pokemon = (globalScene.getCurrentPhase() as CommandPhase).getPokemon(); - if (pokemon.battleSummonData.turnCount <= 1) { + if (pokemon.tempSummonData.turnCount <= 1) { this.setCursor(0); } else { this.setCursor(this.getCursor()); @@ -156,7 +156,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { // Cannot back out of fight menu if skipToFightInput is enabled const { battleType, mysteryEncounter } = globalScene.currentBattle; if (battleType !== BattleType.MYSTERY_ENCOUNTER || !mysteryEncounter?.skipToFightInput) { - ui.setMode(Mode.COMMAND, this.fieldIndex); + ui.setMode(UiMode.COMMAND, this.fieldIndex); success = true; } } @@ -199,7 +199,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { } globalScene.tweens.add({ targets: [this.movesContainer, this.cursorObj], - duration: Utils.fixedInt(125), + duration: fixedInt(125), ease: "Sine.easeInOut", alpha: visible ? 0 : 1, }); @@ -245,7 +245,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { if (hasMove) { const pokemonMove = moveset[cursor]; const moveType = pokemon.getMoveType(pokemonMove.getMove()); - const textureKey = Utils.getLocalizedSpriteKey("types"); + const textureKey = getLocalizedSpriteKey("types"); this.typeIcon.setTexture(textureKey, PokemonType[moveType].toLowerCase()).setScale(0.8); const moveCategory = pokemonMove.getMove().category; @@ -255,8 +255,8 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { const maxPP = pokemonMove.getMovePp(); const pp = maxPP - pokemonMove.ppUsed; - const ppLeftStr = Utils.padInt(pp, 2, " "); - const ppMaxStr = Utils.padInt(maxPP, 2, " "); + const ppLeftStr = padInt(pp, 2, " "); + const ppMaxStr = padInt(maxPP, 2, " "); this.ppText.setText(`${ppLeftStr}/${ppMaxStr}`); this.powerText.setText(`${power >= 0 ? power : "---"}`); this.accuracyText.setText(`${accuracy >= 0 ? accuracy : "---"}`); @@ -305,7 +305,10 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { const effectiveness = opponent.getMoveEffectiveness( pokemon, pokemonMove.getMove(), - !opponent.battleData?.abilityRevealed, + !opponent.waveData.abilityRevealed, + undefined, + undefined, + true, ); if (effectiveness === undefined) { return undefined; @@ -350,7 +353,14 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { const moveColors = opponents .map(opponent => - opponent.getMoveEffectiveness(pokemon, pokemonMove.getMove(), !opponent.battleData.abilityRevealed), + opponent.getMoveEffectiveness( + pokemon, + pokemonMove.getMove(), + !opponent.waveData.abilityRevealed, + undefined, + undefined, + true, + ), ) .sort((a, b) => b - a) .map(effectiveness => getTypeDamageMultiplierColor(effectiveness ?? 0, "offense")); diff --git a/src/ui/filter-text.ts b/src/ui/filter-text.ts index a6b01ba39e6..7e27a806478 100644 --- a/src/ui/filter-text.ts +++ b/src/ui/filter-text.ts @@ -5,7 +5,7 @@ import { addWindow, WindowVariant } from "./ui-theme"; import i18next from "i18next"; import type AwaitableUiHandler from "./awaitable-ui-handler"; import type UI from "./ui"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import { globalScene } from "#app/global-scene"; export enum FilterTextRow { @@ -20,7 +20,6 @@ export class FilterText extends Phaser.GameObjects.Container { private window: Phaser.GameObjects.NineSlice; private labels: Phaser.GameObjects.Text[] = []; private selections: Phaser.GameObjects.Text[] = []; - private selectionStrings: string[] = []; private rows: FilterTextRow[] = []; public cursorObj: Phaser.GameObjects.Image; public numFilters = 0; @@ -112,8 +111,6 @@ export class FilterText extends Phaser.GameObjects.Container { this.selections.push(filterTypesSelection); this.add(filterTypesSelection); - this.selectionStrings.push(""); - this.calcFilterPositions(); this.numFilters++; @@ -122,7 +119,6 @@ export class FilterText extends Phaser.GameObjects.Container { resetSelection(index: number): void { this.selections[index].setText(this.defaultText); - this.selectionStrings[index] = ""; this.onChange(); } @@ -154,7 +150,7 @@ export class FilterText extends Phaser.GameObjects.Container { this.onChange; }, ]; - ui.setOverlayMode(Mode.POKEDEX_SCAN, buttonAction, prefilledText, index); + ui.setOverlayMode(UiMode.POKEDEX_SCAN, buttonAction, prefilledText, index); } setCursor(cursor: number): void { @@ -204,6 +200,17 @@ export class FilterText extends Phaser.GameObjects.Container { return this.selections[row].getWrappedText()[0]; } + /** + * Forcibly set the selection text for a specific filter row and then call the `onChange` function + * + * @param row - The filter row to set the text for + * @param value - The text to set for the filter row + */ + setValue(row: FilterTextRow, value: string) { + this.selections[row].setText(value); + this.onChange(); + } + /** * Find the nearest filter to the provided container on the y-axis * @param container the StarterContainer to compare position against diff --git a/src/ui/form-modal-ui-handler.ts b/src/ui/form-modal-ui-handler.ts index 8784145acd6..8c30b4e0bc4 100644 --- a/src/ui/form-modal-ui-handler.ts +++ b/src/ui/form-modal-ui-handler.ts @@ -1,10 +1,10 @@ import type { ModalConfig } from "./modal-ui-handler"; import { ModalUiHandler } from "./modal-ui-handler"; -import type { Mode } from "./ui"; +import type { UiMode } from "#enums/ui-mode"; import { TextStyle, addTextInputObject, addTextObject } from "./text"; import { WindowVariant, addWindow } from "./ui-theme"; import type InputText from "phaser3-rex-plugins/plugins/inputtext"; -import * as Utils from "../utils"; +import { fixedInt } from "#app/utils/common"; import { Button } from "#enums/buttons"; import { globalScene } from "#app/global-scene"; @@ -21,7 +21,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler { protected tween: Phaser.Tweens.Tween; protected formLabels: Phaser.GameObjects.Text[]; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.editing = false; @@ -124,7 +124,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler { if (this.buttonBgs.length) { this.buttonBgs[0].off("pointerdown"); this.buttonBgs[0].on("pointerdown", () => { - if (this.submitAction) { + if (this.submitAction && globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { this.submitAction(); } }); @@ -135,7 +135,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler { this.tween = globalScene.tweens.add({ targets: this.modalContainer, - duration: Utils.fixedInt(1000), + duration: fixedInt(1000), ease: "Sine.easeInOut", y: "-=24", alpha: 1, diff --git a/src/ui/game-stats-ui-handler.ts b/src/ui/game-stats-ui-handler.ts index 7d3decf0c4c..dc184a34866 100644 --- a/src/ui/game-stats-ui-handler.ts +++ b/src/ui/game-stats-ui-handler.ts @@ -1,9 +1,9 @@ import Phaser from "phaser"; import { TextStyle, addTextObject } from "#app/ui/text"; -import type { Mode } from "#app/ui/ui"; +import type { UiMode } from "#enums/ui-mode"; import UiHandler from "#app/ui/ui-handler"; import { addWindow } from "#app/ui/ui-theme"; -import * as Utils from "#app/utils"; +import { getPlayTimeString, formatFancyLargeNumber, toReadableString } from "#app/utils/common"; import type { GameData } from "#app/system/game-data"; import { DexAttr } from "#app/system/game-data"; import { speciesStarterCosts } from "#app/data/balance/starters"; @@ -25,7 +25,7 @@ interface DisplayStats { const displayStats: DisplayStats = { playTime: { label_key: "playTime", - sourceFunc: gameData => Utils.getPlayTimeString(gameData.gameStats.playTime), + sourceFunc: gameData => getPlayTimeString(gameData.gameStats.playTime), }, battles: { label_key: "totalBattles", @@ -91,7 +91,7 @@ const displayStats: DisplayStats = { }, highestMoney: { label_key: "highestMoney", - sourceFunc: gameData => Utils.formatFancyLargeNumber(gameData.gameStats.highestMoney), + sourceFunc: gameData => formatFancyLargeNumber(gameData.gameStats.highestMoney), }, highestDamage: { label_key: "highestDamage", @@ -223,7 +223,7 @@ export default class GameStatsUiHandler extends UiHandler { private arrowUp: Phaser.GameObjects.Sprite; private arrowDown: Phaser.GameObjects.Sprite; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.statLabels = []; @@ -435,7 +435,7 @@ export function initStatsKeys() { } if (!(displayStats[key] as DisplayStat).label_key) { const splittableKey = key.replace(/([a-z]{2,})([A-Z]{1}(?:[^A-Z]|$))/g, "$1_$2"); - (displayStats[key] as DisplayStat).label_key = Utils.toReadableString( + (displayStats[key] as DisplayStat).label_key = toReadableString( `${splittableKey[0].toUpperCase()}${splittableKey.slice(1)}`, ); } diff --git a/src/ui/hatched-pokemon-container.ts b/src/ui/hatched-pokemon-container.ts index 0b283c2e063..9d1c13e19d5 100644 --- a/src/ui/hatched-pokemon-container.ts +++ b/src/ui/hatched-pokemon-container.ts @@ -1,6 +1,6 @@ import type { EggHatchData } from "#app/data/egg-hatch-data"; import { Gender } from "#app/data/gender"; -import { getVariantTint } from "#app/data/variant"; +import { getVariantTint } from "#app/sprites/variant"; import { DexAttr } from "#app/system/game-data"; import { globalScene } from "#app/global-scene"; import type PokemonSpecies from "#app/data/pokemon-species"; diff --git a/src/ui/loading-modal-ui-handler.ts b/src/ui/loading-modal-ui-handler.ts index 9626276245d..13dffe5614c 100644 --- a/src/ui/loading-modal-ui-handler.ts +++ b/src/ui/loading-modal-ui-handler.ts @@ -1,10 +1,10 @@ import i18next from "i18next"; import { ModalUiHandler } from "./modal-ui-handler"; import { addTextObject, TextStyle } from "./text"; -import type { Mode } from "./ui"; +import type { UiMode } from "#enums/ui-mode"; export default class LoadingModalUiHandler extends ModalUiHandler { - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); } diff --git a/src/ui/login-form-ui-handler.ts b/src/ui/login-form-ui-handler.ts index 1087ffa3fd1..714a9b39771 100644 --- a/src/ui/login-form-ui-handler.ts +++ b/src/ui/login-form-ui-handler.ts @@ -1,8 +1,8 @@ import type { InputFieldConfig } from "./form-modal-ui-handler"; import { FormModalUiHandler } from "./form-modal-ui-handler"; import type { ModalConfig } from "./modal-ui-handler"; -import * as Utils from "../utils"; -import { Mode } from "./ui"; +import { fixedInt } from "#app/utils/common"; +import { UiMode } from "#enums/ui-mode"; import i18next from "i18next"; import { addTextObject, TextStyle } from "./text"; import { addWindow } from "./ui-theme"; @@ -34,31 +34,15 @@ export default class LoginFormUiHandler extends FormModalUiHandler { private infoContainer: Phaser.GameObjects.Container; private externalPartyBg: Phaser.GameObjects.NineSlice; private externalPartyTitle: Phaser.GameObjects.Text; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); } setup(): void { super.setup(); + this.buildExternalPartyContainer(); - - this.infoContainer = globalScene.add.container(0, 0); - - this.usernameInfoImage = this.buildInteractableImage("settings_icon", "username-info-icon", { - x: 20, - scale: 0.5, - }); - - this.saveDownloadImage = this.buildInteractableImage("saving_icon", "save-download-icon", { - x: 0, - scale: 0.75, - }); - - this.infoContainer.add(this.usernameInfoImage); - this.infoContainer.add(this.saveDownloadImage); - this.getUi().add(this.infoContainer); - this.infoContainer.setVisible(false); - this.infoContainer.disableInteractive(); + this.buildInfoContainer(); } private buildExternalPartyContainer() { @@ -84,6 +68,26 @@ export default class LoginFormUiHandler extends FormModalUiHandler { this.externalPartyContainer.setVisible(false); } + private buildInfoContainer() { + this.infoContainer = globalScene.add.container(0, 0); + + this.usernameInfoImage = this.buildInteractableImage("settings_icon", "username-info-icon", { + x: 20, + scale: 0.5, + }); + + this.saveDownloadImage = this.buildInteractableImage("saving_icon", "save-download-icon", { + x: 0, + scale: 0.75, + }); + + this.infoContainer.add(this.usernameInfoImage); + this.infoContainer.add(this.saveDownloadImage); + this.getUi().add(this.infoContainer); + this.infoContainer.setVisible(false); + this.infoContainer.disableInteractive(); + } + override getModalTitle(_config?: ModalConfig): string { let key = "menu:login"; if (import.meta.env.VITE_SERVER_URL === "https://apibeta.pokerogue.net") { @@ -143,27 +147,29 @@ export default class LoginFormUiHandler extends FormModalUiHandler { this.processExternalProvider(config); const originalLoginAction = this.submitAction; this.submitAction = _ => { - // Prevent overlapping overrides on action modification - this.submitAction = originalLoginAction; - this.sanitizeInputs(); - globalScene.ui.setMode(Mode.LOADING, { buttonActions: [] }); - const onFail = error => { - globalScene.ui.setMode(Mode.LOGIN_FORM, Object.assign(config, { errorMessage: error?.trim() })); - globalScene.ui.playError(); - }; - if (!this.inputs[0].text) { - return onFail(i18next.t("menu:emptyUsername")); - } - - const [usernameInput, passwordInput] = this.inputs; - - pokerogueApi.account.login({ username: usernameInput.text, password: passwordInput.text }).then(error => { - if (!error && originalLoginAction) { - originalLoginAction(); - } else { - onFail(error); + if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { + // Prevent overlapping overrides on action modification + this.submitAction = originalLoginAction; + this.sanitizeInputs(); + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); + const onFail = error => { + globalScene.ui.setMode(UiMode.LOGIN_FORM, Object.assign(config, { errorMessage: error?.trim() })); + globalScene.ui.playError(); + }; + if (!this.inputs[0].text) { + return onFail(i18next.t("menu:emptyUsername")); } - }); + + const [usernameInput, passwordInput] = this.inputs; + + pokerogueApi.account.login({ username: usernameInput.text, password: passwordInput.text }).then(error => { + if (!error && originalLoginAction) { + originalLoginAction(); + } else { + onFail(error); + } + }); + } }; return true; @@ -215,40 +221,42 @@ export default class LoginFormUiHandler extends FormModalUiHandler { }); const onFail = error => { - globalScene.ui.setMode(Mode.LOADING, { buttonActions: [] }); - globalScene.ui.setModeForceTransition(Mode.LOGIN_FORM, Object.assign(config, { errorMessage: error?.trim() })); + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); + globalScene.ui.setModeForceTransition(UiMode.LOGIN_FORM, Object.assign(config, { errorMessage: error?.trim() })); globalScene.ui.playError(); }; this.usernameInfoImage.on("pointerdown", () => { - const localStorageKeys = Object.keys(localStorage); // this gets the keys for localStorage - const keyToFind = "data_"; - const dataKeys = localStorageKeys.filter(ls => ls.indexOf(keyToFind) >= 0); - if (dataKeys.length > 0 && dataKeys.length <= 2) { - const options: OptionSelectItem[] = []; - for (let i = 0; i < dataKeys.length; i++) { - options.push({ - label: dataKeys[i].replace(keyToFind, ""), - handler: () => { - globalScene.ui.revertMode(); - this.infoContainer.disableInteractive(); - return true; - }, + if (globalScene.tweens.getTweensOf(this.infoContainer).length === 0) { + const localStorageKeys = Object.keys(localStorage); // this gets the keys for localStorage + const keyToFind = "data_"; + const dataKeys = localStorageKeys.filter(ls => ls.indexOf(keyToFind) >= 0); + if (dataKeys.length > 0 && dataKeys.length <= 2) { + const options: OptionSelectItem[] = []; + for (let i = 0; i < dataKeys.length; i++) { + options.push({ + label: dataKeys[i].replace(keyToFind, ""), + handler: () => { + globalScene.ui.revertMode(); + this.infoContainer.disableInteractive(); + return true; + }, + }); + } + globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, { + options: options, + delay: 1000, }); + this.infoContainer.setInteractive( + new Phaser.Geom.Rectangle(0, 0, globalScene.game.canvas.width, globalScene.game.canvas.height), + Phaser.Geom.Rectangle.Contains, + ); + } else { + if (dataKeys.length > 2) { + return onFail(this.ERR_TOO_MANY_SAVES); + } + return onFail(this.ERR_NO_SAVES); } - globalScene.ui.setOverlayMode(Mode.OPTION_SELECT, { - options: options, - delay: 1000, - }); - this.infoContainer.setInteractive( - new Phaser.Geom.Rectangle(0, 0, globalScene.game.canvas.width, globalScene.game.canvas.height), - Phaser.Geom.Rectangle.Contains, - ); - } else { - if (dataKeys.length > 2) { - return onFail(this.ERR_TOO_MANY_SAVES); - } - return onFail(this.ERR_NO_SAVES); } }); @@ -283,7 +291,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler { this.externalPartyContainer.setAlpha(0); globalScene.tweens.add({ targets: this.externalPartyContainer, - duration: Utils.fixedInt(1000), + duration: fixedInt(1000), ease: "Sine.easeInOut", y: "-=24", alpha: 1, @@ -292,7 +300,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler { this.infoContainer.setAlpha(0); globalScene.tweens.add({ targets: this.infoContainer, - duration: Utils.fixedInt(1000), + duration: fixedInt(1000), ease: "Sine.easeInOut", y: "-=24", alpha: 1, diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index b83ae24c9e0..7f0cd4d6a78 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -1,8 +1,10 @@ -import { bypassLogin } from "#app/battle-scene"; +import { bypassLogin } from "#app/global-vars/bypass-login"; import { globalScene } from "#app/global-scene"; import { TextStyle, addTextObject, getTextStyleOptions } from "./text"; -import { Mode } from "./ui"; -import * as Utils from "../utils"; +import { UiMode } from "#enums/ui-mode"; +import { getEnumKeys, isLocal, fixedInt, sessionIdKey } from "#app/utils/common"; +import { isBeta } from "#app/utils/utility-vars"; +import { getCookie } from "#app/utils/cookies"; import { addWindow, WindowVariant } from "./ui-theme"; import MessageUiHandler from "./message-ui-handler"; import type { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui-handler"; @@ -64,18 +66,18 @@ export default class MenuUiHandler extends MessageUiHandler { public bgmBar: BgmBar; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.excludedMenus = () => [ { - condition: [Mode.COMMAND, Mode.TITLE].includes(mode ?? Mode.TITLE), + condition: [UiMode.COMMAND, UiMode.TITLE].includes(mode ?? UiMode.TITLE), options: [MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST], }, { condition: bypassLogin, options: [MenuOptions.LOG_OUT] }, ]; - this.menuOptions = Utils.getEnumKeys(MenuOptions) + this.menuOptions = getEnumKeys(MenuOptions) .map(m => Number.parseInt(MenuOptions[m]) as MenuOptions) .filter(m => { return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m)); @@ -130,7 +132,7 @@ export default class MenuUiHandler extends MessageUiHandler { { condition: bypassLogin, options: [MenuOptions.LOG_OUT] }, ]; - this.menuOptions = Utils.getEnumKeys(MenuOptions) + this.menuOptions = getEnumKeys(MenuOptions) .map(m => Number.parseInt(MenuOptions[m]) as MenuOptions) .filter(m => { return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m)); @@ -234,11 +236,11 @@ export default class MenuUiHandler extends MessageUiHandler { ]), xOffset: 98, }; - ui.setOverlayMode(Mode.MENU_OPTION_SELECT, config); + ui.setOverlayMode(UiMode.MENU_OPTION_SELECT, config); }); }; - if (Utils.isLocal || Utils.isBeta) { + if (isLocal || isBeta) { manageDataOptions.push({ label: i18next.t("menuUiHandler:importSession"), handler: () => { @@ -292,7 +294,7 @@ export default class MenuUiHandler extends MessageUiHandler { }, keepOpen: true, }); - if (Utils.isLocal || Utils.isBeta) { + if (isLocal || isBeta) { manageDataOptions.push({ label: i18next.t("menuUiHandler:importData"), handler: () => { @@ -328,7 +330,7 @@ export default class MenuUiHandler extends MessageUiHandler { keepOpen: true, }, ); - if (Utils.isLocal || Utils.isBeta) { + if (isLocal || isBeta) { // this should make sure we don't have this option in live manageDataOptions.push({ label: "Test Dialogue", @@ -377,7 +379,7 @@ export default class MenuUiHandler extends MessageUiHandler { ui.revertMode(); }, ]; - ui.setMode(Mode.TEST_DIALOGUE, buttonAction, prefilledText); + ui.setMode(UiMode.TEST_DIALOGUE, buttonAction, prefilledText); return true; }, keepOpen: true, @@ -456,7 +458,7 @@ export default class MenuUiHandler extends MessageUiHandler { handler: () => { ui.playSelect(); ui.setOverlayMode( - Mode.ADMIN, + UiMode.ADMIN, { buttonActions: [ // we double revert here and below to go back 2 layers of menus @@ -483,7 +485,7 @@ export default class MenuUiHandler extends MessageUiHandler { return true; }, }); - globalScene.ui.setOverlayMode(Mode.OPTION_SELECT, { + globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, { options: options, delay: 0, }); @@ -510,7 +512,7 @@ export default class MenuUiHandler extends MessageUiHandler { this.render(); super.show(args); - this.menuOptions = Utils.getEnumKeys(MenuOptions) + this.menuOptions = getEnumKeys(MenuOptions) .map(m => Number.parseInt(MenuOptions[m]) as MenuOptions) .filter(m => { return !this.excludedMenus().some(exclusion => exclusion.condition && exclusion.options.includes(m)); @@ -557,35 +559,35 @@ export default class MenuUiHandler extends MessageUiHandler { this.showText("", 0); switch (adjustedCursor) { case MenuOptions.GAME_SETTINGS: - ui.setOverlayMode(Mode.SETTINGS); + ui.setOverlayMode(UiMode.SETTINGS); success = true; break; case MenuOptions.ACHIEVEMENTS: - ui.setOverlayMode(Mode.ACHIEVEMENTS); + ui.setOverlayMode(UiMode.ACHIEVEMENTS); success = true; break; case MenuOptions.STATS: - ui.setOverlayMode(Mode.GAME_STATS); + ui.setOverlayMode(UiMode.GAME_STATS); success = true; break; case MenuOptions.EGG_LIST: if (globalScene.gameData.eggs.length) { ui.revertMode(); - ui.setOverlayMode(Mode.EGG_LIST); + ui.setOverlayMode(UiMode.EGG_LIST); success = true; } else { - ui.showText(i18next.t("menuUiHandler:noEggs"), null, () => ui.showText(""), Utils.fixedInt(1500)); + ui.showText(i18next.t("menuUiHandler:noEggs"), null, () => ui.showText(""), fixedInt(1500)); error = true; } break; case MenuOptions.EGG_GACHA: ui.revertMode(); - ui.setOverlayMode(Mode.EGG_GACHA); + ui.setOverlayMode(UiMode.EGG_GACHA); success = true; break; case MenuOptions.POKEDEX: ui.revertMode(); - ui.setOverlayMode(Mode.POKEDEX); + ui.setOverlayMode(UiMode.POKEDEX); success = true; break; case MenuOptions.MANAGE_DATA: @@ -607,7 +609,7 @@ export default class MenuUiHandler extends MessageUiHandler { : i18next.t("menuUiHandler:unlinkDiscord"), handler: () => { if (loggedInUser?.discordId === "") { - const token = Utils.getCookie(Utils.sessionIdKey); + const token = getCookie(sessionIdKey); const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`); const discordId = import.meta.env.VITE_DISCORD_CLIENT_ID; const discordUrl = `https://discord.com/api/oauth2/authorize?client_id=${discordId}&redirect_uri=${redirectUri}&response_type=code&scope=identify&state=${token}&prompt=none`; @@ -627,7 +629,7 @@ export default class MenuUiHandler extends MessageUiHandler { : i18next.t("menuUiHandler:unlinkGoogle"), handler: () => { if (loggedInUser?.googleId === "") { - const token = Utils.getCookie(Utils.sessionIdKey); + const token = getCookie(sessionIdKey); const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/google/callback`); const googleId = import.meta.env.VITE_GOOGLE_CLIENT_ID; const googleUrl = `https://accounts.google.com/o/oauth2/auth?client_id=${googleId}&response_type=code&redirect_uri=${redirectUri}&scope=openid&state=${token}`; @@ -642,18 +644,18 @@ export default class MenuUiHandler extends MessageUiHandler { }, ); } - ui.setOverlayMode(Mode.MENU_OPTION_SELECT, this.manageDataConfig); + ui.setOverlayMode(UiMode.MENU_OPTION_SELECT, this.manageDataConfig); success = true; break; case MenuOptions.COMMUNITY: - ui.setOverlayMode(Mode.MENU_OPTION_SELECT, this.communityConfig); + ui.setOverlayMode(UiMode.MENU_OPTION_SELECT, this.communityConfig); success = true; break; case MenuOptions.SAVE_AND_QUIT: if (globalScene.currentBattle) { success = true; const doSaveQuit = () => { - ui.setMode(Mode.LOADING, { + ui.setMode(UiMode.LOADING, { buttonActions: [], fadeOut: () => globalScene.gameData.saveAll(true, true, true, true).then(() => { @@ -668,7 +670,7 @@ export default class MenuUiHandler extends MessageUiHandler { return; } ui.setOverlayMode( - Mode.CONFIRM, + UiMode.CONFIRM, doSaveQuit, () => { ui.revertMode(); @@ -688,7 +690,7 @@ export default class MenuUiHandler extends MessageUiHandler { case MenuOptions.LOG_OUT: success = true; const doLogout = () => { - ui.setMode(Mode.LOADING, { + ui.setMode(UiMode.LOADING, { buttonActions: [], fadeOut: () => pokerogueApi.account.logout().then(() => { @@ -703,7 +705,7 @@ export default class MenuUiHandler extends MessageUiHandler { return; } ui.setOverlayMode( - Mode.CONFIRM, + UiMode.CONFIRM, doLogout, () => { ui.revertMode(); @@ -722,7 +724,7 @@ export default class MenuUiHandler extends MessageUiHandler { success = true; ui.revertMode().then(result => { if (!result) { - ui.setMode(Mode.MESSAGE); + ui.setMode(UiMode.MESSAGE); } }); } else { diff --git a/src/ui/message-ui-handler.ts b/src/ui/message-ui-handler.ts index e927793e0ab..efa53b63808 100644 --- a/src/ui/message-ui-handler.ts +++ b/src/ui/message-ui-handler.ts @@ -1,6 +1,6 @@ import AwaitableUiHandler from "./awaitable-ui-handler"; -import type { Mode } from "./ui"; -import * as Utils from "../utils"; +import type { UiMode } from "#enums/ui-mode"; +import { getFrameMs } from "#app/utils/common"; import { globalScene } from "#app/global-scene"; export default abstract class MessageUiHandler extends AwaitableUiHandler { @@ -11,7 +11,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { public message: Phaser.GameObjects.Text; public prompt: Phaser.GameObjects.Sprite; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.pendingPrompt = false; @@ -183,7 +183,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { if (charDelay) { this.textTimer!.paused = true; // TODO: is the bang correct? globalScene.tweens.addCounter({ - duration: Utils.getFrameMs(charDelay), + duration: getFrameMs(charDelay), onComplete: () => { this.textTimer!.paused = false; // TODO: is the bang correct? advance(); @@ -193,7 +193,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { this.textTimer!.paused = true; globalScene.time.delayedCall(150, () => { globalScene.ui.fadeOut(750).then(() => { - const delay = Utils.getFrameMs(charFade); + const delay = getFrameMs(charFade); globalScene.time.delayedCall(delay, () => { globalScene.ui.fadeIn(500).then(() => { this.textTimer!.paused = false; diff --git a/src/ui/modal-ui-handler.ts b/src/ui/modal-ui-handler.ts index b7dbbeb202d..56c1c2c3fcf 100644 --- a/src/ui/modal-ui-handler.ts +++ b/src/ui/modal-ui-handler.ts @@ -1,5 +1,5 @@ import { TextStyle, addTextObject } from "./text"; -import type { Mode } from "./ui"; +import type { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; import { WindowVariant, addWindow } from "./ui-theme"; import type { Button } from "#enums/buttons"; @@ -17,7 +17,7 @@ export abstract class ModalUiHandler extends UiHandler { protected buttonBgs: Phaser.GameObjects.NineSlice[]; protected buttonLabels: Phaser.GameObjects.Text[]; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.buttonContainers = []; @@ -134,7 +134,11 @@ export abstract class ModalUiHandler extends UiHandler { for (let a = 0; a < this.buttonBgs.length; a++) { if (a < this.buttonBgs.length) { - this.buttonBgs[a].on("pointerdown", _ => config.buttonActions[a]()); + this.buttonBgs[a].on("pointerdown", _ => { + if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { + config.buttonActions[a](); + } + }); } } diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index e5d8f858782..9ba54491175 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -4,17 +4,16 @@ import { getPlayerShopModifierTypeOptionsForWave, TmModifierType } from "../modi import { getPokeballAtlasKey } from "#app/data/pokeball"; import { addTextObject, getTextStyleOptions, getModifierTierTextTint, getTextColor, TextStyle } from "./text"; import AwaitableUiHandler from "./awaitable-ui-handler"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import { LockModifierTiersModifier, PokemonHeldItemModifier, HealShopCostModifier } from "../modifier/modifier"; import { handleTutorial, Tutorial } from "../tutorial"; import { Button } from "#enums/buttons"; import MoveInfoOverlay from "./move-info-overlay"; import { allMoves } from "../data/moves/move"; -import * as Utils from "./../utils"; +import { formatMoney, NumberHolder } from "#app/utils/common"; import Overrides from "#app/overrides"; import i18next from "i18next"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; -import { NumberHolder } from "./../utils"; import Phaser from "phaser"; import type { PokeballType } from "#enums/pokeball"; @@ -51,7 +50,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { private cursorObj: Phaser.GameObjects.Image | null; constructor() { - super(Mode.CONFIRM); + super(UiMode.CONFIRM); this.options = []; this.shopOptionsRows = []; @@ -645,7 +644,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { this.rerollCostText.setVisible(true); const canReroll = globalScene.money >= this.rerollCost; - const formattedMoney = Utils.formatMoney(globalScene.moneyFormat, this.rerollCost); + const formattedMoney = formatMoney(globalScene.moneyFormat, this.rerollCost); this.rerollCostText.setText(i18next.t("modifierSelectUiHandler:rerollCost", { formattedMoney })); this.rerollCostText.setColor(this.getTextColor(canReroll ? TextStyle.MONEY : TextStyle.PARTY_RED)); @@ -933,7 +932,7 @@ class ModifierOption extends Phaser.GameObjects.Container { const cost = Overrides.WAIVE_ROLL_FEE_OVERRIDE ? 0 : this.modifierTypeOption.cost; const textStyle = cost <= globalScene.money ? TextStyle.MONEY : TextStyle.PARTY_RED; - const formattedMoney = Utils.formatMoney(globalScene.moneyFormat, cost); + const formattedMoney = formatMoney(globalScene.moneyFormat, cost); this.itemCostText.setText(i18next.t("modifierSelectUiHandler:itemCost", { formattedMoney })); this.itemCostText.setColor(getTextColor(textStyle, false, globalScene.uiTheme)); diff --git a/src/ui/move-info-overlay.ts b/src/ui/move-info-overlay.ts index 6fc99beb0ae..2b230d609fd 100644 --- a/src/ui/move-info-overlay.ts +++ b/src/ui/move-info-overlay.ts @@ -2,7 +2,7 @@ import type { InfoToggle } from "#app/battle-scene"; import { globalScene } from "#app/global-scene"; import { TextStyle, addTextObject } from "./text"; import { addWindow } from "./ui-theme"; -import * as Utils from "../utils"; +import { getLocalizedSpriteKey, fixedInt } from "#app/utils/common"; import type Move from "../data/moves/move"; import { MoveCategory } from "#enums/MoveCategory"; import { PokemonType } from "#enums/pokemon-type"; @@ -120,7 +120,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem valuesBg.setOrigin(0, 0); this.val.add(valuesBg); - this.typ = globalScene.add.sprite(25, EFF_HEIGHT - 35, Utils.getLocalizedSpriteKey("types"), "unknown"); + this.typ = globalScene.add.sprite(25, EFF_HEIGHT - 35, getLocalizedSpriteKey("types"), "unknown"); this.typ.setScale(0.8); this.val.add(this.typ); @@ -175,7 +175,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem this.pow.setText(move.power >= 0 ? move.power.toString() : "---"); this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---"); this.pp.setText(move.pp >= 0 ? move.pp.toString() : "---"); - this.typ.setTexture(Utils.getLocalizedSpriteKey("types"), PokemonType[move.type].toLowerCase()); + this.typ.setTexture(getLocalizedSpriteKey("types"), PokemonType[move.type].toLowerCase()); this.cat.setFrame(MoveCategory[move.category].toLowerCase()); this.desc.setText(move?.effect || ""); @@ -193,10 +193,10 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem // generate scrolling effects this.descScroll = globalScene.tweens.add({ targets: this.desc, - delay: Utils.fixedInt(2000), + delay: fixedInt(2000), loop: -1, - hold: Utils.fixedInt(2000), - duration: Utils.fixedInt((moveDescriptionLineCount - 3) * 2000), + hold: fixedInt(2000), + duration: fixedInt((moveDescriptionLineCount - 3) * 2000), y: `-=${14.83 * (72 / 96) * (moveDescriptionLineCount - 3)}`, }); } @@ -219,7 +219,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem } globalScene.tweens.add({ targets: this.desc, - duration: Utils.fixedInt(125), + duration: fixedInt(125), ease: "Sine.easeInOut", alpha: visible ? 1 : 0, }); diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/mystery-encounter-ui-handler.ts index 87d2e2ba28c..0866ed8788e 100644 --- a/src/ui/mystery-encounter-ui-handler.ts +++ b/src/ui/mystery-encounter-ui-handler.ts @@ -1,13 +1,12 @@ import { addBBCodeTextObject, getBBCodeFrag, TextStyle } from "./text"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; import { Button } from "#enums/buttons"; import { addWindow, WindowVariant } from "./ui-theme"; import type { MysteryEncounterPhase } from "../phases/mystery-encounter-phases"; import { PartyUiMode } from "./party-ui-handler"; import type MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option"; -import * as Utils from "../utils"; -import { isNullOrUndefined } from "../utils"; +import { fixedInt, isNullOrUndefined } from "#app/utils/common"; import { getPokeballAtlasKey } from "../data/pokeball"; import type { OptionSelectSettings } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; @@ -48,7 +47,7 @@ export default class MysteryEncounterUiHandler extends UiHandler { protected blockInput = true; constructor() { - super(Mode.MYSTERY_ENCOUNTER); + super(UiMode.MYSTERY_ENCOUNTER); } override setup() { @@ -142,8 +141,8 @@ export default class MysteryEncounterUiHandler extends UiHandler { ...this.overrideSettings, slideInDescription: false, }; - globalScene.ui.setMode(Mode.PARTY, PartyUiMode.CHECK, -1, () => { - globalScene.ui.setMode(Mode.MYSTERY_ENCOUNTER, overrideSettings); + globalScene.ui.setMode(UiMode.PARTY, PartyUiMode.CHECK, -1, () => { + globalScene.ui.setMode(UiMode.MYSTERY_ENCOUNTER, overrideSettings); setTimeout(() => { this.setCursor(this.viewPartyIndex); this.unblockInput(); @@ -456,10 +455,10 @@ export default class MysteryEncounterUiHandler extends UiHandler { if (optionTextWidth > nonScrollWidth) { this.optionScrollTweens[i] = globalScene.tweens.add({ targets: optionText, - delay: Utils.fixedInt(2000), + delay: fixedInt(2000), loop: -1, - hold: Utils.fixedInt(2000), - duration: Utils.fixedInt(((optionTextWidth - nonScrollWidth) / 15) * 2000), + hold: fixedInt(2000), + duration: fixedInt(((optionTextWidth - nonScrollWidth) / 15) * 2000), x: `-=${optionTextWidth - nonScrollWidth}`, }); } @@ -527,10 +526,10 @@ export default class MysteryEncounterUiHandler extends UiHandler { if (descriptionLineCount > 6) { this.descriptionScrollTween = globalScene.tweens.add({ targets: descriptionTextObject, - delay: Utils.fixedInt(2000), + delay: fixedInt(2000), loop: -1, - hold: Utils.fixedInt(2000), - duration: Utils.fixedInt((descriptionLineCount - 6) * 2000), + hold: fixedInt(2000), + duration: fixedInt((descriptionLineCount - 6) * 2000), y: `-=${10 * (descriptionLineCount - 6)}`, }); } @@ -637,10 +636,10 @@ export default class MysteryEncounterUiHandler extends UiHandler { if (tooltipLineCount > 3) { this.tooltipScrollTween = globalScene.tweens.add({ targets: tooltipTextObject, - delay: Utils.fixedInt(1200), + delay: fixedInt(1200), loop: -1, - hold: Utils.fixedInt(1200), - duration: Utils.fixedInt((tooltipLineCount - 3) * 1200), + hold: fixedInt(1200), + duration: fixedInt((tooltipLineCount - 3) * 1200), y: `-=${11.2 * (tooltipLineCount - 3)}`, }); } diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index caddd64cd28..6e947796d63 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -4,8 +4,8 @@ import { MoveResult } from "#app/field/pokemon"; import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "#app/ui/text"; import { Command } from "#app/ui/command-ui-handler"; import MessageUiHandler from "#app/ui/message-ui-handler"; -import { Mode } from "#app/ui/ui"; -import * as Utils from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import { BooleanHolder, toReadableString, randInt, getLocalizedSpriteKey } from "#app/utils/common"; import { PokemonFormChangeItemModifier, PokemonHeldItemModifier, @@ -18,7 +18,7 @@ import PokemonIconAnimHandler, { PokemonIconAnimMode } from "#app/ui/pokemon-ico import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { addWindow } from "#app/ui/ui-theme"; import { SpeciesFormChangeItemTrigger, FormChangeItem } from "#app/data/pokemon-forms"; -import { getVariantTint } from "#app/data/variant"; +import { getVariantTint } from "#app/sprites/variant"; import { Button } from "#enums/buttons"; import { applyChallenges, ChallengeType } from "#app/data/challenge"; import MoveInfoOverlay from "#app/ui/move-info-overlay"; @@ -193,18 +193,14 @@ export default class PartyUiHandler extends MessageUiHandler { public static FilterNonFainted = (pokemon: PlayerPokemon) => { if (pokemon.isFainted()) { - return i18next.t("partyUiHandler:noEnergy", { - pokemonName: getPokemonNameWithAffix(pokemon), - }); + return i18next.t("partyUiHandler:noEnergy", { pokemonName: getPokemonNameWithAffix(pokemon, false) }); } return null; }; public static FilterFainted = (pokemon: PlayerPokemon) => { if (!pokemon.isFainted()) { - return i18next.t("partyUiHandler:hasEnergy", { - pokemonName: getPokemonNameWithAffix(pokemon), - }); + return i18next.t("partyUiHandler:hasEnergy", { pokemonName: getPokemonNameWithAffix(pokemon, false) }); } return null; }; @@ -215,12 +211,10 @@ export default class PartyUiHandler extends MessageUiHandler { * @returns */ private FilterChallengeLegal = (pokemon: PlayerPokemon) => { - const challengeAllowed = new Utils.BooleanHolder(true); + const challengeAllowed = new BooleanHolder(true); applyChallenges(ChallengeType.POKEMON_IN_BATTLE, pokemon, challengeAllowed); if (!challengeAllowed.value) { - return i18next.t("partyUiHandler:cantBeUsed", { - pokemonName: getPokemonNameWithAffix(pokemon), - }); + return i18next.t("partyUiHandler:cantBeUsed", { pokemonName: getPokemonNameWithAffix(pokemon, false) }); } return null; }; @@ -232,9 +226,7 @@ export default class PartyUiHandler extends MessageUiHandler { m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id && m.matchType(modifier), ) as PokemonHeldItemModifier; if (matchingModifier && matchingModifier.stackCount === matchingModifier.getMaxStackCount()) { - return i18next.t("partyUiHandler:tooManyItems", { - pokemonName: getPokemonNameWithAffix(pokemon), - }); + return i18next.t("partyUiHandler:tooManyItems", { pokemonName: getPokemonNameWithAffix(pokemon, false) }); } return null; }; @@ -260,7 +252,7 @@ export default class PartyUiHandler extends MessageUiHandler { ]; constructor() { - super(Mode.PARTY); + super(UiMode.PARTY); } setup() { @@ -564,7 +556,7 @@ export default class PartyUiHandler extends MessageUiHandler { this.showText(filterResult as string, undefined, () => this.showText("", 0), undefined, true); } else if (option === PartyOption.SUMMARY) { ui.playSelect(); - ui.setModeWithoutClear(Mode.SUMMARY, pokemon).then(() => this.clearOptions()); + ui.setModeWithoutClear(UiMode.SUMMARY, pokemon).then(() => this.clearOptions()); return true; } else if (option === PartyOption.POKEDEX) { ui.playSelect(); @@ -574,7 +566,7 @@ export default class PartyUiHandler extends MessageUiHandler { form: pokemon.formIndex, female: pokemon.gender === Gender.FEMALE, }; - ui.setOverlayMode(Mode.POKEDEX_PAGE, pokemon.species, attributes).then(() => this.clearOptions()); + ui.setOverlayMode(UiMode.POKEDEX_PAGE, pokemon.species, attributes).then(() => this.clearOptions()); return true; } else if (option === PartyOption.UNPAUSE_EVOLUTION) { this.clearOptions(); @@ -583,7 +575,7 @@ export default class PartyUiHandler extends MessageUiHandler { this.showText( i18next.t( pokemon.pauseEvolutions ? "partyUiHandler:pausedEvolutions" : "partyUiHandler:unpausedEvolutions", - { pokemonName: getPokemonNameWithAffix(pokemon) }, + { pokemonName: getPokemonNameWithAffix(pokemon, false) }, ), undefined, () => this.showText("", 0), @@ -596,26 +588,26 @@ export default class PartyUiHandler extends MessageUiHandler { this.showText( i18next.t("partyUiHandler:unspliceConfirmation", { fusionName: pokemon.fusionSpecies?.name, - pokemonName: pokemon.name, + pokemonName: pokemon.getName(), }), null, () => { ui.setModeWithoutClear( - Mode.CONFIRM, + UiMode.CONFIRM, () => { - const fusionName = pokemon.name; + const fusionName = pokemon.getName(); pokemon.unfuse().then(() => { this.clearPartySlots(); this.populatePartySlots(); - ui.setMode(Mode.PARTY); + ui.setMode(UiMode.PARTY); this.showText( i18next.t("partyUiHandler:wasReverted", { fusionName: fusionName, - pokemonName: pokemon.name, + pokemonName: pokemon.getName(false), }), undefined, () => { - ui.setMode(Mode.PARTY); + ui.setMode(UiMode.PARTY); this.showText("", 0); }, null, @@ -624,7 +616,7 @@ export default class PartyUiHandler extends MessageUiHandler { }); }, () => { - ui.setMode(Mode.PARTY); + ui.setMode(UiMode.PARTY); this.showText("", 0); }, ); @@ -637,19 +629,19 @@ export default class PartyUiHandler extends MessageUiHandler { this.blockInput = true; this.showText( i18next.t("partyUiHandler:releaseConfirmation", { - pokemonName: getPokemonNameWithAffix(pokemon), + pokemonName: getPokemonNameWithAffix(pokemon, false), }), null, () => { this.blockInput = false; ui.setModeWithoutClear( - Mode.CONFIRM, + UiMode.CONFIRM, () => { - ui.setMode(Mode.PARTY); + ui.setMode(UiMode.PARTY); this.doRelease(this.cursor); }, () => { - ui.setMode(Mode.PARTY); + ui.setMode(UiMode.PARTY); this.showText("", 0); }, ); @@ -663,7 +655,7 @@ export default class PartyUiHandler extends MessageUiHandler { this.clearOptions(); ui.playSelect(); ui.setModeWithoutClear( - Mode.RENAME_POKEMON, + UiMode.RENAME_POKEMON, { buttonActions: [ (nickname: string) => { @@ -672,10 +664,10 @@ export default class PartyUiHandler extends MessageUiHandler { pokemon.updateInfo(); this.clearPartySlots(); this.populatePartySlots(); - ui.setMode(Mode.PARTY); + ui.setMode(UiMode.PARTY); }, () => { - ui.setMode(Mode.PARTY); + ui.setMode(UiMode.PARTY); }, ], }, @@ -796,7 +788,7 @@ export default class PartyUiHandler extends MessageUiHandler { selectCallback(6, PartyOption.CANCEL); ui.playSelect(); } else { - ui.setMode(Mode.COMMAND, this.fieldIndex); + ui.setMode(UiMode.COMMAND, this.fieldIndex); ui.playSelect(); } } @@ -1201,7 +1193,7 @@ export default class PartyUiHandler extends MessageUiHandler { if (this.localizedOptions.includes(option)) { optionName = i18next.t(`partyUiHandler:${PartyOption[option]}`); } else { - optionName = Utils.toReadableString(PartyOption[option]); + optionName = toReadableString(PartyOption[option]); } } break; @@ -1285,7 +1277,7 @@ export default class PartyUiHandler extends MessageUiHandler { doRelease(slotIndex: number): void { this.showText( - this.getReleaseMessage(getPokemonNameWithAffix(globalScene.getPlayerParty()[slotIndex])), + this.getReleaseMessage(getPokemonNameWithAffix(globalScene.getPlayerParty()[slotIndex], false)), null, () => { this.clearPartySlots(); @@ -1309,7 +1301,7 @@ export default class PartyUiHandler extends MessageUiHandler { } getReleaseMessage(pokemonName: string): string { - const rand = Utils.randInt(128); + const rand = randInt(128); if (rand < 20) { return i18next.t("partyUiHandler:goodbye", { pokemonName: pokemonName }); } @@ -1495,7 +1487,7 @@ class PartySlot extends Phaser.GameObjects.Container { const slotInfoContainer = globalScene.add.container(0, 0); this.add(slotInfoContainer); - let displayName = this.pokemon.getNameToRender(); + let displayName = this.pokemon.getNameToRender(false); let nameTextWidth: number; const nameSizeTest = addTextObject(0, 0, displayName, TextStyle.PARTY); @@ -1566,7 +1558,7 @@ class PartySlot extends Phaser.GameObjects.Container { } if (this.pokemon.status) { - const statusIndicator = globalScene.add.sprite(0, 0, Utils.getLocalizedSpriteKey("statuses")); + const statusIndicator = globalScene.add.sprite(0, 0, getLocalizedSpriteKey("statuses")); statusIndicator.setFrame(StatusEffect[this.pokemon.status?.effect].toLowerCase()); statusIndicator.setOrigin(0, 0); statusIndicator.setPositionRelative(slotLevelLabel, this.slotIndex >= battlerCount ? 43 : 55, 0); @@ -1575,12 +1567,12 @@ class PartySlot extends Phaser.GameObjects.Container { } if (this.pokemon.isShiny()) { - const doubleShiny = this.pokemon.isFusion() && this.pokemon.shiny && this.pokemon.fusionShiny; + const doubleShiny = this.pokemon.isDoubleShiny(false); const shinyStar = globalScene.add.image(0, 0, `shiny_star_small${doubleShiny ? "_1" : ""}`); shinyStar.setOrigin(0, 0); shinyStar.setPositionRelative(this.slotName, -9, 3); - shinyStar.setTint(getVariantTint(!doubleShiny ? this.pokemon.getVariant() : this.pokemon.variant)); + shinyStar.setTint(getVariantTint(this.pokemon.getBaseVariant(doubleShiny))); slotInfoContainer.add(shinyStar); @@ -1588,7 +1580,9 @@ class PartySlot extends Phaser.GameObjects.Container { const fusionShinyStar = globalScene.add.image(0, 0, "shiny_star_small_2"); fusionShinyStar.setOrigin(0, 0); fusionShinyStar.setPosition(shinyStar.x, shinyStar.y); - fusionShinyStar.setTint(getVariantTint(this.pokemon.fusionVariant)); + fusionShinyStar.setTint( + getVariantTint(this.pokemon.summonData.illusion?.basePokemon.fusionVariant ?? this.pokemon.fusionVariant), + ); slotInfoContainer.add(fusionShinyStar); } diff --git a/src/ui/pokedex-info-overlay.ts b/src/ui/pokedex-info-overlay.ts index 7dfa3745cb7..2e889f6d2a9 100644 --- a/src/ui/pokedex-info-overlay.ts +++ b/src/ui/pokedex-info-overlay.ts @@ -1,7 +1,7 @@ import type { InfoToggle } from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { addWindow } from "./ui-theme"; -import * as Utils from "../utils"; +import { fixedInt } from "#app/utils/common"; import i18next from "i18next"; import { globalScene } from "#app/global-scene"; @@ -128,10 +128,10 @@ export default class PokedexInfoOverlay extends Phaser.GameObjects.Container imp // generate scrolling effects this.descScroll = globalScene.tweens.add({ targets: this.desc, - delay: Utils.fixedInt(2000), + delay: fixedInt(2000), loop: -1, - hold: Utils.fixedInt(2000), - duration: Utils.fixedInt((lineCount - 3) * 2000), + hold: fixedInt(2000), + duration: fixedInt((lineCount - 3) * 2000), y: `-=${14.83 * (72 / 96) * (lineCount - 3)}`, }); } @@ -154,7 +154,7 @@ export default class PokedexInfoOverlay extends Phaser.GameObjects.Container imp } globalScene.tweens.add({ targets: this.desc, - duration: Utils.fixedInt(125), + duration: fixedInt(125), ease: "Sine.easeInOut", alpha: visible ? 1 : 0, }); diff --git a/src/ui/pokedex-mon-container.ts b/src/ui/pokedex-mon-container.ts index e61da86e95e..da79320850d 100644 --- a/src/ui/pokedex-mon-container.ts +++ b/src/ui/pokedex-mon-container.ts @@ -1,6 +1,6 @@ -import type { Variant } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; import { globalScene } from "#app/global-scene"; -import { isNullOrUndefined } from "#app/utils"; +import { isNullOrUndefined } from "#app/utils/common"; import type PokemonSpecies from "../data/pokemon-species"; import { addTextObject, TextStyle } from "./text"; diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index 062b4c3797c..ddc16ab5a88 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -1,11 +1,11 @@ import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions"; import { pokemonEvolutions, pokemonPrevolutions, pokemonStarters } from "#app/data/balance/pokemon-evolutions"; -import type { Variant } from "#app/data/variant"; -import { getVariantTint, getVariantIcon } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; +import { getVariantTint, getVariantIcon } from "#app/sprites/variant"; import { argbFromRgba } from "@material/material-color-utilities"; import i18next from "i18next"; -import { starterColors } from "#app/battle-scene"; -import { allAbilities } from "#app/data/ability"; +import { starterColors } from "#app/global-vars/starter-colors"; +import { allAbilities } from "#app/data/data-lists"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { GrowthRate, getGrowthRateColor } from "#app/data/exp"; import { Gender, getGenderColor, getGenderSymbol } from "#app/data/gender"; @@ -26,7 +26,7 @@ import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler" import MessageUiHandler from "#app/ui/message-ui-handler"; import { StatsContainer } from "#app/ui/stats-container"; import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor, getTextStyleOptions } from "#app/ui/text"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { addWindow } from "#app/ui/ui-theme"; import { Egg } from "#app/data/egg"; import Overrides from "#app/overrides"; @@ -52,9 +52,9 @@ import { padInt, rgbHexToRgba, toReadableString, -} from "#app/utils"; +} from "#app/utils/common"; import type { Nature } from "#enums/nature"; -import * as Utils from "../utils"; +import { getEnumKeys } from "#app/utils/common"; import { speciesTmMoves } from "#app/data/balance/tms"; import type { BiomeTierTod } from "#app/data/balance/biomes"; import { BiomePoolTier, catchableSpecies } from "#app/data/balance/biomes"; @@ -265,7 +265,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { private exitCallback; constructor() { - super(Mode.POKEDEX_PAGE); + super(UiMode.POKEDEX_PAGE); } setup() { @@ -292,6 +292,13 @@ export default class PokedexPageUiHandler extends MessageUiHandler { starterSelectBg.setOrigin(0, 0); this.starterSelectContainer.add(starterSelectBg); + this.pokemonSprite = globalScene.add.sprite(53, 63, "pkmn__sub"); + this.pokemonSprite.setPipeline(globalScene.spritePipeline, { + tone: [0.0, 0.0, 0.0, 0.0], + ignoreTimeTint: true, + }); + this.starterSelectContainer.add(this.pokemonSprite); + this.shinyOverlay = globalScene.add.image(6, 6, "summary_overlay_shiny"); this.shinyOverlay.setOrigin(0, 0); this.shinyOverlay.setVisible(false); @@ -343,13 +350,6 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.starterSelectContainer.add(starterBoxContainer); - this.pokemonSprite = globalScene.add.sprite(53, 63, "pkmn__sub"); - this.pokemonSprite.setPipeline(globalScene.spritePipeline, { - tone: [0.0, 0.0, 0.0, 0.0], - ignoreTimeTint: true, - }); - this.starterSelectContainer.add(this.pokemonSprite); - this.type1Icon = globalScene.add.sprite(8, 98, getLocalizedSpriteKey("types")); this.type1Icon.setScale(0.5); this.type1Icon.setOrigin(0, 0); @@ -592,7 +592,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.menuContainer.setVisible(false); - this.menuOptions = Utils.getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions); + this.menuOptions = getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions); this.optionSelectText = addBBCodeTextObject( 0, @@ -696,7 +696,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.starterAttributes = this.initStarterPrefs(); - this.menuOptions = Utils.getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions); + this.menuOptions = getEnumKeys(MenuOptions).map(m => Number.parseInt(MenuOptions[m]) as MenuOptions); this.menuContainer.setVisible(true); @@ -921,16 +921,22 @@ export default class PokedexPageUiHandler extends MessageUiHandler { return biomes; } + /** + * Return the caughtAttr of a given species, sanitized. + * + * @param otherSpecies The species to check; defaults to current species + * @returns caught DexAttr for the species + */ isCaught(otherSpecies?: PokemonSpecies): bigint { + const species = otherSpecies ? otherSpecies : this.species; + if (globalScene.dexForDevs) { - return 255n; + species.getFullUnlocksData(); } - const species = otherSpecies ? otherSpecies : this.species; const dexEntry = globalScene.gameData.dexData[species.speciesId]; - const starterDexEntry = globalScene.gameData.dexData[this.getStarterSpeciesId(species.speciesId)]; - return (dexEntry?.caughtAttr ?? 0n) & (starterDexEntry?.caughtAttr ?? 0n) & species.getFullUnlocksData(); + return (dexEntry?.caughtAttr ?? 0n) & species.getFullUnlocksData(); } /** @@ -939,7 +945,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { * * @param otherSpecies The species to check; defaults to current species * @param otherFormIndex The form index of the form to check; defaults to current form - * @returns StarterAttributes for the species + * @returns `true` if the form is caught */ isFormCaught(otherSpecies?: PokemonSpecies, otherFormIndex?: number | undefined): boolean { if (globalScene.dexForDevs) { @@ -954,6 +960,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } const isFormCaught = (caughtAttr & globalScene.gameData.getFormAttr(formIndex ?? 0)) > 0n; + return isFormCaught; } @@ -1140,18 +1147,17 @@ export default class PokedexPageUiHandler extends MessageUiHandler { success = true; } else if (this.previousSpecies.length > 0) { this.blockInput = true; - ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => { + ui.setModeWithoutClear(UiMode.OPTION_SELECT).then(() => { const species = this.previousSpecies.pop(); const starterAttributes = this.previousStarterAttributes.pop(); this.moveInfoOverlay.clear(); this.clearText(); - ui.setModeForceTransition(Mode.POKEDEX_PAGE, species, starterAttributes); + ui.setModeForceTransition(UiMode.POKEDEX_PAGE, species, starterAttributes); success = true; }); this.blockInput = false; } else { ui.revertMode().then(() => { - console.log("exitCallback", this.exitCallback); if (this.exitCallback instanceof Function) { const exitCallback = this.exitCallback; this.exitCallback = null; @@ -1173,7 +1179,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } else { this.blockInput = true; - ui.setMode(Mode.POKEDEX_PAGE, "refresh").then(() => { + ui.setMode(UiMode.POKEDEX_PAGE, "refresh").then(() => { ui.showText(i18next.t("pokedexUiHandler:showBaseStats"), null, () => { this.baseStatsOverlay.show(this.baseStats, this.baseTotal); @@ -1193,11 +1199,11 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } else { this.blockInput = true; - ui.setMode(Mode.POKEDEX_PAGE, "refresh").then(() => { + ui.setMode(UiMode.POKEDEX_PAGE, "refresh").then(() => { ui.showText(i18next.t("pokedexUiHandler:showLevelMoves"), null, () => { this.moveInfoOverlay.show(allMoves[this.levelMoves[0][1]]); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: this.levelMoves .map(m => { const levelNumber = m[0] > 0 ? String(m[0]) : ""; @@ -1226,7 +1232,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { handler: () => { this.moveInfoOverlay.clear(); this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); return true; }, onHover: () => { @@ -1251,7 +1257,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } else { this.blockInput = true; - ui.setMode(Mode.POKEDEX_PAGE, "refresh").then(() => { + ui.setMode(UiMode.POKEDEX_PAGE, "refresh").then(() => { if (this.eggMoves.length === 0) { ui.showText(i18next.t("pokedexUiHandler:noEggMoves")); this.blockInput = false; @@ -1261,7 +1267,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { ui.showText(i18next.t("pokedexUiHandler:showEggMoves"), null, () => { this.moveInfoOverlay.show(allMoves[this.eggMoves[0]]); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: [ { label: i18next.t("pokedexUiHandler:common"), @@ -1294,7 +1300,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { handler: () => { this.moveInfoOverlay.clear(); this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); return true; }, onHover: () => this.moveInfoOverlay.clear(), @@ -1321,11 +1327,11 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } else { this.blockInput = true; - ui.setMode(Mode.POKEDEX_PAGE, "refresh").then(() => { + ui.setMode(UiMode.POKEDEX_PAGE, "refresh").then(() => { ui.showText(i18next.t("pokedexUiHandler:showTmMoves"), null, () => { this.moveInfoOverlay.show(allMoves[this.tmMoves[0]]); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: this.tmMoves .map(m => { const option: OptionSelectItem = { @@ -1344,7 +1350,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { handler: () => { this.moveInfoOverlay.clear(); this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); return true; }, onHover: () => { @@ -1369,7 +1375,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } else { this.blockInput = true; - ui.setMode(Mode.POKEDEX_PAGE, "refresh").then(() => { + ui.setMode(UiMode.POKEDEX_PAGE, "refresh").then(() => { ui.showText(i18next.t("pokedexUiHandler:showAbilities"), null, () => { this.infoOverlay.show(allAbilities[this.ability1].description); @@ -1431,13 +1437,13 @@ export default class PokedexPageUiHandler extends MessageUiHandler { handler: () => { this.infoOverlay.clear(); this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); return true; }, onHover: () => this.infoOverlay.clear(), }); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: options, supportHover: true, maxOptions: 8, @@ -1457,7 +1463,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } else { this.blockInput = true; - ui.setMode(Mode.POKEDEX_PAGE, "refresh").then(() => { + ui.setMode(UiMode.POKEDEX_PAGE, "refresh").then(() => { if ((!this.biomes || this.biomes?.length === 0) && (!this.preBiomes || this.preBiomes?.length === 0)) { ui.showText(i18next.t("pokedexUiHandler:noBiomes")); ui.playError(); @@ -1510,13 +1516,13 @@ export default class PokedexPageUiHandler extends MessageUiHandler { handler: () => { this.moveInfoOverlay.clear(); this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); return true; }, onHover: () => this.moveInfoOverlay.clear(), }); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: options, supportHover: true, maxOptions: 8, @@ -1536,7 +1542,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } else { this.blockInput = true; - ui.setMode(Mode.POKEDEX_PAGE, "refresh").then(() => { + ui.setMode(UiMode.POKEDEX_PAGE, "refresh").then(() => { const options: any[] = []; if ( @@ -1589,7 +1595,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.savedStarterAttributes.form = newFormIndex; this.moveInfoOverlay.clear(); this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, newSpecies, this.savedStarterAttributes); + ui.setMode(UiMode.POKEDEX_PAGE, newSpecies, this.savedStarterAttributes); return true; }, onHover: () => this.showText(conditionText), @@ -1631,7 +1637,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.savedStarterAttributes.form = newFormIndex; this.moveInfoOverlay.clear(); this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, evoSpecies, this.savedStarterAttributes); + ui.setMode(UiMode.POKEDEX_PAGE, evoSpecies, this.savedStarterAttributes); return true; }, onHover: () => this.showText(conditionText), @@ -1676,7 +1682,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.moveInfoOverlay.clear(); this.clearText(); ui.setMode( - Mode.POKEDEX_PAGE, + UiMode.POKEDEX_PAGE, newSpecies, this.savedStarterAttributes, this.filteredIndices, @@ -1694,13 +1700,13 @@ export default class PokedexPageUiHandler extends MessageUiHandler { handler: () => { this.moveInfoOverlay.clear(); this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); return true; }, onHover: () => this.moveInfoOverlay.clear(), }); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: options, supportHover: true, maxOptions: 8, @@ -1719,7 +1725,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { error = true; } else { this.toggleStatsMode(); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); success = true; } break; @@ -1729,10 +1735,10 @@ export default class PokedexPageUiHandler extends MessageUiHandler { error = true; } else { this.blockInput = true; - ui.setMode(Mode.POKEDEX_PAGE, "refresh").then(() => { + ui.setMode(UiMode.POKEDEX_PAGE, "refresh").then(() => { ui.showText(i18next.t("pokedexUiHandler:showNature"), null, () => { const natures = globalScene.gameData.getNaturesForAttr(this.speciesStarterDexEntry?.natureAttr); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: natures .map((n: Nature, _i: number) => { const option: OptionSelectItem = { @@ -1747,7 +1753,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { label: i18next.t("menu:cancel"), handler: () => { this.clearText(); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); this.blockInput = false; return true; }, @@ -1897,7 +1903,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { }); this.setSpeciesDetails(this.species); globalScene.playSound("se/buy"); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); return true; } @@ -1927,7 +1933,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { return globalScene.reset(true); } }); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); globalScene.playSound("se/buy"); return true; @@ -1976,7 +1982,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { return globalScene.reset(true); } }); - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); globalScene.playSound("se/buy"); return true; @@ -1990,11 +1996,11 @@ export default class PokedexPageUiHandler extends MessageUiHandler { options.push({ label: i18next.t("menu:cancel"), handler: () => { - ui.setMode(Mode.POKEDEX_PAGE, "refresh"); + ui.setMode(UiMode.POKEDEX_PAGE, "refresh"); return true; }, }); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: options, yOffset: 47, }); @@ -2032,7 +2038,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { return true; } this.blockInput = true; - ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => { + ui.setModeWithoutClear(UiMode.OPTION_SELECT).then(() => { // Always go back to first selection after scrolling around if (this.previousSpecies.length === 0) { this.previousSpecies.push(this.species); @@ -2057,7 +2063,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.moveInfoOverlay.clear(); this.clearText(); ui.setModeForceTransition( - Mode.POKEDEX_PAGE, + UiMode.POKEDEX_PAGE, newSpecies, this.savedStarterAttributes, this.filteredIndices, @@ -2071,7 +2077,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.blockInput = false; return true; } - ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => { + ui.setModeWithoutClear(UiMode.OPTION_SELECT).then(() => { // Always go back to first selection after scrolling around if (this.previousSpecies.length === 0) { this.previousSpecies.push(this.species); @@ -2096,7 +2102,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.moveInfoOverlay.clear(); this.clearText(); ui.setModeForceTransition( - Mode.POKEDEX_PAGE, + UiMode.POKEDEX_PAGE, newSpecies, this.savedStarterAttributes, this.filteredIndices, diff --git a/src/ui/pokedex-scan-ui-handler.ts b/src/ui/pokedex-scan-ui-handler.ts index b34246b97d1..45092d461a3 100644 --- a/src/ui/pokedex-scan-ui-handler.ts +++ b/src/ui/pokedex-scan-ui-handler.ts @@ -3,10 +3,10 @@ import { FormModalUiHandler } from "./form-modal-ui-handler"; import type { ModalConfig } from "./modal-ui-handler"; import type { PlayerPokemon } from "#app/field/pokemon"; import type { OptionSelectItem } from "./abstact-option-select-ui-handler"; -import { isNullOrUndefined } from "#app/utils"; -import { Mode } from "./ui"; +import { isNullOrUndefined } from "#app/utils/common"; +import { UiMode } from "#enums/ui-mode"; import { FilterTextRow } from "./filter-text"; -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { allMoves } from "#app/data/moves/move"; import { allSpecies } from "#app/data/pokemon-species"; import i18next from "i18next"; @@ -115,7 +115,7 @@ export default class PokedexScanUiHandler extends FormModalUiHandler { input.on("keydown", (inputObject, evt: KeyboardEvent) => { if ( ["escape", "space"].some(v => v === evt.key.toLowerCase() || v === evt.code.toLowerCase()) && - ui.getMode() === Mode.AUTO_COMPLETE + ui.getMode() === UiMode.AUTO_COMPLETE ) { // Delete autocomplete list and recovery focus. inputObject.on("blur", () => inputObject.node.focus(), { once: true }); @@ -125,7 +125,7 @@ export default class PokedexScanUiHandler extends FormModalUiHandler { input.on("textchange", (inputObject, evt: InputEvent) => { // Delete autocomplete. - if (ui.getMode() === Mode.AUTO_COMPLETE) { + if (ui.getMode() === UiMode.AUTO_COMPLETE) { ui.revertMode(); } @@ -154,7 +154,7 @@ export default class PokedexScanUiHandler extends FormModalUiHandler { maxOptions: 5, modalContainer: this.modalContainer, }; - ui.setOverlayMode(Mode.AUTO_COMPLETE, modalOpts); + ui.setOverlayMode(UiMode.AUTO_COMPLETE, modalOpts); } }); @@ -168,7 +168,7 @@ export default class PokedexScanUiHandler extends FormModalUiHandler { this.inputs[0].text = args[1]; } this.submitAction = _ => { - if (ui.getMode() === Mode.POKEDEX_SCAN) { + if (ui.getMode() === UiMode.POKEDEX_SCAN) { this.sanitizeInputs(); const outputName = this.reducedKeys.includes(this.inputs[0].text) ? this.inputs[0].text : ""; const sanitizedName = btoa(unescape(encodeURIComponent(outputName))); diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/pokedex-ui-handler.ts index 230b1bcb42b..b1d0945de07 100644 --- a/src/ui/pokedex-ui-handler.ts +++ b/src/ui/pokedex-ui-handler.ts @@ -1,8 +1,8 @@ -import type { Variant } from "#app/data/variant"; -import { getVariantTint, getVariantIcon } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; +import { getVariantTint, getVariantIcon } from "#app/sprites/variant"; import { argbFromRgba } from "@material/material-color-utilities"; import i18next from "i18next"; -import { starterColors } from "#app/battle-scene"; +import { starterColors } from "#app/global-vars/starter-colors"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "#app/data/balance/pokemon-level-moves"; import type { PokemonForm } from "#app/data/pokemon-species"; @@ -16,7 +16,7 @@ import { AbilityAttr, DexAttr, loadStarterPreferences } from "#app/system/game-d import MessageUiHandler from "#app/ui/message-ui-handler"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "#app/ui/pokemon-icon-anim-handler"; import { TextStyle, addTextObject } from "#app/ui/text"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; import { Passive as PassiveAttr } from "#enums/passive"; import type { Species } from "#enums/species"; @@ -31,16 +31,15 @@ import { getValueReductionCandyCounts, getSameSpeciesEggCandyCounts, } from "#app/data/balance/starters"; -import { BooleanHolder, fixedInt, getLocalizedSpriteKey, padInt, randIntRange, rgbHexToRgba } from "#app/utils"; +import { BooleanHolder, fixedInt, getLocalizedSpriteKey, padInt, randIntRange, rgbHexToRgba } from "#app/utils/common"; import type { Nature } from "#enums/nature"; import { addWindow } from "./ui-theme"; import type { OptionSelectConfig } from "./abstact-option-select-ui-handler"; import { FilterText, FilterTextRow } from "./filter-text"; -import { allAbilities } from "#app/data/ability"; -import { starterPassiveAbilities } from "#app/data/balance/passives"; +import { allAbilities } from "#app/data/data-lists"; import { allMoves } from "#app/data/moves/move"; import { speciesTmMoves } from "#app/data/balance/tms"; -import { pokemonPrevolutions, pokemonStarters } from "#app/data/balance/pokemon-evolutions"; +import { pokemonStarters } from "#app/data/balance/pokemon-evolutions"; import { Biome } from "#enums/biome"; import { globalScene } from "#app/global-scene"; @@ -174,7 +173,6 @@ export default class PokedexUiHandler extends MessageUiHandler { private scrollCursor: number; private oldCursor = -1; - private allSpecies: PokemonSpecies[] = []; private lastSpecies: PokemonSpecies; private speciesLoaded: Map = new Map(); private pokerusSpecies: PokemonSpecies[] = []; @@ -231,7 +229,7 @@ export default class PokedexUiHandler extends MessageUiHandler { private filteredIndices: Species[]; constructor() { - super(Mode.POKEDEX); + super(UiMode.POKEDEX); } setup() { @@ -493,12 +491,11 @@ export default class PokedexUiHandler extends MessageUiHandler { for (const species of allSpecies) { this.speciesLoaded.set(species.speciesId, false); - this.allSpecies.push(species); } // Here code to declare 81 containers for (let i = 0; i < 81; i++) { - const pokemonContainer = new PokedexMonContainer(this.allSpecies[i]).setVisible(false); + const pokemonContainer = new PokedexMonContainer(allSpecies[i]).setVisible(false); const pos = calcStarterPosition(i); pokemonContainer.setPosition(pos.x, pos.y); this.iconAnimHandler.addOrUpdate(pokemonContainer.icon, PokemonIconAnimMode.NONE); @@ -1133,7 +1130,7 @@ export default class PokedexUiHandler extends MessageUiHandler { } else if (this.showingTray) { if (button === Button.ACTION) { const formIndex = this.trayForms[this.trayCursor].formIndex; - ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, { form: formIndex }, this.filteredIndices); + ui.setOverlayMode(UiMode.POKEDEX_PAGE, this.lastSpecies, { form: formIndex }, this.filteredIndices); success = true; } else { const numberOfForms = this.trayContainers.length; @@ -1182,7 +1179,7 @@ export default class PokedexUiHandler extends MessageUiHandler { } } else { if (button === Button.ACTION) { - ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, null, this.filteredIndices); + ui.setOverlayMode(UiMode.POKEDEX_PAGE, this.lastSpecies, null, this.filteredIndices); success = true; } else { switch (button) { @@ -1342,7 +1339,7 @@ export default class PokedexUiHandler extends MessageUiHandler { this.filteredPokemonData = []; - this.allSpecies.forEach(species => { + allSpecies.forEach(species => { const starterId = this.getStarterSpeciesId(species.speciesId); const currentDexAttr = this.getCurrentDexProps(species.speciesId); @@ -1412,12 +1409,11 @@ export default class PokedexUiHandler extends MessageUiHandler { // Ability filter const abilities = [species.ability1, species.ability2, species.abilityHidden].map(a => allAbilities[a].name); - const passiveId = starterPassiveAbilities.hasOwnProperty(species.speciesId) - ? species.speciesId - : starterPassiveAbilities.hasOwnProperty(starterId) - ? starterId - : pokemonPrevolutions[starterId]; - const passives = starterPassiveAbilities[passiveId]; + // get the passive ability for the species + const passives = [species.getPassiveAbility()]; + for (const form of species.forms) { + passives.push(form.getPassiveAbility()); + } const selectedAbility1 = this.filterText.getValue(FilterTextRow.ABILITY_1); const fitsFormAbility1 = species.forms.some(form => @@ -2268,15 +2264,15 @@ export default class PokedexUiHandler extends MessageUiHandler { const ui = this.getUi(); const cancel = () => { - ui.setMode(Mode.POKEDEX, "refresh"); + ui.setMode(UiMode.POKEDEX, "refresh"); this.clearText(); this.blockInput = false; }; ui.showText(i18next.t("pokedexUiHandler:confirmExit"), null, () => { ui.setModeWithoutClear( - Mode.CONFIRM, + UiMode.CONFIRM, () => { - ui.setMode(Mode.POKEDEX, "refresh"); + ui.setMode(UiMode.POKEDEX, "refresh"); this.clearText(); this.clear(); ui.revertMode(); diff --git a/src/ui/pokemon-hatch-info-container.ts b/src/ui/pokemon-hatch-info-container.ts index 99940b92351..f3095cb48bf 100644 --- a/src/ui/pokemon-hatch-info-container.ts +++ b/src/ui/pokemon-hatch-info-container.ts @@ -1,13 +1,13 @@ import PokemonInfoContainer from "#app/ui/pokemon-info-container"; import { Gender } from "#app/data/gender"; import { PokemonType } from "#enums/pokemon-type"; -import * as Utils from "#app/utils"; +import { rgbHexToRgba, padInt } from "#app/utils/common"; import { TextStyle, addTextObject } from "#app/ui/text"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { allMoves } from "#app/data/moves/move"; import { Species } from "#enums/species"; import { getEggTierForSpecies } from "#app/data/egg"; -import { starterColors } from "#app/battle-scene"; +import { starterColors } from "#app/global-vars/starter-colors"; import { globalScene } from "#app/global-scene"; import { argbFromRgba } from "@material/material-color-utilities"; import type { EggHatchData } from "#app/data/egg-hatch-data"; @@ -154,14 +154,14 @@ export default class PokemonHatchInfoContainer extends PokemonInfoContainer { super.show(pokemon, false, 1, hatchInfo.getDex(), hatchInfo.getStarterEntry(), true); const colorScheme = starterColors[species.speciesId]; - this.pokemonCandyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0]))); + this.pokemonCandyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0]))); this.pokemonCandyIcon.setVisible(true); - this.pokemonCandyOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1]))); + this.pokemonCandyOverlayIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1]))); this.pokemonCandyOverlayIcon.setVisible(true); this.pokemonCandyCountText.setText(`x${globalScene.gameData.starterData[species.speciesId].candyCount}`); this.pokemonCandyCountText.setVisible(true); - this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 4)); + this.pokemonNumberText.setText(padInt(species.speciesId, 4)); this.pokemonNameText.setText(species.name); const hasEggMoves = species && speciesEggMoves.hasOwnProperty(species.speciesId); diff --git a/src/ui/pokemon-icon-anim-handler.ts b/src/ui/pokemon-icon-anim-handler.ts index c84ee2a0f9a..253ccbe3623 100644 --- a/src/ui/pokemon-icon-anim-handler.ts +++ b/src/ui/pokemon-icon-anim-handler.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import * as Utils from "../utils"; +import { fixedInt } from "#app/utils/common"; export enum PokemonIconAnimMode { NONE, @@ -27,7 +27,7 @@ export default class PokemonIconAnimHandler { } }; globalScene.tweens.addCounter({ - duration: Utils.fixedInt(200), + duration: fixedInt(200), from: 0, to: 1, yoyo: true, diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index 56201f38748..18b5d2384ef 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -1,4 +1,4 @@ -import { getVariantTint } from "#app/data/variant"; +import { getVariantTint } from "#app/sprites/variant"; import type BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import { globalScene } from "#app/global-scene"; import { Gender, getGenderColor, getGenderSymbol } from "../data/gender"; @@ -8,7 +8,7 @@ import type Pokemon from "../field/pokemon"; import i18next from "i18next"; import type { DexEntry, StarterDataEntry } from "../system/game-data"; import { DexAttr } from "../system/game-data"; -import * as Utils from "../utils"; +import { fixedInt } from "#app/utils/common"; import ConfirmUiHandler from "./confirm-ui-handler"; import { StatsContainer } from "./stats-container"; import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text"; @@ -393,7 +393,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { if (!eggInfo) { globalScene.tweens.add({ targets: this, - duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)), + duration: fixedInt(Math.floor(750 / speedMultiplier)), ease: "Cubic.easeInOut", x: this.initialX - this.infoWindowWidth, onComplete: () => { @@ -403,9 +403,9 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { if (showMoves) { globalScene.tweens.add({ - delay: Utils.fixedInt(Math.floor(325 / speedMultiplier)), + delay: fixedInt(Math.floor(325 / speedMultiplier)), targets: this.pokemonMovesContainer, - duration: Utils.fixedInt(Math.floor(325 / speedMultiplier)), + duration: fixedInt(Math.floor(325 / speedMultiplier)), ease: "Cubic.easeInOut", x: this.movesContainerInitialX - 57, onComplete: () => resolve(), @@ -463,7 +463,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { return new Promise(resolve => { globalScene.tweens.add({ targets: this, - duration: Utils.fixedInt(Math.floor(150 / speedMultiplier)), + duration: fixedInt(Math.floor(150 / speedMultiplier)), ease: "Cubic.easeInOut", x: xPosition, onComplete: () => { @@ -482,14 +482,14 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { globalScene.tweens.add({ targets: this.pokemonMovesContainer, - duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)), + duration: fixedInt(Math.floor(750 / speedMultiplier)), ease: "Cubic.easeInOut", x: this.movesContainerInitialX, }); globalScene.tweens.add({ targets: this, - duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)), + duration: fixedInt(Math.floor(750 / speedMultiplier)), ease: "Cubic.easeInOut", x: this.initialX, onComplete: () => { diff --git a/src/ui/registration-form-ui-handler.ts b/src/ui/registration-form-ui-handler.ts index 74669bc1f44..a60a53a8e7a 100644 --- a/src/ui/registration-form-ui-handler.ts +++ b/src/ui/registration-form-ui-handler.ts @@ -1,7 +1,7 @@ import type { InputFieldConfig } from "./form-modal-ui-handler"; import { FormModalUiHandler } from "./form-modal-ui-handler"; import type { ModalConfig } from "./modal-ui-handler"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import { TextStyle, addTextObject } from "./text"; import i18next from "i18next"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; @@ -98,51 +98,53 @@ export default class RegistrationFormUiHandler extends FormModalUiHandler { const originalRegistrationAction = this.submitAction; this.submitAction = _ => { - // Prevent overlapping overrides on action modification - this.submitAction = originalRegistrationAction; - this.sanitizeInputs(); - globalScene.ui.setMode(Mode.LOADING, { buttonActions: [] }); - const onFail = error => { - globalScene.ui.setMode(Mode.REGISTRATION_FORM, Object.assign(config, { errorMessage: error?.trim() })); - globalScene.ui.playError(); - const errorMessageFontSize = languageSettings[i18next.resolvedLanguage!]?.errorMessageFontSize; - if (errorMessageFontSize) { - this.errorMessage.setFontSize(errorMessageFontSize); - } - }; - if (!this.inputs[0].text) { - return onFail(i18next.t("menu:emptyUsername")); - } - if (!this.inputs[1].text) { - return onFail(this.getReadableErrorMessage("invalid password")); - } - if (this.inputs[1].text !== this.inputs[2].text) { - return onFail(i18next.t("menu:passwordNotMatchingConfirmPassword")); - } - const [usernameInput, passwordInput] = this.inputs; - pokerogueApi.account - .register({ - username: usernameInput.text, - password: passwordInput.text, - }) - .then(registerError => { - if (!registerError) { - pokerogueApi.account - .login({ - username: usernameInput.text, - password: passwordInput.text, - }) - .then(loginError => { - if (!loginError) { - originalRegistrationAction?.(); - } else { - onFail(loginError); - } - }); - } else { - onFail(registerError); + if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { + // Prevent overlapping overrides on action modification + this.submitAction = originalRegistrationAction; + this.sanitizeInputs(); + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); + const onFail = error => { + globalScene.ui.setMode(UiMode.REGISTRATION_FORM, Object.assign(config, { errorMessage: error?.trim() })); + globalScene.ui.playError(); + const errorMessageFontSize = languageSettings[i18next.resolvedLanguage!]?.errorMessageFontSize; + if (errorMessageFontSize) { + this.errorMessage.setFontSize(errorMessageFontSize); } - }); + }; + if (!this.inputs[0].text) { + return onFail(i18next.t("menu:emptyUsername")); + } + if (!this.inputs[1].text) { + return onFail(this.getReadableErrorMessage("invalid password")); + } + if (this.inputs[1].text !== this.inputs[2].text) { + return onFail(i18next.t("menu:passwordNotMatchingConfirmPassword")); + } + const [usernameInput, passwordInput] = this.inputs; + pokerogueApi.account + .register({ + username: usernameInput.text, + password: passwordInput.text, + }) + .then(registerError => { + if (!registerError) { + pokerogueApi.account + .login({ + username: usernameInput.text, + password: passwordInput.text, + }) + .then(loginError => { + if (!loginError) { + originalRegistrationAction?.(); + } else { + onFail(loginError); + } + }); + } else { + onFail(registerError); + } + }); + } }; return true; diff --git a/src/ui/rename-form-ui-handler.ts b/src/ui/rename-form-ui-handler.ts index 91c0025d283..7083f83865b 100644 --- a/src/ui/rename-form-ui-handler.ts +++ b/src/ui/rename-form-ui-handler.ts @@ -38,7 +38,7 @@ export default class RenameFormUiHandler extends FormModalUiHandler { if (super.show(args)) { const config = args[0] as ModalConfig; if (args[1] && typeof (args[1] as PlayerPokemon).getNameToRender === "function") { - this.inputs[0].text = (args[1] as PlayerPokemon).getNameToRender(); + this.inputs[0].text = (args[1] as PlayerPokemon).getNameToRender(false); } else { this.inputs[0].text = args[1]; } diff --git a/src/ui/run-history-ui-handler.ts b/src/ui/run-history-ui-handler.ts index 85ea1e93e8d..92c5a2fde07 100644 --- a/src/ui/run-history-ui-handler.ts +++ b/src/ui/run-history-ui-handler.ts @@ -1,14 +1,14 @@ import { globalScene } from "#app/global-scene"; import { GameModes } from "../game-mode"; import { TextStyle, addTextObject } from "./text"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import { addWindow } from "./ui-theme"; -import * as Utils from "../utils"; +import { fixedInt, formatLargeNumber } from "#app/utils/common"; import type PokemonData from "../system/pokemon-data"; import MessageUiHandler from "./message-ui-handler"; import i18next from "i18next"; import { Button } from "../enums/buttons"; -import { BattleType } from "../battle"; +import { BattleType } from "#enums/battle-type"; import type { RunEntry } from "../system/game-data"; import { PlayerGender } from "#enums/player-gender"; import { TrainerVariant } from "../field/trainer"; @@ -40,7 +40,7 @@ export default class RunHistoryUiHandler extends MessageUiHandler { private runContainerInitialY: number; constructor() { - super(Mode.RUN_HISTORY); + super(UiMode.RUN_HISTORY); } override setup() { @@ -110,7 +110,7 @@ export default class RunHistoryUiHandler extends MessageUiHandler { if (button === Button.ACTION) { const cursor = this.cursor + this.scrollCursor; if (this.runs[cursor]) { - globalScene.ui.setOverlayMode(Mode.RUN_INFO, this.runs[cursor].entryData, RunDisplayMode.RUN_HISTORY, true); + globalScene.ui.setOverlayMode(UiMode.RUN_INFO, this.runs[cursor].entryData, RunDisplayMode.RUN_HISTORY, true); } else { return false; } @@ -218,7 +218,7 @@ export default class RunHistoryUiHandler extends MessageUiHandler { globalScene.tweens.add({ targets: this.runsContainer, y: this.runContainerInitialY - 56 * scrollCursor, - duration: Utils.fixedInt(325), + duration: fixedInt(325), ease: "Sine.easeInOut", }); } @@ -314,7 +314,7 @@ class RunEntryContainer extends Phaser.GameObjects.Container { const enemyLevel = addTextObject( 32, 20, - `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, + `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(enemy.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" }, ); @@ -408,7 +408,7 @@ class RunEntryContainer extends Phaser.GameObjects.Container { const text = addTextObject( 32, 20, - `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(pokemon.level, 1000)}`, + `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(pokemon.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" }, ); diff --git a/src/ui/run-info-ui-handler.ts b/src/ui/run-info-ui-handler.ts index 364cb8e4003..8487533f465 100644 --- a/src/ui/run-info-ui-handler.ts +++ b/src/ui/run-info-ui-handler.ts @@ -2,14 +2,14 @@ import { GameModes } from "../game-mode"; import UiHandler from "./ui-handler"; import type { SessionSaveData } from "../system/game-data"; import { TextStyle, addTextObject, addBBCodeTextObject, getTextColor } from "./text"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import { addWindow } from "./ui-theme"; import { getPokeballAtlasKey } from "#app/data/pokeball"; -import * as Utils from "../utils"; +import { formatLargeNumber, getPlayTimeString, formatMoney, formatFancyLargeNumber } from "#app/utils/common"; import type PokemonData from "../system/pokemon-data"; import i18next from "i18next"; import { Button } from "../enums/buttons"; -import { BattleType } from "../battle"; +import { BattleType } from "#enums/battle-type"; import { TrainerVariant } from "../field/trainer"; import { Challenges } from "#enums/challenges"; import { getLuckString, getLuckTextTint } from "../modifier/modifier-type"; @@ -18,8 +18,9 @@ import { getTypeRgb } from "#app/data/type"; import { PokemonType } from "#enums/pokemon-type"; import { TypeColor, TypeShadow } from "#app/enums/color"; import { getNatureStatMultiplier, getNatureName } from "../data/nature"; -import { getVariantTint } from "#app/data/variant"; -import * as Modifier from "../modifier/modifier"; +import { getVariantTint } from "#app/sprites/variant"; +// biome-ignore lint/style/noNamespaceImport: See `src/system/game-data.ts` +import * as Modifier from "#app/modifier/modifier"; import type { Species } from "#enums/species"; import { PlayerGender } from "#enums/player-gender"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; @@ -68,7 +69,7 @@ export default class RunInfoUiHandler extends UiHandler { private modifiersModule: any; constructor() { - super(Mode.RUN_INFO); + super(UiMode.RUN_INFO); } override async setup() { @@ -411,7 +412,7 @@ export default class RunInfoUiHandler extends UiHandler { const enemyLevel = addTextObject( 36, 26, - `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, + `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(enemy.level, 1000)}`, enemyLevelStyle, { fontSize: "44px", color: "#f8f8f8" }, ); @@ -441,7 +442,7 @@ export default class RunInfoUiHandler extends UiHandler { const enemyLevel = addTextObject( 36, 26, - `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, + `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(enemy.level, 1000)}`, bossStatus ? TextStyle.PARTY_RED : TextStyle.PARTY, { fontSize: "44px", color: "#f8f8f8" }, ); @@ -527,7 +528,7 @@ export default class RunInfoUiHandler extends UiHandler { const enemyLevel = addTextObject( 43 * (e % 3), 27 * (pokemonRowHeight + 1), - `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, + `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(enemy.level, 1000)}`, isBoss ? TextStyle.PARTY_RED : TextStyle.PARTY, { fontSize: "54px" }, ); @@ -606,9 +607,9 @@ export default class RunInfoUiHandler extends UiHandler { fontSize: "50px", lineSpacing: lineSpacing, }); - const runTime = Utils.getPlayTimeString(this.runInfo.playTime); + const runTime = getPlayTimeString(this.runInfo.playTime); runInfoText.appendText(`${i18next.t("runHistory:runLength")}: ${runTime}`, false); - const runMoney = Utils.formatMoney(globalScene.moneyFormat, this.runInfo.money); + const runMoney = formatMoney(globalScene.moneyFormat, this.runInfo.money); const moneyTextColor = getTextColor(TextStyle.MONEY_WINDOW, false, globalScene.uiTheme); runInfoText.appendText( `[color=${moneyTextColor}]${i18next.t("battleScene:moneyOwned", { formattedMoney: runMoney })}[/color]`, @@ -770,7 +771,7 @@ export default class RunInfoUiHandler extends UiHandler { lineSpacing: lineSpacing, }); pokeInfoText.appendText( - `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatFancyLargeNumber(pokemon.level, 1)} - ${pNatureName}`, + `${i18next.t("saveSlotSelectUiHandler:lv")}${formatFancyLargeNumber(pokemon.level, 1)} - ${pNatureName}`, ); pokeInfoText.appendText(pAbilityInfo); pokeInfoText.appendText(pPassiveInfo); @@ -780,7 +781,7 @@ export default class RunInfoUiHandler extends UiHandler { // Colored Arrows (Red/Blue) are placed by stats that are boosted from natures const pokeStatTextContainer = globalScene.add.container(-35, 6); const pStats: string[] = []; - pokemon.stats.forEach(element => pStats.push(Utils.formatFancyLargeNumber(element, 1))); + pokemon.stats.forEach(element => pStats.push(formatFancyLargeNumber(element, 1))); for (let i = 0; i < pStats.length; i++) { const isMult = getNatureStatMultiplier(pNature, i); pStats[i] = isMult < 1 ? pStats[i] + "[color=#40c8f8]↓[/color]" : pStats[i]; diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index a1e9e5219b4..7b4d46203c9 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -2,13 +2,14 @@ import i18next from "i18next"; import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import { GameMode } from "../game-mode"; -import * as Modifier from "../modifier/modifier"; +// biome-ignore lint/style/noNamespaceImport: See `src/system/game-data.ts` +import * as Modifier from "#app/modifier/modifier"; import type { SessionSaveData } from "../system/game-data"; import type PokemonData from "../system/pokemon-data"; -import * as Utils from "../utils"; +import { isNullOrUndefined, fixedInt, getPlayTimeString, formatLargeNumber } from "#app/utils/common"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import { addWindow } from "./ui-theme"; import { RunDisplayMode } from "#app/ui/run-info-ui-handler"; @@ -39,7 +40,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { private sessionSlotsContainerInitialY: number; constructor() { - super(Mode.SAVE_SLOT); + super(UiMode.SAVE_SLOT); } setup() { @@ -121,13 +122,13 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { this.saveSlotSelectCallback = null; ui.revertMode(); ui.showText("", 0); - ui.setMode(Mode.MESSAGE); + ui.setMode(UiMode.MESSAGE); originalCallback?.(cursor); }; if (this.sessionSlots[cursor].hasData) { ui.showText(i18next.t("saveSlotSelectUiHandler:overwriteData"), null, () => { ui.setOverlayMode( - Mode.CONFIRM, + UiMode.CONFIRM, () => { globalScene.gameData.deleteSession(cursor).then(response => { if (response === false) { @@ -197,7 +198,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { case Button.RIGHT: if (this.sessionSlots[cursorPosition].hasData && this.sessionSlots[cursorPosition].saveData) { globalScene.ui.setOverlayMode( - Mode.RUN_INFO, + UiMode.RUN_INFO, this.sessionSlots[cursorPosition].saveData, RunDisplayMode.SESSION_PREVIEW, ); @@ -296,7 +297,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { } this.setArrowVisibility(hasData); } - if (!Utils.isNullOrUndefined(prevSlotIndex)) { + if (!isNullOrUndefined(prevSlotIndex)) { this.revertSessionSlot(prevSlotIndex); } @@ -339,7 +340,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { globalScene.tweens.add({ targets: this.sessionSlotsContainer, y: this.sessionSlotsContainerInitialY - 56 * scrollCursor, - duration: Utils.fixedInt(325), + duration: fixedInt(325), ease: "Sine.easeInOut", }); } @@ -407,7 +408,7 @@ class SessionSlot extends Phaser.GameObjects.Container { const timestampLabel = addTextObject(8, 19, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW); this.add(timestampLabel); - const playTimeLabel = addTextObject(8, 33, Utils.getPlayTimeString(data.playTime), TextStyle.WINDOW); + const playTimeLabel = addTextObject(8, 33, getPlayTimeString(data.playTime), TextStyle.WINDOW); this.add(playTimeLabel); const pokemonIconsContainer = globalScene.add.container(144, 4); @@ -421,7 +422,7 @@ class SessionSlot extends Phaser.GameObjects.Container { const text = addTextObject( 32, 20, - `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(pokemon.level, 1000)}`, + `${i18next.t("saveSlotSelectUiHandler:lv")}${formatLargeNumber(pokemon.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" }, ); diff --git a/src/ui/saving-icon-handler.ts b/src/ui/saving-icon-handler.ts index 4404ea423b1..3b7db549a4a 100644 --- a/src/ui/saving-icon-handler.ts +++ b/src/ui/saving-icon-handler.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import * as Utils from "../utils"; +import { fixedInt } from "#app/utils/common"; export default class SavingIconHandler extends Phaser.GameObjects.Container { private icon: Phaser.GameObjects.Sprite; @@ -36,10 +36,10 @@ export default class SavingIconHandler extends Phaser.GameObjects.Container { globalScene.tweens.add({ targets: this, alpha: 1, - duration: Utils.fixedInt(250), + duration: fixedInt(250), ease: "Sine.easeInOut", onComplete: () => { - globalScene.time.delayedCall(Utils.fixedInt(500), () => { + globalScene.time.delayedCall(fixedInt(500), () => { this.animActive = false; if (!this.shown) { this.hide(); @@ -64,7 +64,7 @@ export default class SavingIconHandler extends Phaser.GameObjects.Container { globalScene.tweens.add({ targets: this, alpha: 0, - duration: Utils.fixedInt(250), + duration: fixedInt(250), ease: "Sine.easeInOut", onComplete: () => { this.animActive = false; diff --git a/src/ui/session-reload-modal-ui-handler.ts b/src/ui/session-reload-modal-ui-handler.ts index d3b88da9e63..f866783afe8 100644 --- a/src/ui/session-reload-modal-ui-handler.ts +++ b/src/ui/session-reload-modal-ui-handler.ts @@ -1,10 +1,10 @@ import type { ModalConfig } from "./modal-ui-handler"; import { ModalUiHandler } from "./modal-ui-handler"; import { addTextObject, TextStyle } from "./text"; -import type { Mode } from "./ui"; +import type { UiMode } from "#enums/ui-mode"; export default class SessionReloadModalUiHandler extends ModalUiHandler { - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); } diff --git a/src/ui/settings/abstract-binding-ui-handler.ts b/src/ui/settings/abstract-binding-ui-handler.ts index 62f78da89f5..a4707418b7c 100644 --- a/src/ui/settings/abstract-binding-ui-handler.ts +++ b/src/ui/settings/abstract-binding-ui-handler.ts @@ -1,5 +1,5 @@ import UiHandler from "../ui-handler"; -import type { Mode } from "../ui"; +import type { UiMode } from "#enums/ui-mode"; import { addWindow } from "../ui-theme"; import { addTextObject, TextStyle } from "../text"; import { Button } from "#enums/buttons"; @@ -51,7 +51,7 @@ export default abstract class AbstractBindingUiHandler extends UiHandler { * * @param mode - The UI mode. */ - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); } diff --git a/src/ui/settings/abstract-control-settings-ui-handler.ts b/src/ui/settings/abstract-control-settings-ui-handler.ts index 2c634e2c5bf..495a0f68540 100644 --- a/src/ui/settings/abstract-control-settings-ui-handler.ts +++ b/src/ui/settings/abstract-control-settings-ui-handler.ts @@ -1,5 +1,5 @@ import UiHandler from "#app/ui/ui-handler"; -import type { Mode } from "#app/ui/ui"; +import type { UiMode } from "#enums/ui-mode"; import type { InterfaceConfig } from "#app/inputs-controller"; import { addWindow } from "#app/ui/ui-theme"; import { addTextObject, TextStyle } from "#app/ui/text"; @@ -74,7 +74,7 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler * * @param mode - The UI mode. */ - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.rowsToDisplay = 8; } diff --git a/src/ui/settings/abstract-settings-ui-handler.ts b/src/ui/settings/abstract-settings-ui-handler.ts index 0c14b91251e..27ca95c25ac 100644 --- a/src/ui/settings/abstract-settings-ui-handler.ts +++ b/src/ui/settings/abstract-settings-ui-handler.ts @@ -1,5 +1,5 @@ import { TextStyle, addTextObject } from "#app/ui/text"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import MessageUiHandler from "#app/ui/message-ui-handler"; import { addWindow } from "#app/ui/ui-theme"; import { ScrollBar } from "#app/ui/scroll-bar"; @@ -42,7 +42,7 @@ export default class AbstractSettingsUiHandler extends MessageUiHandler { protected settings: Array; protected localStorageKey: string; - constructor(type: SettingType, mode: Mode | null = null) { + constructor(type: SettingType, mode: UiMode | null = null) { super(mode); this.settings = Setting.filter(s => s.type === type && !s?.isHidden?.()); this.reloadRequired = false; @@ -425,7 +425,7 @@ export default class AbstractSettingsUiHandler extends MessageUiHandler { const confirmationMessage = setting.options[cursor].confirmationMessage ?? i18next.t("settings:defaultConfirmMessage"); globalScene.ui.showText(confirmationMessage, null, () => { - globalScene.ui.setOverlayMode(Mode.CONFIRM, confirmUpdateSetting, cancelUpdateSetting, null, null, 1, 750); + globalScene.ui.setOverlayMode(UiMode.CONFIRM, confirmUpdateSetting, cancelUpdateSetting, null, null, 1, 750); }); } else { saveSetting(); diff --git a/src/ui/settings/gamepad-binding-ui-handler.ts b/src/ui/settings/gamepad-binding-ui-handler.ts index 62bc2db7825..0f226ddcafa 100644 --- a/src/ui/settings/gamepad-binding-ui-handler.ts +++ b/src/ui/settings/gamepad-binding-ui-handler.ts @@ -1,12 +1,12 @@ import AbstractBindingUiHandler from "./abstract-binding-ui-handler"; -import type { Mode } from "../ui"; +import type { UiMode } from "#enums/ui-mode"; import { Device } from "#enums/devices"; import { getIconWithSettingName, getKeyWithKeycode } from "#app/configs/inputs/configHandler"; import { addTextObject, TextStyle } from "#app/ui/text"; import { globalScene } from "#app/global-scene"; export default class GamepadBindingUiHandler extends AbstractBindingUiHandler { - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); globalScene.input.gamepad?.on("down", this.gamepadButtonDown, this); } diff --git a/src/ui/settings/keyboard-binding-ui-handler.ts b/src/ui/settings/keyboard-binding-ui-handler.ts index 8735faeaaab..c05a31ca91e 100644 --- a/src/ui/settings/keyboard-binding-ui-handler.ts +++ b/src/ui/settings/keyboard-binding-ui-handler.ts @@ -1,12 +1,12 @@ import AbstractBindingUiHandler from "./abstract-binding-ui-handler"; -import type { Mode } from "../ui"; +import type { UiMode } from "#enums/ui-mode"; import { getKeyWithKeycode } from "#app/configs/inputs/configHandler"; import { Device } from "#enums/devices"; import { addTextObject, TextStyle } from "#app/ui/text"; import { globalScene } from "#app/global-scene"; export default class KeyboardBindingUiHandler extends AbstractBindingUiHandler { - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); // Listen to gamepad button down events to initiate binding. globalScene.input.keyboard?.on("keydown", this.onKeyDown, this); diff --git a/src/ui/settings/navigationMenu.ts b/src/ui/settings/navigationMenu.ts index 1d2d71e1e20..ad3d4ccf0b5 100644 --- a/src/ui/settings/navigationMenu.ts +++ b/src/ui/settings/navigationMenu.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type { InputsIcons } from "#app/ui/settings/abstract-control-settings-ui-handler"; import { addTextObject, setTextStyle, TextStyle } from "#app/ui/text"; import { addWindow } from "#app/ui/ui-theme"; @@ -14,8 +14,8 @@ const RIGHT = "RIGHT"; */ export class NavigationManager { private static instance: NavigationManager; - public modes: Mode[]; - public selectedMode: Mode = Mode.SETTINGS; + public modes: UiMode[]; + public selectedMode: UiMode = UiMode.SETTINGS; public navigationMenus: NavigationMenu[] = new Array(); public labels: string[]; @@ -27,11 +27,11 @@ export class NavigationManager { */ constructor() { this.modes = [ - Mode.SETTINGS, - Mode.SETTINGS_DISPLAY, - Mode.SETTINGS_AUDIO, - Mode.SETTINGS_GAMEPAD, - Mode.SETTINGS_KEYBOARD, + UiMode.SETTINGS, + UiMode.SETTINGS_DISPLAY, + UiMode.SETTINGS_AUDIO, + UiMode.SETTINGS_GAMEPAD, + UiMode.SETTINGS_KEYBOARD, ]; this.labels = [ i18next.t("settings:general"), @@ -43,7 +43,7 @@ export class NavigationManager { } public reset() { - this.selectedMode = Mode.SETTINGS; + this.selectedMode = UiMode.SETTINGS; this.updateNavigationMenus(); } diff --git a/src/ui/settings/option-select-ui-handler.ts b/src/ui/settings/option-select-ui-handler.ts index b3d1735dc19..af9760814ac 100644 --- a/src/ui/settings/option-select-ui-handler.ts +++ b/src/ui/settings/option-select-ui-handler.ts @@ -1,8 +1,8 @@ import AbstractOptionSelectUiHandler from "../abstact-option-select-ui-handler"; -import { Mode } from "../ui"; +import { UiMode } from "#enums/ui-mode"; export default class OptionSelectUiHandler extends AbstractOptionSelectUiHandler { - constructor(mode: Mode = Mode.OPTION_SELECT) { + constructor(mode: UiMode = UiMode.OPTION_SELECT) { super(mode); } diff --git a/src/ui/settings/settings-audio-ui-handler.ts b/src/ui/settings/settings-audio-ui-handler.ts index f8cb4da4ba2..019d66d7428 100644 --- a/src/ui/settings/settings-audio-ui-handler.ts +++ b/src/ui/settings/settings-audio-ui-handler.ts @@ -1,4 +1,4 @@ -import type { Mode } from "../ui"; +import type { UiMode } from "#enums/ui-mode"; import AbstractSettingsUiHandler from "./abstract-settings-ui-handler"; import { SettingType } from "#app/system/settings/settings"; ("#app/inputs-controller"); @@ -9,7 +9,7 @@ export default class SettingsAudioUiHandler extends AbstractSettingsUiHandler { * * @param mode - The UI mode, optional. */ - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(SettingType.AUDIO, mode); this.title = "Audio"; this.localStorageKey = "settings"; diff --git a/src/ui/settings/settings-display-ui-handler.ts b/src/ui/settings/settings-display-ui-handler.ts index 985aa9adca2..4878bae72cb 100644 --- a/src/ui/settings/settings-display-ui-handler.ts +++ b/src/ui/settings/settings-display-ui-handler.ts @@ -1,4 +1,4 @@ -import type { Mode } from "../ui"; +import type { UiMode } from "#enums/ui-mode"; import AbstractSettingsUiHandler from "./abstract-settings-ui-handler"; import { SettingKeys, SettingType } from "#app/system/settings/settings"; ("#app/inputs-controller"); @@ -9,7 +9,7 @@ export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler * * @param mode - The UI mode, optional. */ - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(SettingType.DISPLAY, mode); this.title = "Display"; diff --git a/src/ui/settings/settings-gamepad-ui-handler.ts b/src/ui/settings/settings-gamepad-ui-handler.ts index 0b3a7241ff2..7d269deab14 100644 --- a/src/ui/settings/settings-gamepad-ui-handler.ts +++ b/src/ui/settings/settings-gamepad-ui-handler.ts @@ -1,5 +1,5 @@ import { addTextObject, TextStyle } from "../text"; -import type { Mode } from "../ui"; +import type { UiMode } from "#enums/ui-mode"; import { setSettingGamepad, SettingGamepad, @@ -13,7 +13,7 @@ import pad_unlicensedSNES from "#app/configs/inputs/pad_unlicensedSNES"; import type { InterfaceConfig } from "#app/inputs-controller"; import AbstractControlSettingsUiHandler from "#app/ui/settings/abstract-control-settings-ui-handler"; import { Device } from "#enums/devices"; -import { truncateString } from "#app/utils"; +import { truncateString } from "#app/utils/common"; import i18next from "i18next"; import { globalScene } from "#app/global-scene"; @@ -29,7 +29,7 @@ export default class SettingsGamepadUiHandler extends AbstractControlSettingsUiH * * @param mode - The UI mode, optional. */ - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.titleSelected = "Gamepad"; this.setting = SettingGamepad; diff --git a/src/ui/settings/settings-keyboard-ui-handler.ts b/src/ui/settings/settings-keyboard-ui-handler.ts index a7837c8961e..c334ee8f1fc 100644 --- a/src/ui/settings/settings-keyboard-ui-handler.ts +++ b/src/ui/settings/settings-keyboard-ui-handler.ts @@ -1,4 +1,4 @@ -import { Mode } from "../ui"; +import { UiMode } from "#enums/ui-mode"; import cfg_keyboard_qwerty from "#app/configs/inputs/cfg_keyboard_qwerty"; import { setSettingKeyboard, @@ -7,7 +7,7 @@ import { settingKeyboardDefaults, settingKeyboardOptions, } from "#app/system/settings/settings-keyboard"; -import { reverseValueToKeySetting, truncateString } from "#app/utils"; +import { reverseValueToKeySetting, truncateString } from "#app/utils/common"; import AbstractControlSettingsUiHandler from "#app/ui/settings/abstract-control-settings-ui-handler"; import type { InterfaceConfig } from "#app/inputs-controller"; import { addTextObject, TextStyle } from "#app/ui/text"; @@ -28,7 +28,7 @@ export default class SettingsKeyboardUiHandler extends AbstractControlSettingsUi * * @param mode - The UI mode, optional. */ - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.titleSelected = "Keyboard"; this.setting = SettingKeyboard; @@ -84,7 +84,7 @@ export default class SettingsKeyboardUiHandler extends AbstractControlSettingsUi * Handle the home key press event. */ onHomeDown(): void { - if (![Mode.SETTINGS_KEYBOARD, Mode.SETTINGS_GAMEPAD].includes(globalScene.ui.getMode())) { + if (![UiMode.SETTINGS_KEYBOARD, UiMode.SETTINGS_GAMEPAD].includes(globalScene.ui.getMode())) { return; } globalScene.gameData.resetMappingToFactory(); @@ -95,7 +95,7 @@ export default class SettingsKeyboardUiHandler extends AbstractControlSettingsUi * Handle the delete key press event. */ onDeleteDown(): void { - if (globalScene.ui.getMode() !== Mode.SETTINGS_KEYBOARD) { + if (globalScene.ui.getMode() !== UiMode.SETTINGS_KEYBOARD) { return; } const cursor = this.cursor + this.scrollCursor; // Calculate the absolute cursor position. diff --git a/src/ui/settings/settings-ui-handler.ts b/src/ui/settings/settings-ui-handler.ts index 22ea76d798b..8d61044ff91 100644 --- a/src/ui/settings/settings-ui-handler.ts +++ b/src/ui/settings/settings-ui-handler.ts @@ -1,5 +1,5 @@ import { SettingType } from "../../system/settings/settings"; -import type { Mode } from "../ui"; +import type { UiMode } from "#enums/ui-mode"; import AbstractSettingsUiHandler from "./abstract-settings-ui-handler"; export default class SettingsUiHandler extends AbstractSettingsUiHandler { @@ -8,7 +8,7 @@ export default class SettingsUiHandler extends AbstractSettingsUiHandler { * * @param mode - The UI mode, optional. */ - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(SettingType.GENERAL, mode); this.title = "General"; this.localStorageKey = "settings"; diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 1e84b367791..7c345f1735e 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -1,15 +1,15 @@ import type { CandyUpgradeNotificationChangedEvent } from "#app/events/battle-scene"; import { BattleSceneEventType } from "#app/events/battle-scene"; import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; -import type { Variant } from "#app/data/variant"; -import { getVariantTint, getVariantIcon } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; +import { getVariantTint, getVariantIcon } from "#app/sprites/variant"; import { argbFromRgba } from "@material/material-color-utilities"; import i18next from "i18next"; import type BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; -import { starterColors } from "#app/battle-scene"; +import { starterColors } from "#app/global-vars/starter-colors"; import { globalScene } from "#app/global-scene"; -import type { Ability } from "#app/data/ability"; -import { allAbilities } from "#app/data/ability"; +import type { Ability } from "#app/data/abilities/ability-class"; +import { allAbilities } from "#app/data/data-lists"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { GrowthRate, getGrowthRateColor } from "#app/data/exp"; import { Gender, getGenderColor, getGenderSymbol } from "#app/data/gender"; @@ -37,13 +37,13 @@ import MessageUiHandler from "#app/ui/message-ui-handler"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "#app/ui/pokemon-icon-anim-handler"; import { StatsContainer } from "#app/ui/stats-container"; import { TextStyle, addBBCodeTextObject, addTextObject } from "#app/ui/text"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { addWindow } from "#app/ui/ui-theme"; import { Egg } from "#app/data/egg"; import Overrides from "#app/overrides"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; import { Passive as PassiveAttr } from "#enums/passive"; -import * as Challenge from "#app/data/challenge"; +import { applyChallenges, ChallengeType } from "#app/data/challenge"; import MoveInfoOverlay from "#app/ui/move-info-overlay"; import { getEggTierForSpecies } from "#app/data/egg"; import { Device } from "#enums/devices"; @@ -74,11 +74,10 @@ import { randIntRange, rgbHexToRgba, toReadableString, -} from "#app/utils"; +} from "#app/utils/common"; import type { Nature } from "#enums/nature"; import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; import { achvs } from "#app/system/achv"; -import * as Utils from "../utils"; import type { GameObjects } from "phaser"; import { checkStarterValidForChallenge } from "#app/data/challenge"; @@ -376,7 +375,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { protected blockInput = false; constructor() { - super(Mode.STARTER_SELECT); + super(UiMode.STARTER_SELECT); } setup() { @@ -597,6 +596,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.iconAnimHandler = new PokemonIconAnimHandler(); this.iconAnimHandler.setup(); + this.pokemonSprite = globalScene.add.sprite(53, 63, "pkmn__sub"); + this.pokemonSprite.setPipeline(globalScene.spritePipeline, { + tone: [0.0, 0.0, 0.0, 0.0], + ignoreTimeTint: true, + }); + this.starterSelectContainer.add(this.pokemonSprite); + this.pokemonNumberText = addTextObject(17, 1, "0000", TextStyle.SUMMARY); this.pokemonNumberText.setOrigin(0, 0); this.starterSelectContainer.add(this.pokemonNumberText); @@ -826,13 +832,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler { return icon; }); - this.pokemonSprite = globalScene.add.sprite(53, 63, "pkmn__sub"); - this.pokemonSprite.setPipeline(globalScene.spritePipeline, { - tone: [0.0, 0.0, 0.0, 0.0], - ignoreTimeTint: true, - }); - this.starterSelectContainer.add(this.pokemonSprite); - this.type1Icon = globalScene.add.sprite(8, 98, getLocalizedSpriteKey("types")); this.type1Icon.setScale(0.5); this.type1Icon.setOrigin(0, 0); @@ -1889,7 +1888,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { { label: i18next.t("starterSelectUiHandler:addToParty"), handler: () => { - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); const isOverValueLimit = this.tryUpdateValue( globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId), true, @@ -1922,7 +1921,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { label: i18next.t("starterSelectUiHandler:removeFromParty"), handler: () => { this.popStarter(removeIndex); - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); return true; }, }, @@ -1935,7 +1934,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { label: i18next.t("starterSelectUiHandler:toggleIVs"), handler: () => { this.toggleStatsMode(); - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); return true; }, }, @@ -1945,18 +1944,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const showSwapOptions = (moveset: StarterMoveset) => { this.blockInput = true; - ui.setMode(Mode.STARTER_SELECT).then(() => { + ui.setMode(UiMode.STARTER_SELECT).then(() => { ui.showText(i18next.t("starterSelectUiHandler:selectMoveSwapOut"), null, () => { this.moveInfoOverlay.show(allMoves[moveset[0]]); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: moveset .map((m: Moves, i: number) => { const option: OptionSelectItem = { label: allMoves[m].name, handler: () => { this.blockInput = true; - ui.setMode(Mode.STARTER_SELECT).then(() => { + ui.setMode(UiMode.STARTER_SELECT).then(() => { ui.showText( `${i18next.t("starterSelectUiHandler:selectMoveSwapWith")} ${allMoves[m].name}.`, null, @@ -1964,7 +1963,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const possibleMoves = this.speciesStarterMoves.filter((sm: Moves) => sm !== m); this.moveInfoOverlay.show(allMoves[possibleMoves[0]]); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: possibleMoves .map(sm => { // make an option for each available starter move @@ -2012,7 +2011,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { handler: () => { this.moveInfoOverlay.clear(); this.clearText(); - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); return true; }, onHover: () => { @@ -2040,10 +2039,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const showNatureOptions = () => { this.blockInput = true; - ui.setMode(Mode.STARTER_SELECT).then(() => { + ui.setMode(UiMode.STARTER_SELECT).then(() => { ui.showText(i18next.t("starterSelectUiHandler:selectNature"), null, () => { const natures = globalScene.gameData.getNaturesForAttr(this.speciesStarterDexEntry?.natureAttr); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: natures .map((n: Nature, _i: number) => { const option: OptionSelectItem = { @@ -2055,7 +2054,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } starterAttributes.nature = n; this.clearText(); - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); // set nature for starter this.setSpeciesDetails(this.lastSpecies, { natureIndex: n, @@ -2070,7 +2069,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { label: i18next.t("menu:cancel"), handler: () => { this.clearText(); - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); this.blockInput = false; return true; }, @@ -2098,7 +2097,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { label: i18next.t("starterSelectUiHandler:enablePassive"), handler: () => { starterData.passiveAttr |= PassiveAttr.ENABLED; - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); this.setSpeciesDetails(this.lastSpecies); return true; }, @@ -2108,7 +2107,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { label: i18next.t("starterSelectUiHandler:disablePassive"), handler: () => { starterData.passiveAttr ^= PassiveAttr.ENABLED; - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); this.setSpeciesDetails(this.lastSpecies); return true; }, @@ -2126,7 +2125,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (starterContainer) { starterContainer.favoriteIcon.setVisible(starterAttributes.favorite); } - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); return true; }, }); @@ -2139,7 +2138,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (starterContainer) { starterContainer.favoriteIcon.setVisible(starterAttributes.favorite); } - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); return true; }, }); @@ -2151,7 +2150,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { let nickname = starterAttributes.nickname ? String(starterAttributes.nickname) : ""; nickname = decodeURIComponent(escape(atob(nickname))); ui.setModeWithoutClear( - Mode.RENAME_POKEMON, + UiMode.RENAME_POKEMON, { buttonActions: [ (sanitizedName: string) => { @@ -2163,10 +2162,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } else { this.pokemonNameText.setText(this.lastSpecies.name); } - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); }, () => { - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); }, ], }, @@ -2198,7 +2197,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { return globalScene.reset(true); } }); - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); this.setSpeciesDetails(this.lastSpecies); globalScene.playSound("se/buy"); @@ -2239,7 +2238,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); this.tryUpdateValue(0); - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); globalScene.playSound("se/buy"); // update the value label and icon/animation for available upgrade @@ -2291,7 +2290,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { return globalScene.reset(true); } }); - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); globalScene.playSound("se/buy"); // update the icon/animation for available upgrade @@ -2309,11 +2308,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { options.push({ label: i18next.t("menu:cancel"), handler: () => { - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); return true; }, }); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: options, yOffset: 47, }); @@ -2321,14 +2320,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { options.push({ label: i18next.t("menuUiHandler:POKEDEX"), handler: () => { - ui.setMode(Mode.STARTER_SELECT).then(() => { + ui.setMode(UiMode.STARTER_SELECT).then(() => { const attributes = { shiny: starterAttributes.shiny, variant: starterAttributes.variant, form: starterAttributes.form, female: starterAttributes.female, }; - ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, attributes); + ui.setOverlayMode(UiMode.POKEDEX_PAGE, this.lastSpecies, attributes); }); return true; }, @@ -2337,7 +2336,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { options.push({ label: i18next.t("starterSelectUiHandler:useCandies"), handler: () => { - ui.setMode(Mode.STARTER_SELECT).then(() => showUseCandies()); + ui.setMode(UiMode.STARTER_SELECT).then(() => showUseCandies()); return true; }, }); @@ -2345,11 +2344,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { options.push({ label: i18next.t("menu:cancel"), handler: () => { - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); return true; }, }); - ui.setModeWithoutClear(Mode.OPTION_SELECT, { + ui.setModeWithoutClear(UiMode.OPTION_SELECT, { options: options, yOffset: 47, }); @@ -2518,7 +2517,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { case Button.CYCLE_TERA: if (this.canCycleTera) { const speciesForm = getPokemonSpeciesForm(this.lastSpecies.speciesId, starterAttributes.form ?? 0); - if (speciesForm.type1 === this.teraCursor && !Utils.isNullOrUndefined(speciesForm.type2)) { + if (speciesForm.type1 === this.teraCursor && !isNullOrUndefined(speciesForm.type2)) { starterAttributes.tera = speciesForm.type2!; this.setSpeciesDetails(this.lastSpecies, { teraType: speciesForm.type2!, @@ -2960,7 +2959,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { valueLimit.value = 10; } - Challenge.applyChallenges(Challenge.ChallengeType.STARTER_POINTS, valueLimit); + applyChallenges(ChallengeType.STARTER_POINTS, valueLimit); return valueLimit.value; } @@ -3748,7 +3747,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { ); // TODO: is this bang correct? this.abilityCursor = abilityIndex !== undefined ? abilityIndex : (abilityIndex = oldAbilityIndex); this.natureCursor = natureIndex !== undefined ? natureIndex : (natureIndex = oldNatureIndex); - this.teraCursor = !Utils.isNullOrUndefined(teraType) ? teraType : (teraType = species.type1); + this.teraCursor = !isNullOrUndefined(teraType) ? teraType : (teraType = species.type1); const [isInParty, partyIndex]: [boolean, number] = this.isInParty(species); // we use this to firstly check if the pokemon is in the party, and if so, to get the party index in order to update the icon image if (isInParty) { this.updatePartyIcon(species, partyIndex); @@ -3886,7 +3885,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.canCycleTera = !this.statsMode && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && - !Utils.isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2); + !isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2); } if (dexEntry.caughtAttr && species.malePercent !== null) { @@ -4282,15 +4281,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const ui = this.getUi(); const cancel = () => { - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); this.clearText(); this.blockInput = false; }; ui.showText(i18next.t("starterSelectUiHandler:confirmExit"), null, () => { ui.setModeWithoutClear( - Mode.CONFIRM, + UiMode.CONFIRM, () => { - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); globalScene.clearPhaseQueue(); if (globalScene.gameMode.isChallenge) { globalScene.pushPhase(new SelectChallengePhase()); @@ -4319,7 +4318,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const ui = this.getUi(); const cancel = () => { - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); if (!manualTrigger) { this.popStarter(this.starterSpecies.length - 1); } @@ -4331,11 +4330,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (canStart) { ui.showText(i18next.t("starterSelectUiHandler:confirmStartTeam"), null, () => { ui.setModeWithoutClear( - Mode.CONFIRM, + UiMode.CONFIRM, () => { const startRun = () => { globalScene.money = globalScene.gameMode.getStartingMoney(); - ui.setMode(Mode.STARTER_SELECT); + ui.setMode(UiMode.STARTER_SELECT); const thisObj = this; const originalStarterSelectCallback = this.starterSelectCallback; this.starterSelectCallback = null; @@ -4483,7 +4482,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.canCycleTera = !this.statsMode && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && - !Utils.isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2); + !isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2); this.updateInstructions(); } } diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index 9b209ded57a..f93a1826b3e 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -1,8 +1,17 @@ -import { starterColors } from "#app/battle-scene"; +import { starterColors } from "#app/global-vars/starter-colors"; import { globalScene } from "#app/global-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import UiHandler from "#app/ui/ui-handler"; -import * as Utils from "#app/utils"; +import { + getLocalizedSpriteKey, + rgbHexToRgba, + padInt, + getEnumValues, + fixedInt, + isNullOrUndefined, + toReadableString, + formatStat, +} from "#app/utils/common"; import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; import { argbFromRgba } from "@material/material-color-utilities"; @@ -19,10 +28,10 @@ import { StatusEffect } from "#enums/status-effect"; import { getBiomeName } from "#app/data/balance/biomes"; import { getNatureName, getNatureStatMultiplier } from "#app/data/nature"; import { loggedInUser } from "#app/account"; -import type { Variant } from "#app/data/variant"; -import { getVariantTint } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; +import { getVariantTint } from "#app/sprites/variant"; import { Button } from "#enums/buttons"; -import type { Ability } from "#app/data/ability"; +import type { Ability } from "#app/data/abilities/ability-class"; import i18next from "i18next"; import { modifierSortFunc } from "#app/modifier/modifier"; import { PlayerGender } from "#enums/player-gender"; @@ -119,7 +128,7 @@ export default class SummaryUiHandler extends UiHandler { private selectCallback: Function | null; constructor() { - super(Mode.SUMMARY); + super(UiMode.SUMMARY); } setup() { @@ -255,7 +264,7 @@ export default class SummaryUiHandler extends UiHandler { this.statusContainer.add(statusLabel); - this.status = globalScene.add.sprite(91, 4, Utils.getLocalizedSpriteKey("statuses")); + this.status = globalScene.add.sprite(91, 4, getLocalizedSpriteKey("statuses")); this.status.setOrigin(0.5, 0); this.statusContainer.add(this.status); @@ -330,10 +339,10 @@ export default class SummaryUiHandler extends UiHandler { this.shinyOverlay.setVisible(this.pokemon.isShiny()); const colorScheme = starterColors[this.pokemon.species.getRootSpeciesId()]; - this.candyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0]))); - this.candyOverlay.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1]))); + this.candyIcon.setTint(argbFromRgba(rgbHexToRgba(colorScheme[0]))); + this.candyOverlay.setTint(argbFromRgba(rgbHexToRgba(colorScheme[1]))); - this.numberText.setText(Utils.padInt(this.pokemon.species.speciesId, 4)); + this.numberText.setText(padInt(this.pokemon.species.speciesId, 4)); this.numberText.setColor(this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD)); this.numberText.setShadowColor( this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true), @@ -348,18 +357,24 @@ export default class SummaryUiHandler extends UiHandler { this.pokemonSprite.setPipelineData("isTerastallized", this.pokemon.isTerastallized); this.pokemonSprite.setPipelineData("ignoreTimeTint", true); this.pokemonSprite.setPipelineData("spriteKey", this.pokemon.getSpriteKey()); - this.pokemonSprite.setPipelineData("shiny", this.pokemon.shiny); - this.pokemonSprite.setPipelineData("variant", this.pokemon.variant); + this.pokemonSprite.setPipelineData( + "shiny", + this.pokemon.summonData.illusion?.basePokemon.shiny ?? this.pokemon.shiny, + ); + this.pokemonSprite.setPipelineData( + "variant", + this.pokemon.summonData.illusion?.basePokemon.variant ?? this.pokemon.variant, + ); ["spriteColors", "fusionSpriteColors"].map(k => { delete this.pokemonSprite.pipelineData[`${k}Base`]; - if (this.pokemon?.summonData?.speciesForm) { + if (this.pokemon?.summonData.speciesForm) { k += "Base"; } this.pokemonSprite.pipelineData[k] = this.pokemon?.getSprite().pipelineData[k]; }); this.pokemon.cry(); - this.nameText.setText(this.pokemon.getNameToRender()); + this.nameText.setText(this.pokemon.getNameToRender(false)); const isFusion = this.pokemon.isFusion(); @@ -417,8 +432,8 @@ export default class SummaryUiHandler extends UiHandler { this.friendshipShadow.setCrop(0, 0, 16, 16 - 16 * ((this.pokemon?.friendship || 0) / 255)); - const doubleShiny = isFusion && this.pokemon.shiny && this.pokemon.fusionShiny; - const baseVariant = !doubleShiny ? this.pokemon.getVariant() : this.pokemon.variant; + const doubleShiny = this.pokemon.isDoubleShiny(false); + const baseVariant = this.pokemon.getBaseVariant(doubleShiny); this.shinyIcon.setPositionRelative( this.nameText, @@ -426,7 +441,7 @@ export default class SummaryUiHandler extends UiHandler { 3, ); this.shinyIcon.setTexture(`shiny_star${doubleShiny ? "_1" : ""}`); - this.shinyIcon.setVisible(this.pokemon.isShiny()); + this.shinyIcon.setVisible(this.pokemon.isShiny(false)); this.shinyIcon.setTint(getVariantTint(baseVariant)); if (this.shinyIcon.visible) { const shinyDescriptor = @@ -446,7 +461,9 @@ export default class SummaryUiHandler extends UiHandler { this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); this.fusionShinyIcon.setVisible(doubleShiny); if (isFusion) { - this.fusionShinyIcon.setTint(getVariantTint(this.pokemon.fusionVariant)); + this.fusionShinyIcon.setTint( + getVariantTint(this.pokemon.summonData.illusion?.basePokemon.fusionVariant ?? this.pokemon.fusionVariant), + ); } this.pokeball.setFrame(getPokeballAtlasKey(this.pokemon.pokeball)); @@ -493,7 +510,7 @@ export default class SummaryUiHandler extends UiHandler { } const ui = this.getUi(); - const fromPartyMode = ui.handlers[Mode.PARTY].active; + const fromPartyMode = ui.handlers[UiMode.PARTY].active; let success = false; let error = false; @@ -593,14 +610,14 @@ export default class SummaryUiHandler extends UiHandler { } if (!fromPartyMode) { - ui.setMode(Mode.MESSAGE); + ui.setMode(UiMode.MESSAGE); } else { - ui.setMode(Mode.PARTY); + ui.setMode(UiMode.PARTY); } } success = true; } else { - const pages = Utils.getEnumValues(Page); + const pages = getEnumValues(Page); switch (button) { case Button.UP: case Button.DOWN: { @@ -675,10 +692,10 @@ export default class SummaryUiHandler extends UiHandler { if (moveDescriptionLineCount > 3) { this.descriptionScrollTween = globalScene.tweens.add({ targets: this.moveDescriptionText, - delay: Utils.fixedInt(2000), + delay: fixedInt(2000), loop: -1, - hold: Utils.fixedInt(2000), - duration: Utils.fixedInt((moveDescriptionLineCount - 3) * 2000), + hold: fixedInt(2000), + duration: fixedInt((moveDescriptionLineCount - 3) * 2000), y: `-=${14.83 * (moveDescriptionLineCount - 3)}`, }); } @@ -697,10 +714,10 @@ export default class SummaryUiHandler extends UiHandler { this.moveCursorObj.setVisible(true); this.moveCursorBlinkTimer = globalScene.time.addEvent({ loop: true, - delay: Utils.fixedInt(600), + delay: fixedInt(600), callback: () => { this.moveCursorObj?.setVisible(false); - globalScene.time.delayedCall(Utils.fixedInt(100), () => { + globalScene.time.delayedCall(fixedInt(100), () => { if (!this.moveCursorObj) { return; } @@ -818,7 +835,7 @@ export default class SummaryUiHandler extends UiHandler { const getTypeIcon = (index: number, type: PokemonType, tera = false) => { const xCoord = typeLabel.width * typeLabel.scale + 9 + 34 * index; const typeIcon = !tera - ? globalScene.add.sprite(xCoord, 42, Utils.getLocalizedSpriteKey("types"), PokemonType[type].toLowerCase()) + ? globalScene.add.sprite(xCoord, 42, getLocalizedSpriteKey("types"), PokemonType[type].toLowerCase()) : globalScene.add.sprite(xCoord, 42, "type_tera"); if (tera) { typeIcon.setScale(0.5); @@ -829,7 +846,7 @@ export default class SummaryUiHandler extends UiHandler { return typeIcon; }; - const types = this.pokemon?.getTypes(false, false, true)!; // TODO: is this bang correct? + const types = this.pokemon?.getTypes(false, false, true, false)!; // TODO: is this bang correct? profileContainer.add(getTypeIcon(0, types[0])); if (types.length > 1) { profileContainer.add(getTypeIcon(1, types[1])); @@ -853,7 +870,7 @@ export default class SummaryUiHandler extends UiHandler { if ( globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && - !Utils.isNullOrUndefined(this.pokemon) + !isNullOrUndefined(this.pokemon) ) { const teraIcon = globalScene.add.sprite(123, 26, "button_tera"); teraIcon.setName("terrastallize-icon"); @@ -925,10 +942,10 @@ export default class SummaryUiHandler extends UiHandler { abilityInfo.descriptionText.setY(69); this.descriptionScrollTween = globalScene.tweens.add({ targets: abilityInfo.descriptionText, - delay: Utils.fixedInt(2000), + delay: fixedInt(2000), loop: -1, - hold: Utils.fixedInt(2000), - duration: Utils.fixedInt((abilityDescriptionLineCount - 2) * 2000), + hold: fixedInt(2000), + duration: fixedInt((abilityDescriptionLineCount - 2) * 2000), y: `-=${14.83 * (abilityDescriptionLineCount - 2)}`, }); } @@ -939,8 +956,8 @@ export default class SummaryUiHandler extends UiHandler { this.passiveContainer?.descriptionText?.setVisible(false); const closeFragment = getBBCodeFrag("", TextStyle.WINDOW_ALT); - const rawNature = Utils.toReadableString(Nature[this.pokemon?.getNature()!]); // TODO: is this bang correct? - const nature = `${getBBCodeFrag(Utils.toReadableString(getNatureName(this.pokemon?.getNature()!)), TextStyle.SUMMARY_RED)}${closeFragment}`; // TODO: is this bang correct? + const rawNature = toReadableString(Nature[this.pokemon?.getNature()!]); // TODO: is this bang correct? + const nature = `${getBBCodeFrag(toReadableString(getNatureName(this.pokemon?.getNature()!)), TextStyle.SUMMARY_RED)}${closeFragment}`; // TODO: is this bang correct? const memoString = i18next.t("pokemonSummary:memoString", { metFragment: i18next.t( @@ -999,8 +1016,8 @@ export default class SummaryUiHandler extends UiHandler { const statValueText = stat !== Stat.HP - ? Utils.formatStat(this.pokemon?.getStat(stat)!) // TODO: is this bang correct? - : `${Utils.formatStat(this.pokemon?.hp!, true)}/${Utils.formatStat(this.pokemon?.getMaxHp()!, true)}`; // TODO: are those bangs correct? + ? formatStat(this.pokemon?.getStat(stat)!) // TODO: is this bang correct? + : `${formatStat(this.pokemon?.hp!, true)}/${formatStat(this.pokemon?.getMaxHp()!, true)}`; // TODO: are those bangs correct? const ivText = `${this.pokemon?.ivs[stat]}/31`; const statValue = addTextObject(93 + 88 * colIndex, 16 * rowIndex, statValueText, TextStyle.WINDOW_ALT); @@ -1106,7 +1123,7 @@ export default class SummaryUiHandler extends UiHandler { this.extraMoveRowContainer.setVisible(true); if (this.newMove && this.pokemon) { - const spriteKey = Utils.getLocalizedSpriteKey("types"); + const spriteKey = getLocalizedSpriteKey("types"); const moveType = this.pokemon.getMoveType(this.newMove); const newMoveTypeIcon = globalScene.add.sprite(0, 0, spriteKey, PokemonType[moveType].toLowerCase()); newMoveTypeIcon.setOrigin(0, 1); @@ -1116,7 +1133,7 @@ export default class SummaryUiHandler extends UiHandler { ppOverlay.setOrigin(0, 1); this.extraMoveRowContainer.add(ppOverlay); - const pp = Utils.padInt(this.newMove?.pp!, 2, " "); // TODO: is this bang correct? + const pp = padInt(this.newMove?.pp!, 2, " "); // TODO: is this bang correct? const ppText = addTextObject(173, 1, `${pp}/${pp}`, TextStyle.WINDOW); ppText.setOrigin(0, 1); this.extraMoveRowContainer.add(ppText); @@ -1132,7 +1149,7 @@ export default class SummaryUiHandler extends UiHandler { this.moveRowsContainer.add(moveRowContainer); if (move && this.pokemon) { - const spriteKey = Utils.getLocalizedSpriteKey("types"); + const spriteKey = getLocalizedSpriteKey("types"); const moveType = this.pokemon.getMoveType(move.getMove()); const typeIcon = globalScene.add.sprite(0, 0, spriteKey, PokemonType[moveType].toLowerCase()); typeIcon.setOrigin(0, 1); @@ -1153,7 +1170,7 @@ export default class SummaryUiHandler extends UiHandler { if (move) { const maxPP = move.getMovePp(); const pp = maxPP - move.ppUsed; - ppText.setText(`${Utils.padInt(pp, 2, " ")}/${Utils.padInt(maxPP, 2, " ")}`); + ppText.setText(`${padInt(pp, 2, " ")}/${padInt(maxPP, 2, " ")}`); } moveRowContainer.add(ppText); diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/target-select-ui-handler.ts index d2f72ef4a4c..5e14e5f7771 100644 --- a/src/ui/target-select-ui-handler.ts +++ b/src/ui/target-select-ui-handler.ts @@ -1,7 +1,7 @@ import { BattlerIndex } from "../battle"; -import { Mode } from "./ui"; +import { UiMode } from "#enums/ui-mode"; import UiHandler from "./ui-handler"; -import * as Utils from "../utils"; +import { isNullOrUndefined, fixedInt } from "#app/utils/common"; import { getMoveTargets } from "../data/moves/move"; import { Button } from "#enums/buttons"; import type { Moves } from "#enums/moves"; @@ -27,7 +27,7 @@ export default class TargetSelectUiHandler extends UiHandler { private targetBattleInfoMoveTween: Phaser.Tweens.Tween[] = []; constructor() { - super(Mode.TARGET_SELECT); + super(UiMode.TARGET_SELECT); this.cursor = -1; } @@ -70,8 +70,8 @@ export default class TargetSelectUiHandler extends UiHandler { * @param user the Pokemon using the move */ resetCursor(cursorN: number, user: Pokemon): void { - if (!Utils.isNullOrUndefined(cursorN)) { - if ([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2].includes(cursorN) || user.battleSummonData.waveTurnCount === 1) { + if (!isNullOrUndefined(cursorN)) { + if ([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2].includes(cursorN) || user.tempSummonData.waveTurnCount === 1) { // Reset cursor on the first turn of a fight or if an ally was targeted last turn cursorN = -1; } @@ -89,11 +89,11 @@ export default class TargetSelectUiHandler extends UiHandler { this.targetSelectCallback(button === Button.ACTION ? targetIndexes : []); success = true; if (this.fieldIndex === BattlerIndex.PLAYER) { - if (Utils.isNullOrUndefined(this.cursor0) || this.cursor0 !== this.cursor) { + if (isNullOrUndefined(this.cursor0) || this.cursor0 !== this.cursor) { this.cursor0 = this.cursor; } } else if (this.fieldIndex === BattlerIndex.PLAYER_2) { - if (Utils.isNullOrUndefined(this.cursor1) || this.cursor1 !== this.cursor) { + if (isNullOrUndefined(this.cursor1) || this.cursor1 !== this.cursor) { this.cursor1 = this.cursor; } } @@ -152,7 +152,7 @@ export default class TargetSelectUiHandler extends UiHandler { key: { start: 1, to: 0.25 }, loop: -1, loopDelay: 150, - duration: Utils.fixedInt(450), + duration: fixedInt(450), ease: "Sine.easeInOut", yoyo: true, onUpdate: t => { @@ -178,7 +178,7 @@ export default class TargetSelectUiHandler extends UiHandler { targets: [info], y: { start: info.getBaseY(), to: info.getBaseY() + 1 }, loop: -1, - duration: Utils.fixedInt(250), + duration: fixedInt(250), ease: "Linear", yoyo: true, }), diff --git a/src/ui/test-dialogue-ui-handler.ts b/src/ui/test-dialogue-ui-handler.ts index 9fbfc01a317..9ecf1641e7b 100644 --- a/src/ui/test-dialogue-ui-handler.ts +++ b/src/ui/test-dialogue-ui-handler.ts @@ -4,8 +4,8 @@ import type { ModalConfig } from "./modal-ui-handler"; import i18next from "i18next"; import type { PlayerPokemon } from "#app/field/pokemon"; import type { OptionSelectItem } from "./abstact-option-select-ui-handler"; -import { isNullOrUndefined } from "#app/utils"; -import { Mode } from "./ui"; +import { isNullOrUndefined } from "#app/utils/common"; +import { UiMode } from "#enums/ui-mode"; export default class TestDialogueUiHandler extends FormModalUiHandler { keys: string[]; @@ -88,7 +88,7 @@ export default class TestDialogueUiHandler extends FormModalUiHandler { input.on("keydown", (inputObject, evt: KeyboardEvent) => { if ( ["escape", "space"].some(v => v === evt.key.toLowerCase() || v === evt.code.toLowerCase()) && - ui.getMode() === Mode.AUTO_COMPLETE + ui.getMode() === UiMode.AUTO_COMPLETE ) { // Delete autocomplete list and recovery focus. inputObject.on("blur", () => inputObject.node.focus(), { once: true }); @@ -98,7 +98,7 @@ export default class TestDialogueUiHandler extends FormModalUiHandler { input.on("textchange", (inputObject, evt: InputEvent) => { // Delete autocomplete. - if (ui.getMode() === Mode.AUTO_COMPLETE) { + if (ui.getMode() === UiMode.AUTO_COMPLETE) { ui.revertMode(); } @@ -133,7 +133,7 @@ export default class TestDialogueUiHandler extends FormModalUiHandler { maxOptions: 5, modalContainer: this.modalContainer, }; - ui.setOverlayMode(Mode.AUTO_COMPLETE, modalOpts); + ui.setOverlayMode(UiMode.AUTO_COMPLETE, modalOpts); } }); @@ -147,7 +147,7 @@ export default class TestDialogueUiHandler extends FormModalUiHandler { this.inputs[0].text = args[1]; } this.submitAction = _ => { - if (ui.getMode() === Mode.TEST_DIALOGUE) { + if (ui.getMode() === UiMode.TEST_DIALOGUE) { this.sanitizeInputs(); const sanitizedName = btoa(unescape(encodeURIComponent(this.inputs[0].text))); config.buttonActions[0](sanitizedName); diff --git a/src/ui/time-of-day-widget.ts b/src/ui/time-of-day-widget.ts index bda1f750cb1..5f5116a2da0 100644 --- a/src/ui/time-of-day-widget.ts +++ b/src/ui/time-of-day-widget.ts @@ -1,4 +1,4 @@ -import * as Utils from "../utils"; +import { fixedInt } from "#app/utils/common"; import { globalScene } from "#app/global-scene"; import { BattleSceneEventType } from "../events/battle-scene"; import { EaseType } from "#enums/ease-type"; @@ -75,14 +75,14 @@ export default class TimeOfDayWidget extends Phaser.GameObjects.Container { const rotate = { targets: [this.timeOfDayIconMgs[0], this.timeOfDayIconMgs[1]], angle: "+=90", - duration: Utils.fixedInt(1500), + duration: fixedInt(1500), ease: "Back.easeOut", paused: !this.parentVisible, }; const fade = { targets: [this.timeOfDayIconBgs[1], this.timeOfDayIconMgs[1], this.timeOfDayIconFgs[1]], alpha: 0, - duration: Utils.fixedInt(500), + duration: fixedInt(500), ease: "Linear", paused: !this.parentVisible, }; @@ -98,14 +98,14 @@ export default class TimeOfDayWidget extends Phaser.GameObjects.Container { const bounce = { targets: [this.timeOfDayIconMgs[0], this.timeOfDayIconMgs[1]], angle: "+=90", - duration: Utils.fixedInt(2000), + duration: fixedInt(2000), ease: "Bounce.easeOut", paused: !this.parentVisible, }; const fade = { targets: [this.timeOfDayIconBgs[1], this.timeOfDayIconMgs[1], this.timeOfDayIconFgs[1]], alpha: 0, - duration: Utils.fixedInt(800), + duration: fixedInt(800), ease: "Linear", paused: !this.parentVisible, }; diff --git a/src/ui/title-ui-handler.ts b/src/ui/title-ui-handler.ts index d87d4e5ca79..bed4d568481 100644 --- a/src/ui/title-ui-handler.ts +++ b/src/ui/title-ui-handler.ts @@ -1,6 +1,6 @@ import OptionSelectUiHandler from "./settings/option-select-ui-handler"; -import { Mode } from "./ui"; -import * as Utils from "../utils"; +import { UiMode } from "#enums/ui-mode"; +import { fixedInt, randInt, randItem } from "#app/utils/common"; import { TextStyle, addTextObject } from "./text"; import { getSplashMessages } from "../data/splash-messages"; import i18next from "i18next"; @@ -26,7 +26,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler { private titleStatsTimer: NodeJS.Timeout | null; - constructor(mode: Mode = Mode.TITLE) { + constructor(mode: UiMode = UiMode.TITLE) { super(mode); } @@ -72,7 +72,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler { globalScene.tweens.add({ targets: this.splashMessageText, - duration: Utils.fixedInt(350), + duration: fixedInt(350), scale: originalSplashMessageScale * 1.25, loop: -1, yoyo: true, @@ -104,7 +104,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler { /** Used solely to display a random Pokémon name in a splash message. */ randomPokemon(): void { - const rand = Utils.randInt(1025, 1); + const rand = randInt(1025, 1); const pokemon = getPokemonSpecies(rand as Species); if ( this.splashMessage === "splashMessages:underratedPokemon" || @@ -132,7 +132,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler { // Moving player count to top of the menu this.playerCountLabel.setY(globalScene.game.canvas.height / 6 - 13 - this.getWindowHeight()); - this.splashMessage = Utils.randItem(getSplashMessages()); + this.splashMessage = randItem(getSplashMessages()); this.splashMessageText.setText( i18next.t(this.splashMessage, { count: TitleUiHandler.BATTLES_WON_FALLBACK, @@ -159,7 +159,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler { globalScene.tweens.add({ targets: [this.titleContainer, ui.getMessageHandler().bg], - duration: Utils.fixedInt(325), + duration: fixedInt(325), alpha: (target: any) => (target === this.titleContainer ? 1 : 0), ease: "Sine.easeInOut", }); @@ -180,7 +180,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler { globalScene.tweens.add({ targets: [this.titleContainer, ui.getMessageHandler().bg], - duration: Utils.fixedInt(325), + duration: fixedInt(325), alpha: (target: any) => (target === this.titleContainer ? 0 : 1), ease: "Sine.easeInOut", }); diff --git a/src/ui/ui-handler.ts b/src/ui/ui-handler.ts index 433f85d0f92..d3784c1225c 100644 --- a/src/ui/ui-handler.ts +++ b/src/ui/ui-handler.ts @@ -1,7 +1,7 @@ import { globalScene } from "#app/global-scene"; import type { TextStyle } from "./text"; import { getTextColor } from "./text"; -import type { Mode } from "./ui"; +import type { UiMode } from "#enums/ui-mode"; import type { Button } from "#enums/buttons"; /** @@ -15,7 +15,7 @@ export default abstract class UiHandler { /** * @param mode The mode of the UI element. These should be unique. */ - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { this.mode = mode; } diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 6605e5ef730..ad496df6382 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -28,7 +28,7 @@ import { addWindow } from "./ui-theme"; import LoginFormUiHandler from "./login-form-ui-handler"; import RegistrationFormUiHandler from "./registration-form-ui-handler"; import LoadingModalUiHandler from "./loading-modal-ui-handler"; -import * as Utils from "../utils"; +import { executeIf } from "#app/utils/common"; import GameStatsUiHandler from "./game-stats-ui-handler"; import AwaitableUiHandler from "./awaitable-ui-handler"; import SaveSlotSelectUiHandler from "./save-slot-select-ui-handler"; @@ -57,102 +57,55 @@ import MysteryEncounterUiHandler from "./mystery-encounter-ui-handler"; import PokedexScanUiHandler from "./pokedex-scan-ui-handler"; import PokedexPageUiHandler from "./pokedex-page-ui-handler"; import { NavigationManager } from "./settings/navigationMenu"; - -export enum Mode { - MESSAGE, - TITLE, - COMMAND, - FIGHT, - BALL, - TARGET_SELECT, - MODIFIER_SELECT, - SAVE_SLOT, - PARTY, - SUMMARY, - STARTER_SELECT, - EVOLUTION_SCENE, - EGG_HATCH_SCENE, - EGG_HATCH_SUMMARY, - CONFIRM, - OPTION_SELECT, - MENU, - MENU_OPTION_SELECT, - SETTINGS, - SETTINGS_DISPLAY, - SETTINGS_AUDIO, - SETTINGS_GAMEPAD, - GAMEPAD_BINDING, - SETTINGS_KEYBOARD, - KEYBOARD_BINDING, - ACHIEVEMENTS, - GAME_STATS, - EGG_LIST, - EGG_GACHA, - POKEDEX, - POKEDEX_SCAN, - POKEDEX_PAGE, - LOGIN_FORM, - REGISTRATION_FORM, - LOADING, - SESSION_RELOAD, - UNAVAILABLE, - CHALLENGE_SELECT, - RENAME_POKEMON, - RUN_HISTORY, - RUN_INFO, - TEST_DIALOGUE, - AUTO_COMPLETE, - ADMIN, - MYSTERY_ENCOUNTER, -} +import { UiMode } from "#enums/ui-mode"; const transitionModes = [ - Mode.SAVE_SLOT, - Mode.PARTY, - Mode.SUMMARY, - Mode.STARTER_SELECT, - Mode.EVOLUTION_SCENE, - Mode.EGG_HATCH_SCENE, - Mode.EGG_LIST, - Mode.EGG_GACHA, - Mode.POKEDEX, - Mode.POKEDEX_PAGE, - Mode.CHALLENGE_SELECT, - Mode.RUN_HISTORY, + UiMode.SAVE_SLOT, + UiMode.PARTY, + UiMode.SUMMARY, + UiMode.STARTER_SELECT, + UiMode.EVOLUTION_SCENE, + UiMode.EGG_HATCH_SCENE, + UiMode.EGG_LIST, + UiMode.EGG_GACHA, + UiMode.POKEDEX, + UiMode.POKEDEX_PAGE, + UiMode.CHALLENGE_SELECT, + UiMode.RUN_HISTORY, ]; const noTransitionModes = [ - Mode.TITLE, - Mode.CONFIRM, - Mode.OPTION_SELECT, - Mode.MENU, - Mode.MENU_OPTION_SELECT, - Mode.GAMEPAD_BINDING, - Mode.KEYBOARD_BINDING, - Mode.SETTINGS, - Mode.SETTINGS_AUDIO, - Mode.SETTINGS_DISPLAY, - Mode.SETTINGS_GAMEPAD, - Mode.SETTINGS_KEYBOARD, - Mode.ACHIEVEMENTS, - Mode.GAME_STATS, - Mode.POKEDEX_SCAN, - Mode.LOGIN_FORM, - Mode.REGISTRATION_FORM, - Mode.LOADING, - Mode.SESSION_RELOAD, - Mode.UNAVAILABLE, - Mode.RENAME_POKEMON, - Mode.TEST_DIALOGUE, - Mode.AUTO_COMPLETE, - Mode.ADMIN, - Mode.MYSTERY_ENCOUNTER, - Mode.RUN_INFO, + UiMode.TITLE, + UiMode.CONFIRM, + UiMode.OPTION_SELECT, + UiMode.MENU, + UiMode.MENU_OPTION_SELECT, + UiMode.GAMEPAD_BINDING, + UiMode.KEYBOARD_BINDING, + UiMode.SETTINGS, + UiMode.SETTINGS_AUDIO, + UiMode.SETTINGS_DISPLAY, + UiMode.SETTINGS_GAMEPAD, + UiMode.SETTINGS_KEYBOARD, + UiMode.ACHIEVEMENTS, + UiMode.GAME_STATS, + UiMode.POKEDEX_SCAN, + UiMode.LOGIN_FORM, + UiMode.REGISTRATION_FORM, + UiMode.LOADING, + UiMode.SESSION_RELOAD, + UiMode.UNAVAILABLE, + UiMode.RENAME_POKEMON, + UiMode.TEST_DIALOGUE, + UiMode.AUTO_COMPLETE, + UiMode.ADMIN, + UiMode.MYSTERY_ENCOUNTER, + UiMode.RUN_INFO, ]; export default class UI extends Phaser.GameObjects.Container { - private mode: Mode; - private modeChain: Mode[]; + private mode: UiMode; + private modeChain: UiMode[]; public handlers: UiHandler[]; private overlay: Phaser.GameObjects.Rectangle; public achvBar: AchvBar; @@ -169,7 +122,7 @@ export default class UI extends Phaser.GameObjects.Container { constructor() { super(globalScene, 0, globalScene.game.canvas.height / 6); - this.mode = Mode.MESSAGE; + this.mode = UiMode.MESSAGE; this.modeChain = []; this.handlers = [ new BattleMessageUiHandler(), @@ -189,7 +142,7 @@ export default class UI extends Phaser.GameObjects.Container { new ConfirmUiHandler(), new OptionSelectUiHandler(), new MenuUiHandler(), - new OptionSelectUiHandler(Mode.MENU_OPTION_SELECT), + new OptionSelectUiHandler(UiMode.MENU_OPTION_SELECT), // settings new SettingsUiHandler(), new SettingsDisplayUiHandler(), @@ -203,7 +156,7 @@ export default class UI extends Phaser.GameObjects.Container { new EggListUiHandler(), new EggGachaUiHandler(), new PokedexUiHandler(), - new PokedexScanUiHandler(Mode.TEST_DIALOGUE), + new PokedexScanUiHandler(UiMode.TEST_DIALOGUE), new PokedexPageUiHandler(), new LoginFormUiHandler(), new RegistrationFormUiHandler(), @@ -214,7 +167,7 @@ export default class UI extends Phaser.GameObjects.Container { new RenameFormUiHandler(), new RunHistoryUiHandler(), new RunInfoUiHandler(), - new TestDialogueUiHandler(Mode.TEST_DIALOGUE), + new TestDialogueUiHandler(UiMode.TEST_DIALOGUE), new AutoCompleteUiHandler(), new AdminUiHandler(), new MysteryEncounterUiHandler(), @@ -222,7 +175,7 @@ export default class UI extends Phaser.GameObjects.Container { } setup(): void { - this.setName(`ui-${Mode[this.mode]}`); + this.setName(`ui-${UiMode[this.mode]}`); for (const handler of this.handlers) { handler.setup(); } @@ -279,7 +232,7 @@ export default class UI extends Phaser.GameObjects.Container { } getMessageHandler(): BattleMessageUiHandler { - return this.handlers[Mode.MESSAGE] as BattleMessageUiHandler; + return this.handlers[UiMode.MESSAGE] as BattleMessageUiHandler; } processInfoButton(pressed: boolean) { @@ -287,7 +240,7 @@ export default class UI extends Phaser.GameObjects.Container { return false; } - if ([Mode.CONFIRM, Mode.COMMAND, Mode.FIGHT, Mode.MESSAGE, Mode.TARGET_SELECT].includes(this.mode)) { + if ([UiMode.CONFIRM, UiMode.COMMAND, UiMode.FIGHT, UiMode.MESSAGE, UiMode.TARGET_SELECT].includes(this.mode)) { globalScene?.processInfoButton(pressed); return true; } @@ -564,7 +517,7 @@ export default class UI extends Phaser.GameObjects.Container { } private setModeInternal( - mode: Mode, + mode: UiMode, clear: boolean, forceTransition: boolean, chainMode: boolean, @@ -587,7 +540,7 @@ export default class UI extends Phaser.GameObjects.Container { this.mode = mode; const touchControls = document?.getElementById("touchControls"); if (touchControls) { - touchControls.dataset.uiMode = Mode[mode]; + touchControls.dataset.uiMode = UiMode[mode]; } this.getHandler().show(args); } @@ -612,23 +565,23 @@ export default class UI extends Phaser.GameObjects.Container { }); } - getMode(): Mode { + getMode(): UiMode { return this.mode; } - setMode(mode: Mode, ...args: any[]): Promise { + setMode(mode: UiMode, ...args: any[]): Promise { return this.setModeInternal(mode, true, false, false, args); } - setModeForceTransition(mode: Mode, ...args: any[]): Promise { + setModeForceTransition(mode: UiMode, ...args: any[]): Promise { return this.setModeInternal(mode, true, true, false, args); } - setModeWithoutClear(mode: Mode, ...args: any[]): Promise { + setModeWithoutClear(mode: UiMode, ...args: any[]): Promise { return this.setModeInternal(mode, false, false, false, args); } - setOverlayMode(mode: Mode, ...args: any[]): Promise { + setOverlayMode(mode: UiMode, ...args: any[]): Promise { return this.setModeInternal(mode, false, false, true, args); } @@ -651,7 +604,7 @@ export default class UI extends Phaser.GameObjects.Container { globalScene.updateGameInfo(); const touchControls = document.getElementById("touchControls"); if (touchControls) { - touchControls.dataset.uiMode = Mode[this.mode]; + touchControls.dataset.uiMode = UiMode[this.mode]; } resolve(true); }; @@ -674,11 +627,11 @@ export default class UI extends Phaser.GameObjects.Container { if (!this?.modeChain?.length) { return resolve(); } - this.revertMode().then(success => Utils.executeIf(success, this.revertModes).then(() => resolve())); + this.revertMode().then(success => executeIf(success, this.revertModes).then(() => resolve())); }); } - public getModeChain(): Mode[] { + public getModeChain(): UiMode[] { return this.modeChain; } diff --git a/src/ui/unavailable-modal-ui-handler.ts b/src/ui/unavailable-modal-ui-handler.ts index 3007f7247f1..5bed55ec24a 100644 --- a/src/ui/unavailable-modal-ui-handler.ts +++ b/src/ui/unavailable-modal-ui-handler.ts @@ -1,9 +1,10 @@ import type { ModalConfig } from "./modal-ui-handler"; import { ModalUiHandler } from "./modal-ui-handler"; import { addTextObject, TextStyle } from "./text"; -import type { Mode } from "./ui"; +import type { UiMode } from "#enums/ui-mode"; import { updateUserInfo } from "#app/account"; -import * as Utils from "#app/utils"; +import { sessionIdKey } from "#app/utils/common"; +import { removeCookie } from "#app/utils/cookies"; import i18next from "i18next"; import { globalScene } from "#app/global-scene"; @@ -17,7 +18,7 @@ export default class UnavailableModalUiHandler extends ModalUiHandler { private readonly randVarianceTime = 1000 * 10; - constructor(mode: Mode | null = null) { + constructor(mode: UiMode | null = null) { super(mode); this.reconnectDuration = this.minTime; } @@ -65,7 +66,7 @@ export default class UnavailableModalUiHandler extends ModalUiHandler { globalScene.playSound("se/pb_bounce_1"); this.reconnectCallback(); } else if (response[1] === 401) { - Utils.removeCookie(Utils.sessionIdKey); + removeCookie(sessionIdKey); globalScene.reset(true, true); } else { this.reconnectDuration = Math.min(this.reconnectDuration * 2, this.maxTime); // Set a max delay so it isn't infinite diff --git a/src/utils.ts b/src/utils/common.ts similarity index 86% rename from src/utils.ts rename to src/utils/common.ts index 4092b68b405..4cf7ceccff2 100644 --- a/src/utils.ts +++ b/src/utils/common.ts @@ -276,43 +276,6 @@ export const apiUrl = localServerUrl ?? "https://api.pokerogue.net"; // used to disable api calls when isLocal is true and a server is not found export let isLocalServerConnected = true; -export const isBeta = import.meta.env.MODE === "beta"; // this checks to see if the env mode is development. Technically this gives the same value for beta AND for dev envs - -export function setCookie(cName: string, cValue: string): void { - const expiration = new Date(); - expiration.setTime(new Date().getTime() + 3600000 * 24 * 30 * 3 /*7*/); - document.cookie = `${cName}=${cValue};Secure;SameSite=Strict;Domain=${window.location.hostname};Path=/;Expires=${expiration.toUTCString()}`; -} - -export function removeCookie(cName: string): void { - if (isBeta) { - document.cookie = `${cName}=;Secure;SameSite=Strict;Domain=pokerogue.net;Path=/;Max-Age=-1`; // we need to remove the cookie from the main domain as well - } - - document.cookie = `${cName}=;Secure;SameSite=Strict;Domain=${window.location.hostname};Path=/;Max-Age=-1`; - document.cookie = `${cName}=;Secure;SameSite=Strict;Path=/;Max-Age=-1`; // legacy cookie without domain, for older cookies to prevent a login loop -} - -export function getCookie(cName: string): string { - // check if there are multiple cookies with the same name and delete them - if (document.cookie.split(";").filter(c => c.includes(cName)).length > 1) { - removeCookie(cName); - return ""; - } - const name = `${cName}=`; - const ca = document.cookie.split(";"); - for (let i = 0; i < ca.length; i++) { - let c = ca[i]; - while (c.charAt(0) === " ") { - c = c.substring(1); - } - if (c.indexOf(name) === 0) { - return c.substring(name.length, c.length); - } - } - return ""; -} - /** * When locally running the game, "pings" the local server * with a GET request to verify if a server is running, @@ -405,8 +368,11 @@ export function deltaRgb(rgb1: number[], rgb2: number[]): number { return Math.ceil(Math.sqrt(2 * drp2 + 4 * dgp2 + 3 * dbp2 + (t * (drp2 - dbp2)) / 256)); } +// Extract out the rgb values from a hex string +const hexRegex = /^([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i; + export function rgbHexToRgba(hex: string) { - const color = hex.match(/^([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i) ?? ["000000", "00", "00", "00"]; + const color = hex.match(hexRegex) ?? ["000000", "00", "00", "00"]; return { r: Number.parseInt(color[1], 16), g: Number.parseInt(color[2], 16), @@ -501,35 +467,22 @@ export function truncateString(str: string, maxLength = 10) { return str; } -/** - * Perform a deep copy of an object. - * - * @param values - The object to be deep copied. - * @returns A new object that is a deep copy of the input. - */ -export function deepCopy(values: object): object { - // Convert the object to a JSON string and parse it back to an object to perform a deep copy - return JSON.parse(JSON.stringify(values)); -} - /** * Convert a space-separated string into a capitalized and underscored string. - * * @param input - The string to be converted. * @returns The converted string with words capitalized and separated by underscores. */ -export function reverseValueToKeySetting(input) { +export function reverseValueToKeySetting(input: string) { // Split the input string into an array of words const words = input.split(" "); // Capitalize the first letter of each word and convert the rest to lowercase - const capitalizedWords = words.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()); + const capitalizedWords = words.map((word: string) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()); // Join the capitalized words with underscores and return the result return capitalizedWords.join("_"); } /** * Capitalize a string. - * * @param str - The string to be capitalized. * @param sep - The separator between the words of the string. * @param lowerFirstChar - Whether the first character of the string should be lowercase or not. @@ -549,8 +502,8 @@ export function capitalizeString(str: string, sep: string, lowerFirstChar = true return null; } -export function isNullOrUndefined(object: any): object is undefined | null { - return null === object || undefined === object; +export function isNullOrUndefined(object: any): object is null | undefined { + return object === null || object === undefined; } /** @@ -584,14 +537,14 @@ export function getLocalizedSpriteKey(baseKey: string) { } /** - * Check if a number is **inclusive** between two numbers - * @param num the number to check - * @param min the minimum value (included) - * @param max the maximum value (included) - * @returns `true` if number is **inclusive** between min and max + * Check if a number is **inclusively** between two numbers + * @param num - the number to check + * @param min - the minimum value (inclusive) + * @param max - the maximum value (inclusive) + * @returns Whether num is no less than min and no greater than max */ export function isBetween(num: number, min: number, max: number): boolean { - return num >= min && num <= max; + return min <= num && num <= max; } /** diff --git a/src/utils/cookies.ts b/src/utils/cookies.ts new file mode 100644 index 00000000000..5ed793c0451 --- /dev/null +++ b/src/utils/cookies.ts @@ -0,0 +1,36 @@ +import { isBeta } from "./utility-vars"; + +export function setCookie(cName: string, cValue: string): void { + const expiration = new Date(); + expiration.setTime(new Date().getTime() + 3600000 * 24 * 30 * 3 /*7*/); + document.cookie = `${cName}=${cValue};Secure;SameSite=Strict;Domain=${window.location.hostname};Path=/;Expires=${expiration.toUTCString()}`; +} + +export function removeCookie(cName: string): void { + if (isBeta) { + document.cookie = `${cName}=;Secure;SameSite=Strict;Domain=pokerogue.net;Path=/;Max-Age=-1`; // we need to remove the cookie from the main domain as well + } + + document.cookie = `${cName}=;Secure;SameSite=Strict;Domain=${window.location.hostname};Path=/;Max-Age=-1`; + document.cookie = `${cName}=;Secure;SameSite=Strict;Path=/;Max-Age=-1`; // legacy cookie without domain, for older cookies to prevent a login loop +} + +export function getCookie(cName: string): string { + // check if there are multiple cookies with the same name and delete them + if (document.cookie.split(";").filter(c => c.includes(cName)).length > 1) { + removeCookie(cName); + return ""; + } + const name = `${cName}=`; + const ca = document.cookie.split(";"); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) === " ") { + c = c.substring(1); + } + if (c.indexOf(name) === 0) { + return c.substring(name.length, c.length); + } + } + return ""; +} diff --git a/src/utils/data.ts b/src/utils/data.ts new file mode 100644 index 00000000000..33623dc5e40 --- /dev/null +++ b/src/utils/data.ts @@ -0,0 +1,40 @@ +/** + * Perform a deep copy of an object. + * @param values - The object to be deep copied. + * @returns A new object that is a deep copy of the input. + */ +export function deepCopy(values: object): object { + // Convert the object to a JSON string and parse it back to an object to perform a deep copy + return JSON.parse(JSON.stringify(values)); +} + +/** + * Deeply merge two JSON objects' common properties together. + * This copies all values from `source` that match properties inside `dest`, + * checking recursively for non-null nested objects. + + * If a property in `source` does not exist in `dest` or its `typeof` evaluates differently, it is skipped. + * If it is a non-array object, its properties are recursed into and checked in turn. + * All other values are copied verbatim. + * @param dest - The object to merge values into + * @param source - The object to source merged values from + * @remarks Do not use for regular objects; this is specifically made for JSON copying. + */ +export function deepMergeSpriteData(dest: object, source: object) { + for (const key of Object.keys(source)) { + if ( + !(key in dest) || + typeof source[key] !== typeof dest[key] || + Array.isArray(source[key]) !== Array.isArray(dest[key]) + ) { + continue; + } + + // Pure objects get recursed into; everything else gets overwritten + if (typeof source[key] !== "object" || source[key] === null || Array.isArray(source[key])) { + dest[key] = source[key]; + } else { + deepMergeSpriteData(dest[key], source[key]); + } + } +} diff --git a/src/utils/utility-vars.ts b/src/utils/utility-vars.ts new file mode 100644 index 00000000000..081f70164c8 --- /dev/null +++ b/src/utils/utility-vars.ts @@ -0,0 +1 @@ +export const isBeta = import.meta.env.MODE === "beta"; // this checks to see if the env mode is development. Technically this gives the same value for beta AND for dev envs diff --git a/test/abilities/ability_duplication.test.ts b/test/abilities/ability_duplication.test.ts index 08b74f682f2..de429045bb8 100644 --- a/test/abilities/ability_duplication.test.ts +++ b/test/abilities/ability_duplication.test.ts @@ -24,7 +24,7 @@ describe("Ability Duplication", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.SPLASH]) - .battleType("single") + .battleStyle("single") .ability(Abilities.HUGE_POWER) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); diff --git a/test/abilities/ability_timing.test.ts b/test/abilities/ability_timing.test.ts index d59c4f7c38d..6128a3e6196 100644 --- a/test/abilities/ability_timing.test.ts +++ b/test/abilities/ability_timing.test.ts @@ -2,7 +2,7 @@ import { BattleStyle } from "#app/enums/battle-style"; import { CommandPhase } from "#app/phases/command-phase"; import { TurnInitPhase } from "#app/phases/turn-init-phase"; import i18next from "#app/plugins/i18n"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Abilities } from "#enums/abilities"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; @@ -27,7 +27,7 @@ describe("Ability Timing", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.INTIMIDATE) .ability(Abilities.BALL_FETCH); @@ -40,9 +40,9 @@ describe("Ability Timing", () => { game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - game.setMode(Mode.MESSAGE); + game.setMode(UiMode.MESSAGE); game.endPhase(); }, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase), diff --git a/test/abilities/analytic.test.ts b/test/abilities/analytic.test.ts index e488b467ce0..108c712da00 100644 --- a/test/abilities/analytic.test.ts +++ b/test/abilities/analytic.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { isBetween, toDmgValue } from "#app/utils"; +import { isBetween, toDmgValue } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -26,7 +26,7 @@ describe("Abilities - Analytic", () => { game.override .moveset([Moves.SPLASH, Moves.TACKLE]) .ability(Abilities.ANALYTIC) - .battleType("single") + .battleStyle("single") .disableCrits() .startingLevel(200) .enemyLevel(200) @@ -53,7 +53,7 @@ describe("Abilities - Analytic", () => { }); it("should increase damage only if the user moves last in doubles", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.classicMode.startBattle([Species.GENGAR, Species.SHUCKLE]); const [enemy] = game.scene.getEnemyField(); diff --git a/test/abilities/arena_trap.test.ts b/test/abilities/arena_trap.test.ts index e0d093a91aa..f37b8a2859f 100644 --- a/test/abilities/arena_trap.test.ts +++ b/test/abilities/arena_trap.test.ts @@ -1,4 +1,4 @@ -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -32,7 +32,7 @@ describe("Abilities - Arena Trap", () => { // TODO: Enable test when Issue #935 is addressed it.todo("should not allow grounded Pokémon to flee", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); await game.classicMode.startBattle(); @@ -61,7 +61,7 @@ describe("Abilities - Arena Trap", () => { */ it("should lift if pokemon with this ability leaves the field", async () => { game.override - .battleType("double") + .battleStyle("double") .enemyMoveset(Moves.SPLASH) .moveset([Moves.ROAR, Moves.SPLASH]) .ability(Abilities.BALL_FETCH); diff --git a/test/abilities/aroma_veil.test.ts b/test/abilities/aroma_veil.test.ts index af8a0233a60..38683bcb1e3 100644 --- a/test/abilities/aroma_veil.test.ts +++ b/test/abilities/aroma_veil.test.ts @@ -25,7 +25,7 @@ describe("Moves - Aroma Veil", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset([Moves.HEAL_BLOCK, Moves.IMPRISON, Moves.SPLASH]) .enemySpecies(Species.SHUCKLE) diff --git a/test/abilities/aura_break.test.ts b/test/abilities/aura_break.test.ts index 86b6c69ec8b..523a2773c99 100644 --- a/test/abilities/aura_break.test.ts +++ b/test/abilities/aura_break.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Aura Break", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.moveset([Moves.MOONBLAST, Moves.DARK_PULSE, Moves.MOONBLAST, Moves.DARK_PULSE]); game.override.enemyMoveset(Moves.SPLASH); game.override.enemyAbility(Abilities.AURA_BREAK); diff --git a/test/abilities/battery.test.ts b/test/abilities/battery.test.ts index cc7570c3d31..6a1f77f4b27 100644 --- a/test/abilities/battery.test.ts +++ b/test/abilities/battery.test.ts @@ -26,7 +26,7 @@ describe("Abilities - Battery", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.enemySpecies(Species.SHUCKLE); game.override.enemyAbility(Abilities.BALL_FETCH); game.override.moveset([Moves.TACKLE, Moves.BREAKING_SWIPE, Moves.SPLASH, Moves.DAZZLING_GLEAM]); diff --git a/test/abilities/battle_bond.test.ts b/test/abilities/battle_bond.test.ts index 6305d7dedc5..d599b3212f9 100644 --- a/test/abilities/battle_bond.test.ts +++ b/test/abilities/battle_bond.test.ts @@ -28,7 +28,7 @@ describe("Abilities - BATTLE BOND", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .startingWave(4) // Leads to arena reset on Wave 5 trainer battle .ability(Abilities.BATTLE_BOND) .starterForms({ [Species.GRENINJA]: ashForm }) diff --git a/test/abilities/beast_boost.test.ts b/test/abilities/beast_boost.test.ts index b307a9eeeba..a6b6ec0aacf 100644 --- a/test/abilities/beast_boost.test.ts +++ b/test/abilities/beast_boost.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Beast Boost", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.BULBASAUR) .enemyAbility(Abilities.BEAST_BOOST) .ability(Abilities.BEAST_BOOST) diff --git a/test/abilities/commander.test.ts b/test/abilities/commander.test.ts index 9d16d474dd4..0e6cb1b9208 100644 --- a/test/abilities/commander.test.ts +++ b/test/abilities/commander.test.ts @@ -34,7 +34,7 @@ describe("Abilities - Commander", () => { .enemyLevel(100) .moveset([Moves.LIQUIDATION, Moves.MEMENTO, Moves.SPLASH, Moves.FLIP_TURN]) .ability(Abilities.COMMANDER) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/competitive.test.ts b/test/abilities/competitive.test.ts index cad35be18f7..1e0b5fcf40e 100644 --- a/test/abilities/competitive.test.ts +++ b/test/abilities/competitive.test.ts @@ -25,7 +25,7 @@ describe("Abilities - Competitive", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.BEEDRILL) .enemyMoveset(Moves.TICKLE) .startingLevel(1) diff --git a/test/abilities/contrary.test.ts b/test/abilities/contrary.test.ts index 19041eb2801..929d620c232 100644 --- a/test/abilities/contrary.test.ts +++ b/test/abilities/contrary.test.ts @@ -23,7 +23,7 @@ describe("Abilities - Contrary", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.BULBASAUR) .enemyAbility(Abilities.CONTRARY) .ability(Abilities.INTIMIDATE) diff --git a/test/abilities/corrosion.test.ts b/test/abilities/corrosion.test.ts index b7f316fbe2d..c72aef9f0a3 100644 --- a/test/abilities/corrosion.test.ts +++ b/test/abilities/corrosion.test.ts @@ -23,7 +23,7 @@ describe("Abilities - Corrosion", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.SPLASH]) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.GRIMER) .enemyAbility(Abilities.CORROSION) diff --git a/test/abilities/costar.test.ts b/test/abilities/costar.test.ts index c6a44bffe54..7b1e362689d 100644 --- a/test/abilities/costar.test.ts +++ b/test/abilities/costar.test.ts @@ -24,7 +24,7 @@ describe("Abilities - COSTAR", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.ability(Abilities.COSTAR); game.override.moveset([Moves.SPLASH, Moves.NASTY_PLOT]); game.override.enemyMoveset(Moves.SPLASH); diff --git a/test/abilities/cud_chew.test.ts b/test/abilities/cud_chew.test.ts new file mode 100644 index 00000000000..f99060cb744 --- /dev/null +++ b/test/abilities/cud_chew.test.ts @@ -0,0 +1,322 @@ +import { RepeatBerryNextTurnAbAttr } from "#app/data/abilities/ability"; +import Pokemon from "#app/field/pokemon"; +import { globalScene } from "#app/global-scene"; +import { getPokemonNameWithAffix } from "#app/messages"; +import { Abilities } from "#enums/abilities"; +import { BerryType } from "#enums/berry-type"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { Stat } from "#enums/stat"; +import GameManager from "#test/testUtils/gameManager"; +import i18next from "i18next"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Abilities - Cud Chew", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.BUG_BITE, Moves.SPLASH, Moves.HYPER_VOICE, Moves.STUFF_CHEEKS]) + .startingHeldItems([{ name: "BERRY", type: BerryType.SITRUS, count: 1 }]) + .ability(Abilities.CUD_CHEW) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + describe("tracks berries eaten", () => { + it("stores inside summonData at end of turn", async () => { + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = 1; // needed to allow sitrus procs + + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("BerryPhase"); + + // berries tracked in turnData; not moved to battleData yet + expect(farigiraf.summonData.berriesEatenLast).toEqual([]); + expect(farigiraf.turnData.berriesEaten).toEqual([BerryType.SITRUS]); + + await game.phaseInterceptor.to("TurnEndPhase"); + + // berries stored in battleData; not yet cleared from turnData + expect(farigiraf.summonData.berriesEatenLast).toEqual([BerryType.SITRUS]); + expect(farigiraf.turnData.berriesEaten).toEqual([BerryType.SITRUS]); + + await game.toNextTurn(); + + // turnData cleared on turn start + expect(farigiraf.summonData.berriesEatenLast).toEqual([BerryType.SITRUS]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + }); + + it("shows ability popup for eating berry, even if berry is useless", async () => { + const abDisplaySpy = vi.spyOn(globalScene, "queueAbilityDisplay"); + game.override.enemyMoveset([Moves.SPLASH, Moves.HEAL_PULSE]); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + // Dip below half to eat berry + farigiraf.hp = farigiraf.getMaxHp() / 2 - 1; + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase"); + + // doesn't trigger since cud chew hasn't eaten berry yet + expect(farigiraf.summonData.berriesEatenLast).toContain(BerryType.SITRUS); + expect(abDisplaySpy).not.toHaveBeenCalledWith(farigiraf); + await game.toNextTurn(); + + // get heal pulsed back to full before the cud chew proc + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.HEAL_PULSE); + await game.phaseInterceptor.to("TurnEndPhase"); + + // globalScene.queueAbilityDisplay should be called twice: + // once to show cud chew text before regurgitating berries, + // once to hide ability text after finishing. + expect(abDisplaySpy).toBeCalledTimes(2); + expect(abDisplaySpy.mock.calls[0][0]).toBe(farigiraf); + expect(abDisplaySpy.mock.calls[0][2]).toBe(true); + expect(abDisplaySpy.mock.calls[1][0]).toBe(farigiraf); + expect(abDisplaySpy.mock.calls[1][2]).toBe(false); + + // should display messgae + expect(game.textInterceptor.getLatestMessage()).toBe( + i18next.t("battle:hpIsFull", { + pokemonName: getPokemonNameWithAffix(farigiraf), + }), + ); + + // not called again at turn end + expect(abDisplaySpy).toBeCalledTimes(2); + }); + + it("can store multiple berries across 2 turns with teatime", async () => { + // always eat first berry for stuff cheeks & company + vi.spyOn(Pokemon.prototype, "randSeedInt").mockReturnValue(0); + game.override + .startingHeldItems([ + { name: "BERRY", type: BerryType.PETAYA, count: 3 }, + { name: "BERRY", type: BerryType.LIECHI, count: 3 }, + ]) + .enemyMoveset(Moves.TEATIME); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = 1; // needed to allow berry procs + + game.move.select(Moves.STUFF_CHEEKS); + await game.toNextTurn(); + + // Ate 2 petayas from moves + 1 of each at turn end; all 4 get tallied on turn end + expect(farigiraf.summonData.berriesEatenLast).toEqual([ + BerryType.PETAYA, + BerryType.PETAYA, + BerryType.PETAYA, + BerryType.LIECHI, + ]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // previous berries eaten and deleted from summon data as remaining eaten berries move to replace them + expect(farigiraf.summonData.berriesEatenLast).toEqual([BerryType.LIECHI, BerryType.LIECHI]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + expect(farigiraf.getStatStage(Stat.SPATK)).toBe(6); // 3+0+3 + expect(farigiraf.getStatStage(Stat.ATK)).toBe(4); // 1+2+1 + }); + + it("should reset both arrays on switch", async () => { + await game.classicMode.startBattle([Species.FARIGIRAF, Species.GIRAFARIG]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = 1; + + // eat berry turn 1, switch out turn 2 + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + const turn1Hp = farigiraf.hp; + game.doSwitchPokemon(1); + await game.toNextTurn(); + + // summonData got cleared due to switch, turnData got cleared due to turn end + expect(farigiraf.summonData.berriesEatenLast).toEqual([]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + expect(farigiraf.hp).toEqual(turn1Hp); + + game.doSwitchPokemon(1); + await game.toNextTurn(); + + // TurnData gets cleared while switching in + expect(farigiraf.summonData.berriesEatenLast).toEqual([]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + expect(farigiraf.hp).toEqual(turn1Hp); + }); + + it("clears array if disabled", async () => { + game.override.enemyAbility(Abilities.NEUTRALIZING_GAS); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = 1; + + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("BerryPhase"); + + expect(farigiraf.summonData.berriesEatenLast).toEqual([]); + expect(farigiraf.turnData.berriesEaten).toEqual([BerryType.SITRUS]); + + await game.toNextTurn(); + + // both arrays empty since neut gas disabled both the mid-turn and post-turn effects + expect(farigiraf.summonData.berriesEatenLast).toEqual([]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + }); + }); + + describe("regurgiates berries", () => { + it("re-triggers effects on eater without pushing to array", async () => { + const apply = vi.spyOn(RepeatBerryNextTurnAbAttr.prototype, "apply"); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = 1; + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // ate 1 sitrus the turn prior, spitball pending + expect(farigiraf.summonData.berriesEatenLast).toEqual([BerryType.SITRUS]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + expect(apply.mock.lastCall).toBeUndefined(); + + const turn1Hp = farigiraf.hp; + + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase"); + + // healed back up to half without adding any more to array + expect(farigiraf.hp).toBeGreaterThan(turn1Hp); + expect(farigiraf.summonData.berriesEatenLast).toEqual([]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + }); + + it("bypasses unnerve", async () => { + game.override.enemyAbility(Abilities.UNNERVE); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = 1; + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase"); + + // Turn end proc set the berriesEatenLast array back to being empty + expect(farigiraf.summonData.berriesEatenLast).toEqual([]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + expect(farigiraf.hp).toBeGreaterThanOrEqual(farigiraf.hp / 2); + }); + + it("doesn't trigger on non-eating removal", async () => { + game.override.enemyMoveset(Moves.INCINERATE); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = farigiraf.getMaxHp() / 4; + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // no berries eaten due to getting cooked + expect(farigiraf.summonData.berriesEatenLast).toEqual([]); + expect(farigiraf.turnData.berriesEaten).toEqual([]); + expect(farigiraf.hp).toBeLessThan(farigiraf.getMaxHp() / 4); + }); + + it("works with pluck", async () => { + game.override + .enemySpecies(Species.BLAZIKEN) + .enemyHeldItems([{ name: "BERRY", type: BerryType.PETAYA, count: 1 }]) + .startingHeldItems([]); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + + game.move.select(Moves.BUG_BITE); + await game.toNextTurn(); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // berry effect triggered twice - once for bug bite, once for cud chew + expect(farigiraf.getStatStage(Stat.SPATK)).toBe(2); + }); + + it("works with Ripen", async () => { + game.override.passiveAbility(Abilities.RIPEN); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = 1; + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + // Rounding errors only ever cost a maximum of 4 hp + expect(farigiraf.getInverseHp()).toBeLessThanOrEqual(3); + }); + + it("is preserved on reload/wave clear", async () => { + game.override.enemyLevel(1); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = 1; + + game.move.select(Moves.HYPER_VOICE); + await game.toNextWave(); + + // berry went yummy yummy in big fat giraffe tummy + expect(farigiraf.summonData.berriesEatenLast).toEqual([BerryType.SITRUS]); + expect(farigiraf.hp).toBeGreaterThan(1); + + // reload and the berry should still be there + await game.reload.reloadSession(); + + const farigirafReloaded = game.scene.getPlayerPokemon()!; + expect(farigirafReloaded.summonData.berriesEatenLast).toEqual([BerryType.SITRUS]); + + const wave1Hp = farigirafReloaded.hp; + + // blow up next wave and we should proc the repeat eating + game.move.select(Moves.HYPER_VOICE); + await game.toNextWave(); + + expect(farigirafReloaded.hp).toBeGreaterThan(wave1Hp); + }); + }); +}); diff --git a/test/abilities/dancer.test.ts b/test/abilities/dancer.test.ts index 56c357b2212..cdd1e3221e9 100644 --- a/test/abilities/dancer.test.ts +++ b/test/abilities/dancer.test.ts @@ -23,7 +23,7 @@ describe("Abilities - Dancer", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); }); // Reference Link: https://bulbapedia.bulbagarden.net/wiki/Dancer_(Ability) @@ -39,20 +39,24 @@ describe("Abilities - Dancer", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SWORDS_DANCE, 1); await game.setTurnOrder([BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2]); - await game.phaseInterceptor.to("MovePhase"); - // immediately copies ally move - await game.phaseInterceptor.to("MovePhase", false); + await game.phaseInterceptor.to("MovePhase"); // feebas uses swords dance + await game.phaseInterceptor.to("MovePhase", false); // oricorio copies swords dance + let currentPhase = game.scene.getCurrentPhase() as MovePhase; expect(currentPhase.pokemon).toBe(oricorio); expect(currentPhase.move.moveId).toBe(Moves.SWORDS_DANCE); - await game.phaseInterceptor.to("MoveEndPhase"); - await game.phaseInterceptor.to("MovePhase"); - // immediately copies enemy move - await game.phaseInterceptor.to("MovePhase", false); + + await game.phaseInterceptor.to("MoveEndPhase"); // end oricorio's move + await game.phaseInterceptor.to("MovePhase"); // magikarp 1 copies swords dance + await game.phaseInterceptor.to("MovePhase"); // magikarp 2 copies swords dance + await game.phaseInterceptor.to("MovePhase"); // magikarp (left) uses victory dance + await game.phaseInterceptor.to("MovePhase", false); // oricorio copies magikarp's victory dance + currentPhase = game.scene.getCurrentPhase() as MovePhase; expect(currentPhase.pokemon).toBe(oricorio); expect(currentPhase.move.moveId).toBe(Moves.VICTORY_DANCE); - await game.phaseInterceptor.to("BerryPhase"); + + await game.phaseInterceptor.to("BerryPhase"); // finish the turn // doesn't use PP if copied move is also in moveset expect(oricorio.moveset[0]?.ppUsed).toBe(0); diff --git a/test/abilities/defiant.test.ts b/test/abilities/defiant.test.ts index a73002d999c..d06aef4d785 100644 --- a/test/abilities/defiant.test.ts +++ b/test/abilities/defiant.test.ts @@ -25,7 +25,7 @@ describe("Abilities - Defiant", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.BEEDRILL) .enemyMoveset(Moves.TICKLE) .startingLevel(1) diff --git a/test/abilities/desolate-land.test.ts b/test/abilities/desolate-land.test.ts index bb0b152418d..d6f01f7aa5e 100644 --- a/test/abilities/desolate-land.test.ts +++ b/test/abilities/desolate-land.test.ts @@ -38,7 +38,7 @@ describe("Abilities - Desolate Land", () => { * is forcefully moved out of the field from moves such as Roar {@linkcode Moves.ROAR} */ it("should lift only when all pokemon with this ability leave the field", async () => { - game.override.battleType("double").enemyMoveset([Moves.SPLASH, Moves.ROAR]); + game.override.battleStyle("double").enemyMoveset([Moves.SPLASH, Moves.ROAR]); await game.classicMode.startBattle([Species.MAGCARGO, Species.MAGCARGO, Species.MAGIKARP, Species.MAGIKARP]); expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.HARSH_SUN); @@ -76,7 +76,7 @@ describe("Abilities - Desolate Land", () => { it("should lift when enemy faints", async () => { game.override - .battleType("single") + .battleStyle("single") .moveset([Moves.SHEER_COLD]) .ability(Abilities.NO_GUARD) .startingLevel(100) @@ -96,7 +96,7 @@ describe("Abilities - Desolate Land", () => { }); it("should lift when pokemon returns upon switching from double to single battle", async () => { - game.override.battleType("even-doubles").enemyMoveset([Moves.SPLASH, Moves.MEMENTO]).startingWave(12); + game.override.battleStyle("even-doubles").enemyMoveset([Moves.SPLASH, Moves.MEMENTO]).startingWave(12); await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGCARGO]); expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.HARSH_SUN); @@ -117,7 +117,7 @@ describe("Abilities - Desolate Land", () => { it("should lift when enemy is captured", async () => { game.override - .battleType("single") + .battleStyle("single") .enemyMoveset([Moves.SPLASH]) .enemySpecies(Species.MAGCARGO) .enemyHasPassiveAbility(true); diff --git a/test/abilities/disguise.test.ts b/test/abilities/disguise.test.ts index a971f5c2733..0e62b8ad448 100644 --- a/test/abilities/disguise.test.ts +++ b/test/abilities/disguise.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { toDmgValue } from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -27,7 +27,7 @@ describe("Abilities - Disguise", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MIMIKYU) .enemyMoveset(Moves.SPLASH) .starterSpecies(Species.REGIELEKI) @@ -186,7 +186,7 @@ describe("Abilities - Disguise", () => { await game.toNextTurn(); game.move.select(Moves.SPLASH); await game.doKillOpponents(); - await game.phaseInterceptor.to("PartyHealPhase"); + await game.phaseInterceptor.to("QuietFormChangePhase"); expect(mimikyu1.formIndex).toBe(disguisedForm); }); diff --git a/test/abilities/dry_skin.test.ts b/test/abilities/dry_skin.test.ts index 9d8a29c431a..398d09393ab 100644 --- a/test/abilities/dry_skin.test.ts +++ b/test/abilities/dry_skin.test.ts @@ -22,7 +22,7 @@ describe("Abilities - Dry Skin", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .enemyAbility(Abilities.DRY_SKIN) .enemyMoveset(Moves.SPLASH) diff --git a/test/abilities/early_bird.test.ts b/test/abilities/early_bird.test.ts index cc486672c95..0f298ba479d 100644 --- a/test/abilities/early_bird.test.ts +++ b/test/abilities/early_bird.test.ts @@ -27,7 +27,7 @@ describe("Abilities - Early Bird", () => { game.override .moveset([Moves.REST, Moves.BELLY_DRUM, Moves.SPLASH]) .ability(Abilities.EARLY_BIRD) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/flash_fire.test.ts b/test/abilities/flash_fire.test.ts index 3cec9cd9cb7..8d94d21adf8 100644 --- a/test/abilities/flash_fire.test.ts +++ b/test/abilities/flash_fire.test.ts @@ -27,7 +27,7 @@ describe("Abilities - Flash Fire", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .ability(Abilities.FLASH_FIRE) .enemyAbility(Abilities.BALL_FETCH) .startingLevel(20) diff --git a/test/abilities/flower_gift.test.ts b/test/abilities/flower_gift.test.ts index 5da796539e5..f2b32dc4c80 100644 --- a/test/abilities/flower_gift.test.ts +++ b/test/abilities/flower_gift.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { Abilities } from "#app/enums/abilities"; import { Stat } from "#app/enums/stat"; import { WeatherType } from "#app/enums/weather-type"; @@ -47,7 +47,7 @@ describe("Abilities - Flower Gift", () => { allyAbility = Abilities.BALL_FETCH, enemyAbility = Abilities.BALL_FETCH, ): Promise<[number, number]> => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.SPLASH, Moves.SUNNY_DAY, move, Moves.HEAL_PULSE]); game.override.enemyMoveset([Moves.SPLASH, Moves.HEAL_PULSE]); const target_index = allyAttacker ? BattlerIndex.ENEMY : BattlerIndex.PLAYER_2; @@ -110,7 +110,7 @@ describe("Abilities - Flower Gift", () => { }); it("increases the ATK and SPDEF stat stages of the Pokémon with this Ability and its allies by 1.5× during Harsh Sunlight", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.classicMode.startBattle([Species.CHERRIM, Species.MAGIKARP]); const [cherrim, magikarp] = game.scene.getPlayerField(); diff --git a/test/abilities/flower_veil.test.ts b/test/abilities/flower_veil.test.ts index c26a952acff..1fd7dbb3ed7 100644 --- a/test/abilities/flower_veil.test.ts +++ b/test/abilities/flower_veil.test.ts @@ -9,7 +9,7 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { allMoves } from "#app/data/moves/move"; import { BattlerTagType } from "#enums/battler-tag-type"; -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; describe("Abilities - Flower Veil", () => { let phaserGame: Phaser.Game; @@ -31,7 +31,7 @@ describe("Abilities - Flower Veil", () => { .moveset([Moves.SPLASH]) .enemySpecies(Species.BULBASAUR) .ability(Abilities.FLOWER_VEIL) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) @@ -63,7 +63,7 @@ describe("Abilities - Flower Veil", () => { }); it("should prevent drowsiness from yawn for a grass user and its grass allies", async () => { - game.override.enemyMoveset([Moves.YAWN]).moveset([Moves.SPLASH]).battleType("double"); + game.override.enemyMoveset([Moves.YAWN]).moveset([Moves.SPLASH]).battleStyle("double"); await game.classicMode.startBattle([Species.BULBASAUR, Species.BULBASAUR]); // Clear the ability of the ally to isolate the test @@ -81,7 +81,7 @@ describe("Abilities - Flower Veil", () => { }); it("should prevent status conditions from moves like Thunder Wave for a grass user and its grass allies", async () => { - game.override.enemyMoveset([Moves.THUNDER_WAVE]).moveset([Moves.SPLASH]).battleType("double"); + game.override.enemyMoveset([Moves.THUNDER_WAVE]).moveset([Moves.SPLASH]).battleStyle("double"); vi.spyOn(allMoves[Moves.THUNDER_WAVE], "accuracy", "get").mockReturnValue(100); await game.classicMode.startBattle([Species.BULBASAUR]); @@ -93,7 +93,7 @@ describe("Abilities - Flower Veil", () => { }); it("should not prevent status conditions for a non-grass user and its non-grass allies", async () => { - game.override.enemyMoveset([Moves.THUNDER_WAVE]).moveset([Moves.SPLASH]).battleType("double"); + game.override.enemyMoveset([Moves.THUNDER_WAVE]).moveset([Moves.SPLASH]).battleStyle("double"); await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); const [user, ally] = game.scene.getPlayerField(); vi.spyOn(allMoves[Moves.THUNDER_WAVE], "accuracy", "get").mockReturnValue(100); @@ -113,7 +113,7 @@ describe("Abilities - Flower Veil", () => { *******************************************/ it("should prevent the status drops from enemies for the a grass user and its grass allies", async () => { - game.override.enemyMoveset([Moves.GROWL]).moveset([Moves.SPLASH]).battleType("double"); + game.override.enemyMoveset([Moves.GROWL]).moveset([Moves.SPLASH]).battleStyle("double"); await game.classicMode.startBattle([Species.BULBASAUR, Species.BULBASAUR]); const [user, ally] = game.scene.getPlayerField(); // Clear the ally ability to isolate the test @@ -126,7 +126,7 @@ describe("Abilities - Flower Veil", () => { }); it("should not prevent status drops for a non-grass user and its non-grass allies", async () => { - game.override.enemyMoveset([Moves.GROWL]).moveset([Moves.SPLASH]).battleType("double"); + game.override.enemyMoveset([Moves.GROWL]).moveset([Moves.SPLASH]).battleStyle("double"); await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); const [user, ally] = game.scene.getPlayerField(); // Clear the ally ability to isolate the test @@ -139,7 +139,7 @@ describe("Abilities - Flower Veil", () => { }); it("should not prevent self-inflicted stat drops from moves like Close Combat for a user or its allies", async () => { - game.override.moveset([Moves.CLOSE_COMBAT]).battleType("double"); + game.override.moveset([Moves.CLOSE_COMBAT]).battleStyle("double"); await game.classicMode.startBattle([Species.BULBASAUR, Species.BULBASAUR]); const [user, ally] = game.scene.getPlayerField(); // Clear the ally ability to isolate the test diff --git a/test/abilities/forecast.test.ts b/test/abilities/forecast.test.ts index a25af32537d..03b5d993a54 100644 --- a/test/abilities/forecast.test.ts +++ b/test/abilities/forecast.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { Abilities } from "#app/enums/abilities"; import { WeatherType } from "#app/enums/weather-type"; import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; @@ -75,7 +75,7 @@ describe("Abilities - Forecast", () => { async () => { game.override .moveset([Moves.RAIN_DANCE, Moves.SUNNY_DAY, Moves.SNOWSCAPE, Moves.SPLASH]) - .battleType("double") + .battleStyle("double") .starterForms({ [Species.KYOGRE]: 1, [Species.GROUDON]: 1, diff --git a/test/abilities/friend_guard.test.ts b/test/abilities/friend_guard.test.ts index 30175fe37e0..43a378c47a2 100644 --- a/test/abilities/friend_guard.test.ts +++ b/test/abilities/friend_guard.test.ts @@ -5,7 +5,7 @@ import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { BattlerIndex } from "#app/battle"; -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { allMoves } from "#app/data/moves/move"; import { MoveCategory } from "#enums/MoveCategory"; @@ -26,7 +26,7 @@ describe("Moves - Friend Guard", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset([Moves.TACKLE, Moves.SPLASH, Moves.DRAGON_RAGE]) .enemySpecies(Species.SHUCKLE) @@ -50,7 +50,11 @@ describe("Moves - Friend Guard", () => { // Get the last return value from `getAttackDamage` const turn1Damage = spy.mock.results[spy.mock.results.length - 1].value.damage; // Making sure the test is controlled; turn 1 damage is equal to base damage (after rounding) - expect(turn1Damage).toBe(Math.floor(player1.getBaseDamage(enemy1, allMoves[Moves.TACKLE], MoveCategory.PHYSICAL))); + expect(turn1Damage).toBe( + Math.floor( + player1.getBaseDamage({ source: enemy1, move: allMoves[Moves.TACKLE], moveCategory: MoveCategory.PHYSICAL }), + ), + ); vi.spyOn(player2, "getAbility").mockReturnValue(allAbilities[Abilities.FRIEND_GUARD]); @@ -64,7 +68,10 @@ describe("Moves - Friend Guard", () => { const turn2Damage = spy.mock.results[spy.mock.results.length - 1].value.damage; // With the ally's Friend Guard, damage should have been reduced from base damage by 25% expect(turn2Damage).toBe( - Math.floor(player1.getBaseDamage(enemy1, allMoves[Moves.TACKLE], MoveCategory.PHYSICAL) * 0.75), + Math.floor( + player1.getBaseDamage({ source: enemy1, move: allMoves[Moves.TACKLE], moveCategory: MoveCategory.PHYSICAL }) * + 0.75, + ), ); }); diff --git a/test/abilities/galvanize.test.ts b/test/abilities/galvanize.test.ts deleted file mode 100644 index c1e02c6c8d8..00000000000 --- a/test/abilities/galvanize.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { BattlerIndex } from "#app/battle"; -import { allMoves } from "#app/data/moves/move"; -import { PokemonType } from "#enums/pokemon-type"; -import { Abilities } from "#app/enums/abilities"; -import { Moves } from "#app/enums/moves"; -import { Species } from "#app/enums/species"; -import { HitResult } from "#app/field/pokemon"; -import GameManager from "#test/testUtils/gameManager"; -import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; - -describe("Abilities - Galvanize", () => { - let phaserGame: Phaser.Game; - let game: GameManager; - - beforeAll(() => { - phaserGame = new Phaser.Game({ - type: Phaser.HEADLESS, - }); - }); - - afterEach(() => { - game.phaseInterceptor.restoreOg(); - }); - - beforeEach(() => { - game = new GameManager(phaserGame); - - game.override - .battleType("single") - .startingLevel(100) - .ability(Abilities.GALVANIZE) - .moveset([Moves.TACKLE, Moves.REVELATION_DANCE, Moves.FURY_SWIPES]) - .enemySpecies(Species.DUSCLOPS) - .enemyAbility(Abilities.BALL_FETCH) - .enemyMoveset(Moves.SPLASH) - .enemyLevel(100); - }); - - it("should change Normal-type attacks to Electric type and boost their power", async () => { - await game.startBattle(); - - const playerPokemon = game.scene.getPlayerPokemon()!; - vi.spyOn(playerPokemon, "getMoveType"); - - const enemyPokemon = game.scene.getEnemyPokemon()!; - vi.spyOn(enemyPokemon, "apply"); - - const move = allMoves[Moves.TACKLE]; - vi.spyOn(move, "calculateBattlePower"); - - game.move.select(Moves.TACKLE); - - await game.phaseInterceptor.to("BerryPhase", false); - - expect(playerPokemon.getMoveType).toHaveLastReturnedWith(PokemonType.ELECTRIC); - expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.EFFECTIVE); - expect(move.calculateBattlePower).toHaveReturnedWith(48); - expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp()); - }); - - it("should cause Normal-type attacks to activate Volt Absorb", async () => { - game.override.enemyAbility(Abilities.VOLT_ABSORB); - - await game.startBattle(); - - const playerPokemon = game.scene.getPlayerPokemon()!; - vi.spyOn(playerPokemon, "getMoveType"); - - const enemyPokemon = game.scene.getEnemyPokemon()!; - vi.spyOn(enemyPokemon, "apply"); - - enemyPokemon.hp = Math.floor(enemyPokemon.getMaxHp() * 0.8); - - game.move.select(Moves.TACKLE); - - await game.phaseInterceptor.to("BerryPhase", false); - - expect(playerPokemon.getMoveType).toHaveLastReturnedWith(PokemonType.ELECTRIC); - expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.NO_EFFECT); - expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp()); - }); - - it("should not change the type of variable-type moves", async () => { - game.override.enemySpecies(Species.MIGHTYENA); - - await game.startBattle([Species.ESPEON]); - - const playerPokemon = game.scene.getPlayerPokemon()!; - vi.spyOn(playerPokemon, "getMoveType"); - - const enemyPokemon = game.scene.getEnemyPokemon()!; - vi.spyOn(enemyPokemon, "apply"); - - game.move.select(Moves.REVELATION_DANCE); - await game.phaseInterceptor.to("BerryPhase", false); - - expect(playerPokemon.getMoveType).not.toHaveLastReturnedWith(PokemonType.ELECTRIC); - expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.NO_EFFECT); - expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp()); - }); - - it("should affect all hits of a Normal-type multi-hit move", async () => { - await game.startBattle(); - - const playerPokemon = game.scene.getPlayerPokemon()!; - vi.spyOn(playerPokemon, "getMoveType"); - - const enemyPokemon = game.scene.getEnemyPokemon()!; - vi.spyOn(enemyPokemon, "apply"); - - game.move.select(Moves.FURY_SWIPES); - await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); - await game.move.forceHit(); - - await game.phaseInterceptor.to("MoveEffectPhase"); - expect(playerPokemon.turnData.hitCount).toBeGreaterThan(1); - expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp()); - - while (playerPokemon.turnData.hitsLeft > 0) { - const enemyStartingHp = enemyPokemon.hp; - await game.phaseInterceptor.to("MoveEffectPhase"); - - expect(playerPokemon.getMoveType).toHaveLastReturnedWith(PokemonType.ELECTRIC); - expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp); - } - - expect(enemyPokemon.apply).not.toHaveReturnedWith(HitResult.NO_EFFECT); - }); -}); diff --git a/test/abilities/good_as_gold.test.ts b/test/abilities/good_as_gold.test.ts index 7cc543c4a0d..09bdaafb11f 100644 --- a/test/abilities/good_as_gold.test.ts +++ b/test/abilities/good_as_gold.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { ArenaTagSide } from "#app/data/arena-tag"; import { ArenaTagType } from "#app/enums/arena-tag-type"; import { BattlerTagType } from "#app/enums/battler-tag-type"; @@ -32,7 +32,7 @@ describe("Abilities - Good As Gold", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.GOOD_AS_GOLD) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) @@ -49,7 +49,7 @@ describe("Abilities - Good As Gold", () => { await game.phaseInterceptor.to("BerryPhase"); - expect(player.battleData.abilitiesApplied[0]).toBe(Abilities.GOOD_AS_GOLD); + expect(player.waveData.abilitiesApplied).toContain(Abilities.GOOD_AS_GOLD); expect(player.getStatStage(Stat.ATK)).toBe(0); }); @@ -63,7 +63,7 @@ describe("Abilities - Good As Gold", () => { }); it("should not block any status moves that target the field, one side, or all pokemon", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.enemyMoveset([Moves.STEALTH_ROCK, Moves.HAZE]); game.override.moveset([Moves.SWORDS_DANCE, Moves.SAFEGUARD]); await game.classicMode.startBattle([Species.MAGIKARP, Species.FEEBAS]); @@ -85,7 +85,7 @@ describe("Abilities - Good As Gold", () => { }); it("should not block field targeted effects in singles", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemyMoveset([Moves.SPIKES]); await game.classicMode.startBattle([Species.MAGIKARP]); @@ -96,7 +96,7 @@ describe("Abilities - Good As Gold", () => { }); it("should block the ally's helping hand", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.HELPING_HAND, Moves.TACKLE]); await game.classicMode.startBattle([Species.MAGIKARP, Species.FEEBAS]); @@ -108,7 +108,7 @@ describe("Abilities - Good As Gold", () => { }); it("should block the ally's heal bell, but only if the good as gold user is on the field", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.HEAL_BELL, Moves.SPLASH]); game.override.statusEffect(StatusEffect.BURN); await game.classicMode.startBattle([Species.MAGIKARP, Species.FEEBAS, Species.ABRA]); @@ -130,7 +130,7 @@ describe("Abilities - Good As Gold", () => { }); it("should not block field targeted effects like rain dance", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemyMoveset([Moves.RAIN_DANCE]); game.override.weather(WeatherType.NONE); await game.classicMode.startBattle([Species.MAGIKARP]); diff --git a/test/abilities/gorilla_tactics.test.ts b/test/abilities/gorilla_tactics.test.ts index 48dab262b82..edaf1669809 100644 --- a/test/abilities/gorilla_tactics.test.ts +++ b/test/abilities/gorilla_tactics.test.ts @@ -23,7 +23,7 @@ describe("Abilities - Gorilla Tactics", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset([Moves.SPLASH, Moves.DISABLE]) .enemySpecies(Species.MAGIKARP) diff --git a/test/abilities/gulp_missile.test.ts b/test/abilities/gulp_missile.test.ts index 8ebd583d3ab..4db2ae4190d 100644 --- a/test/abilities/gulp_missile.test.ts +++ b/test/abilities/gulp_missile.test.ts @@ -42,7 +42,7 @@ describe("Abilities - Gulp Missile", () => { game = new GameManager(phaserGame); game.override .disableCrits() - .battleType("single") + .battleStyle("single") .moveset([Moves.SURF, Moves.DIVE, Moves.SPLASH, Moves.SUBSTITUTE]) .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/harvest.test.ts b/test/abilities/harvest.test.ts new file mode 100644 index 00000000000..23c0ed9088c --- /dev/null +++ b/test/abilities/harvest.test.ts @@ -0,0 +1,346 @@ +import { BattlerIndex } from "#app/battle"; +import { PostTurnRestoreBerryAbAttr } from "#app/data/abilities/ability"; +import type Pokemon from "#app/field/pokemon"; +import { BerryModifier, PreserveBerryModifier } from "#app/modifier/modifier"; +import type { ModifierOverride } from "#app/modifier/modifier-type"; +import type { BooleanHolder } from "#app/utils/common"; +import { Abilities } from "#enums/abilities"; +import { BerryType } from "#enums/berry-type"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { Stat } from "#enums/stat"; +import { WeatherType } from "#enums/weather-type"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Abilities - Harvest", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + const getPlayerBerries = () => + game.scene.getModifiers(BerryModifier, true).filter(b => b.pokemonId === game.scene.getPlayerPokemon()?.id); + + /** Check whether the player's Modifiers contains the specified berries and nothing else. */ + function expectBerriesContaining(...berries: ModifierOverride[]): void { + const actualBerries: ModifierOverride[] = getPlayerBerries().map( + // only grab berry type and quantity since that's literally all we care about + b => ({ name: "BERRY", type: b.berryType, count: b.getStackCount() }), + ); + expect(actualBerries).toEqual(berries); + } + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH, Moves.NATURAL_GIFT, Moves.FALSE_SWIPE, Moves.GASTRO_ACID]) + .ability(Abilities.HARVEST) + .startingLevel(100) + .battleStyle("single") + .disableCrits() + .statusActivation(false) // Since we're using nuzzle to proc both enigma and sitrus berries + .weather(WeatherType.SUNNY) // guaranteed recovery + .enemyLevel(1) + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset([Moves.SPLASH, Moves.NUZZLE, Moves.KNOCK_OFF, Moves.INCINERATE]); + }); + + it("replenishes eaten berries", async () => { + game.override.startingHeldItems([{ name: "BERRY", type: BerryType.LUM, count: 1 }]); + await game.classicMode.startBattle([Species.FEEBAS]); + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.NUZZLE); + await game.phaseInterceptor.to("BerryPhase"); + expect(getPlayerBerries()).toHaveLength(0); + expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toHaveLength(1); + await game.phaseInterceptor.to("TurnEndPhase"); + + expectBerriesContaining({ name: "BERRY", type: BerryType.LUM, count: 1 }); + expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); + }); + + it("tracks berries eaten while disabled/not present", async () => { + // Note: this also checks for harvest not being present as neutralizing gas works by making + // the game consider all other pokemon to *not* have their respective abilities. + game.override + .startingHeldItems([ + { name: "BERRY", type: BerryType.ENIGMA, count: 2 }, + { name: "BERRY", type: BerryType.LUM, count: 2 }, + ]) + .enemyAbility(Abilities.NEUTRALIZING_GAS); + await game.classicMode.startBattle([Species.MILOTIC]); + + const milotic = game.scene.getPlayerPokemon()!; + expect(milotic).toBeDefined(); + + // Chug a few berries without harvest (should get tracked) + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.NUZZLE); + await game.toNextTurn(); + + expect(milotic.battleData.berriesEaten).toEqual(expect.arrayContaining([BerryType.ENIGMA, BerryType.LUM])); + expect(getPlayerBerries()).toHaveLength(2); + + // Give ourselves harvest and disable enemy neut gas, + // but force our roll to fail so we don't accidentally recover anything + vi.spyOn(PostTurnRestoreBerryAbAttr.prototype, "canApplyPostTurn").mockReturnValueOnce(false); + game.override.ability(Abilities.HARVEST); + game.move.select(Moves.GASTRO_ACID); + await game.forceEnemyMove(Moves.NUZZLE); + + await game.toNextTurn(); + + expect(milotic.battleData.berriesEaten).toEqual( + expect.arrayContaining([BerryType.ENIGMA, BerryType.LUM, BerryType.ENIGMA, BerryType.LUM]), + ); + expect(getPlayerBerries()).toHaveLength(0); + + // proc a high roll and we _should_ get a berry back! + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.toNextTurn(); + + expect(milotic.battleData.berriesEaten).toHaveLength(3); + expect(getPlayerBerries()).toHaveLength(1); + }); + + it("remembers berries eaten array across waves", async () => { + game.override + .startingHeldItems([{ name: "BERRY", type: BerryType.PETAYA, count: 2 }]) + .ability(Abilities.BALL_FETCH); // don't actually need harvest for this test + await game.classicMode.startBattle([Species.REGIELEKI]); + + const regieleki = game.scene.getPlayerPokemon()!; + regieleki.hp = 1; + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.doKillOpponents(); + await game.phaseInterceptor.to("TurnEndPhase"); + + // ate 1 berry without recovering (no harvest) + expect(regieleki.battleData.berriesEaten).toEqual([BerryType.PETAYA]); + expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA }); + expect(regieleki.getStatStage(Stat.SPATK)).toBe(1); + + await game.toNextWave(); + + expect(regieleki.battleData.berriesEaten).toEqual([BerryType.PETAYA]); + expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA }); + expect(regieleki.getStatStage(Stat.SPATK)).toBe(1); + }); + + it("keeps harvested berries across reloads", async () => { + game.override + .startingHeldItems([{ name: "BERRY", type: BerryType.PETAYA, count: 1 }]) + .moveset([Moves.SPLASH, Moves.EARTHQUAKE]) + .enemyMoveset([Moves.SUPER_FANG, Moves.HEAL_PULSE]) + .enemyAbility(Abilities.COMPOUND_EYES); + await game.classicMode.startBattle([Species.REGIELEKI]); + + const regieleki = game.scene.getPlayerPokemon()!; + regieleki.hp = regieleki.getMaxHp() / 4 + 1; + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SUPER_FANG); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.toNextTurn(); + + // ate 1 berry and recovered it + expect(regieleki.battleData.berriesEaten).toEqual([]); + expect(getPlayerBerries()).toEqual([expect.objectContaining({ berryType: BerryType.PETAYA, stackCount: 1 })]); + expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1); + + // heal up so harvest doesn't proc and kill enemy + game.move.select(Moves.EARTHQUAKE); + await game.forceEnemyMove(Moves.HEAL_PULSE); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.toNextWave(); + + expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA }); + expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1); + + await game.reload.reloadSession(); + + expect(regieleki.battleData.berriesEaten).toEqual([]); + expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA }); + expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1); + }); + + it("cannot restore capped berries", async () => { + const initBerries: ModifierOverride[] = [ + { name: "BERRY", type: BerryType.LUM, count: 2 }, + { name: "BERRY", type: BerryType.STARF, count: 2 }, + ]; + game.override.startingHeldItems(initBerries); + await game.classicMode.startBattle([Species.FEEBAS]); + + const feebas = game.scene.getPlayerPokemon()!; + feebas.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF]; + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.phaseInterceptor.to("BerryPhase"); + + // Force RNG roll to hit the first berry we find that matches. + // This does nothing on a success (since there'd only be a starf left to grab), + // but ensures we don't accidentally let any false positives through. + vi.spyOn(Phaser.Math.RND, "integerInRange").mockReturnValue(0); + await game.phaseInterceptor.to("TurnEndPhase"); + + // recovered a starf + expectBerriesContaining( + { name: "BERRY", type: BerryType.LUM, count: 2 }, + { name: "BERRY", type: BerryType.STARF, count: 3 }, + ); + }); + + it("does nothing if all berries are capped", async () => { + const initBerries: ModifierOverride[] = [ + { name: "BERRY", type: BerryType.LUM, count: 2 }, + { name: "BERRY", type: BerryType.STARF, count: 3 }, + ]; + game.override.startingHeldItems(initBerries); + await game.classicMode.startBattle([Species.FEEBAS]); + + const player = game.scene.getPlayerPokemon()!; + player.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF]; + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase"); + + expectBerriesContaining(...initBerries); + }); + + describe("move/ability interactions", () => { + it("cannot restore incinerated berries", async () => { + game.override.startingHeldItems([{ name: "BERRY", type: BerryType.STARF, count: 3 }]); + await game.classicMode.startBattle([Species.FEEBAS]); + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.INCINERATE); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); + }); + + it("cannot restore knocked off berries", async () => { + game.override.startingHeldItems([{ name: "BERRY", type: BerryType.STARF, count: 3 }]); + await game.classicMode.startBattle([Species.FEEBAS]); + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.KNOCK_OFF); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); + }); + + it("can restore berries eaten by Teatime", async () => { + const initBerries: ModifierOverride[] = [{ name: "BERRY", type: BerryType.STARF, count: 1 }]; + game.override.startingHeldItems(initBerries).enemyMoveset(Moves.TEATIME); + await game.classicMode.startBattle([Species.FEEBAS]); + + // nom nom the berr berr yay yay + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); + expectBerriesContaining(...initBerries); + }); + + it("cannot restore Plucked berries for either side", async () => { + const initBerries: ModifierOverride[] = [{ name: "BERRY", type: BerryType.PETAYA, count: 1 }]; + game.override.startingHeldItems(initBerries).enemyAbility(Abilities.HARVEST).enemyMoveset(Moves.PLUCK); + await game.classicMode.startBattle([Species.FEEBAS]); + + // gobble gobble gobble + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("BerryPhase"); + + // pluck triggers harvest for neither side + expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); + expect(game.scene.getEnemyPokemon()?.battleData.berriesEaten).toEqual([]); + expect(getPlayerBerries()).toEqual([]); + }); + + it("cannot restore berries preserved via Berry Pouch", async () => { + // mock berry pouch to have a 100% success rate + vi.spyOn(PreserveBerryModifier.prototype, "apply").mockImplementation( + (_pokemon: Pokemon, doPreserve: BooleanHolder): boolean => { + doPreserve.value = false; + return true; + }, + ); + + const initBerries: ModifierOverride[] = [{ name: "BERRY", type: BerryType.PETAYA, count: 1 }]; + game.override.startingHeldItems(initBerries).startingModifier([{ name: "BERRY_POUCH", count: 1 }]); + await game.classicMode.startBattle([Species.FEEBAS]); + + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase", false); + + // won't trigger harvest since we didn't lose the berry (it just doesn't ever add it to the array) + expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); + expectBerriesContaining(...initBerries); + }); + + it("can restore stolen berries", async () => { + const initBerries: ModifierOverride[] = [{ name: "BERRY", type: BerryType.SITRUS, count: 1 }]; + game.override.enemyHeldItems(initBerries).passiveAbility(Abilities.MAGICIAN).hasPassiveAbility(true); + await game.classicMode.startBattle([Species.MEOWSCARADA]); + + // pre damage + const player = game.scene.getPlayerPokemon()!; + player.hp = 1; + + // steal a sitrus and immediately consume it + game.move.select(Moves.FALSE_SWIPE); + await game.forceEnemyMove(Moves.SPLASH); + await game.phaseInterceptor.to("BerryPhase"); + expect(player.battleData.berriesEaten).toEqual([BerryType.SITRUS]); + + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(player.battleData.berriesEaten).toEqual([]); + expectBerriesContaining(...initBerries); + }); + + // TODO: Enable once fling actually works...??? + it.todo("can restore berries flung at user", async () => { + game.override.enemyHeldItems([{ name: "BERRY", type: BerryType.STARF, count: 1 }]).enemyMoveset(Moves.FLING); + await game.classicMode.startBattle([Species.FEEBAS]); + + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toBe([]); + expect(getPlayerBerries()).toEqual([]); + }); + + // TODO: Enable once Nat Gift gets implemented...??? + it.todo("can restore berries consumed via Natural Gift", async () => { + const initBerries: ModifierOverride[] = [{ name: "BERRY", type: BerryType.STARF, count: 1 }]; + game.override.startingHeldItems(initBerries); + await game.classicMode.startBattle([Species.FEEBAS]); + + game.move.select(Moves.NATURAL_GIFT); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toHaveLength(0); + expectBerriesContaining(...initBerries); + }); + }); +}); diff --git a/test/abilities/healer.test.ts b/test/abilities/healer.test.ts new file mode 100644 index 00000000000..d292ad0f625 --- /dev/null +++ b/test/abilities/healer.test.ts @@ -0,0 +1,97 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi, type MockInstance } from "vitest"; +import { isNullOrUndefined } from "#app/utils/common"; +import { PostTurnResetStatusAbAttr } from "#app/data/abilities/ability"; +import { allAbilities } from "#app/data/data-lists"; +import type Pokemon from "#app/field/pokemon"; + +describe("Abilities - Healer", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + let healerAttrSpy: MockInstance; + let healerAttr: PostTurnResetStatusAbAttr; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + healerAttrSpy.mockRestore(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("double") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + + healerAttr = allAbilities[Abilities.HEALER].getAttrs(PostTurnResetStatusAbAttr)[0]; + healerAttrSpy = vi + .spyOn(healerAttr, "getCondition") + .mockReturnValue((pokemon: Pokemon) => !isNullOrUndefined(pokemon.getAlly())); + }); + + it("should not queue a message phase for healing if the ally has fainted", async () => { + game.override.moveset([Moves.SPLASH, Moves.LUNAR_DANCE]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + const user = game.scene.getPlayerPokemon()!; + // Only want one magikarp to have the ability. + vi.spyOn(user, "getAbility").mockReturnValue(allAbilities[Abilities.HEALER]); + game.move.select(Moves.SPLASH); + // faint the ally + game.move.select(Moves.LUNAR_DANCE, 1); + const abSpy = vi.spyOn(healerAttr, "canApplyPostTurn"); + await game.phaseInterceptor.to("TurnEndPhase"); + + // It's not enough to just test that the ally still has its status. + // We need to ensure that the ability failed to meet its condition + expect(abSpy).toHaveReturnedWith(false); + + // Explicitly restore the mock to ensure pollution doesn't happen + abSpy.mockRestore(); + }); + + it("should heal the status of an ally if the ally has a status", async () => { + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + const [user, ally] = game.scene.getPlayerField(); + // Only want one magikarp to have the ability. + vi.spyOn(user, "getAbility").mockReturnValue(allAbilities[Abilities.HEALER]); + expect(ally.trySetStatus(StatusEffect.BURN)).toBe(true); + game.move.select(Moves.SPLASH); + game.move.select(Moves.SPLASH, 1); + + await game.phaseInterceptor.to("TurnEndPhase"); + await game.toNextTurn(); + + expect(ally.status?.effect, "status effect was not healed").toBeFalsy(); + }); + + // TODO: Healer is currently checked before the + it.todo("should heal a burn before its end of turn damage", async () => { + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + const [user, ally] = game.scene.getPlayerField(); + // Only want one magikarp to have the ability. + vi.spyOn(user, "getAbility").mockReturnValue(allAbilities[Abilities.HEALER]); + expect(ally.trySetStatus(StatusEffect.BURN)).toBe(true); + game.move.select(Moves.SPLASH); + game.move.select(Moves.SPLASH, 1); + await game.phaseInterceptor.to("TurnEndPhase"); + await game.toNextTurn(); + + expect(ally.status?.effect, "status effect was not healed").toBeFalsy(); + expect(ally.hp).toBe(ally.getMaxHp()); + }); +}); diff --git a/test/abilities/heatproof.test.ts b/test/abilities/heatproof.test.ts index fa065d1ed03..016237bb02f 100644 --- a/test/abilities/heatproof.test.ts +++ b/test/abilities/heatproof.test.ts @@ -1,7 +1,7 @@ import { Species } from "#app/enums/species"; import { StatusEffect } from "#app/enums/status-effect"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; -import { toDmgValue } from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import GameManager from "#test/testUtils/gameManager"; @@ -25,7 +25,7 @@ describe("Abilities - Heatproof", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.CHARMANDER) .enemyAbility(Abilities.HEATPROOF) diff --git a/test/abilities/honey_gather.test.ts b/test/abilities/honey_gather.test.ts index bea5c25c878..a74a40c9c1e 100644 --- a/test/abilities/honey_gather.test.ts +++ b/test/abilities/honey_gather.test.ts @@ -28,7 +28,7 @@ describe("Abilities - Honey Gather", () => { .startingLevel(100) .ability(Abilities.HONEY_GATHER) .passiveAbility(Abilities.RUN_AWAY) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/hustle.test.ts b/test/abilities/hustle.test.ts index 40197cf9e97..bf2889eab63 100644 --- a/test/abilities/hustle.test.ts +++ b/test/abilities/hustle.test.ts @@ -27,7 +27,7 @@ describe("Abilities - Hustle", () => { .ability(Abilities.HUSTLE) .moveset([Moves.TACKLE, Moves.GIGA_DRAIN, Moves.FISSURE]) .disableCrits() - .battleType("single") + .battleStyle("single") .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.SHUCKLE) .enemyAbility(Abilities.BALL_FETCH); diff --git a/test/abilities/hyper_cutter.test.ts b/test/abilities/hyper_cutter.test.ts index fe5623e4e0f..99a9db28025 100644 --- a/test/abilities/hyper_cutter.test.ts +++ b/test/abilities/hyper_cutter.test.ts @@ -23,7 +23,7 @@ describe("Abilities - Hyper Cutter", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .moveset([Moves.SAND_ATTACK, Moves.NOBLE_ROAR, Moves.DEFOG, Moves.OCTOLOCK]) .ability(Abilities.BALL_FETCH) .enemySpecies(Species.SHUCKLE) diff --git a/test/abilities/ice_face.test.ts b/test/abilities/ice_face.test.ts index e85794928d6..38269c29af1 100644 --- a/test/abilities/ice_face.test.ts +++ b/test/abilities/ice_face.test.ts @@ -30,7 +30,7 @@ describe("Abilities - Ice Face", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.EISCUE); game.override.enemyAbility(Abilities.ICE_FACE); game.override.moveset([Moves.TACKLE, Moves.ICE_BEAM, Moves.TOXIC_THREAD, Moves.HAIL]); diff --git a/test/abilities/illuminate.test.ts b/test/abilities/illuminate.test.ts index 6518fec989b..ba26ed3b7af 100644 --- a/test/abilities/illuminate.test.ts +++ b/test/abilities/illuminate.test.ts @@ -29,7 +29,7 @@ describe("Abilities - Illuminate", () => { }); it("should prevent ACC stat stage from being lowered", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); await game.classicMode.startBattle(); diff --git a/test/abilities/illusion.test.ts b/test/abilities/illusion.test.ts new file mode 100644 index 00000000000..998d29f169c --- /dev/null +++ b/test/abilities/illusion.test.ts @@ -0,0 +1,157 @@ +import { Gender } from "#app/data/gender"; +import { PokeballType } from "#app/enums/pokeball"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Illusion", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .battleStyle("single") + .enemySpecies(Species.ZORUA) + .enemyAbility(Abilities.ILLUSION) + .enemyMoveset(Moves.TACKLE) + .enemyHeldItems([{ name: "WIDE_LENS", count: 3 }]) + .moveset([Moves.WORRY_SEED, Moves.SOAK, Moves.TACKLE]) + .startingHeldItems([{ name: "WIDE_LENS", count: 3 }]); + }); + + it("creates illusion at the start", async () => { + await game.classicMode.startBattle([Species.ZOROARK, Species.FEEBAS]); + const zoroark = game.scene.getPlayerPokemon()!; + const zorua = game.scene.getEnemyPokemon()!; + + expect(!!zoroark.summonData.illusion).equals(true); + expect(!!zorua.summonData.illusion).equals(true); + }); + + it("break after receiving damaging move", async () => { + await game.classicMode.startBattle([Species.FEEBAS]); + game.move.select(Moves.TACKLE); + + await game.phaseInterceptor.to("TurnEndPhase"); + + const zorua = game.scene.getEnemyPokemon()!; + + expect(!!zorua.summonData.illusion).equals(false); + expect(zorua.name).equals("Zorua"); + }); + + it("break after getting ability changed", async () => { + await game.classicMode.startBattle([Species.FEEBAS]); + game.move.select(Moves.WORRY_SEED); + + await game.phaseInterceptor.to("TurnEndPhase"); + + const zorua = game.scene.getEnemyPokemon()!; + + expect(!!zorua.summonData.illusion).equals(false); + }); + + it("break with neutralizing gas", async () => { + game.override.enemyAbility(Abilities.NEUTRALIZING_GAS); + await game.classicMode.startBattle([Species.KOFFING]); + + const zorua = game.scene.getEnemyPokemon()!; + + expect(!!zorua.summonData.illusion).equals(false); + }); + + it("causes enemy AI to consider the illusion's type instead of the actual type when considering move effectiveness", async () => { + game.override.enemyMoveset([Moves.FLAMETHROWER, Moves.PSYCHIC, Moves.TACKLE]); + await game.classicMode.startBattle([Species.ZOROARK, Species.FEEBAS]); + + const enemy = game.scene.getEnemyPokemon()!; + const zoroark = game.scene.getPlayerPokemon()!; + + const flameThrower = enemy.getMoveset()[0]!.getMove(); + const psychic = enemy.getMoveset()[1]!.getMove(); + const flameThrowerEffectiveness = zoroark.getAttackTypeEffectiveness( + flameThrower.type, + enemy, + undefined, + undefined, + flameThrower, + true, + ); + const psychicEffectiveness = zoroark.getAttackTypeEffectiveness( + psychic.type, + enemy, + undefined, + undefined, + psychic, + true, + ); + expect(psychicEffectiveness).above(flameThrowerEffectiveness); + }); + + it("does not break from indirect damage", async () => { + game.override.enemySpecies(Species.GIGALITH); + game.override.enemyAbility(Abilities.SAND_STREAM); + game.override.enemyMoveset(Moves.WILL_O_WISP); + game.override.moveset([Moves.FLARE_BLITZ]); + + await game.classicMode.startBattle([Species.ZOROARK, Species.AZUMARILL]); + + game.move.select(Moves.FLARE_BLITZ); + + await game.phaseInterceptor.to("TurnEndPhase"); + + const zoroark = game.scene.getPlayerPokemon()!; + + expect(!!zoroark.summonData.illusion).equals(true); + }); + + it("copies the the name, nickname, gender, shininess, and pokeball from the illusion source", async () => { + game.override.enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.ABRA, Species.ZOROARK, Species.AXEW]); + const axew = game.scene.getPlayerParty().at(2)!; + axew.shiny = true; + axew.nickname = btoa(unescape(encodeURIComponent("axew nickname"))); + axew.gender = Gender.FEMALE; + axew.pokeball = PokeballType.GREAT_BALL; + + game.doSwitchPokemon(1); + + await game.phaseInterceptor.to("TurnEndPhase"); + + const zoroark = game.scene.getPlayerPokemon()!; + + expect(zoroark.name).equals("Axew"); + expect(zoroark.getNameToRender()).equals("axew nickname"); + expect(zoroark.getGender(false, true)).equals(Gender.FEMALE); + expect(zoroark.isShiny(true)).equals(true); + expect(zoroark.getPokeball(true)).equals(PokeballType.GREAT_BALL); + }); + + it("breaks when suppressed", async () => { + game.override.moveset(Moves.GASTRO_ACID); + await game.classicMode.startBattle([Species.MAGIKARP]); + const zorua = game.scene.getEnemyPokemon()!; + + expect(!!zorua.summonData?.illusion).toBe(true); + + game.move.select(Moves.GASTRO_ACID); + await game.phaseInterceptor.to("BerryPhase"); + + expect(zorua.isFullHp()).toBe(true); + expect(!!zorua.summonData?.illusion).toBe(false); + }); +}); diff --git a/test/abilities/immunity.test.ts b/test/abilities/immunity.test.ts new file mode 100644 index 00000000000..dd9026cac50 --- /dev/null +++ b/test/abilities/immunity.test.ts @@ -0,0 +1,51 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Immunity", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove poison when gained", async () => { + game.override + .ability(Abilities.IMMUNITY) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.trySetStatus(StatusEffect.POISON); + expect(enemy?.status?.effect).toBe(StatusEffect.POISON); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.status).toBeNull(); + }); +}); diff --git a/test/abilities/imposter.test.ts b/test/abilities/imposter.test.ts index 2c7302d04b7..b5e902f442f 100644 --- a/test/abilities/imposter.test.ts +++ b/test/abilities/imposter.test.ts @@ -25,7 +25,7 @@ describe("Abilities - Imposter", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MEW) .enemyLevel(200) .enemyAbility(Abilities.BEAST_BOOST) diff --git a/test/abilities/infiltrator.test.ts b/test/abilities/infiltrator.test.ts index 6278439651c..1a9f802dd9c 100644 --- a/test/abilities/infiltrator.test.ts +++ b/test/abilities/infiltrator.test.ts @@ -30,7 +30,7 @@ describe("Abilities - Infiltrator", () => { game.override .moveset([Moves.TACKLE, Moves.WATER_GUN, Moves.SPORE, Moves.BABY_DOLL_EYES]) .ability(Abilities.INFILTRATOR) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) @@ -61,14 +61,14 @@ describe("Abilities - Infiltrator", () => { const player = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; - const preScreenDmg = enemy.getAttackDamage(player, allMoves[move]).damage; + const preScreenDmg = enemy.getAttackDamage({ source: player, move: allMoves[move] }).damage; game.scene.arena.addTag(tagType, 1, Moves.NONE, enemy.id, ArenaTagSide.ENEMY, true); - const postScreenDmg = enemy.getAttackDamage(player, allMoves[move]).damage; + const postScreenDmg = enemy.getAttackDamage({ source: player, move: allMoves[move] }).damage; expect(postScreenDmg).toBe(preScreenDmg); - expect(player.battleData.abilitiesApplied[0]).toBe(Abilities.INFILTRATOR); + expect(player.waveData.abilitiesApplied).toContain(Abilities.INFILTRATOR); }); it("should bypass the target's Safeguard", async () => { @@ -83,7 +83,7 @@ describe("Abilities - Infiltrator", () => { await game.phaseInterceptor.to("BerryPhase", false); expect(enemy.status?.effect).toBe(StatusEffect.SLEEP); - expect(player.battleData.abilitiesApplied[0]).toBe(Abilities.INFILTRATOR); + expect(player.waveData.abilitiesApplied).toContain(Abilities.INFILTRATOR); }); // TODO: fix this interaction to pass this test @@ -99,7 +99,7 @@ describe("Abilities - Infiltrator", () => { await game.phaseInterceptor.to("MoveEndPhase"); expect(enemy.getStatStage(Stat.ATK)).toBe(-1); - expect(player.battleData.abilitiesApplied[0]).toBe(Abilities.INFILTRATOR); + expect(player.waveData.abilitiesApplied).toContain(Abilities.INFILTRATOR); }); it("should bypass the target's Substitute", async () => { @@ -114,6 +114,6 @@ describe("Abilities - Infiltrator", () => { await game.phaseInterceptor.to("MoveEndPhase"); expect(enemy.getStatStage(Stat.ATK)).toBe(-1); - expect(player.battleData.abilitiesApplied[0]).toBe(Abilities.INFILTRATOR); + expect(player.waveData.abilitiesApplied).toContain(Abilities.INFILTRATOR); }); }); diff --git a/test/abilities/insomnia.test.ts b/test/abilities/insomnia.test.ts new file mode 100644 index 00000000000..49765a641b0 --- /dev/null +++ b/test/abilities/insomnia.test.ts @@ -0,0 +1,51 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Insomnia", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove sleep when gained", async () => { + game.override + .ability(Abilities.INSOMNIA) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.trySetStatus(StatusEffect.SLEEP); + expect(enemy?.status?.effect).toBe(StatusEffect.SLEEP); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.status).toBeNull(); + }); +}); diff --git a/test/abilities/intimidate.test.ts b/test/abilities/intimidate.test.ts index 53286d354c8..8db39270dcf 100644 --- a/test/abilities/intimidate.test.ts +++ b/test/abilities/intimidate.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/testUtils/gameManager"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Stat } from "#enums/stat"; import { getMovePosition } from "#test/testUtils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; @@ -25,7 +25,7 @@ describe("Abilities - Intimidate", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.RATTATA) .enemyAbility(Abilities.INTIMIDATE) .enemyPassiveAbility(Abilities.HYDRATION) @@ -38,9 +38,9 @@ describe("Abilities - Intimidate", () => { await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - game.setMode(Mode.MESSAGE); + game.setMode(UiMode.MESSAGE); game.endPhase(); }, () => game.isCurrentPhase("CommandPhase") || game.isCurrentPhase("TurnInitPhase"), @@ -65,13 +65,13 @@ describe("Abilities - Intimidate", () => { }, 20000); it("should lower ATK stat stage by 1 for every enemy Pokemon in a double battle on entry", async () => { - game.override.battleType("double").startingWave(3); + game.override.battleStyle("double").startingWave(3); await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - game.setMode(Mode.MESSAGE); + game.setMode(UiMode.MESSAGE); game.endPhase(); }, () => game.isCurrentPhase("CommandPhase") || game.isCurrentPhase("TurnInitPhase"), diff --git a/test/abilities/intrepid_sword.test.ts b/test/abilities/intrepid_sword.test.ts index 28d0cd02c7f..b30ae4a9bd0 100644 --- a/test/abilities/intrepid_sword.test.ts +++ b/test/abilities/intrepid_sword.test.ts @@ -22,7 +22,7 @@ describe("Abilities - Intrepid Sword", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.ZACIAN); game.override.enemyAbility(Abilities.INTREPID_SWORD); game.override.ability(Abilities.INTREPID_SWORD); diff --git a/test/abilities/libero.test.ts b/test/abilities/libero.test.ts index 22abf1c248f..4adb828180e 100644 --- a/test/abilities/libero.test.ts +++ b/test/abilities/libero.test.ts @@ -29,7 +29,7 @@ describe("Abilities - Libero", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.LIBERO); game.override.startingLevel(100); game.override.enemySpecies(Species.RATTATA); @@ -67,7 +67,7 @@ describe("Abilities - Libero", () => { game.move.select(Moves.AGILITY); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied.filter(a => a === Abilities.LIBERO)).toHaveLength(1); + expect(leadPokemon.waveData.abilitiesApplied).toContain(Abilities.LIBERO); const leadPokemonType = PokemonType[leadPokemon.getTypes()[0]]; const moveType = PokemonType[allMoves[Moves.AGILITY].type]; expect(leadPokemonType).not.toBe(moveType); @@ -99,7 +99,7 @@ describe("Abilities - Libero", () => { game.move.select(Moves.WEATHER_BALL); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO); + expect(leadPokemon.waveData.abilitiesApplied).toContain(Abilities.LIBERO); expect(leadPokemon.getTypes()).toHaveLength(1); const leadPokemonType = PokemonType[leadPokemon.getTypes()[0]], moveType = PokemonType[PokemonType.FIRE]; @@ -118,7 +118,7 @@ describe("Abilities - Libero", () => { game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO); + expect(leadPokemon.waveData.abilitiesApplied).toContain(Abilities.LIBERO); expect(leadPokemon.getTypes()).toHaveLength(1); const leadPokemonType = PokemonType[leadPokemon.getTypes()[0]], moveType = PokemonType[PokemonType.ICE]; @@ -214,7 +214,7 @@ describe("Abilities - Libero", () => { game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); + expect(leadPokemon.waveData.abilitiesApplied).not.toContain(Abilities.LIBERO); }); test("ability is not applied if pokemon is terastallized", async () => { @@ -230,7 +230,7 @@ describe("Abilities - Libero", () => { game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); + expect(leadPokemon.waveData.abilitiesApplied).not.toContain(Abilities.LIBERO); }); test("ability is not applied if pokemon uses struggle", async () => { @@ -244,7 +244,7 @@ describe("Abilities - Libero", () => { game.move.select(Moves.STRUGGLE); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); + expect(leadPokemon.waveData.abilitiesApplied).not.toContain(Abilities.LIBERO); }); test("ability is not applied if the pokemon's move fails", async () => { @@ -258,7 +258,7 @@ describe("Abilities - Libero", () => { game.move.select(Moves.BURN_UP); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.LIBERO); + expect(leadPokemon.waveData.abilitiesApplied).not.toContain(Abilities.LIBERO); }); test("ability applies correctly even if the pokemon's Trick-or-Treat fails", async () => { @@ -293,7 +293,7 @@ describe("Abilities - Libero", () => { }); function testPokemonTypeMatchesDefaultMoveType(pokemon: PlayerPokemon, move: Moves) { - expect(pokemon.summonData.abilitiesApplied).toContain(Abilities.LIBERO); + expect(pokemon.waveData.abilitiesApplied).toContain(Abilities.LIBERO); expect(pokemon.getTypes()).toHaveLength(1); const pokemonType = PokemonType[pokemon.getTypes()[0]], moveType = PokemonType[allMoves[move].type]; diff --git a/test/abilities/lightningrod.test.ts b/test/abilities/lightningrod.test.ts index 986899353ff..21a03baf12b 100644 --- a/test/abilities/lightningrod.test.ts +++ b/test/abilities/lightningrod.test.ts @@ -26,7 +26,7 @@ describe("Abilities - Lightningrod", () => { game.override .moveset([Moves.SPLASH, Moves.SHOCK_WAVE]) .ability(Abilities.BALL_FETCH) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/limber.test.ts b/test/abilities/limber.test.ts new file mode 100644 index 00000000000..4cdaa86f44c --- /dev/null +++ b/test/abilities/limber.test.ts @@ -0,0 +1,51 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Limber", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove paralysis when gained", async () => { + game.override + .ability(Abilities.LIMBER) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.trySetStatus(StatusEffect.PARALYSIS); + expect(enemy?.status?.effect).toBe(StatusEffect.PARALYSIS); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.status).toBeNull(); + }); +}); diff --git a/test/abilities/magic_bounce.test.ts b/test/abilities/magic_bounce.test.ts index f9a076776aa..11131640a0f 100644 --- a/test/abilities/magic_bounce.test.ts +++ b/test/abilities/magic_bounce.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { ArenaTagSide } from "#app/data/arena-tag"; import { allMoves } from "#app/data/moves/move"; import { ArenaTagType } from "#app/enums/arena-tag-type"; @@ -30,7 +30,7 @@ describe("Abilities - Magic Bounce", () => { game = new GameManager(phaserGame); game.override .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .moveset([Moves.GROWL, Moves.SPLASH]) .disableCrits() .enemySpecies(Species.MAGIKARP) @@ -60,7 +60,7 @@ describe("Abilities - Magic Bounce", () => { }); it("should individually bounce back multi-target moves", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.GROWL, Moves.SPLASH]); await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); @@ -114,7 +114,7 @@ describe("Abilities - Magic Bounce", () => { }); it("should bounce back a spread status move against both pokemon", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.GROWL, Moves.SPLASH]); game.override.enemyMoveset([Moves.SPLASH]); await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); @@ -127,7 +127,7 @@ describe("Abilities - Magic Bounce", () => { }); it("should only bounce spikes back once in doubles when both targets have magic bounce", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.classicMode.startBattle([Species.MAGIKARP]); game.override.moveset([Moves.SPIKES]); @@ -227,7 +227,7 @@ describe("Abilities - Magic Bounce", () => { // TODO: stomping tantrum should consider moves that were bounced. it.todo("should cause stomping tantrum to double in power when the last move was bounced", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); await game.classicMode.startBattle([Species.MAGIKARP]); game.override.moveset([Moves.STOMPING_TANTRUM, Moves.CHARM]); @@ -309,7 +309,7 @@ describe("Abilities - Magic Bounce", () => { }); it("should always apply the leftmost available target's magic bounce when bouncing moves like sticky webs in doubles", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.STICKY_WEB, Moves.SPLASH, Moves.TRICK_ROOM]); await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); diff --git a/test/abilities/magma_armor.test.ts b/test/abilities/magma_armor.test.ts new file mode 100644 index 00000000000..c5af522ca6f --- /dev/null +++ b/test/abilities/magma_armor.test.ts @@ -0,0 +1,51 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Magma Armor", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove freeze when gained", async () => { + game.override + .ability(Abilities.MAGMA_ARMOR) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.trySetStatus(StatusEffect.FREEZE); + expect(enemy?.status?.effect).toBe(StatusEffect.FREEZE); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.status).toBeNull(); + }); +}); diff --git a/test/abilities/mimicry.test.ts b/test/abilities/mimicry.test.ts index df6f7905c83..598f5790aa8 100644 --- a/test/abilities/mimicry.test.ts +++ b/test/abilities/mimicry.test.ts @@ -25,7 +25,7 @@ describe("Abilities - Mimicry", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.MIMICRY) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyMoveset(Moves.SPLASH); diff --git a/test/abilities/mirror_armor.test.ts b/test/abilities/mirror_armor.test.ts index 6b0c3f10c84..bd61f39ba75 100644 --- a/test/abilities/mirror_armor.test.ts +++ b/test/abilities/mirror_armor.test.ts @@ -27,7 +27,7 @@ describe("Ability - Mirror Armor", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.RATTATA) .enemyMoveset([Moves.SPLASH, Moves.STICKY_WEB, Moves.TICKLE, Moves.OCTOLOCK]) .enemyAbility(Abilities.BALL_FETCH) @@ -71,7 +71,7 @@ describe("Ability - Mirror Armor", () => { }); it("Player side + double battle Intimidate - opponents each lose -2 atk", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.ability(Abilities.MIRROR_ARMOR); game.override.enemyAbility(Abilities.INTIMIDATE); await game.classicMode.startBattle([Species.BULBASAUR, Species.CHARMANDER]); @@ -93,7 +93,7 @@ describe("Ability - Mirror Armor", () => { }); it("Enemy side + double battle Intimidate - players each lose -2 atk", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.enemyAbility(Abilities.MIRROR_ARMOR); game.override.ability(Abilities.INTIMIDATE); await game.classicMode.startBattle([Species.BULBASAUR, Species.CHARMANDER]); @@ -134,7 +134,7 @@ describe("Ability - Mirror Armor", () => { }); it("Player side + double battle Intimidate + Tickle - opponents each lose -3 atk, -1 def", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.ability(Abilities.MIRROR_ARMOR); game.override.enemyAbility(Abilities.INTIMIDATE); await game.classicMode.startBattle([Species.BULBASAUR, Species.CHARMANDER]); @@ -288,7 +288,7 @@ describe("Ability - Mirror Armor", () => { }); it("Double battle + sticky web applied player side - player switches out and enemy 1 should lose -1 speed", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.ability(Abilities.MIRROR_ARMOR); await game.classicMode.startBattle([Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE]); diff --git a/test/abilities/mold_breaker.test.ts b/test/abilities/mold_breaker.test.ts new file mode 100644 index 00000000000..ba33909364f --- /dev/null +++ b/test/abilities/mold_breaker.test.ts @@ -0,0 +1,52 @@ +import { BattlerIndex } from "#app/battle"; +import { globalScene } from "#app/global-scene"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Mold Breaker", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.MOLD_BREAKER) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should turn off the ignore abilities arena variable after the user's move", async () => { + game.override + .enemyMoveset(Moves.SPLASH) + .ability(Abilities.MOLD_BREAKER) + .moveset([Moves.ERUPTION]) + .startingLevel(100) + .enemyLevel(2); + await game.classicMode.startBattle([Species.MAGIKARP]); + const enemy = game.scene.getEnemyPokemon()!; + + expect(enemy.isFainted()).toBe(false); + game.move.select(Moves.SPLASH); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.phaseInterceptor.to("MoveEndPhase", true); + expect(globalScene.arena.ignoreAbilities).toBe(false); + }); +}); diff --git a/test/abilities/moody.test.ts b/test/abilities/moody.test.ts index da24899a4b0..9b658820391 100644 --- a/test/abilities/moody.test.ts +++ b/test/abilities/moody.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Moody", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.RATTATA) .enemyAbility(Abilities.BALL_FETCH) .ability(Abilities.MOODY) diff --git a/test/abilities/moxie.test.ts b/test/abilities/moxie.test.ts index ec93aebd2c0..bccdeda2b93 100644 --- a/test/abilities/moxie.test.ts +++ b/test/abilities/moxie.test.ts @@ -27,7 +27,7 @@ describe("Abilities - Moxie", () => { beforeEach(() => { game = new GameManager(phaserGame); const moveToUse = Moves.AERIAL_ACE; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.RATTATA); game.override.enemyAbility(Abilities.MOXIE); game.override.ability(Abilities.MOXIE); @@ -54,7 +54,7 @@ describe("Abilities - Moxie", () => { it.todo( "should raise ATK stat stage by 1 when defeating an ally Pokemon", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); const moveToUse = Moves.AERIAL_ACE; await game.startBattle([Species.MIGHTYENA, Species.MIGHTYENA]); diff --git a/test/abilities/mummy.test.ts b/test/abilities/mummy.test.ts index 0971353c14d..c53b0b33598 100644 --- a/test/abilities/mummy.test.ts +++ b/test/abilities/mummy.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Mummy", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.MUMMY) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/mycelium_might.test.ts b/test/abilities/mycelium_might.test.ts index 8c7796ec736..4a5700045fa 100644 --- a/test/abilities/mycelium_might.test.ts +++ b/test/abilities/mycelium_might.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Mycelium Might", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.disableCrits(); game.override.enemySpecies(Species.SHUCKLE); game.override.enemyAbility(Abilities.CLEAR_BODY); diff --git a/test/abilities/neutralizing_gas.test.ts b/test/abilities/neutralizing_gas.test.ts index a10a246d855..32c61b72e4d 100644 --- a/test/abilities/neutralizing_gas.test.ts +++ b/test/abilities/neutralizing_gas.test.ts @@ -1,7 +1,7 @@ import { BattlerIndex } from "#app/battle"; import type { CommandPhase } from "#app/phases/command-phase"; import { Command } from "#app/ui/command-ui-handler"; -import { PostSummonWeatherChangeAbAttr } from "#app/data/ability"; +import { PostSummonWeatherChangeAbAttr } from "#app/data/abilities/ability"; import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { Moves } from "#enums/moves"; @@ -31,7 +31,7 @@ describe("Abilities - Neutralizing Gas", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.NEUTRALIZING_GAS) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) @@ -105,7 +105,7 @@ describe("Abilities - Neutralizing Gas", () => { }); it("should only deactivate when all setters are off the field", async () => { - game.override.enemyMoveset([Moves.ENTRAINMENT, Moves.SPLASH]).battleType("double"); + game.override.enemyMoveset([Moves.ENTRAINMENT, Moves.SPLASH]).battleStyle("double"); await game.classicMode.startBattle([Species.ACCELGOR, Species.ACCELGOR]); game.move.select(Moves.SPLASH, 0); @@ -148,7 +148,7 @@ describe("Abilities - Neutralizing Gas", () => { }); it("should deactivate upon catching a wild pokemon", async () => { - game.override.battleType("single").enemyAbility(Abilities.NEUTRALIZING_GAS).ability(Abilities.BALL_FETCH); + game.override.battleStyle("single").enemyAbility(Abilities.NEUTRALIZING_GAS).ability(Abilities.BALL_FETCH); await game.classicMode.startBattle([Species.MAGIKARP]); expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined(); @@ -174,7 +174,7 @@ describe("Abilities - Neutralizing Gas", () => { }); it("should not activate abilities of pokemon no longer on the field", async () => { - game.override.battleType("single").ability(Abilities.NEUTRALIZING_GAS).enemyAbility(Abilities.DELTA_STREAM); + game.override.battleStyle("single").ability(Abilities.NEUTRALIZING_GAS).enemyAbility(Abilities.DELTA_STREAM); await game.classicMode.startBattle([Species.MAGIKARP]); const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/abilities/no_guard.test.ts b/test/abilities/no_guard.test.ts index 41b8fbd27b9..a09e16388ee 100644 --- a/test/abilities/no_guard.test.ts +++ b/test/abilities/no_guard.test.ts @@ -4,6 +4,7 @@ import { MoveEndPhase } from "#app/phases/move-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { HitCheckResult } from "#enums/hit-check-result"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest"; @@ -28,12 +29,13 @@ describe("Abilities - No Guard", () => { .moveset(Moves.ZAP_CANNON) .ability(Abilities.NO_GUARD) .enemyLevel(200) + .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); }); it("should make moves always hit regardless of move accuracy", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); await game.classicMode.startBattle([Species.REGIELEKI]); @@ -48,7 +50,7 @@ describe("Abilities - No Guard", () => { await game.phaseInterceptor.to(MoveEndPhase); - expect(moveEffectPhase.hitCheck).toHaveReturnedWith(true); + expect(moveEffectPhase.hitCheck).toHaveReturnedWith([HitCheckResult.HIT, 1]); }); it("should guarantee double battle with any one LURE", async () => { diff --git a/test/abilities/normal-move-type-change.test.ts b/test/abilities/normal-move-type-change.test.ts new file mode 100644 index 00000000000..50c8e04af1f --- /dev/null +++ b/test/abilities/normal-move-type-change.test.ts @@ -0,0 +1,190 @@ +import { BattlerIndex } from "#app/battle"; +import { allMoves } from "#app/data/moves/move"; +import { PokemonType } from "#enums/pokemon-type"; +import { Abilities } from "#app/enums/abilities"; +import { Moves } from "#app/enums/moves"; +import { Species } from "#app/enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { TYPE_BOOST_ITEM_BOOST_PERCENT } from "#app/constants"; +import { allAbilities } from "#app/data/data-lists"; +import { MoveTypeChangeAbAttr } from "#app/data/abilities/ability"; +import { toDmgValue } from "#app/utils/common"; + +/** + * Tests for abilities that change the type of normal moves to + * a different type and boost their power + * + * Includes + * - Aerialate + * - Galvanize + * - Pixilate + * - Refrigerate + */ + +describe.each([ + { ab: Abilities.GALVANIZE, ab_name: "Galvanize", ty: PokemonType.ELECTRIC, tyName: "electric" }, + { ab: Abilities.PIXILATE, ab_name: "Pixilate", ty: PokemonType.FAIRY, tyName: "fairy" }, + { ab: Abilities.REFRIGERATE, ab_name: "Refrigerate", ty: PokemonType.ICE, tyName: "ice" }, + { ab: Abilities.AERILATE, ab_name: "Aerilate", ty: PokemonType.FLYING, tyName: "flying" }, +])("Abilities - $ab_name", ({ ab, ty, tyName }) => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override + .battleStyle("single") + .startingLevel(100) + .starterSpecies(Species.MAGIKARP) + .ability(ab) + .moveset([Moves.TACKLE, Moves.REVELATION_DANCE, Moves.FURY_SWIPES]) + .enemySpecies(Species.DUSCLOPS) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH) + .enemyLevel(100); + }); + + it(`should change Normal-type attacks to ${tyName} type and boost their power`, async () => { + await game.classicMode.startBattle(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const typeSpy = vi.spyOn(playerPokemon, "getMoveType"); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + const enemySpy = vi.spyOn(enemyPokemon, "getMoveEffectiveness"); + const powerSpy = vi.spyOn(allMoves[Moves.TACKLE], "calculateBattlePower"); + + game.move.select(Moves.TACKLE); + + await game.phaseInterceptor.to("BerryPhase", false); + + expect(typeSpy).toHaveLastReturnedWith(ty); + expect(enemySpy).toHaveReturnedWith(1); + expect(powerSpy).toHaveReturnedWith(48); + expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp()); + }); + + // Galvanize specifically would like to check for volt absorb's activation + if (ab === Abilities.GALVANIZE) { + it("should cause Normal-type attacks to activate Volt Absorb", async () => { + game.override.enemyAbility(Abilities.VOLT_ABSORB); + + await game.classicMode.startBattle(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const tySpy = vi.spyOn(playerPokemon, "getMoveType"); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + const enemyEffectivenessSpy = vi.spyOn(enemyPokemon, "getMoveEffectiveness"); + + enemyPokemon.hp = Math.floor(enemyPokemon.getMaxHp() * 0.8); + + game.move.select(Moves.TACKLE); + + await game.phaseInterceptor.to("BerryPhase", false); + + expect(tySpy).toHaveLastReturnedWith(PokemonType.ELECTRIC); + expect(enemyEffectivenessSpy).toHaveReturnedWith(0); + expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp()); + }); + } + + it.each([ + { moveName: "Revelation Dance", move: Moves.REVELATION_DANCE, expected_ty: PokemonType.WATER }, + { moveName: "Judgement", move: Moves.JUDGMENT, expected_ty: PokemonType.NORMAL }, + { moveName: "Terrain Pulse", move: Moves.TERRAIN_PULSE, expected_ty: PokemonType.NORMAL }, + { moveName: "Weather Ball", move: Moves.WEATHER_BALL, expected_ty: PokemonType.NORMAL }, + { moveName: "Multi Attack", move: Moves.MULTI_ATTACK, expected_ty: PokemonType.NORMAL }, + { moveName: "Techno Blast", move: Moves.TECHNO_BLAST, expected_ty: PokemonType.NORMAL }, + ])("should not change the type of $moveName", async ({ move, expected_ty: expectedTy }) => { + game.override + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .moveset([move]) + .starterSpecies(Species.MAGIKARP); + + await game.classicMode.startBattle([Species.MAGIKARP]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const tySpy = vi.spyOn(playerPokemon, "getMoveType"); + + game.move.select(move); + await game.phaseInterceptor.to("BerryPhase", false); + + expect(tySpy).toHaveLastReturnedWith(expectedTy); + }); + + it("should affect all hits of a Normal-type multi-hit move", async () => { + await game.classicMode.startBattle(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const tySpy = vi.spyOn(playerPokemon, "getMoveType"); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.FURY_SWIPES); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.move.forceHit(); + + await game.phaseInterceptor.to("MoveEffectPhase"); + expect(playerPokemon.turnData.hitCount).toBeGreaterThan(1); + expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp()); + + while (playerPokemon.turnData.hitsLeft > 0) { + const enemyStartingHp = enemyPokemon.hp; + await game.phaseInterceptor.to("MoveEffectPhase"); + + expect(tySpy).toHaveLastReturnedWith(ty); + expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp); + } + }); + + it("should not be affected by silk scarf after changing the move's type", async () => { + game.override.startingHeldItems([{ name: "ATTACK_TYPE_BOOSTER", count: 1, type: PokemonType.NORMAL }]); + await game.classicMode.startBattle(); + + const testMoveInstance = allMoves[Moves.TACKLE]; + + // get the power boost from the ability so we can compare it to the item + // @ts-expect-error power multiplier is private + const boost = allAbilities[ab]?.getAttrs(MoveTypeChangeAbAttr)[0]?.powerMultiplier; + expect(boost, "power boost should be defined").toBeDefined(); + + const powerSpy = vi.spyOn(testMoveInstance, "calculateBattlePower"); + const typeSpy = vi.spyOn(game.scene.getPlayerPokemon()!, "getMoveType"); + game.move.select(Moves.TACKLE); + await game.phaseInterceptor.to("BerryPhase", false); + expect(typeSpy, "type was not changed").toHaveLastReturnedWith(ty); + expect(powerSpy).toHaveLastReturnedWith(toDmgValue(testMoveInstance.power * boost)); + }); + + it("should be affected by the type boosting item after changing the move's type", async () => { + game.override.startingHeldItems([{ name: "ATTACK_TYPE_BOOSTER", count: 1, type: ty }]); + await game.classicMode.startBattle(); + + // get the power boost from the ability so we can compare it to the item + // @ts-expect-error power multiplier is private + const boost = allAbilities[ab]?.getAttrs(MoveTypeChangeAbAttr)[0]?.powerMultiplier; + expect(boost, "power boost should be defined").toBeDefined(); + + const tackle = allMoves[Moves.TACKLE]; + + const spy = vi.spyOn(tackle, "calculateBattlePower"); + game.move.select(Moves.TACKLE); + await game.phaseInterceptor.to("BerryPhase", false); + expect(spy).toHaveLastReturnedWith(toDmgValue(tackle.power * boost * (1 + TYPE_BOOST_ITEM_BOOST_PERCENT / 100))); + }); +}); diff --git a/test/abilities/normalize.test.ts b/test/abilities/normalize.test.ts new file mode 100644 index 00000000000..3256f0188d1 --- /dev/null +++ b/test/abilities/normalize.test.ts @@ -0,0 +1,92 @@ +import { TYPE_BOOST_ITEM_BOOST_PERCENT } from "#app/constants"; +import { allMoves } from "#app/data/moves/move"; +import { toDmgValue } from "#app/utils/common"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { PokemonType } from "#enums/pokemon-type"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Abilities - Normalize", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.TACKLE]) + .ability(Abilities.NORMALIZE) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should boost the power of normal type moves by 20%", async () => { + await game.classicMode.startBattle([Species.MAGIKARP]); + const powerSpy = vi.spyOn(allMoves[Moves.TACKLE], "calculateBattlePower"); + + game.move.select(Moves.TACKLE); + await game.phaseInterceptor.to("BerryPhase"); + expect(powerSpy).toHaveLastReturnedWith(toDmgValue(allMoves[Moves.TACKLE].power * 1.2)); + }); + + it("should not apply the old type boost item after changing a move's type", async () => { + game.override.startingHeldItems([{ name: "ATTACK_TYPE_BOOSTER", count: 1, type: PokemonType.GRASS }]); + game.override.moveset([Moves.LEAFAGE]); + + const powerSpy = vi.spyOn(allMoves[Moves.LEAFAGE], "calculateBattlePower"); + await game.classicMode.startBattle([Species.MAGIKARP]); + game.move.select(Moves.LEAFAGE); + await game.phaseInterceptor.to("BerryPhase"); + + // It should return with 1.2 (that is, only the power boost from the ability) + expect(powerSpy).toHaveLastReturnedWith(toDmgValue(allMoves[Moves.LEAFAGE].power * 1.2)); + }); + + it("should apply silk scarf's power boost after changing a move's type", async () => { + game.override.startingHeldItems([{ name: "ATTACK_TYPE_BOOSTER", count: 1, type: PokemonType.NORMAL }]); + game.override.moveset([Moves.LEAFAGE]); + + const powerSpy = vi.spyOn(allMoves[Moves.LEAFAGE], "calculateBattlePower"); + await game.classicMode.startBattle([Species.MAGIKARP]); + game.move.select(Moves.LEAFAGE); + await game.phaseInterceptor.to("BerryPhase"); + + // 1.2 from normalize boost, second 1.2 from + expect(powerSpy).toHaveLastReturnedWith( + toDmgValue(allMoves[Moves.LEAFAGE].power * 1.2 * (1 + TYPE_BOOST_ITEM_BOOST_PERCENT / 100)), + ); + }); + + it.each([ + { moveName: "Revelation Dance", move: Moves.REVELATION_DANCE }, + { moveName: "Judgement", move: Moves.JUDGMENT, expected_ty: PokemonType.NORMAL }, + { moveName: "Terrain Pulse", move: Moves.TERRAIN_PULSE }, + { moveName: "Weather Ball", move: Moves.WEATHER_BALL }, + { moveName: "Multi Attack", move: Moves.MULTI_ATTACK }, + { moveName: "Techno Blast", move: Moves.TECHNO_BLAST }, + { moveName: "Hidden Power", move: Moves.HIDDEN_POWER }, + ])("should not boost the power of $moveName", async ({ move }) => { + game.override.moveset([move]); + await game.classicMode.startBattle([Species.MAGIKARP]); + const powerSpy = vi.spyOn(allMoves[move], "calculateBattlePower"); + + game.move.select(move); + await game.phaseInterceptor.to("BerryPhase"); + expect(powerSpy).toHaveLastReturnedWith(allMoves[move].power); + }); +}); diff --git a/test/abilities/oblivious.test.ts b/test/abilities/oblivious.test.ts new file mode 100644 index 00000000000..a86899ec9c6 --- /dev/null +++ b/test/abilities/oblivious.test.ts @@ -0,0 +1,69 @@ +import { Abilities } from "#enums/abilities"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Abilities - Oblivious", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove taunt when gained", async () => { + game.override + .ability(Abilities.OBLIVIOUS) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.addTag(BattlerTagType.TAUNT); + expect(enemy?.getTag(BattlerTagType.TAUNT)).toBeTruthy(); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.getTag(BattlerTagType.TAUNT)).toBeFalsy(); + }); + + it("should remove infatuation when gained", async () => { + game.override + .ability(Abilities.OBLIVIOUS) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + vi.spyOn(enemy!, "isOppositeGender").mockReturnValue(true); + enemy?.addTag(BattlerTagType.INFATUATED, 5, Moves.JUDGMENT, game.scene.getPlayerPokemon()?.id); // sourceID needs to be defined + expect(enemy?.getTag(BattlerTagType.INFATUATED)).toBeTruthy(); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.getTag(BattlerTagType.INFATUATED)).toBeFalsy(); + }); +}); diff --git a/test/abilities/own_tempo.test.ts b/test/abilities/own_tempo.test.ts new file mode 100644 index 00000000000..b2f2c2f3030 --- /dev/null +++ b/test/abilities/own_tempo.test.ts @@ -0,0 +1,51 @@ +import { Abilities } from "#enums/abilities"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Own Tempo", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove confusion when gained", async () => { + game.override + .ability(Abilities.OWN_TEMPO) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.addTag(BattlerTagType.CONFUSED); + expect(enemy?.getTag(BattlerTagType.CONFUSED)).toBeTruthy(); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.getTag(BattlerTagType.CONFUSED)).toBeFalsy(); + }); +}); diff --git a/test/abilities/parental_bond.test.ts b/test/abilities/parental_bond.test.ts index 2aa24e78d6e..a75fea82830 100644 --- a/test/abilities/parental_bond.test.ts +++ b/test/abilities/parental_bond.test.ts @@ -1,6 +1,6 @@ import { PokemonType } from "#enums/pokemon-type"; import { BattlerTagType } from "#enums/battler-tag-type"; -import { toDmgValue } from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -26,7 +26,7 @@ describe("Abilities - Parental Bond", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.disableCrits(); game.override.ability(Abilities.PARENTAL_BOND); game.override.enemySpecies(Species.SNORLAX); @@ -167,7 +167,7 @@ describe("Abilities - Parental Bond", () => { }); it("should not apply to multi-target moves", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.EARTHQUAKE]); game.override.passiveAbility(Abilities.LEVITATE); diff --git a/test/abilities/pastel_veil.test.ts b/test/abilities/pastel_veil.test.ts index 65e391b7c22..4ae9763c4a6 100644 --- a/test/abilities/pastel_veil.test.ts +++ b/test/abilities/pastel_veil.test.ts @@ -26,7 +26,7 @@ describe("Abilities - Pastel Veil", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .moveset([Moves.TOXIC_THREAD, Moves.SPLASH]) .enemyAbility(Abilities.BALL_FETCH) .enemySpecies(Species.SUNKERN) diff --git a/test/abilities/perish_body.test.ts b/test/abilities/perish_body.test.ts index 424d35e2542..27e76cb52ad 100644 --- a/test/abilities/perish_body.test.ts +++ b/test/abilities/perish_body.test.ts @@ -21,7 +21,7 @@ describe("Abilities - Perish Song", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.disableCrits(); game.override.enemySpecies(Species.MAGIKARP); diff --git a/test/abilities/power_construct.test.ts b/test/abilities/power_construct.test.ts index c253f2ae4df..0ff90a2c0df 100644 --- a/test/abilities/power_construct.test.ts +++ b/test/abilities/power_construct.test.ts @@ -25,7 +25,7 @@ describe("Abilities - POWER CONSTRUCT", () => { beforeEach(() => { game = new GameManager(phaserGame); const moveToUse = Moves.SPLASH; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.POWER_CONSTRUCT); game.override.moveset([moveToUse]); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); diff --git a/test/abilities/power_spot.test.ts b/test/abilities/power_spot.test.ts index e29b5ecf775..3e4f79d7445 100644 --- a/test/abilities/power_spot.test.ts +++ b/test/abilities/power_spot.test.ts @@ -26,7 +26,7 @@ describe("Abilities - Power Spot", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.TACKLE, Moves.BREAKING_SWIPE, Moves.SPLASH, Moves.DAZZLING_GLEAM]); game.override.enemyMoveset(Moves.SPLASH); game.override.enemySpecies(Species.SHUCKLE); diff --git a/test/abilities/protean.test.ts b/test/abilities/protean.test.ts index 574033bb13f..8f7633e1327 100644 --- a/test/abilities/protean.test.ts +++ b/test/abilities/protean.test.ts @@ -29,7 +29,7 @@ describe("Abilities - Protean", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.PROTEAN); game.override.startingLevel(100); game.override.enemySpecies(Species.RATTATA); @@ -67,7 +67,7 @@ describe("Abilities - Protean", () => { game.move.select(Moves.AGILITY); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied.filter(a => a === Abilities.PROTEAN)).toHaveLength(1); + expect(leadPokemon.waveData.abilitiesApplied).toContain(Abilities.PROTEAN); const leadPokemonType = PokemonType[leadPokemon.getTypes()[0]]; const moveType = PokemonType[allMoves[Moves.AGILITY].type]; expect(leadPokemonType).not.toBe(moveType); @@ -99,7 +99,7 @@ describe("Abilities - Protean", () => { game.move.select(Moves.WEATHER_BALL); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN); + expect(leadPokemon.waveData.abilitiesApplied).toContain(Abilities.PROTEAN); expect(leadPokemon.getTypes()).toHaveLength(1); const leadPokemonType = PokemonType[leadPokemon.getTypes()[0]], moveType = PokemonType[PokemonType.FIRE]; @@ -118,7 +118,7 @@ describe("Abilities - Protean", () => { game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN); + expect(leadPokemon.waveData.abilitiesApplied).toContain(Abilities.PROTEAN); expect(leadPokemon.getTypes()).toHaveLength(1); const leadPokemonType = PokemonType[leadPokemon.getTypes()[0]], moveType = PokemonType[PokemonType.ICE]; @@ -214,7 +214,7 @@ describe("Abilities - Protean", () => { game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); + expect(leadPokemon.waveData.abilitiesApplied).not.toContain(Abilities.PROTEAN); }); test("ability is not applied if pokemon is terastallized", async () => { @@ -230,7 +230,7 @@ describe("Abilities - Protean", () => { game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); + expect(leadPokemon.waveData.abilitiesApplied).not.toContain(Abilities.PROTEAN); }); test("ability is not applied if pokemon uses struggle", async () => { @@ -244,7 +244,7 @@ describe("Abilities - Protean", () => { game.move.select(Moves.STRUGGLE); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); + expect(leadPokemon.waveData.abilitiesApplied).not.toContain(Abilities.PROTEAN); }); test("ability is not applied if the pokemon's move fails", async () => { @@ -258,7 +258,7 @@ describe("Abilities - Protean", () => { game.move.select(Moves.BURN_UP); await game.phaseInterceptor.to(TurnEndPhase); - expect(leadPokemon.summonData.abilitiesApplied).not.toContain(Abilities.PROTEAN); + expect(leadPokemon.waveData.abilitiesApplied).not.toContain(Abilities.PROTEAN); }); test("ability applies correctly even if the pokemon's Trick-or-Treat fails", async () => { @@ -293,7 +293,7 @@ describe("Abilities - Protean", () => { }); function testPokemonTypeMatchesDefaultMoveType(pokemon: PlayerPokemon, move: Moves) { - expect(pokemon.summonData.abilitiesApplied).toContain(Abilities.PROTEAN); + expect(pokemon.waveData.abilitiesApplied).toContain(Abilities.PROTEAN); expect(pokemon.getTypes()).toHaveLength(1); const pokemonType = PokemonType[pokemon.getTypes()[0]], moveType = PokemonType[allMoves[move].type]; diff --git a/test/abilities/protosynthesis.test.ts b/test/abilities/protosynthesis.test.ts index 882474b7cef..e312ebd572c 100644 --- a/test/abilities/protosynthesis.test.ts +++ b/test/abilities/protosynthesis.test.ts @@ -27,7 +27,7 @@ describe("Abilities - Protosynthesis", () => { game.override .moveset([Moves.SPLASH, Moves.TACKLE]) .ability(Abilities.PROTOSYNTHESIS) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/quick_draw.test.ts b/test/abilities/quick_draw.test.ts index 9969dc2aa75..79a29b0ce77 100644 --- a/test/abilities/quick_draw.test.ts +++ b/test/abilities/quick_draw.test.ts @@ -1,4 +1,5 @@ -import { allAbilities, BypassSpeedChanceAbAttr } from "#app/data/ability"; +import { BypassSpeedChanceAbAttr } from "#app/data/abilities/ability"; +import { allAbilities } from "#app/data/data-lists"; import { FaintPhase } from "#app/phases/faint-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; @@ -23,7 +24,7 @@ describe("Abilities - Quick Draw", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.starterSpecies(Species.MAGIKARP); game.override.ability(Abilities.QUICK_DRAW); @@ -53,7 +54,7 @@ describe("Abilities - Quick Draw", () => { expect(pokemon.isFainted()).toBe(false); expect(enemy.isFainted()).toBe(true); - expect(pokemon.battleData.abilitiesApplied).contain(Abilities.QUICK_DRAW); + expect(pokemon.waveData.abilitiesApplied).contain(Abilities.QUICK_DRAW); }, 20000); test( @@ -75,7 +76,7 @@ describe("Abilities - Quick Draw", () => { expect(pokemon.isFainted()).toBe(true); expect(enemy.isFainted()).toBe(false); - expect(pokemon.battleData.abilitiesApplied).not.contain(Abilities.QUICK_DRAW); + expect(pokemon.waveData.abilitiesApplied).not.contain(Abilities.QUICK_DRAW); }, ); @@ -95,6 +96,6 @@ describe("Abilities - Quick Draw", () => { expect(pokemon.isFainted()).toBe(true); expect(enemy.isFainted()).toBe(false); - expect(pokemon.battleData.abilitiesApplied).contain(Abilities.QUICK_DRAW); + expect(pokemon.waveData.abilitiesApplied).contain(Abilities.QUICK_DRAW); }, 20000); }); diff --git a/test/abilities/sand_spit.test.ts b/test/abilities/sand_spit.test.ts index 6896c286eed..2b655f92466 100644 --- a/test/abilities/sand_spit.test.ts +++ b/test/abilities/sand_spit.test.ts @@ -22,7 +22,7 @@ describe("Abilities - Sand Spit", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.disableCrits(); game.override.enemySpecies(Species.MAGIKARP); diff --git a/test/abilities/sand_veil.test.ts b/test/abilities/sand_veil.test.ts index 5e0a3f567dd..b82c79c681b 100644 --- a/test/abilities/sand_veil.test.ts +++ b/test/abilities/sand_veil.test.ts @@ -1,4 +1,5 @@ -import { StatMultiplierAbAttr, allAbilities } from "#app/data/ability"; +import { StatMultiplierAbAttr } from "#app/data/abilities/ability"; +import { allAbilities } from "#app/data/data-lists"; import { CommandPhase } from "#app/phases/command-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; @@ -33,7 +34,7 @@ describe("Abilities - Sand Veil", () => { game.override.enemyMoveset([Moves.TWISTER, Moves.TWISTER, Moves.TWISTER, Moves.TWISTER]); game.override.startingLevel(100); game.override.enemyLevel(100); - game.override.weather(WeatherType.SANDSTORM).battleType("double"); + game.override.weather(WeatherType.SANDSTORM).battleStyle("double"); }); test("ability should increase the evasiveness of the source", async () => { diff --git a/test/abilities/sap_sipper.test.ts b/test/abilities/sap_sipper.test.ts index f4f02844cbc..2157177b84c 100644 --- a/test/abilities/sap_sipper.test.ts +++ b/test/abilities/sap_sipper.test.ts @@ -29,7 +29,7 @@ describe("Abilities - Sap Sipper", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .ability(Abilities.SAP_SIPPER) .enemySpecies(Species.RATTATA) diff --git a/test/abilities/schooling.test.ts b/test/abilities/schooling.test.ts index 35244b08e4c..803b4d2062a 100644 --- a/test/abilities/schooling.test.ts +++ b/test/abilities/schooling.test.ts @@ -25,7 +25,7 @@ describe("Abilities - SCHOOLING", () => { beforeEach(() => { game = new GameManager(phaserGame); const moveToUse = Moves.SPLASH; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.SCHOOLING); game.override.moveset([moveToUse]); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); diff --git a/test/abilities/screen_cleaner.test.ts b/test/abilities/screen_cleaner.test.ts index d8be1d64697..840291f6420 100644 --- a/test/abilities/screen_cleaner.test.ts +++ b/test/abilities/screen_cleaner.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Screen Cleaner", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.SCREEN_CLEANER); game.override.enemySpecies(Species.SHUCKLE); }); diff --git a/test/abilities/seed_sower.test.ts b/test/abilities/seed_sower.test.ts index d78007f7500..d8edbe59857 100644 --- a/test/abilities/seed_sower.test.ts +++ b/test/abilities/seed_sower.test.ts @@ -22,7 +22,7 @@ describe("Abilities - Seed Sower", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.disableCrits(); game.override.enemySpecies(Species.MAGIKARP); diff --git a/test/abilities/serene_grace.test.ts b/test/abilities/serene_grace.test.ts index 65ca96acbbc..2547971a4b8 100644 --- a/test/abilities/serene_grace.test.ts +++ b/test/abilities/serene_grace.test.ts @@ -26,7 +26,7 @@ describe("Abilities - Serene Grace", () => { game = new GameManager(phaserGame); game.override .disableCrits() - .battleType("single") + .battleStyle("single") .ability(Abilities.SERENE_GRACE) .moveset([Moves.AIR_SLASH]) .enemySpecies(Species.ALOLA_GEODUDE) diff --git a/test/abilities/sheer_force.test.ts b/test/abilities/sheer_force.test.ts index 4a1c20cde5c..ce3232a1869 100644 --- a/test/abilities/sheer_force.test.ts +++ b/test/abilities/sheer_force.test.ts @@ -26,7 +26,7 @@ describe("Abilities - Sheer Force", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .ability(Abilities.SHEER_FORCE) .enemySpecies(Species.ONIX) .enemyAbility(Abilities.BALL_FETCH) @@ -34,7 +34,7 @@ describe("Abilities - Sheer Force", () => { .disableCrits(); }); - const SHEER_FORCE_MULT = 5461 / 4096; + const SHEER_FORCE_MULT = 1.3; it("Sheer Force should boost the power of the move but disable secondary effects", async () => { game.override.moveset([Moves.AIR_SLASH]); diff --git a/test/abilities/shield_dust.test.ts b/test/abilities/shield_dust.test.ts index 8e02b5a7713..4ab58e8c2a6 100644 --- a/test/abilities/shield_dust.test.ts +++ b/test/abilities/shield_dust.test.ts @@ -4,9 +4,9 @@ import { applyPreDefendAbAttrs, IgnoreMoveEffectsAbAttr, MoveEffectChanceMultiplierAbAttr, -} from "#app/data/ability"; +} from "#app/data/abilities/ability"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; -import { NumberHolder } from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -31,7 +31,7 @@ describe("Abilities - Shield Dust", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.ONIX); game.override.enemyAbility(Abilities.SHIELD_DUST); game.override.startingLevel(100); @@ -52,7 +52,7 @@ describe("Abilities - Shield Dust", () => { // Shield Dust negates secondary effect const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - const move = phase.move.getMove(); + const move = phase.move; expect(move.id).toBe(Moves.AIR_SLASH); const chance = new NumberHolder(move.chance); diff --git a/test/abilities/shields_down.test.ts b/test/abilities/shields_down.test.ts index 4bdf22869cb..2f9d2fb1f97 100644 --- a/test/abilities/shields_down.test.ts +++ b/test/abilities/shields_down.test.ts @@ -26,7 +26,7 @@ describe("Abilities - SHIELDS DOWN", () => { beforeEach(() => { game = new GameManager(phaserGame); const moveToUse = Moves.SPLASH; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.SHIELDS_DOWN); game.override.moveset([moveToUse]); game.override.enemyMoveset([Moves.TACKLE]); diff --git a/test/abilities/simple.test.ts b/test/abilities/simple.test.ts index b6c5fd116c0..1f084b1bf4c 100644 --- a/test/abilities/simple.test.ts +++ b/test/abilities/simple.test.ts @@ -23,7 +23,7 @@ describe("Abilities - Simple", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.BULBASAUR) .enemyAbility(Abilities.SIMPLE) .ability(Abilities.INTIMIDATE) diff --git a/test/abilities/speed_boost.test.ts b/test/abilities/speed_boost.test.ts index fa20e74108f..45ee54ffb07 100644 --- a/test/abilities/speed_boost.test.ts +++ b/test/abilities/speed_boost.test.ts @@ -27,7 +27,7 @@ describe("Abilities - Speed Boost", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SHUCKLE) .enemyAbility(Abilities.BALL_FETCH) .enemyLevel(100) diff --git a/test/abilities/stakeout.test.ts b/test/abilities/stakeout.test.ts index b464b3f1dfc..8a2231bba0b 100644 --- a/test/abilities/stakeout.test.ts +++ b/test/abilities/stakeout.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { isBetween } from "#app/utils"; +import { isBetween } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -26,7 +26,7 @@ describe("Abilities - Stakeout", () => { game.override .moveset([Moves.SPLASH, Moves.SURF]) .ability(Abilities.STAKEOUT) - .battleType("single") + .battleStyle("single") .disableCrits() .startingLevel(100) .enemyLevel(100) diff --git a/test/abilities/stall.test.ts b/test/abilities/stall.test.ts index 5b67e5f4b7a..68b3fdedcd8 100644 --- a/test/abilities/stall.test.ts +++ b/test/abilities/stall.test.ts @@ -22,7 +22,7 @@ describe("Abilities - Stall", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.disableCrits(); game.override.enemySpecies(Species.REGIELEKI); game.override.enemyAbility(Abilities.STALL); diff --git a/test/abilities/steely_spirit.test.ts b/test/abilities/steely_spirit.test.ts index b180ff8919e..be759724c3a 100644 --- a/test/abilities/steely_spirit.test.ts +++ b/test/abilities/steely_spirit.test.ts @@ -1,4 +1,4 @@ -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { allMoves } from "#app/data/moves/move"; import { Abilities } from "#app/enums/abilities"; import { Moves } from "#enums/moves"; @@ -28,7 +28,7 @@ describe("Abilities - Steely Spirit", () => { beforeEach(() => { ironHeadPower = allMoves[moveToCheck].power; game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.enemySpecies(Species.SHUCKLE); game.override.enemyAbility(Abilities.BALL_FETCH); game.override.moveset([Moves.IRON_HEAD, Moves.SPLASH]); diff --git a/test/abilities/storm_drain.test.ts b/test/abilities/storm_drain.test.ts index 58ff477fa43..0cbad796ad8 100644 --- a/test/abilities/storm_drain.test.ts +++ b/test/abilities/storm_drain.test.ts @@ -26,7 +26,7 @@ describe("Abilities - Storm Drain", () => { game.override .moveset([Moves.SPLASH, Moves.WATER_GUN]) .ability(Abilities.BALL_FETCH) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/sturdy.test.ts b/test/abilities/sturdy.test.ts index 7b7254cff15..bda8c6d1e35 100644 --- a/test/abilities/sturdy.test.ts +++ b/test/abilities/sturdy.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Sturdy", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.starterSpecies(Species.LUCARIO); game.override.startingLevel(100); diff --git a/test/abilities/super_luck.test.ts b/test/abilities/super_luck.test.ts new file mode 100644 index 00000000000..fbcbd02bdd2 --- /dev/null +++ b/test/abilities/super_luck.test.ts @@ -0,0 +1,42 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Abilities - Super Luck", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.TACKLE]) + .ability(Abilities.SUPER_LUCK) + .battleStyle("single") + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should increase the crit stage of a user by 1", async () => { + await game.classicMode.startBattle([Species.MAGIKARP]); + const enemy = game.scene.getEnemyPokemon()!; + const fn = vi.spyOn(enemy, "getCritStage"); + game.move.select(Moves.TACKLE); + await game.phaseInterceptor.to("BerryPhase"); + expect(fn).toHaveReturnedWith(1); + fn.mockRestore(); + }); +}); diff --git a/test/abilities/supreme_overlord.test.ts b/test/abilities/supreme_overlord.test.ts index a71bf0a9354..8af0a0ac37c 100644 --- a/test/abilities/supreme_overlord.test.ts +++ b/test/abilities/supreme_overlord.test.ts @@ -31,7 +31,7 @@ describe("Abilities - Supreme Overlord", () => { basePower = move.power; game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyLevel(100) .startingLevel(1) diff --git a/test/abilities/sweet_veil.test.ts b/test/abilities/sweet_veil.test.ts index 650ee53a474..e609aa6e7d2 100644 --- a/test/abilities/sweet_veil.test.ts +++ b/test/abilities/sweet_veil.test.ts @@ -25,7 +25,7 @@ describe("Abilities - Sweet Veil", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.SPLASH, Moves.REST, Moves.YAWN]); game.override.enemySpecies(Species.MAGIKARP); game.override.enemyAbility(Abilities.BALL_FETCH); diff --git a/test/abilities/synchronize.test.ts b/test/abilities/synchronize.test.ts index 95ebf96f2fd..783201d7a5b 100644 --- a/test/abilities/synchronize.test.ts +++ b/test/abilities/synchronize.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Synchronize", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .startingLevel(100) .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.SYNCHRONIZE) diff --git a/test/abilities/tera_shell.test.ts b/test/abilities/tera_shell.test.ts index a99ecfd4ce1..fdbcb14947d 100644 --- a/test/abilities/tera_shell.test.ts +++ b/test/abilities/tera_shell.test.ts @@ -2,7 +2,6 @@ import { BattlerIndex } from "#app/battle"; import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; -import { HitResult } from "#app/field/pokemon"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -24,7 +23,7 @@ describe("Abilities - Tera Shell", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .ability(Abilities.TERA_SHELL) .moveset([Moves.SPLASH]) .enemySpecies(Species.SNORLAX) @@ -87,13 +86,15 @@ describe("Abilities - Tera Shell", () => { await game.classicMode.startBattle([Species.CHARIZARD]); const playerPokemon = game.scene.getPlayerPokemon()!; - vi.spyOn(playerPokemon, "apply"); + const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness"); game.move.select(Moves.SPLASH); await game.phaseInterceptor.to("BerryPhase", false); - expect(playerPokemon.apply).toHaveLastReturnedWith(HitResult.EFFECTIVE); + expect(spy).toHaveLastReturnedWith(1); expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp() - 40); + + spy.mockRestore(); }); it("should change the effectiveness of all strikes of a multi-strike move", async () => { @@ -102,7 +103,7 @@ describe("Abilities - Tera Shell", () => { await game.classicMode.startBattle([Species.SNORLAX]); const playerPokemon = game.scene.getPlayerPokemon()!; - vi.spyOn(playerPokemon, "apply"); + const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness"); game.move.select(Moves.SPLASH); @@ -110,8 +111,9 @@ describe("Abilities - Tera Shell", () => { await game.move.forceHit(); for (let i = 0; i < 2; i++) { await game.phaseInterceptor.to("MoveEffectPhase"); - expect(playerPokemon.apply).toHaveLastReturnedWith(HitResult.NOT_VERY_EFFECTIVE); + expect(spy).toHaveLastReturnedWith(0.5); } - expect(playerPokemon.apply).toHaveReturnedTimes(2); + expect(spy).toHaveReturnedTimes(2); + spy.mockRestore(); }); }); diff --git a/test/abilities/thermal_exchange.test.ts b/test/abilities/thermal_exchange.test.ts new file mode 100644 index 00000000000..c33b296d5ae --- /dev/null +++ b/test/abilities/thermal_exchange.test.ts @@ -0,0 +1,51 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Thermal Exchange", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove burn when gained", async () => { + game.override + .ability(Abilities.THERMAL_EXCHANGE) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.trySetStatus(StatusEffect.BURN); + expect(enemy?.status?.effect).toBe(StatusEffect.BURN); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.status).toBeNull(); + }); +}); diff --git a/test/abilities/trace.test.ts b/test/abilities/trace.test.ts index 5d569208d33..7ec8d62ab51 100644 --- a/test/abilities/trace.test.ts +++ b/test/abilities/trace.test.ts @@ -25,7 +25,7 @@ describe("Abilities - Trace", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.TRACE) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/unburden.test.ts b/test/abilities/unburden.test.ts index 8f18604011c..2af889d1da4 100644 --- a/test/abilities/unburden.test.ts +++ b/test/abilities/unburden.test.ts @@ -1,5 +1,5 @@ import { BattlerIndex } from "#app/battle"; -import { PostItemLostAbAttr } from "#app/data/ability"; +import { PostItemLostAbAttr } from "#app/data/abilities/ability"; import { allMoves, StealHeldItemChanceAttr } from "#app/data/moves/move"; import type Pokemon from "#app/field/pokemon"; import type { ContactHeldItemTransferChanceModifier } from "#app/modifier/modifier"; @@ -41,7 +41,7 @@ describe("Abilities - Unburden", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .startingLevel(1) .ability(Abilities.UNBURDEN) .moveset([Moves.SPLASH, Moves.KNOCK_OFF, Moves.PLUCK, Moves.FALSE_SWIPE]) @@ -231,7 +231,7 @@ describe("Abilities - Unburden", () => { }); it("should deactivate temporarily when a neutralizing gas user is on the field", async () => { - game.override.battleType("double").ability(Abilities.NONE); // Disable ability override so that we can properly set abilities below + game.override.battleStyle("double").ability(Abilities.NONE); // Disable ability override so that we can properly set abilities below await game.classicMode.startBattle([Species.TREECKO, Species.MEOWTH, Species.WEEZING]); const [treecko, _meowth, weezing] = game.scene.getPlayerParty(); @@ -359,7 +359,7 @@ describe("Abilities - Unburden", () => { // test for `.bypassFaint()` - doubles it("shouldn't persist when revived by revival blessing if activated while fainting", async () => { game.override - .battleType("double") + .battleStyle("double") .enemyMoveset([Moves.SPLASH, Moves.THIEF]) .moveset([Moves.SPLASH, Moves.REVIVAL_BLESSING]) .startingHeldItems([{ name: "WIDE_LENS" }]); diff --git a/test/abilities/unseen_fist.test.ts b/test/abilities/unseen_fist.test.ts index 459bb00628c..6c14e82fc39 100644 --- a/test/abilities/unseen_fist.test.ts +++ b/test/abilities/unseen_fist.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Unseen Fist", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.starterSpecies(Species.URSHIFU); game.override.enemySpecies(Species.SNORLAX); game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]); diff --git a/test/abilities/victory_star.test.ts b/test/abilities/victory_star.test.ts index 92db522871a..f3c0b5ad6b7 100644 --- a/test/abilities/victory_star.test.ts +++ b/test/abilities/victory_star.test.ts @@ -25,7 +25,7 @@ describe("Abilities - Victory Star", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.TACKLE, Moves.SPLASH]) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/vital_spirit.test.ts b/test/abilities/vital_spirit.test.ts new file mode 100644 index 00000000000..bb274310cc0 --- /dev/null +++ b/test/abilities/vital_spirit.test.ts @@ -0,0 +1,51 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Vital Spirit", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove sleep when gained", async () => { + game.override + .ability(Abilities.INSOMNIA) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.trySetStatus(StatusEffect.SLEEP); + expect(enemy?.status?.effect).toBe(StatusEffect.SLEEP); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.status).toBeNull(); + }); +}); diff --git a/test/abilities/volt_absorb.test.ts b/test/abilities/volt_absorb.test.ts index 10735f31987..920c822eb90 100644 --- a/test/abilities/volt_absorb.test.ts +++ b/test/abilities/volt_absorb.test.ts @@ -26,7 +26,7 @@ describe("Abilities - Volt Absorb", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.disableCrits(); }); diff --git a/test/abilities/wandering_spirit.test.ts b/test/abilities/wandering_spirit.test.ts index 375faa41972..639241aecc8 100644 --- a/test/abilities/wandering_spirit.test.ts +++ b/test/abilities/wandering_spirit.test.ts @@ -25,7 +25,7 @@ describe("Abilities - Wandering Spirit", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.WANDERING_SPIRIT) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/water_bubble.test.ts b/test/abilities/water_bubble.test.ts new file mode 100644 index 00000000000..c1e2acbd468 --- /dev/null +++ b/test/abilities/water_bubble.test.ts @@ -0,0 +1,51 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Water Bubble", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove burn when gained", async () => { + game.override + .ability(Abilities.THERMAL_EXCHANGE) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.trySetStatus(StatusEffect.BURN); + expect(enemy?.status?.effect).toBe(StatusEffect.BURN); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.status).toBeNull(); + }); +}); diff --git a/test/abilities/water_veil.test.ts b/test/abilities/water_veil.test.ts new file mode 100644 index 00000000000..8e187ad8e58 --- /dev/null +++ b/test/abilities/water_veil.test.ts @@ -0,0 +1,51 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Water Veil", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should remove burn when gained", async () => { + game.override + .ability(Abilities.THERMAL_EXCHANGE) + .enemyAbility(Abilities.BALL_FETCH) + .moveset(Moves.SKILL_SWAP) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.FEEBAS]); + const enemy = game.scene.getEnemyPokemon(); + enemy?.trySetStatus(StatusEffect.BURN); + expect(enemy?.status?.effect).toBe(StatusEffect.BURN); + + game.move.select(Moves.SKILL_SWAP); + await game.phaseInterceptor.to("BerryPhase"); + + expect(enemy?.status).toBeNull(); + }); +}); diff --git a/test/abilities/wimp_out.test.ts b/test/abilities/wimp_out.test.ts index ef201cbf8dd..f558efdb103 100644 --- a/test/abilities/wimp_out.test.ts +++ b/test/abilities/wimp_out.test.ts @@ -2,7 +2,7 @@ import { BattlerIndex } from "#app/battle"; import { ArenaTagSide } from "#app/data/arena-tag"; import { allMoves } from "#app/data/moves/move"; import GameManager from "#test/testUtils/gameManager"; -import { toDmgValue } from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; @@ -31,7 +31,7 @@ describe("Abilities - Wimp Out", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .ability(Abilities.WIMP_OUT) .enemySpecies(Species.NINJASK) .enemyPassiveAbility(Abilities.NO_GUARD) @@ -155,7 +155,7 @@ describe("Abilities - Wimp Out", () => { game.doSelectPartyPokemon(1); await game.phaseInterceptor.to("SwitchSummonPhase", false); - expect(wimpod.summonData.abilitiesApplied).not.toContain(Abilities.WIMP_OUT); + expect(wimpod.waveData.abilitiesApplied).not.toContain(Abilities.WIMP_OUT); await game.phaseInterceptor.to("TurnEndPhase"); @@ -342,7 +342,7 @@ describe("Abilities - Wimp Out", () => { }); it("Wimp Out activating should not cancel a double battle", async () => { - game.override.battleType("double").enemyAbility(Abilities.WIMP_OUT).enemyMoveset([Moves.SPLASH]).enemyLevel(1); + game.override.battleStyle("double").enemyAbility(Abilities.WIMP_OUT).enemyMoveset([Moves.SPLASH]).enemyLevel(1); await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]); const enemyLeadPokemon = game.scene.getEnemyParty()[0]; const enemySecPokemon = game.scene.getEnemyParty()[1]; @@ -498,6 +498,7 @@ describe("Abilities - Wimp Out", () => { const hasFled = enemyPokemon.switchOutStatus; expect(isVisible && !hasFled).toBe(true); }); + it("wimp out will not skip battles when triggered in a double battle", async () => { const wave = 2; game.override @@ -507,7 +508,7 @@ describe("Abilities - Wimp Out", () => { .moveset([Moves.MATCHA_GOTCHA, Moves.FALSE_SWIPE]) .startingLevel(50) .enemyLevel(1) - .battleType("double") + .battleStyle("double") .startingWave(wave); await game.classicMode.startBattle([Species.RAICHU, Species.PIKACHU]); const [wimpod0, wimpod1] = game.scene.getEnemyField(); @@ -525,4 +526,28 @@ describe("Abilities - Wimp Out", () => { await game.toNextWave(); expect(game.scene.currentBattle.waveIndex).toBe(wave + 1); }); + + it("wimp out should not skip battles when triggering the same turn as another enemy faints", async () => { + const wave = 2; + game.override + .enemySpecies(Species.WIMPOD) + .enemyAbility(Abilities.WIMP_OUT) + .startingLevel(50) + .enemyLevel(1) + .enemyMoveset([Moves.SPLASH, Moves.ENDURE]) + .battleStyle("double") + .moveset([Moves.DRAGON_ENERGY, Moves.SPLASH]) + .startingWave(wave); + + await game.classicMode.startBattle([Species.REGIDRAGO, Species.MAGIKARP]); + + // turn 1 + game.move.select(Moves.DRAGON_ENERGY, 0); + game.move.select(Moves.SPLASH, 1); + await game.forceEnemyMove(Moves.SPLASH); + await game.forceEnemyMove(Moves.ENDURE); + + await game.phaseInterceptor.to("SelectModifierPhase"); + expect(game.scene.currentBattle.waveIndex).toBe(wave + 1); + }); }); diff --git a/test/abilities/wind_power.test.ts b/test/abilities/wind_power.test.ts index b28ac3362eb..66c72d454ab 100644 --- a/test/abilities/wind_power.test.ts +++ b/test/abilities/wind_power.test.ts @@ -23,7 +23,7 @@ describe("Abilities - Wind Power", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.SHIFTRY); game.override.enemyAbility(Abilities.WIND_POWER); game.override.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]); diff --git a/test/abilities/wind_rider.test.ts b/test/abilities/wind_rider.test.ts index 8fdae1b24ec..f8301aa03fc 100644 --- a/test/abilities/wind_rider.test.ts +++ b/test/abilities/wind_rider.test.ts @@ -23,7 +23,7 @@ describe("Abilities - Wind Rider", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SHIFTRY) .enemyAbility(Abilities.WIND_RIDER) .moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]) diff --git a/test/abilities/wonder_skin.test.ts b/test/abilities/wonder_skin.test.ts index 18d5be36aef..d039ba1e6a7 100644 --- a/test/abilities/wonder_skin.test.ts +++ b/test/abilities/wonder_skin.test.ts @@ -23,7 +23,7 @@ describe("Abilities - Wonder Skin", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.moveset([Moves.TACKLE, Moves.CHARM]); game.override.ability(Abilities.BALL_FETCH); game.override.enemySpecies(Species.SHUCKLE); diff --git a/test/abilities/zen_mode.test.ts b/test/abilities/zen_mode.test.ts index d552d8c88ca..1eb27a8f6c7 100644 --- a/test/abilities/zen_mode.test.ts +++ b/test/abilities/zen_mode.test.ts @@ -26,7 +26,7 @@ describe("Abilities - ZEN MODE", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/abilities/zero_to_hero.test.ts b/test/abilities/zero_to_hero.test.ts index 4565aa3e8b2..2cdc516dc6b 100644 --- a/test/abilities/zero_to_hero.test.ts +++ b/test/abilities/zero_to_hero.test.ts @@ -27,7 +27,7 @@ describe("Abilities - ZERO TO HERO", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .moveset(Moves.SPLASH) .enemyMoveset(Moves.SPLASH) .enemyAbility(Abilities.BALL_FETCH); diff --git a/test/account.test.ts b/test/account.test.ts index 3f6b9f3f80b..77368b0b64c 100644 --- a/test/account.test.ts +++ b/test/account.test.ts @@ -1,4 +1,4 @@ -import * as battleScene from "#app/battle-scene"; +import * as bypassLogin from "#app/global-vars/bypass-login"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import { describe, expect, it, vi } from "vitest"; import { initLoggedInUser, loggedInUser, updateUserInfo } from "#app/account"; @@ -15,7 +15,7 @@ describe("account", () => { describe("updateUserInfo", () => { it("should set loggedInUser! to Guest if bypassLogin is true", async () => { - vi.spyOn(battleScene, "bypassLogin", "get").mockReturnValue(true); + vi.spyOn(bypassLogin, "bypassLogin", "get").mockReturnValue(true); const [success, status] = await updateUserInfo(); @@ -26,7 +26,7 @@ describe("account", () => { }); it("should fetch user info from the API if bypassLogin is false", async () => { - vi.spyOn(battleScene, "bypassLogin", "get").mockReturnValue(false); + vi.spyOn(bypassLogin, "bypassLogin", "get").mockReturnValue(false); vi.spyOn(pokerogueApi.account, "getInfo").mockResolvedValue([ { username: "test", @@ -47,7 +47,7 @@ describe("account", () => { }); it("should handle resolved API errors", async () => { - vi.spyOn(battleScene, "bypassLogin", "get").mockReturnValue(false); + vi.spyOn(bypassLogin, "bypassLogin", "get").mockReturnValue(false); vi.spyOn(pokerogueApi.account, "getInfo").mockResolvedValue([null, 401]); const [success, status] = await updateUserInfo(); @@ -57,7 +57,7 @@ describe("account", () => { }); it("should handle 500 API errors", async () => { - vi.spyOn(battleScene, "bypassLogin", "get").mockReturnValue(false); + vi.spyOn(bypassLogin, "bypassLogin", "get").mockReturnValue(false); vi.spyOn(pokerogueApi.account, "getInfo").mockResolvedValue([null, 500]); const [success, status] = await updateUserInfo(); diff --git a/test/achievements/achievement.test.ts b/test/achievements/achievement.test.ts index 5c53e38e208..0b49c4d23ab 100644 --- a/test/achievements/achievement.test.ts +++ b/test/achievements/achievement.test.ts @@ -10,7 +10,7 @@ import { RibbonAchv, achvs, } from "#app/system/achv"; -import { NumberHolder } from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/arena/arena_gravity.test.ts b/test/arena/arena_gravity.test.ts index a5ce84667f0..0ce5ac0ea4c 100644 --- a/test/arena/arena_gravity.test.ts +++ b/test/arena/arena_gravity.test.ts @@ -26,7 +26,7 @@ describe("Arena - Gravity", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .moveset([Moves.TACKLE, Moves.GRAVITY, Moves.FISSURE]) .ability(Abilities.UNNERVE) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/arena/grassy_terrain.test.ts b/test/arena/grassy_terrain.test.ts index d92fb24be5a..f8ca07bd65e 100644 --- a/test/arena/grassy_terrain.test.ts +++ b/test/arena/grassy_terrain.test.ts @@ -22,7 +22,7 @@ describe("Arena - Grassy Terrain", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .enemyLevel(1) .enemySpecies(Species.SHUCKLE) diff --git a/test/arena/weather_fog.test.ts b/test/arena/weather_fog.test.ts index 784c4886648..b1edf75704b 100644 --- a/test/arena/weather_fog.test.ts +++ b/test/arena/weather_fog.test.ts @@ -24,7 +24,7 @@ describe("Weather - Fog", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.weather(WeatherType.FOG).battleType("single"); + game.override.weather(WeatherType.FOG).battleStyle("single"); game.override.moveset([Moves.TACKLE]); game.override.ability(Abilities.BALL_FETCH); game.override.enemyAbility(Abilities.BALL_FETCH); diff --git a/test/arena/weather_hail.test.ts b/test/arena/weather_hail.test.ts index 7af2edf26f2..2fa4f71d8ca 100644 --- a/test/arena/weather_hail.test.ts +++ b/test/arena/weather_hail.test.ts @@ -24,7 +24,7 @@ describe("Weather - Hail", () => { game = new GameManager(phaserGame); game.override .weather(WeatherType.HAIL) - .battleType("single") + .battleStyle("single") .moveset(Moves.SPLASH) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.MAGIKARP); diff --git a/test/arena/weather_sandstorm.test.ts b/test/arena/weather_sandstorm.test.ts index d43983c4c01..e7620f6cf30 100644 --- a/test/arena/weather_sandstorm.test.ts +++ b/test/arena/weather_sandstorm.test.ts @@ -25,7 +25,7 @@ describe("Weather - Sandstorm", () => { game = new GameManager(phaserGame); game.override .weather(WeatherType.SANDSTORM) - .battleType("single") + .battleStyle("single") .moveset(Moves.SPLASH) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.MAGIKARP); @@ -60,7 +60,7 @@ describe("Weather - Sandstorm", () => { it("does not inflict damage to Rock, Ground and Steel type Pokemon", async () => { game.override - .battleType("double") + .battleStyle("double") .enemySpecies(Species.SANDSHREW) .ability(Abilities.BALL_FETCH) .enemyAbility(Abilities.BALL_FETCH); diff --git a/test/arena/weather_strong_winds.test.ts b/test/arena/weather_strong_winds.test.ts index 3a9235d9eb9..9fcdb18c872 100644 --- a/test/arena/weather_strong_winds.test.ts +++ b/test/arena/weather_strong_winds.test.ts @@ -24,7 +24,7 @@ describe("Weather - Strong Winds", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.startingLevel(10); game.override.enemySpecies(Species.TAILLOW); game.override.enemyAbility(Abilities.DELTA_STREAM); diff --git a/test/battle/ability_swap.test.ts b/test/battle/ability_swap.test.ts index 72991dba6b0..c9f91df3a48 100644 --- a/test/battle/ability_swap.test.ts +++ b/test/battle/ability_swap.test.ts @@ -1,4 +1,4 @@ -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { Stat } from "#app/enums/stat"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; @@ -26,7 +26,7 @@ describe("Test Ability Swapping", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/battle/battle-order.test.ts b/test/battle/battle-order.test.ts index 012f1ecd4bd..43fa1e59c14 100644 --- a/test/battle/battle-order.test.ts +++ b/test/battle/battle-order.test.ts @@ -24,7 +24,7 @@ describe("Battle order", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.MEWTWO); game.override.enemyAbility(Abilities.INSOMNIA); game.override.ability(Abilities.INSOMNIA); @@ -70,7 +70,7 @@ describe("Battle order", () => { }, 20000); it("double - both opponents faster than player 50/50 vs 150/150", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.startBattle([Species.BULBASAUR, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerField(); @@ -94,7 +94,7 @@ describe("Battle order", () => { }, 20000); it("double - speed tie except 1 - 100/100 vs 100/150", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.startBattle([Species.BULBASAUR, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerField(); @@ -118,7 +118,7 @@ describe("Battle order", () => { }, 20000); it("double - speed tie 100/150 vs 100/150", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.startBattle([Species.BULBASAUR, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerField(); diff --git a/test/battle/battle.test.ts b/test/battle/battle.test.ts index 36d197d1289..e980984580e 100644 --- a/test/battle/battle.test.ts +++ b/test/battle/battle.test.ts @@ -18,7 +18,7 @@ import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { VictoryPhase } from "#app/phases/victory-phase"; import GameManager from "#test/testUtils/gameManager"; import { generateStarter } from "#test/testUtils/gameManagerUtils"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { PlayerGender } from "#enums/player-gender"; @@ -49,7 +49,7 @@ describe("Test Battle Phase", () => { it("test phase interceptor with prompt", async () => { await game.phaseInterceptor.run(LoginPhase); - game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectGenderPhase", UiMode.OPTION_SELECT, () => { game.scene.gameData.gender = PlayerGender.MALE; game.endPhase(); }); @@ -57,36 +57,36 @@ describe("Test Battle Phase", () => { await game.phaseInterceptor.run(SelectGenderPhase); await game.phaseInterceptor.run(TitlePhase); - await game.waitMode(Mode.TITLE); + await game.waitMode(UiMode.TITLE); - expect(game.scene.ui?.getMode()).toBe(Mode.TITLE); + expect(game.scene.ui?.getMode()).toBe(UiMode.TITLE); expect(game.scene.gameData.gender).toBe(PlayerGender.MALE); }, 20000); it("test phase interceptor with prompt with preparation for a future prompt", async () => { await game.phaseInterceptor.run(LoginPhase); - game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectGenderPhase", UiMode.OPTION_SELECT, () => { game.scene.gameData.gender = PlayerGender.MALE; game.endPhase(); }); - game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { - game.setMode(Mode.MESSAGE); + game.onNextPrompt("CheckSwitchPhase", UiMode.CONFIRM, () => { + game.setMode(UiMode.MESSAGE); game.endPhase(); }); await game.phaseInterceptor.run(SelectGenderPhase); await game.phaseInterceptor.run(TitlePhase); - await game.waitMode(Mode.TITLE); + await game.waitMode(UiMode.TITLE); - expect(game.scene.ui?.getMode()).toBe(Mode.TITLE); + expect(game.scene.ui?.getMode()).toBe(UiMode.TITLE); expect(game.scene.gameData.gender).toBe(PlayerGender.MALE); }, 20000); it("newGame one-liner", async () => { await game.startBattle(); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); @@ -94,7 +94,7 @@ describe("Test Battle Phase", () => { game.override.starterSpecies(Species.MEWTWO); game.override.enemySpecies(Species.RATTATA); game.override.startingLevel(2000); - game.override.startingWave(3).battleType("single"); + game.override.startingWave(3).battleStyle("single"); game.override.moveset([Moves.TACKLE]); game.override.enemyAbility(Abilities.HYDRATION); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); @@ -111,7 +111,7 @@ describe("Test Battle Phase", () => { game.override.moveset([Moves.TACKLE]); game.override.enemyAbility(Abilities.HYDRATION); game.override.enemyMoveset([Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP]); - game.override.battleType("single"); + game.override.battleStyle("single"); await game.startBattle(); game.move.select(Moves.TACKLE); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnInitPhase, false); @@ -156,7 +156,7 @@ describe("Test Battle Phase", () => { await game.phaseInterceptor.run(LoginPhase); game.onNextPrompt( "SelectGenderPhase", - Mode.OPTION_SELECT, + UiMode.OPTION_SELECT, () => { game.scene.gameData.gender = PlayerGender.MALE; game.endPhase(); @@ -171,7 +171,7 @@ describe("Test Battle Phase", () => { await game.phaseInterceptor.run(LoginPhase); game.onNextPrompt( "SelectGenderPhase", - Mode.OPTION_SELECT, + UiMode.OPTION_SELECT, () => { game.scene.gameData.gender = PlayerGender.MALE; game.endPhase(); @@ -185,14 +185,14 @@ describe("Test Battle Phase", () => { await game.phaseInterceptor.run(LoginPhase); game.onNextPrompt( "SelectGenderPhase", - Mode.OPTION_SELECT, + UiMode.OPTION_SELECT, () => { game.scene.gameData.gender = PlayerGender.MALE; game.endPhase(); }, () => game.isCurrentPhase(TitlePhase), ); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { game.scene.gameMode = getGameMode(GameModes.CLASSIC); const starters = generateStarter(game.scene); const selectStarterPhase = new SelectStarterPhase(); @@ -203,50 +203,50 @@ describe("Test Battle Phase", () => { }, 20000); it("2vs1", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); game.override.ability(Abilities.HYDRATION); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("1vs1", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); game.override.ability(Abilities.HYDRATION); await game.startBattle([Species.BLASTOISE]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("2vs2", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); game.override.ability(Abilities.HYDRATION); game.override.startingWave(3); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("4vs2", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); game.override.ability(Abilities.HYDRATION); game.override.startingWave(3); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD, Species.DARKRAI, Species.GABITE]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("kill opponent pokemon", async () => { const moveToUse = Moves.SPLASH; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.starterSpecies(Species.MEWTWO); game.override.enemySpecies(Species.RATTATA); game.override.enemyAbility(Abilities.HYDRATION); @@ -266,7 +266,7 @@ describe("Test Battle Phase", () => { it("to next turn", async () => { const moveToUse = Moves.SPLASH; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.starterSpecies(Species.MEWTWO); game.override.enemySpecies(Species.RATTATA); game.override.enemyAbility(Abilities.HYDRATION); @@ -285,7 +285,7 @@ describe("Test Battle Phase", () => { it("does not set new weather if staying in same biome", async () => { const moveToUse = Moves.SPLASH; game.override - .battleType("single") + .battleStyle("single") .starterSpecies(Species.MEWTWO) .enemySpecies(Species.RATTATA) .enemyAbility(Abilities.HYDRATION) @@ -309,7 +309,7 @@ describe("Test Battle Phase", () => { it("does not force switch if active pokemon faints at same time as enemy mon and is revived in post-battle", async () => { const moveToUse = Moves.TAKE_DOWN; game.override - .battleType("single") + .battleStyle("single") .starterSpecies(Species.SAWK) .enemySpecies(Species.RATTATA) .startingWave(1) @@ -328,7 +328,7 @@ describe("Test Battle Phase", () => { game.onNextPrompt( "SwitchPhase", - Mode.PARTY, + UiMode.PARTY, () => { expect.fail("Switch was forced"); }, diff --git a/test/battle/damage_calculation.test.ts b/test/battle/damage_calculation.test.ts index dab1fc81caa..26772cbc4f0 100644 --- a/test/battle/damage_calculation.test.ts +++ b/test/battle/damage_calculation.test.ts @@ -26,7 +26,7 @@ describe("Battle Mechanics - Damage Calculation", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) @@ -47,7 +47,9 @@ describe("Battle Mechanics - Damage Calculation", () => { // expected base damage = [(2*level/5 + 2) * power * playerATK / enemyDEF / 50] + 2 // = 31.8666... - expect(enemyPokemon.getAttackDamage(playerPokemon, allMoves[Moves.TACKLE]).damage).toBeCloseTo(31); + expect(enemyPokemon.getAttackDamage({ source: playerPokemon, move: allMoves[Moves.TACKLE] }).damage).toBeCloseTo( + 31, + ); }); it("Attacks deal 1 damage at minimum", async () => { @@ -91,7 +93,7 @@ describe("Battle Mechanics - Damage Calculation", () => { const magikarp = game.scene.getPlayerPokemon()!; const dragonite = game.scene.getEnemyPokemon()!; - expect(dragonite.getAttackDamage(magikarp, allMoves[Moves.DRAGON_RAGE]).damage).toBe(40); + expect(dragonite.getAttackDamage({ source: magikarp, move: allMoves[Moves.DRAGON_RAGE] }).damage).toBe(40); }); it("One-hit KO moves ignore damage multipliers", async () => { @@ -102,7 +104,7 @@ describe("Battle Mechanics - Damage Calculation", () => { const magikarp = game.scene.getPlayerPokemon()!; const aggron = game.scene.getEnemyPokemon()!; - expect(aggron.getAttackDamage(magikarp, allMoves[Moves.FISSURE]).damage).toBe(aggron.hp); + expect(aggron.getAttackDamage({ source: magikarp, move: allMoves[Moves.FISSURE] }).damage).toBe(aggron.hp); }); it("When the user fails to use Jump Kick with Wonder Guard ability, the damage should be 1.", async () => { diff --git a/test/battle/double_battle.test.ts b/test/battle/double_battle.test.ts index 21d27573d22..a30d55aac3d 100644 --- a/test/battle/double_battle.test.ts +++ b/test/battle/double_battle.test.ts @@ -33,7 +33,7 @@ describe("Double Battles", () => { // double-battle player's pokemon both fainted in same round, then revive one, and next double battle summons two player's pokemon successfully. // (There were bugs that either only summon one when can summon two, player stuck in switchPhase etc) it("3v2 edge case: player summons 2 pokemon on the next battle after being fainted and revived", async () => { - game.override.battleType("double").enemyMoveset(Moves.SPLASH).moveset(Moves.SPLASH); + game.override.battleStyle("double").enemyMoveset(Moves.SPLASH).moveset(Moves.SPLASH); await game.startBattle([Species.BULBASAUR, Species.CHARIZARD, Species.SQUIRTLE]); game.move.select(Moves.SPLASH); diff --git a/test/battle/inverse_battle.test.ts b/test/battle/inverse_battle.test.ts index 83109c35740..799442bb603 100644 --- a/test/battle/inverse_battle.test.ts +++ b/test/battle/inverse_battle.test.ts @@ -30,7 +30,7 @@ describe("Inverse Battle", () => { game.challengeMode.addChallenge(Challenges.INVERSE_BATTLE, 1, 1); game.override - .battleType("single") + .battleStyle("single") .starterSpecies(Species.FEEBAS) .ability(Abilities.BALL_FETCH) .enemySpecies(Species.MAGIKARP) @@ -179,12 +179,12 @@ describe("Inverse Battle", () => { expect(enemy.status?.effect).toBe(StatusEffect.PARALYSIS); }); - it("Anticipation should trigger on 2x effective moves - Anticipation against Thunderbolt", async () => { + it("Anticipation should trigger on 2x effective moves", async () => { game.override.moveset([Moves.THUNDERBOLT]).enemySpecies(Species.SANDSHREW).enemyAbility(Abilities.ANTICIPATION); await game.challengeMode.startBattle(); - expect(game.scene.getEnemyPokemon()?.summonData.abilitiesApplied[0]).toBe(Abilities.ANTICIPATION); + expect(game.scene.getEnemyPokemon()?.waveData.abilitiesApplied).toContain(Abilities.ANTICIPATION); }); it("Conversion 2 should change the type to the resistive type - Conversion 2 against Dragonite", async () => { diff --git a/test/battle/special_battle.test.ts b/test/battle/special_battle.test.ts index cf7f3733484..163f23e488d 100644 --- a/test/battle/special_battle.test.ts +++ b/test/battle/special_battle.test.ts @@ -1,5 +1,5 @@ import { CommandPhase } from "#app/phases/command-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -32,65 +32,65 @@ describe("Test Battle Phase", () => { }); it("startBattle 2vs1 boss", async () => { - game.override.battleType("single").startingWave(10); + game.override.battleStyle("single").startingWave(10); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 boss", async () => { - game.override.battleType("double").startingWave(10); + game.override.battleStyle("double").startingWave(10); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 trainer", async () => { - game.override.battleType("double").startingWave(5); + game.override.battleStyle("double").startingWave(5); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs1 trainer", async () => { - game.override.battleType("single").startingWave(5); + game.override.battleStyle("single").startingWave(5); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs1 rival", async () => { - game.override.battleType("single").startingWave(8); + game.override.battleStyle("single").startingWave(8); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 rival", async () => { - game.override.battleType("double").startingWave(8); + game.override.battleStyle("double").startingWave(8); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 1vs1 trainer", async () => { - game.override.battleType("single").startingWave(5); + game.override.battleStyle("single").startingWave(5); await game.startBattle([Species.BLASTOISE]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 trainer", async () => { - game.override.battleType("double").startingWave(5); + game.override.battleStyle("double").startingWave(5); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 4vs2 trainer", async () => { - game.override.battleType("double").startingWave(5); + game.override.battleStyle("double").startingWave(5); await game.startBattle([Species.BLASTOISE, Species.CHARIZARD, Species.DARKRAI, Species.GABITE]); - expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); + expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); }); diff --git a/test/battlerTags/substitute.test.ts b/test/battlerTags/substitute.test.ts index fca3dc5ef7e..c2a99299716 100644 --- a/test/battlerTags/substitute.test.ts +++ b/test/battlerTags/substitute.test.ts @@ -1,5 +1,5 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import type { PokemonTurnData, TurnMove, PokemonMove } from "#app/field/pokemon"; +import type { PokemonTurnData, TurnMove } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon"; import type BattleScene from "#app/battle-scene"; @@ -42,7 +42,6 @@ describe("BattlerTag - SubstituteTag", () => { // simulate a Trapped tag set by another Pokemon, then expect the filter to catch it. const trapTag = new BindTag(5, 0); expect(tagFilter(trapTag)).toBeTruthy(); - return true; }) as Pokemon["findAndRemoveTags"], } as unknown as Pokemon; @@ -186,12 +185,8 @@ describe("BattlerTag - SubstituteTag", () => { vi.spyOn(mockPokemon.scene as BattleScene, "triggerPokemonBattleAnim").mockReturnValue(true); vi.spyOn(mockPokemon.scene as BattleScene, "queueMessage").mockReturnValue(); - const pokemonMove = { - getMove: vi.fn().mockReturnValue(allMoves[Moves.TACKLE]) as PokemonMove["getMove"], - } as PokemonMove; - const moveEffectPhase = { - move: pokemonMove, + move: allMoves[Moves.TACKLE], getUserPokemon: vi.fn().mockReturnValue(undefined) as MoveEffectPhase["getUserPokemon"], } as MoveEffectPhase; diff --git a/test/boss-pokemon.test.ts b/test/boss-pokemon.test.ts index 6b150de2d2b..ef95ae9bcc2 100644 --- a/test/boss-pokemon.test.ts +++ b/test/boss-pokemon.test.ts @@ -6,7 +6,7 @@ import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { EFFECTIVE_STATS } from "#app/enums/stat"; import type { EnemyPokemon } from "#app/field/pokemon"; -import { toDmgValue } from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; describe("Boss Pokemon / Shields", () => { let phaserGame: Phaser.Game; @@ -26,7 +26,7 @@ describe("Boss Pokemon / Shields", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableTrainerWaves() .disableCrits() .enemySpecies(Species.RATTATA) @@ -63,7 +63,7 @@ describe("Boss Pokemon / Shields", () => { }); it("should reduce the number of shields if we are in a double battle", async () => { - game.override.battleType("double").startingWave(150); // Floor 150 > 2 shields / 3 health segments + game.override.battleStyle("double").startingWave(150); // Floor 150 > 2 shields / 3 health segments await game.classicMode.startBattle([Species.MEWTWO]); @@ -105,7 +105,7 @@ describe("Boss Pokemon / Shields", () => { }); it("breaking multiple shields at once requires extra damage", async () => { - game.override.battleType("double").enemyHealthSegments(5); + game.override.battleStyle("double").enemyHealthSegments(5); await game.classicMode.startBattle([Species.MEWTWO]); @@ -140,7 +140,7 @@ describe("Boss Pokemon / Shields", () => { it("the number of stat stage boosts is consistent when several shields are broken at once", async () => { const shieldsToBreak = 4; - game.override.battleType("double").enemyHealthSegments(shieldsToBreak + 1); + game.override.battleStyle("double").enemyHealthSegments(shieldsToBreak + 1); await game.classicMode.startBattle([Species.MEWTWO]); diff --git a/test/daily_mode.test.ts b/test/daily_mode.test.ts index c530fca61a6..a7f5784087a 100644 --- a/test/daily_mode.test.ts +++ b/test/daily_mode.test.ts @@ -4,7 +4,7 @@ import { MapModifier } from "#app/modifier/modifier"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { Species } from "#enums/species"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import GameManager from "#test/testUtils/gameManager"; @@ -57,7 +57,7 @@ describe("Shop modifications", async () => { game.override .startingWave(9) .startingBiome(Biome.ICE_CAVE) - .battleType("single") + .battleStyle("single") .startingLevel(100) // Avoid levelling up .disableTrainerWaves() .moveset([Moves.SPLASH]) @@ -76,7 +76,7 @@ describe("Shop modifications", async () => { game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.phaseInterceptor.to("BattleEndPhase"); - game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { + game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); game.modifiers.testCheck("EVIOLITE", false).testCheck("MINI_BLACK_HOLE", false); }); @@ -87,7 +87,7 @@ describe("Shop modifications", async () => { game.move.select(Moves.SPLASH); await game.doKillOpponents(); await game.phaseInterceptor.to("BattleEndPhase"); - game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { + game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); game.modifiers.testCheck("EVIOLITE", true).testCheck("MINI_BLACK_HOLE", true); }); diff --git a/test/data/status_effect.test.ts b/test/data/status_effect.test.ts index 0fd2daa308b..111136bf0a2 100644 --- a/test/data/status_effect.test.ts +++ b/test/data/status_effect.test.ts @@ -358,7 +358,7 @@ describe("Status Effects", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) @@ -414,7 +414,7 @@ describe("Status Effects", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/eggs/egg.test.ts b/test/eggs/egg.test.ts index 8875300780b..0110aa5fdaf 100644 --- a/test/eggs/egg.test.ts +++ b/test/eggs/egg.test.ts @@ -5,7 +5,7 @@ import { EggSourceType } from "#app/enums/egg-source-types"; import { EggTier } from "#app/enums/egg-type"; import { VariantTier } from "#app/enums/variant-tier"; import EggData from "#app/system/egg-data"; -import * as Utils from "#app/utils"; +import * as Utils from "#app/utils/common"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; diff --git a/test/enemy_command.test.ts b/test/enemy_command.test.ts index 6d5cc2698a3..ae1f2918798 100644 --- a/test/enemy_command.test.ts +++ b/test/enemy_command.test.ts @@ -6,7 +6,7 @@ import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; import type { EnemyPokemon } from "#app/field/pokemon"; import { AiType } from "#app/field/pokemon"; -import { randSeedInt } from "#app/utils"; +import { randSeedInt } from "#app/utils/common"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/escape-calculations.test.ts b/test/escape-calculations.test.ts index 0cbf11dd230..56333432cee 100644 --- a/test/escape-calculations.test.ts +++ b/test/escape-calculations.test.ts @@ -1,7 +1,7 @@ import { AttemptRunPhase } from "#app/phases/attempt-run-phase"; import type { CommandPhase } from "#app/phases/command-phase"; import { Command } from "#app/ui/command-ui-handler"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; @@ -25,7 +25,7 @@ describe("Escape chance calculations", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.BULBASAUR) .enemyAbility(Abilities.INSOMNIA) .ability(Abilities.INSOMNIA); @@ -45,7 +45,7 @@ describe("Escape chance calculations", () => { await game.phaseInterceptor.to(AttemptRunPhase, false); const phase = game.scene.getCurrentPhase() as AttemptRunPhase; - const escapePercentage = new Utils.NumberHolder(0); + const escapePercentage = new NumberHolder(0); // this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping const escapeChances: { @@ -97,7 +97,7 @@ describe("Escape chance calculations", () => { }, 20000); it("double non-boss opponent", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.classicMode.startBattle([Species.BULBASAUR, Species.ABOMASNOW]); const playerPokemon = game.scene.getPlayerField(); @@ -118,7 +118,7 @@ describe("Escape chance calculations", () => { await game.phaseInterceptor.to(AttemptRunPhase, false); const phase = game.scene.getCurrentPhase() as AttemptRunPhase; - const escapePercentage = new Utils.NumberHolder(0); + const escapePercentage = new NumberHolder(0); // this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping const escapeChances: { @@ -197,7 +197,7 @@ describe("Escape chance calculations", () => { await game.phaseInterceptor.to(AttemptRunPhase, false); const phase = game.scene.getCurrentPhase() as AttemptRunPhase; - const escapePercentage = new Utils.NumberHolder(0); + const escapePercentage = new NumberHolder(0); // this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping const escapeChances: { @@ -262,7 +262,7 @@ describe("Escape chance calculations", () => { }, 20000); it("double boss opponent", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.startingWave(10); await game.classicMode.startBattle([Species.BULBASAUR, Species.ABOMASNOW]); @@ -284,7 +284,7 @@ describe("Escape chance calculations", () => { await game.phaseInterceptor.to(AttemptRunPhase, false); const phase = game.scene.getCurrentPhase() as AttemptRunPhase; - const escapePercentage = new Utils.NumberHolder(0); + const escapePercentage = new NumberHolder(0); // this sets up an object for multiple attempts. The pokemonSpeedRatio is your speed divided by the enemy speed, the escapeAttempts are the number of escape attempts and the expectedEscapeChance is the chance it should be escaping const escapeChances: { diff --git a/test/evolution.test.ts b/test/evolution.test.ts index dd6795bf161..4f91cd99382 100644 --- a/test/evolution.test.ts +++ b/test/evolution.test.ts @@ -6,7 +6,7 @@ import { import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; -import * as Utils from "#app/utils"; +import * as Utils from "#app/utils/common"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -28,7 +28,7 @@ describe("Evolution", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.MAGIKARP); game.override.enemyAbility(Abilities.BALL_FETCH); diff --git a/test/field/pokemon.test.ts b/test/field/pokemon.test.ts index 85128a31f7f..f763ab2c401 100644 --- a/test/field/pokemon.test.ts +++ b/test/field/pokemon.test.ts @@ -209,4 +209,19 @@ describe("Spec - Pokemon", () => { expect(types[1]).toBe(PokemonType.DARK); }); }); + + it.each([5, 25, 55, 95, 145, 195])( + "should set minimum IVs for enemy trainer pokemon based on wave (%i)", + async wave => { + game.override.startingWave(wave); + await game.classicMode.startBattle([Species.FEEBAS]); + const { waveIndex } = game.scene.currentBattle; + + for (const pokemon of game.scene.getEnemyParty()) { + for (const index in pokemon.ivs) { + expect(pokemon.ivs[index]).toBeGreaterThanOrEqual(Math.floor(waveIndex / 10)); + } + } + }, + ); }); diff --git a/test/game-mode.test.ts b/test/game-mode.test.ts index a2da7d1690a..0483d18e492 100644 --- a/test/game-mode.test.ts +++ b/test/game-mode.test.ts @@ -1,7 +1,7 @@ import type { GameMode } from "#app/game-mode"; import { GameModes, getGameMode } from "#app/game-mode"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import * as Utils from "#app/utils"; +import * as Utils from "#app/utils/common"; import GameManager from "#test/testUtils/gameManager"; describe("game-mode", () => { diff --git a/test/items/dire_hit.test.ts b/test/items/dire_hit.test.ts index 038d88ddc73..6e20bc723e5 100644 --- a/test/items/dire_hit.test.ts +++ b/test/items/dire_hit.test.ts @@ -6,7 +6,7 @@ import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { TempCritBoosterModifier } from "#app/modifier/modifier"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { Button } from "#app/enums/buttons"; import { CommandPhase } from "#app/phases/command-phase"; @@ -36,8 +36,7 @@ describe("Items - Dire Hit", () => { .enemyMoveset(Moves.SPLASH) .moveset([Moves.POUND]) .startingHeldItems([{ name: "DIRE_HIT" }]) - .battleType("single") - .disableCrits(); + .battleStyle("single"); }, 20000); it("should raise CRIT stage by 1", async () => { @@ -71,7 +70,7 @@ describe("Items - Dire Hit", () => { // Forced DIRE_HIT to spawn in the first slot with override game.onNextPrompt( "SelectModifierPhase", - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, () => { const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; // Traverse to first modifier slot diff --git a/test/items/double_battle_chance_booster.test.ts b/test/items/double_battle_chance_booster.test.ts index b4818e7e7ba..68a29ef823e 100644 --- a/test/items/double_battle_chance_booster.test.ts +++ b/test/items/double_battle_chance_booster.test.ts @@ -5,7 +5,7 @@ import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import type ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { Button } from "#app/enums/buttons"; @@ -69,7 +69,7 @@ describe("Items - Double Battle Chance Boosters", () => { // Forced LURE to spawn in the first slot with override game.onNextPrompt( "SelectModifierPhase", - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, () => { const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; // Traverse to first modifier slot diff --git a/test/items/eviolite.test.ts b/test/items/eviolite.test.ts index 2b82e2145e9..fafc0f4a10c 100644 --- a/test/items/eviolite.test.ts +++ b/test/items/eviolite.test.ts @@ -1,5 +1,5 @@ import { StatBoosterModifier } from "#app/modifier/modifier"; -import { NumberHolder, randItem } from "#app/utils"; +import { NumberHolder, randItem } from "#app/utils/common"; import { Species } from "#enums/species"; import { Stat } from "#enums/stat"; import GameManager from "#test/testUtils/gameManager"; @@ -22,7 +22,7 @@ describe("Items - Eviolite", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single").startingHeldItems([{ name: "EVIOLITE" }]); + game.override.battleStyle("single").startingHeldItems([{ name: "EVIOLITE" }]); }); it("should provide 50% boost to DEF and SPDEF for unevolved, unfused pokemon", async () => { diff --git a/test/items/exp_booster.test.ts b/test/items/exp_booster.test.ts index e4491b22637..ec7528c3b23 100644 --- a/test/items/exp_booster.test.ts +++ b/test/items/exp_booster.test.ts @@ -1,6 +1,6 @@ import { Abilities } from "#app/enums/abilities"; import { PokemonExpBoosterModifier } from "#app/modifier/modifier"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import GameManager from "#test/testUtils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -24,7 +24,7 @@ describe("EXP Modifier Items", () => { game.override.enemyAbility(Abilities.BALL_FETCH); game.override.ability(Abilities.BALL_FETCH); - game.override.battleType("single"); + game.override.battleStyle("single"); }); it("EXP booster items stack multiplicatively", async () => { @@ -33,7 +33,7 @@ describe("EXP Modifier Items", () => { const partyMember = game.scene.getPlayerPokemon()!; partyMember.exp = 100; - const expHolder = new Utils.NumberHolder(partyMember.exp); + const expHolder = new NumberHolder(partyMember.exp); game.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, expHolder); expect(expHolder.value).toBe(440); }, 20000); diff --git a/test/items/grip_claw.test.ts b/test/items/grip_claw.test.ts index aa7c23ca43d..2396a7ca072 100644 --- a/test/items/grip_claw.test.ts +++ b/test/items/grip_claw.test.ts @@ -27,7 +27,7 @@ describe("Items - Grip Claw", () => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .moveset([Moves.TACKLE, Moves.SPLASH, Moves.ATTRACT]) .startingHeldItems([{ name: "GRIP_CLAW", count: 1 }]) .enemySpecies(Species.SNORLAX) @@ -101,7 +101,7 @@ describe("Items - Grip Claw", () => { it("should not allow Pollen Puff to steal items when healing ally", async () => { game.override - .battleType("double") + .battleStyle("double") .moveset([Moves.POLLEN_PUFF, Moves.ENDURE]) .startingHeldItems([ { name: "GRIP_CLAW", count: 1 }, diff --git a/test/items/leek.test.ts b/test/items/leek.test.ts index ec4d075fe19..9bde2c86339 100644 --- a/test/items/leek.test.ts +++ b/test/items/leek.test.ts @@ -1,5 +1,5 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase"; -import * as Utils from "#app/utils"; +import { randInt } from "#app/utils/common"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; @@ -28,8 +28,7 @@ describe("Items - Leek", () => { .enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]) .startingHeldItems([{ name: "LEEK" }]) .moveset([Moves.TACKLE]) - .disableCrits() - .battleType("single"); + .battleStyle("single"); }); it("should raise CRIT stage by 2 when held by FARFETCHD", async () => { @@ -78,7 +77,7 @@ describe("Items - Leek", () => { // Randomly choose from the Farfetch'd line const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD]; - await game.startBattle([species[Utils.randInt(species.length)], Species.PIKACHU]); + await game.startBattle([species[randInt(species.length)], Species.PIKACHU]); const [partyMember, ally] = game.scene.getPlayerParty(); @@ -106,7 +105,7 @@ describe("Items - Leek", () => { // Randomly choose from the Farfetch'd line const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD]; - await game.startBattle([Species.PIKACHU, species[Utils.randInt(species.length)]]); + await game.startBattle([Species.PIKACHU, species[randInt(species.length)]]); const [partyMember, ally] = game.scene.getPlayerParty(); diff --git a/test/items/leftovers.test.ts b/test/items/leftovers.test.ts index ad22e9c3cae..19739703f19 100644 --- a/test/items/leftovers.test.ts +++ b/test/items/leftovers.test.ts @@ -23,7 +23,7 @@ describe("Items - Leftovers", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.startingLevel(2000); game.override.ability(Abilities.UNNERVE); game.override.moveset([Moves.SPLASH]); diff --git a/test/items/light_ball.test.ts b/test/items/light_ball.test.ts index e4959002904..91195d0b1e5 100644 --- a/test/items/light_ball.test.ts +++ b/test/items/light_ball.test.ts @@ -2,7 +2,7 @@ import { Stat } from "#enums/stat"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; import Phase from "phaser"; @@ -25,7 +25,7 @@ describe("Items - Light Ball", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); }); it("LIGHT_BALL activates in battle correctly", async () => { @@ -90,9 +90,9 @@ describe("Items - Light Ball", () => { const spAtkStat = partyMember.getStat(Stat.SPATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue); - const spAtkValue = new Utils.NumberHolder(spAtkStat); + const spAtkValue = new NumberHolder(spAtkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue); expect(atkValue.value / atkStat).toBe(1); @@ -129,9 +129,9 @@ describe("Items - Light Ball", () => { const spAtkStat = partyMember.getStat(Stat.SPATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue); - const spAtkValue = new Utils.NumberHolder(spAtkStat); + const spAtkValue = new NumberHolder(spAtkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue); expect(atkValue.value / atkStat).toBe(1); @@ -168,9 +168,9 @@ describe("Items - Light Ball", () => { const spAtkStat = partyMember.getStat(Stat.SPATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue); - const spAtkValue = new Utils.NumberHolder(spAtkStat); + const spAtkValue = new NumberHolder(spAtkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue); expect(atkValue.value / atkStat).toBe(1); @@ -197,9 +197,9 @@ describe("Items - Light Ball", () => { const spAtkStat = partyMember.getStat(Stat.SPATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, atkValue); - const spAtkValue = new Utils.NumberHolder(spAtkStat); + const spAtkValue = new NumberHolder(spAtkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPDEF, spAtkValue); expect(atkValue.value / atkStat).toBe(1); diff --git a/test/items/lock_capsule.test.ts b/test/items/lock_capsule.test.ts index 4e4182b3038..19829578d87 100644 --- a/test/items/lock_capsule.test.ts +++ b/test/items/lock_capsule.test.ts @@ -2,7 +2,7 @@ import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import GameManager from "#test/testUtils/gameManager"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -25,7 +25,7 @@ describe("Items - Lock Capsule", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .startingLevel(200) .moveset([Moves.SURF]) .enemyAbility(Abilities.BALL_FETCH) @@ -41,7 +41,7 @@ describe("Items - Lock Capsule", () => { }), ); - game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { + game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { const selectModifierPhase = game.scene.getCurrentPhase() as SelectModifierPhase; const rerollCost = selectModifierPhase.getRerollCost(true); expect(rerollCost).toBe(150); diff --git a/test/items/metal_powder.test.ts b/test/items/metal_powder.test.ts index 460a95d0f06..6be7655ec70 100644 --- a/test/items/metal_powder.test.ts +++ b/test/items/metal_powder.test.ts @@ -2,7 +2,7 @@ import { Stat } from "#enums/stat"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; import Phase from "phaser"; @@ -25,7 +25,7 @@ describe("Items - Metal Powder", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); }); it("METAL_POWDER activates in battle correctly", async () => { @@ -89,7 +89,7 @@ describe("Items - Metal Powder", () => { const defStat = partyMember.getStat(Stat.DEF); // Making sure modifier is not applied without holding item - const defValue = new Utils.NumberHolder(defStat); + const defValue = new NumberHolder(defStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); expect(defValue.value / defStat).toBe(1); @@ -122,7 +122,7 @@ describe("Items - Metal Powder", () => { const defStat = partyMember.getStat(Stat.DEF); // Making sure modifier is not applied without holding item - const defValue = new Utils.NumberHolder(defStat); + const defValue = new NumberHolder(defStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); expect(defValue.value / defStat).toBe(1); @@ -155,7 +155,7 @@ describe("Items - Metal Powder", () => { const defStat = partyMember.getStat(Stat.DEF); // Making sure modifier is not applied without holding item - const defValue = new Utils.NumberHolder(defStat); + const defValue = new NumberHolder(defStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); expect(defValue.value / defStat).toBe(1); @@ -178,7 +178,7 @@ describe("Items - Metal Powder", () => { const defStat = partyMember.getStat(Stat.DEF); // Making sure modifier is not applied without holding item - const defValue = new Utils.NumberHolder(defStat); + const defValue = new NumberHolder(defStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); expect(defValue.value / defStat).toBe(1); diff --git a/test/items/multi_lens.test.ts b/test/items/multi_lens.test.ts index 176e8213f55..ff6154b8283 100644 --- a/test/items/multi_lens.test.ts +++ b/test/items/multi_lens.test.ts @@ -27,7 +27,7 @@ describe("Items - Multi Lens", () => { .moveset([Moves.TACKLE, Moves.TRAILBLAZE, Moves.TACHYON_CUTTER, Moves.FUTURE_SIGHT]) .ability(Abilities.BALL_FETCH) .startingHeldItems([{ name: "MULTI_LENS" }]) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) @@ -99,7 +99,7 @@ describe("Items - Multi Lens", () => { }); it("should enhance multi-target moves", async () => { - game.override.battleType("double").moveset([Moves.SWIFT, Moves.SPLASH]); + game.override.battleStyle("double").moveset([Moves.SWIFT, Moves.SPLASH]); await game.classicMode.startBattle([Species.MAGIKARP, Species.FEEBAS]); @@ -213,7 +213,7 @@ describe("Items - Multi Lens", () => { }); it("should not allow Pollen Puff to heal ally more than once", async () => { - game.override.battleType("double").moveset([Moves.POLLEN_PUFF, Moves.ENDURE]); + game.override.battleStyle("double").moveset([Moves.POLLEN_PUFF, Moves.ENDURE]); await game.classicMode.startBattle([Species.BULBASAUR, Species.OMANYTE]); const [, rightPokemon] = game.scene.getPlayerField(); diff --git a/test/items/mystical_rock.test.ts b/test/items/mystical_rock.test.ts index 0558bc21fe1..59119ce8611 100644 --- a/test/items/mystical_rock.test.ts +++ b/test/items/mystical_rock.test.ts @@ -29,7 +29,7 @@ describe("Items - Mystical Rock", () => { .enemyAbility(Abilities.BALL_FETCH) .moveset([Moves.SUNNY_DAY, Moves.GRASSY_TERRAIN]) .startingHeldItems([{ name: "MYSTICAL_ROCK", count: 2 }]) - .battleType("single"); + .battleStyle("single"); }); it("should increase weather duration by +2 turns per stack", async () => { diff --git a/test/items/quick_powder.test.ts b/test/items/quick_powder.test.ts index 26faf5a0f4f..d77f981f04d 100644 --- a/test/items/quick_powder.test.ts +++ b/test/items/quick_powder.test.ts @@ -2,7 +2,7 @@ import { Stat } from "#enums/stat"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; -import * as Utils from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; import Phase from "phaser"; @@ -25,7 +25,7 @@ describe("Items - Quick Powder", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); }); it("QUICK_POWDER activates in battle correctly", async () => { @@ -89,7 +89,7 @@ describe("Items - Quick Powder", () => { const spdStat = partyMember.getStat(Stat.SPD); // Making sure modifier is not applied without holding item - const spdValue = new Utils.NumberHolder(spdStat); + const spdValue = new NumberHolder(spdStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); expect(spdValue.value / spdStat).toBe(1); @@ -122,7 +122,7 @@ describe("Items - Quick Powder", () => { const spdStat = partyMember.getStat(Stat.SPD); // Making sure modifier is not applied without holding item - const spdValue = new Utils.NumberHolder(spdStat); + const spdValue = new NumberHolder(spdStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); expect(spdValue.value / spdStat).toBe(1); @@ -155,7 +155,7 @@ describe("Items - Quick Powder", () => { const spdStat = partyMember.getStat(Stat.SPD); // Making sure modifier is not applied without holding item - const spdValue = new Utils.NumberHolder(spdStat); + const spdValue = new NumberHolder(spdStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); expect(spdValue.value / spdStat).toBe(1); @@ -178,7 +178,7 @@ describe("Items - Quick Powder", () => { const spdStat = partyMember.getStat(Stat.SPD); // Making sure modifier is not applied without holding item - const spdValue = new Utils.NumberHolder(spdStat); + const spdValue = new NumberHolder(spdStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); expect(spdValue.value / spdStat).toBe(1); diff --git a/test/items/reviver_seed.test.ts b/test/items/reviver_seed.test.ts index c06f354a94a..c109794d3d2 100644 --- a/test/items/reviver_seed.test.ts +++ b/test/items/reviver_seed.test.ts @@ -28,7 +28,7 @@ describe("Items - Reviver Seed", () => { game.override .moveset([Moves.SPLASH, Moves.TACKLE, Moves.ENDURE]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/items/scope_lens.test.ts b/test/items/scope_lens.test.ts index abd5cd7e75c..f67966ea3c9 100644 --- a/test/items/scope_lens.test.ts +++ b/test/items/scope_lens.test.ts @@ -27,8 +27,7 @@ describe("Items - Scope Lens", () => { .enemyMoveset(Moves.SPLASH) .moveset([Moves.POUND]) .startingHeldItems([{ name: "SCOPE_LENS" }]) - .battleType("single") - .disableCrits(); + .battleStyle("single"); }, 20000); it("should raise CRIT stage by 1", async () => { diff --git a/test/items/temp_stat_stage_booster.test.ts b/test/items/temp_stat_stage_booster.test.ts index 6417f898e3e..a3cfc3256bb 100644 --- a/test/items/temp_stat_stage_booster.test.ts +++ b/test/items/temp_stat_stage_booster.test.ts @@ -7,7 +7,7 @@ import { Moves } from "#app/enums/moves"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#app/enums/abilities"; import { TempStatStageBoosterModifier } from "#app/modifier/modifier"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Button } from "#app/enums/buttons"; import type ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; @@ -30,7 +30,7 @@ describe("Items - Temporary Stat Stage Boosters", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SHUCKLE) .enemyMoveset(Moves.SPLASH) .enemyAbility(Abilities.BALL_FETCH) @@ -137,7 +137,7 @@ describe("Items - Temporary Stat Stage Boosters", () => { // Forced X_ATTACK to spawn in the first slot with override game.onNextPrompt( "SelectModifierPhase", - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, () => { const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; // Traverse to first modifier slot diff --git a/test/items/thick_club.test.ts b/test/items/thick_club.test.ts index 9edbbcdc7d9..2a63a60a0e6 100644 --- a/test/items/thick_club.test.ts +++ b/test/items/thick_club.test.ts @@ -2,7 +2,7 @@ import { Stat } from "#enums/stat"; import { SpeciesStatBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; import i18next from "#app/plugins/i18n"; -import * as Utils from "#app/utils"; +import { NumberHolder, randInt } from "#app/utils/common"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; import Phase from "phaser"; @@ -25,7 +25,7 @@ describe("Items - Thick Club", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); }); it("THICK_CLUB activates in battle correctly", async () => { @@ -89,7 +89,7 @@ describe("Items - Thick Club", () => { const atkStat = partyMember.getStat(Stat.ATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(1); @@ -112,7 +112,7 @@ describe("Items - Thick Club", () => { const atkStat = partyMember.getStat(Stat.ATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(1); @@ -135,7 +135,7 @@ describe("Items - Thick Club", () => { const atkStat = partyMember.getStat(Stat.ATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(1); @@ -153,7 +153,7 @@ describe("Items - Thick Club", () => { it("THICK_CLUB held by fused CUBONE line (base)", async () => { // Randomly choose from the Cubone line const species = [Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK]; - const randSpecies = Utils.randInt(species.length); + const randSpecies = randInt(species.length); await game.classicMode.startBattle([species[randSpecies], Species.PIKACHU]); @@ -172,7 +172,7 @@ describe("Items - Thick Club", () => { const atkStat = partyMember.getStat(Stat.ATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(1); @@ -190,7 +190,7 @@ describe("Items - Thick Club", () => { it("THICK_CLUB held by fused CUBONE line (part)", async () => { // Randomly choose from the Cubone line const species = [Species.CUBONE, Species.MAROWAK, Species.ALOLA_MAROWAK]; - const randSpecies = Utils.randInt(species.length); + const randSpecies = randInt(species.length); await game.classicMode.startBattle([Species.PIKACHU, species[randSpecies]]); @@ -209,7 +209,7 @@ describe("Items - Thick Club", () => { const atkStat = partyMember.getStat(Stat.ATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(1); @@ -232,7 +232,7 @@ describe("Items - Thick Club", () => { const atkStat = partyMember.getStat(Stat.ATK); // Making sure modifier is not applied without holding item - const atkValue = new Utils.NumberHolder(atkStat); + const atkValue = new NumberHolder(atkStat); game.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(1); diff --git a/test/items/toxic_orb.test.ts b/test/items/toxic_orb.test.ts index 57e6b651b66..d02679e17c1 100644 --- a/test/items/toxic_orb.test.ts +++ b/test/items/toxic_orb.test.ts @@ -24,7 +24,7 @@ describe("Items - Toxic orb", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .ability(Abilities.BALL_FETCH) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/after_you.test.ts b/test/moves/after_you.test.ts index fde19b87b5d..3fa7c9ceb0a 100644 --- a/test/moves/after_you.test.ts +++ b/test/moves/after_you.test.ts @@ -25,7 +25,7 @@ describe("Moves - After You", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .enemyLevel(5) .enemySpecies(Species.PIKACHU) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/alluring_voice.test.ts b/test/moves/alluring_voice.test.ts index 777078e4786..240e008f311 100644 --- a/test/moves/alluring_voice.test.ts +++ b/test/moves/alluring_voice.test.ts @@ -25,7 +25,7 @@ describe("Moves - Alluring Voice", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.ICE_SCALES) diff --git a/test/moves/aromatherapy.test.ts b/test/moves/aromatherapy.test.ts index fe7a008249f..c361f4e8bbd 100644 --- a/test/moves/aromatherapy.test.ts +++ b/test/moves/aromatherapy.test.ts @@ -26,7 +26,7 @@ describe("Moves - Aromatherapy", () => { game.override .moveset([Moves.AROMATHERAPY, Moves.SPLASH]) .statusEffect(StatusEffect.BURN) - .battleType("double") + .battleStyle("double") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); }); diff --git a/test/moves/assist.test.ts b/test/moves/assist.test.ts index 68322a7f193..d0385399811 100644 --- a/test/moves/assist.test.ts +++ b/test/moves/assist.test.ts @@ -29,7 +29,7 @@ describe("Moves - Assist", () => { // because the normal moveset override doesn't allow for accurate testing of moveset changes game.override .ability(Abilities.BALL_FETCH) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyLevel(100) diff --git a/test/moves/astonish.test.ts b/test/moves/astonish.test.ts index 53922060ae6..1713df1de15 100644 --- a/test/moves/astonish.test.ts +++ b/test/moves/astonish.test.ts @@ -27,7 +27,7 @@ describe("Moves - Astonish", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.moveset([Moves.ASTONISH, Moves.SPLASH]); game.override.enemySpecies(Species.BLASTOISE); game.override.enemyAbility(Abilities.INSOMNIA); diff --git a/test/moves/aurora_veil.test.ts b/test/moves/aurora_veil.test.ts index 31f6497bae5..e9ab66d4203 100644 --- a/test/moves/aurora_veil.test.ts +++ b/test/moves/aurora_veil.test.ts @@ -5,7 +5,7 @@ import { allMoves, CritOnlyAttr } from "#app/data/moves/move"; import { ArenaTagType } from "#app/enums/arena-tag-type"; import type Pokemon from "#app/field/pokemon"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; -import { NumberHolder } from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -35,7 +35,7 @@ describe("Moves - Aurora Veil", () => { beforeEach(() => { game = new GameManager(phaserGame); globalScene = game.scene; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.NONE); game.override.moveset([Moves.ABSORB, Moves.ROCK_SLIDE, Moves.TACKLE]); game.override.enemyLevel(100); @@ -62,7 +62,7 @@ describe("Moves - Aurora Veil", () => { }); it("reduces damage of physical attacks by a third in a double battle", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); const moveToUse = Moves.ROCK_SLIDE; await game.classicMode.startBattle([Species.SHUCKLE, Species.SHUCKLE]); @@ -98,7 +98,7 @@ describe("Moves - Aurora Veil", () => { }); it("reduces damage of special attacks by a third in a double battle", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); const moveToUse = Moves.DAZZLING_GLEAM; await game.classicMode.startBattle([Species.SHUCKLE, Species.SHUCKLE]); diff --git a/test/moves/autotomize.test.ts b/test/moves/autotomize.test.ts index 62ef185dea8..08e55f242bc 100644 --- a/test/moves/autotomize.test.ts +++ b/test/moves/autotomize.test.ts @@ -24,7 +24,7 @@ describe("Moves - Autotomize", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.AUTOTOMIZE, Moves.KINGS_SHIELD, Moves.FALSE_SWIPE]) - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); }); diff --git a/test/moves/baddy_bad.test.ts b/test/moves/baddy_bad.test.ts index cba13c7ac68..ed6c9239eea 100644 --- a/test/moves/baddy_bad.test.ts +++ b/test/moves/baddy_bad.test.ts @@ -22,7 +22,7 @@ describe("Moves - Baddy Bad", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.SPLASH]) - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) diff --git a/test/moves/baneful_bunker.test.ts b/test/moves/baneful_bunker.test.ts index 4624d77dc42..4d0d7237c00 100644 --- a/test/moves/baneful_bunker.test.ts +++ b/test/moves/baneful_bunker.test.ts @@ -24,7 +24,7 @@ describe("Moves - Baneful Bunker", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.moveset(Moves.SLASH); diff --git a/test/moves/baton_pass.test.ts b/test/moves/baton_pass.test.ts index 9db6ec7c518..143ed285023 100644 --- a/test/moves/baton_pass.test.ts +++ b/test/moves/baton_pass.test.ts @@ -25,7 +25,7 @@ describe("Moves - Baton Pass", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) .moveset([Moves.BATON_PASS, Moves.NASTY_PLOT, Moves.SPLASH]) diff --git a/test/moves/beak_blast.test.ts b/test/moves/beak_blast.test.ts index 9f8b1e3d5c3..45841cecd52 100644 --- a/test/moves/beak_blast.test.ts +++ b/test/moves/beak_blast.test.ts @@ -27,7 +27,7 @@ describe("Moves - Beak Blast", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .ability(Abilities.UNNERVE) .moveset([Moves.BEAK_BLAST]) .enemySpecies(Species.SNORLAX) @@ -38,7 +38,7 @@ describe("Moves - Beak Blast", () => { }); it("should add a charge effect that burns attackers on contact", async () => { - await game.startBattle([Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -55,7 +55,7 @@ describe("Moves - Beak Blast", () => { it("should still charge and burn opponents if the user is sleeping", async () => { game.override.statusEffect(StatusEffect.SLEEP); - await game.startBattle([Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -72,7 +72,7 @@ describe("Moves - Beak Blast", () => { it("should not burn attackers that don't make contact", async () => { game.override.enemyMoveset([Moves.WATER_GUN]); - await game.startBattle([Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -89,7 +89,7 @@ describe("Moves - Beak Blast", () => { it("should only hit twice with Multi-Lens", async () => { game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]); - await game.startBattle([Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -102,7 +102,7 @@ describe("Moves - Beak Blast", () => { it("should be blocked by Protect", async () => { game.override.enemyMoveset([Moves.PROTECT]); - await game.startBattle([Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -116,4 +116,25 @@ describe("Moves - Beak Blast", () => { expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp()); expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeUndefined(); }); + + it("should still burn the enemy if the user is knocked out", async () => { + game.override.ability(Abilities.BALL_FETCH); + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + const enemyPokemon = game.scene.getEnemyPokemon()!; + const user = game.scene.getPlayerPokemon()!; + user.hp = 1; + game.move.select(Moves.BEAK_BLAST); + await game.phaseInterceptor.to("BerryPhase", false); + expect(enemyPokemon.status?.effect).toBe(StatusEffect.BURN); + }); + + it("should not burn a long reach enemy that hits the user with a contact move", async () => { + game.override.enemyAbility(Abilities.LONG_REACH); + game.override.enemyMoveset([Moves.FALSE_SWIPE]).enemyLevel(100); + await game.classicMode.startBattle([Species.MAGIKARP]); + game.move.select(Moves.BEAK_BLAST); + await game.phaseInterceptor.to("BerryPhase", false); + const enemyPokemon = game.scene.getEnemyPokemon()!; + expect(enemyPokemon.status?.effect).not.toBe(StatusEffect.BURN); + }); }); diff --git a/test/moves/beat_up.test.ts b/test/moves/beat_up.test.ts index 7e67f2ea363..ad6cad40d32 100644 --- a/test/moves/beat_up.test.ts +++ b/test/moves/beat_up.test.ts @@ -23,7 +23,7 @@ describe("Moves - Beat Up", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.SNORLAX); game.override.enemyLevel(100); diff --git a/test/moves/belly_drum.test.ts b/test/moves/belly_drum.test.ts index f01a50f8a79..8ee1026bf20 100644 --- a/test/moves/belly_drum.test.ts +++ b/test/moves/belly_drum.test.ts @@ -1,5 +1,5 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase"; -import { toDmgValue } from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { Stat } from "#enums/stat"; diff --git a/test/moves/burning_jealousy.test.ts b/test/moves/burning_jealousy.test.ts index 60387df4226..ea02bf5f4f5 100644 --- a/test/moves/burning_jealousy.test.ts +++ b/test/moves/burning_jealousy.test.ts @@ -25,7 +25,7 @@ describe("Moves - Burning Jealousy", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.ICE_SCALES) @@ -50,7 +50,7 @@ describe("Moves - Burning Jealousy", () => { }); it("should still burn the opponent if their stat stages were both raised and lowered in the same turn", async () => { - game.override.starterSpecies(0).battleType("double"); + game.override.starterSpecies(0).battleStyle("double"); await game.classicMode.startBattle([Species.FEEBAS, Species.ABRA]); const enemy = game.scene.getEnemyPokemon()!; @@ -89,7 +89,7 @@ describe("Moves - Burning Jealousy", () => { await game.phaseInterceptor.to("BerryPhase"); expect(allMoves[Moves.BURNING_JEALOUSY].calculateBattlePower).toHaveReturnedWith( - (allMoves[Moves.BURNING_JEALOUSY].power * 5461) / 4096, + allMoves[Moves.BURNING_JEALOUSY].power * 1.3, ); }); }); diff --git a/test/moves/camouflage.test.ts b/test/moves/camouflage.test.ts index 0bbab6a629a..38cdef80fc1 100644 --- a/test/moves/camouflage.test.ts +++ b/test/moves/camouflage.test.ts @@ -27,7 +27,7 @@ describe("Moves - Camouflage", () => { game.override .moveset([Moves.CAMOUFLAGE]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.REGIELEKI) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/ceaseless_edge.test.ts b/test/moves/ceaseless_edge.test.ts index d54f1bd9f21..72e552bef6f 100644 --- a/test/moves/ceaseless_edge.test.ts +++ b/test/moves/ceaseless_edge.test.ts @@ -26,7 +26,7 @@ describe("Moves - Ceaseless Edge", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.RATTATA); game.override.enemyAbility(Abilities.RUN_AWAY); game.override.enemyPassiveAbility(Abilities.RUN_AWAY); diff --git a/test/moves/chilly_reception.test.ts b/test/moves/chilly_reception.test.ts index 39342a921b6..56da5dd400c 100644 --- a/test/moves/chilly_reception.test.ts +++ b/test/moves/chilly_reception.test.ts @@ -24,7 +24,7 @@ describe("Moves - Chilly Reception", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .moveset([Moves.CHILLY_RECEPTION, Moves.SNOWSCAPE]) .enemyMoveset(Array(4).fill(Moves.SPLASH)) .enemyAbility(Abilities.BALL_FETCH) @@ -70,7 +70,7 @@ describe("Moves - Chilly Reception", () => { // enemy uses another move and weather doesn't change it("check case - enemy not selecting chilly reception doesn't change weather ", async () => { game.override - .battleType("single") + .battleStyle("single") .enemyMoveset([Moves.CHILLY_RECEPTION, Moves.TACKLE]) .moveset(Array(4).fill(Moves.SPLASH)); @@ -85,7 +85,7 @@ describe("Moves - Chilly Reception", () => { it("enemy trainer - expected behavior ", async () => { game.override - .battleType("single") + .battleStyle("single") .startingWave(8) .enemyMoveset(Array(4).fill(Moves.CHILLY_RECEPTION)) .enemySpecies(Species.MAGIKARP) diff --git a/test/moves/chloroblast.test.ts b/test/moves/chloroblast.test.ts index f08eca100c4..175227bbd5e 100644 --- a/test/moves/chloroblast.test.ts +++ b/test/moves/chloroblast.test.ts @@ -24,7 +24,7 @@ describe("Moves - Chloroblast", () => { game.override .moveset([Moves.CHLOROBLAST]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/copycat.test.ts b/test/moves/copycat.test.ts index 0d9b0951f89..2e6e8098835 100644 --- a/test/moves/copycat.test.ts +++ b/test/moves/copycat.test.ts @@ -31,7 +31,7 @@ describe("Moves - Copycat", () => { game.override .moveset([Moves.COPYCAT, Moves.SPIKY_SHIELD, Moves.SWORDS_DANCE, Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .starterSpecies(Species.FEEBAS) .enemySpecies(Species.MAGIKARP) diff --git a/test/moves/crafty_shield.test.ts b/test/moves/crafty_shield.test.ts index 3a2df6a3446..c61e6d3848a 100644 --- a/test/moves/crafty_shield.test.ts +++ b/test/moves/crafty_shield.test.ts @@ -26,7 +26,7 @@ describe("Moves - Crafty Shield", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.CRAFTY_SHIELD, Moves.SPLASH, Moves.SWORDS_DANCE]); diff --git a/test/moves/defog.test.ts b/test/moves/defog.test.ts index 64904e964c4..58631150b6f 100644 --- a/test/moves/defog.test.ts +++ b/test/moves/defog.test.ts @@ -25,7 +25,7 @@ describe("Moves - Defog", () => { game.override .moveset([Moves.MIST, Moves.SAFEGUARD, Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.SHUCKLE) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/destiny_bond.test.ts b/test/moves/destiny_bond.test.ts index c39d40427ad..6e6446f464f 100644 --- a/test/moves/destiny_bond.test.ts +++ b/test/moves/destiny_bond.test.ts @@ -33,7 +33,7 @@ describe("Moves - Destiny Bond", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .ability(Abilities.UNNERVE) // Pre-emptively prevent flakiness from opponent berries .enemySpecies(Species.RATTATA) .enemyAbility(Abilities.RUN_AWAY) @@ -157,7 +157,7 @@ describe("Moves - Destiny Bond", () => { }); it("should not KO an ally", async () => { - game.override.moveset([Moves.DESTINY_BOND, Moves.CRUNCH]).battleType("double"); + game.override.moveset([Moves.DESTINY_BOND, Moves.CRUNCH]).battleStyle("double"); await game.classicMode.startBattle([Species.SHEDINJA, Species.BULBASAUR, Species.SQUIRTLE]); const enemyPokemon0 = game.scene.getEnemyField()[0]; @@ -201,7 +201,7 @@ describe("Moves - Destiny Bond", () => { }); it("should not cause a crash if the user is KO'd by Pledge moves", async () => { - game.override.moveset([Moves.GRASS_PLEDGE, Moves.WATER_PLEDGE]).battleType("double"); + game.override.moveset([Moves.GRASS_PLEDGE, Moves.WATER_PLEDGE]).battleStyle("double"); await game.classicMode.startBattle(defaultParty); const enemyPokemon0 = game.scene.getEnemyField()[0]; diff --git a/test/moves/diamond_storm.test.ts b/test/moves/diamond_storm.test.ts index 2363122f0d7..9ba62bbc52d 100644 --- a/test/moves/diamond_storm.test.ts +++ b/test/moves/diamond_storm.test.ts @@ -25,14 +25,14 @@ describe("Moves - Diamond Storm", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.DIAMOND_STORM]) - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); }); it("should only increase defense once even if hitting 2 pokemon", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); const diamondStorm = allMoves[Moves.DIAMOND_STORM]; vi.spyOn(diamondStorm, "chance", "get").mockReturnValue(100); vi.spyOn(diamondStorm, "accuracy", "get").mockReturnValue(100); diff --git a/test/moves/dig.test.ts b/test/moves/dig.test.ts index 81339111656..80d51a5c2d5 100644 --- a/test/moves/dig.test.ts +++ b/test/moves/dig.test.ts @@ -27,7 +27,7 @@ describe("Moves - Dig", () => { game = new GameManager(phaserGame); game.override .moveset(Moves.DIG) - .battleType("single") + .battleStyle("single") .startingLevel(100) .enemySpecies(Species.SNORLAX) .enemyLevel(100) @@ -97,14 +97,20 @@ describe("Moves - Dig", () => { const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; - const preDigEarthquakeDmg = playerPokemon.getAttackDamage(enemyPokemon, allMoves[Moves.EARTHQUAKE]).damage; + const preDigEarthquakeDmg = playerPokemon.getAttackDamage({ + source: enemyPokemon, + move: allMoves[Moves.EARTHQUAKE], + }).damage; game.move.select(Moves.DIG); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("MoveEffectPhase"); - const postDigEarthquakeDmg = playerPokemon.getAttackDamage(enemyPokemon, allMoves[Moves.EARTHQUAKE]).damage; + const postDigEarthquakeDmg = playerPokemon.getAttackDamage({ + source: enemyPokemon, + move: allMoves[Moves.EARTHQUAKE], + }).damage; // these hopefully get avoid rounding errors :shrug: expect(postDigEarthquakeDmg).toBeGreaterThanOrEqual(2 * preDigEarthquakeDmg); expect(postDigEarthquakeDmg).toBeLessThan(2 * (preDigEarthquakeDmg + 1)); diff --git a/test/moves/disable.test.ts b/test/moves/disable.test.ts index fdfb748df9d..d21716145a4 100644 --- a/test/moves/disable.test.ts +++ b/test/moves/disable.test.ts @@ -23,7 +23,7 @@ describe("Moves - Disable", () => { beforeEach(async () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .ability(Abilities.BALL_FETCH) .enemyAbility(Abilities.BALL_FETCH) .moveset([Moves.DISABLE, Moves.SPLASH]) diff --git a/test/moves/dive.test.ts b/test/moves/dive.test.ts index d7b53701a25..95c3349c8a6 100644 --- a/test/moves/dive.test.ts +++ b/test/moves/dive.test.ts @@ -27,7 +27,7 @@ describe("Moves - Dive", () => { game = new GameManager(phaserGame); game.override .moveset(Moves.DIVE) - .battleType("single") + .battleStyle("single") .startingLevel(100) .enemySpecies(Species.SNORLAX) .enemyLevel(100) @@ -105,7 +105,7 @@ describe("Moves - Dive", () => { await game.phaseInterceptor.to("MoveEndPhase"); expect(playerPokemon.hp).toBeLessThan(playerPokemon.getMaxHp()); - expect(enemyPokemon.battleData.abilitiesApplied[0]).toBe(Abilities.ROUGH_SKIN); + expect(enemyPokemon.waveData.abilitiesApplied).toContain(Abilities.ROUGH_SKIN); }); it("should cancel attack after Harsh Sunlight is set", async () => { diff --git a/test/moves/doodle.test.ts b/test/moves/doodle.test.ts index 822e415c918..25dc0ddaede 100644 --- a/test/moves/doodle.test.ts +++ b/test/moves/doodle.test.ts @@ -26,7 +26,7 @@ describe("Moves - Doodle", () => { game.override .moveset([Moves.SPLASH, Moves.DOODLE]) .ability(Abilities.ADAPTABILITY) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) @@ -43,7 +43,7 @@ describe("Moves - Doodle", () => { }); it("should copy the opponent's ability to itself and its ally in doubles", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.classicMode.startBattle([Species.FEEBAS, Species.MAGIKARP]); game.move.select(Moves.DOODLE, 0, BattlerIndex.ENEMY); @@ -55,7 +55,7 @@ describe("Moves - Doodle", () => { }); it("should activate post-summon abilities", async () => { - game.override.battleType("double").enemyAbility(Abilities.INTIMIDATE); + game.override.battleStyle("double").enemyAbility(Abilities.INTIMIDATE); await game.classicMode.startBattle([Species.FEEBAS, Species.MAGIKARP]); diff --git a/test/moves/double_team.test.ts b/test/moves/double_team.test.ts index f6791573132..8eac6be11f4 100644 --- a/test/moves/double_team.test.ts +++ b/test/moves/double_team.test.ts @@ -23,7 +23,7 @@ describe("Moves - Double Team", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.moveset([Moves.DOUBLE_TEAM]); game.override.disableCrits(); game.override.ability(Abilities.BALL_FETCH); diff --git a/test/moves/dragon_cheer.test.ts b/test/moves/dragon_cheer.test.ts index 30d5af3a51b..dcf7f13eb65 100644 --- a/test/moves/dragon_cheer.test.ts +++ b/test/moves/dragon_cheer.test.ts @@ -23,7 +23,7 @@ describe("Moves - Dragon Cheer", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) .enemyLevel(20) diff --git a/test/moves/dragon_rage.test.ts b/test/moves/dragon_rage.test.ts index 99d66421463..188c1511f37 100644 --- a/test/moves/dragon_rage.test.ts +++ b/test/moves/dragon_rage.test.ts @@ -31,7 +31,7 @@ describe("Moves - Dragon Rage", () => { beforeEach(async () => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.starterSpecies(Species.SNORLAX); game.override.moveset([Moves.DRAGON_RAGE]); diff --git a/test/moves/dragon_tail.test.ts b/test/moves/dragon_tail.test.ts index 37e8aa2fe1b..31e5560d4e0 100644 --- a/test/moves/dragon_tail.test.ts +++ b/test/moves/dragon_tail.test.ts @@ -28,7 +28,7 @@ describe("Moves - Dragon Tail", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .moveset([Moves.DRAGON_TAIL, Moves.SPLASH, Moves.FLAMETHROWER]) .enemySpecies(Species.WAILORD) .enemyMoveset(Moves.SPLASH) @@ -73,7 +73,7 @@ describe("Moves - Dragon Tail", () => { }); it("should proceed without crashing in a double battle", async () => { - game.override.battleType("double").enemyMoveset(Moves.SPLASH).enemyAbility(Abilities.ROUGH_SKIN); + game.override.battleStyle("double").enemyMoveset(Moves.SPLASH).enemyAbility(Abilities.ROUGH_SKIN); await game.classicMode.startBattle([Species.DRATINI, Species.DRATINI, Species.WAILORD, Species.WAILORD]); const leadPokemon = game.scene.getPlayerParty()[0]!; @@ -102,7 +102,7 @@ describe("Moves - Dragon Tail", () => { }); it("should redirect targets upon opponent flee", async () => { - game.override.battleType("double").enemyMoveset(Moves.SPLASH).enemyAbility(Abilities.ROUGH_SKIN); + game.override.battleStyle("double").enemyMoveset(Moves.SPLASH).enemyAbility(Abilities.ROUGH_SKIN); await game.classicMode.startBattle([Species.DRATINI, Species.DRATINI, Species.WAILORD, Species.WAILORD]); const leadPokemon = game.scene.getPlayerParty()[0]!; diff --git a/test/moves/dynamax_cannon.test.ts b/test/moves/dynamax_cannon.test.ts index 9cf3106b9c1..84def8a821f 100644 --- a/test/moves/dynamax_cannon.test.ts +++ b/test/moves/dynamax_cannon.test.ts @@ -34,7 +34,7 @@ describe("Moves - Dynamax Cannon", () => { // Note that, for Waves 1-10, the level cap is 10 game.override.startingWave(1); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.disableCrits(); game.override.enemySpecies(Species.MAGIKARP); @@ -50,7 +50,7 @@ describe("Moves - Dynamax Cannon", () => { game.move.select(dynamaxCannon.id); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(dynamaxCannon.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(dynamaxCannon.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(100); }, 20000); @@ -62,7 +62,7 @@ describe("Moves - Dynamax Cannon", () => { game.move.select(dynamaxCannon.id); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(dynamaxCannon.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(dynamaxCannon.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(100); }, 20000); @@ -75,7 +75,7 @@ describe("Moves - Dynamax Cannon", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - expect(phase.move.moveId).toBe(dynamaxCannon.id); + expect(phase.move.id).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(game.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamageAnimPhase, false); @@ -90,7 +90,7 @@ describe("Moves - Dynamax Cannon", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - expect(phase.move.moveId).toBe(dynamaxCannon.id); + expect(phase.move.id).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(game.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamageAnimPhase, false); @@ -105,7 +105,7 @@ describe("Moves - Dynamax Cannon", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - expect(phase.move.moveId).toBe(dynamaxCannon.id); + expect(phase.move.id).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(game.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamageAnimPhase, false); @@ -120,7 +120,7 @@ describe("Moves - Dynamax Cannon", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - expect(phase.move.moveId).toBe(dynamaxCannon.id); + expect(phase.move.id).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(game.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamageAnimPhase, false); @@ -135,7 +135,7 @@ describe("Moves - Dynamax Cannon", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - expect(phase.move.moveId).toBe(dynamaxCannon.id); + expect(phase.move.id).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(game.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamageAnimPhase, false); @@ -150,7 +150,7 @@ describe("Moves - Dynamax Cannon", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(dynamaxCannon.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(dynamaxCannon.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); diff --git a/test/moves/electrify.test.ts b/test/moves/electrify.test.ts index 69e7504b406..25529e0b552 100644 --- a/test/moves/electrify.test.ts +++ b/test/moves/electrify.test.ts @@ -25,7 +25,7 @@ describe("Moves - Electrify", () => { game = new GameManager(phaserGame); game.override .moveset(Moves.ELECTRIFY) - .battleType("single") + .battleStyle("single") .startingLevel(100) .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/electro_shot.test.ts b/test/moves/electro_shot.test.ts index 05ab9c24a7c..0122bf04281 100644 --- a/test/moves/electro_shot.test.ts +++ b/test/moves/electro_shot.test.ts @@ -27,7 +27,7 @@ describe("Moves - Electro Shot", () => { game = new GameManager(phaserGame); game.override .moveset(Moves.ELECTRO_SHOT) - .battleType("single") + .battleStyle("single") .startingLevel(100) .enemySpecies(Species.SNORLAX) .enemyLevel(100) diff --git a/test/moves/encore.test.ts b/test/moves/encore.test.ts index 43b9eb6a77f..519e7860c04 100644 --- a/test/moves/encore.test.ts +++ b/test/moves/encore.test.ts @@ -27,7 +27,7 @@ describe("Moves - Encore", () => { game.override .moveset([Moves.SPLASH, Moves.ENCORE]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/endure.test.ts b/test/moves/endure.test.ts index 8fbb2272ece..190a689f46e 100644 --- a/test/moves/endure.test.ts +++ b/test/moves/endure.test.ts @@ -25,7 +25,7 @@ describe("Moves - Endure", () => { .moveset([Moves.THUNDER, Moves.BULLET_SEED, Moves.TOXIC, Moves.SHEER_COLD]) .ability(Abilities.SKILL_LINK) .startingLevel(100) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.NO_GUARD) diff --git a/test/moves/entrainment.test.ts b/test/moves/entrainment.test.ts index b2a0baf3e27..31a8ffcab85 100644 --- a/test/moves/entrainment.test.ts +++ b/test/moves/entrainment.test.ts @@ -25,7 +25,7 @@ describe("Moves - Entrainment", () => { game.override .moveset([Moves.SPLASH, Moves.ENTRAINMENT]) .ability(Abilities.ADAPTABILITY) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/fairy_lock.test.ts b/test/moves/fairy_lock.test.ts index a47143add4f..e967221bcae 100644 --- a/test/moves/fairy_lock.test.ts +++ b/test/moves/fairy_lock.test.ts @@ -26,7 +26,7 @@ describe("Moves - Fairy Lock", () => { game.override .moveset([Moves.FAIRY_LOCK, Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/fake_out.test.ts b/test/moves/fake_out.test.ts index 929c760ee5b..404473c8fa0 100644 --- a/test/moves/fake_out.test.ts +++ b/test/moves/fake_out.test.ts @@ -21,69 +21,76 @@ describe("Moves - Fake Out", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.CORVIKNIGHT) .moveset([Moves.FAKE_OUT, Moves.SPLASH]) .enemyMoveset(Moves.SPLASH) .enemyLevel(10) - .startingLevel(10) // prevent LevelUpPhase from happening + .startingLevel(1) // prevent LevelUpPhase from happening .disableCrits(); }); - it("can only be used on the first turn a pokemon is sent out in a battle", async () => { + it("should only work the first turn a pokemon is sent out in a battle", async () => { await game.classicMode.startBattle([Species.FEEBAS]); - const enemy = game.scene.getEnemyPokemon()!; + const corv = game.scene.getEnemyPokemon()!; game.move.select(Moves.FAKE_OUT); await game.toNextTurn(); - expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); - const postTurnOneHp = enemy.hp; + expect(corv.hp).toBeLessThan(corv.getMaxHp()); + const postTurnOneHp = corv.hp; game.move.select(Moves.FAKE_OUT); await game.toNextTurn(); - expect(enemy.hp).toBe(postTurnOneHp); - }, 20000); + expect(corv.hp).toBe(postTurnOneHp); + }); // This is a PokeRogue buff to Fake Out - it("can be used at the start of every wave even if the pokemon wasn't recalled", async () => { + it("should succeed at the start of each new wave, even if user wasn't recalled", async () => { await game.classicMode.startBattle([Species.FEEBAS]); - const enemy = game.scene.getEnemyPokemon()!; - enemy.damageAndUpdate(enemy.getMaxHp() - 1); - + // set hp to 1 for easy knockout + game.scene.getEnemyPokemon()!.hp = 1; game.move.select(Moves.FAKE_OUT); await game.toNextWave(); game.move.select(Moves.FAKE_OUT); await game.toNextTurn(); - expect(game.scene.getEnemyPokemon()!.isFullHp()).toBe(false); - }, 20000); + const corv = game.scene.getEnemyPokemon()!; + expect(corv).toBeDefined(); + expect(corv?.hp).toBeLessThan(corv?.getMaxHp()); + }); - it("can be used again if recalled and sent back out", async () => { - game.override.startingWave(4); + // This is a PokeRogue buff to Fake Out + it("should succeed at the start of each new wave, even if user wasn't recalled", async () => { + await game.classicMode.startBattle([Species.FEEBAS]); + + // set hp to 1 for easy knockout + game.scene.getEnemyPokemon()!.hp = 1; + game.move.select(Moves.FAKE_OUT); + await game.toNextWave(); + + game.move.select(Moves.FAKE_OUT); + await game.toNextTurn(); + + const corv = game.scene.getEnemyPokemon()!; + expect(corv).toBeDefined(); + expect(corv.hp).toBeLessThan(corv.getMaxHp()); + }); + + it("should succeed if recalled and sent back out", async () => { await game.classicMode.startBattle([Species.FEEBAS, Species.MAGIKARP]); - const enemy1 = game.scene.getEnemyPokemon()!; - - game.move.select(Moves.FAKE_OUT); - await game.phaseInterceptor.to("MoveEndPhase"); - - expect(enemy1.hp).toBeLessThan(enemy1.getMaxHp()); - - await game.doKillOpponents(); - await game.toNextWave(); - game.move.select(Moves.FAKE_OUT); await game.toNextTurn(); - const enemy2 = game.scene.getEnemyPokemon()!; + const corv = game.scene.getEnemyPokemon()!; - expect(enemy2.hp).toBeLessThan(enemy2.getMaxHp()); - enemy2.hp = enemy2.getMaxHp(); + expect(corv.hp).toBeLessThan(corv.getMaxHp()); + corv.hp = corv.getMaxHp(); game.doSwitchPokemon(1); await game.toNextTurn(); @@ -94,6 +101,6 @@ describe("Moves - Fake Out", () => { game.move.select(Moves.FAKE_OUT); await game.toNextTurn(); - expect(enemy2.hp).toBeLessThan(enemy2.getMaxHp()); - }, 20000); + expect(corv.hp).toBeLessThan(corv.getMaxHp()); + }); }); diff --git a/test/moves/false_swipe.test.ts b/test/moves/false_swipe.test.ts index 4fb5b81ef67..d6743477cae 100644 --- a/test/moves/false_swipe.test.ts +++ b/test/moves/false_swipe.test.ts @@ -26,7 +26,7 @@ describe("Moves - False Swipe", () => { .moveset([Moves.FALSE_SWIPE]) .ability(Abilities.BALL_FETCH) .startingLevel(1000) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/fell_stinger.test.ts b/test/moves/fell_stinger.test.ts index 2ffa44c5a3a..11731d8a06f 100644 --- a/test/moves/fell_stinger.test.ts +++ b/test/moves/fell_stinger.test.ts @@ -27,7 +27,7 @@ describe("Moves - Fell Stinger", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .moveset([Moves.FELL_STINGER, Moves.SALT_CURE, Moves.BIND, Moves.LEECH_SEED]) .startingLevel(50) .disableCrits() @@ -99,7 +99,7 @@ describe("Moves - Fell Stinger", () => { }); it("should not grant stat boost if enemy is KO'd by Salt Cure", async () => { - game.override.battleType("double").startingLevel(5); + game.override.battleStyle("double").startingLevel(5); const saltCure = allMoves[Moves.SALT_CURE]; const fellStinger = allMoves[Moves.FELL_STINGER]; vi.spyOn(saltCure, "accuracy", "get").mockReturnValue(100); @@ -124,7 +124,7 @@ describe("Moves - Fell Stinger", () => { }); it("should not grant stat boost if enemy dies to Bind or a similar effect", async () => { - game.override.battleType("double").startingLevel(5); + game.override.battleStyle("double").startingLevel(5); vi.spyOn(allMoves[Moves.BIND], "accuracy", "get").mockReturnValue(100); vi.spyOn(allMoves[Moves.FELL_STINGER], "power", "get").mockReturnValue(50000); @@ -147,7 +147,7 @@ describe("Moves - Fell Stinger", () => { }); it("should not grant stat boost if enemy dies to Leech Seed", async () => { - game.override.battleType("double").startingLevel(5); + game.override.battleStyle("double").startingLevel(5); vi.spyOn(allMoves[Moves.LEECH_SEED], "accuracy", "get").mockReturnValue(100); vi.spyOn(allMoves[Moves.FELL_STINGER], "power", "get").mockReturnValue(50000); diff --git a/test/moves/fillet_away.test.ts b/test/moves/fillet_away.test.ts index cc462b3746a..477cdf76fc7 100644 --- a/test/moves/fillet_away.test.ts +++ b/test/moves/fillet_away.test.ts @@ -1,5 +1,5 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase"; -import { toDmgValue } from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { Stat } from "#enums/stat"; diff --git a/test/moves/fissure.test.ts b/test/moves/fissure.test.ts index 63de58eb2e7..be6be079cf0 100644 --- a/test/moves/fissure.test.ts +++ b/test/moves/fissure.test.ts @@ -28,7 +28,7 @@ describe("Moves - Fissure", () => { beforeEach(async () => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.disableCrits(); game.override.starterSpecies(Species.SNORLAX); diff --git a/test/moves/flame_burst.test.ts b/test/moves/flame_burst.test.ts index b6a425e7bb5..fb92537a238 100644 --- a/test/moves/flame_burst.test.ts +++ b/test/moves/flame_burst.test.ts @@ -1,4 +1,4 @@ -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { Abilities } from "#app/enums/abilities"; import type Pokemon from "#app/field/pokemon"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; @@ -35,7 +35,7 @@ describe("Moves - Flame Burst", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.FLAME_BURST, Moves.SPLASH]); game.override.disableCrits(); game.override.ability(Abilities.UNNERVE); diff --git a/test/moves/flower_shield.test.ts b/test/moves/flower_shield.test.ts index b66847651c1..4840c6f018f 100644 --- a/test/moves/flower_shield.test.ts +++ b/test/moves/flower_shield.test.ts @@ -28,7 +28,7 @@ describe("Moves - Flower Shield", () => { game = new GameManager(phaserGame); game.override.ability(Abilities.NONE); game.override.enemyAbility(Abilities.NONE); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.moveset([Moves.FLOWER_SHIELD, Moves.SPLASH]); game.override.enemyMoveset(Moves.SPLASH); }); @@ -51,7 +51,7 @@ describe("Moves - Flower Shield", () => { }); it("raises DEF stat stage by 1 for all Grass-type Pokemon on the field by one stage - double battle", async () => { - game.override.enemySpecies(Species.MAGIKARP).startingBiome(Biome.GRASS).battleType("double"); + game.override.enemySpecies(Species.MAGIKARP).startingBiome(Biome.GRASS).battleStyle("double"); await game.startBattle([Species.CHERRIM, Species.MAGIKARP]); const field = game.scene.getField(true); diff --git a/test/moves/fly.test.ts b/test/moves/fly.test.ts index 0bd7d22b2a7..f200e976704 100644 --- a/test/moves/fly.test.ts +++ b/test/moves/fly.test.ts @@ -28,7 +28,7 @@ describe("Moves - Fly", () => { game = new GameManager(phaserGame); game.override .moveset(Moves.FLY) - .battleType("single") + .battleStyle("single") .startingLevel(100) .enemySpecies(Species.SNORLAX) .enemyLevel(100) diff --git a/test/moves/focus_punch.test.ts b/test/moves/focus_punch.test.ts index 2dc5f20f2bf..e05eb008af7 100644 --- a/test/moves/focus_punch.test.ts +++ b/test/moves/focus_punch.test.ts @@ -28,7 +28,7 @@ describe("Moves - Focus Punch", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .ability(Abilities.UNNERVE) .moveset([Moves.FOCUS_PUNCH]) .enemySpecies(Species.GROUDON) diff --git a/test/moves/follow_me.test.ts b/test/moves/follow_me.test.ts index eeb11b36f24..68c4f111bb1 100644 --- a/test/moves/follow_me.test.ts +++ b/test/moves/follow_me.test.ts @@ -24,7 +24,7 @@ describe("Moves - Follow Me", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.starterSpecies(Species.AMOONGUSS); game.override.ability(Abilities.BALL_FETCH); game.override.enemySpecies(Species.SNORLAX); diff --git a/test/moves/forests_curse.test.ts b/test/moves/forests_curse.test.ts index 8850b92662d..f363fdbd19d 100644 --- a/test/moves/forests_curse.test.ts +++ b/test/moves/forests_curse.test.ts @@ -25,7 +25,7 @@ describe("Moves - Forest's Curse", () => { game.override .moveset([Moves.FORESTS_CURSE, Moves.TRICK_OR_TREAT]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/freeze_dry.test.ts b/test/moves/freeze_dry.test.ts index 8cab56ddfd2..62168afb960 100644 --- a/test/moves/freeze_dry.test.ts +++ b/test/moves/freeze_dry.test.ts @@ -24,7 +24,7 @@ describe("Moves - Freeze-Dry", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) diff --git a/test/moves/freezy_frost.test.ts b/test/moves/freezy_frost.test.ts index c1ac4054e70..4eb3114a5ba 100644 --- a/test/moves/freezy_frost.test.ts +++ b/test/moves/freezy_frost.test.ts @@ -24,7 +24,7 @@ describe("Moves - Freezy Frost", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.RATTATA) .enemyLevel(100) .enemyMoveset([Moves.HOWL, Moves.HOWL, Moves.HOWL, Moves.HOWL]) @@ -71,7 +71,7 @@ describe("Moves - Freezy Frost", () => { }); it("should clear all stat changes in double battle", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.classicMode.startBattle([Species.SHUCKLE, Species.RATTATA]); const [leftPlayer, rightPlayer] = game.scene.getPlayerField(); const [leftOpp, rightOpp] = game.scene.getEnemyField(); diff --git a/test/moves/fusion_bolt.test.ts b/test/moves/fusion_bolt.test.ts index fc47a0f04be..33498a857a9 100644 --- a/test/moves/fusion_bolt.test.ts +++ b/test/moves/fusion_bolt.test.ts @@ -30,7 +30,7 @@ describe("Moves - Fusion Bolt", () => { game.override.enemyAbility(Abilities.ROUGH_SKIN); game.override.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.startingWave(97); game.override.disableCrits(); }); diff --git a/test/moves/fusion_flare.test.ts b/test/moves/fusion_flare.test.ts index 17653cf58bc..61bb126a75a 100644 --- a/test/moves/fusion_flare.test.ts +++ b/test/moves/fusion_flare.test.ts @@ -30,7 +30,7 @@ describe("Moves - Fusion Flare", () => { game.override.enemySpecies(Species.RATTATA); game.override.enemyMoveset([Moves.REST, Moves.REST, Moves.REST, Moves.REST]); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.startingWave(97); game.override.disableCrits(); }); diff --git a/test/moves/fusion_flare_bolt.test.ts b/test/moves/fusion_flare_bolt.test.ts index c340aeea63f..ce6bb62d1d0 100644 --- a/test/moves/fusion_flare_bolt.test.ts +++ b/test/moves/fusion_flare_bolt.test.ts @@ -39,7 +39,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.override.enemySpecies(Species.RESHIRAM); game.override.enemyMoveset([Moves.REST, Moves.REST, Moves.REST, Moves.REST]); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.startingWave(97); game.override.disableCrits(); @@ -57,12 +57,12 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -77,12 +77,12 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -97,7 +97,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100); @@ -107,7 +107,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.runFrom(MovePhase).to(MoveEndPhase); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -123,7 +123,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100); @@ -132,7 +132,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.runFrom(MovePhase).to(MoveEndPhase); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); }, 20000); @@ -147,12 +147,12 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -191,22 +191,22 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -245,22 +245,22 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); await game.phaseInterceptor.to(MoveEffectPhase, false); - expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); + expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id); await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); diff --git a/test/moves/future_sight.test.ts b/test/moves/future_sight.test.ts index 40a940447e4..48be2451195 100644 --- a/test/moves/future_sight.test.ts +++ b/test/moves/future_sight.test.ts @@ -24,7 +24,7 @@ describe("Moves - Future Sight", () => { game.override .startingLevel(50) .moveset([Moves.FUTURE_SIGHT, Moves.SPLASH]) - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.STURDY) .enemyMoveset(Moves.SPLASH); diff --git a/test/moves/gastro_acid.test.ts b/test/moves/gastro_acid.test.ts index c9f2428845e..8247d29c0a0 100644 --- a/test/moves/gastro_acid.test.ts +++ b/test/moves/gastro_acid.test.ts @@ -22,7 +22,7 @@ describe("Moves - Gastro Acid", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.startingLevel(1); game.override.enemyLevel(100); game.override.ability(Abilities.NONE); @@ -61,7 +61,7 @@ describe("Moves - Gastro Acid", () => { }); it("fails if used on an enemy with an already-suppressed ability", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); await game.startBattle(); diff --git a/test/moves/geomancy.test.ts b/test/moves/geomancy.test.ts index 34281c96c60..51659f01b12 100644 --- a/test/moves/geomancy.test.ts +++ b/test/moves/geomancy.test.ts @@ -26,7 +26,7 @@ describe("Moves - Geomancy", () => { game = new GameManager(phaserGame); game.override .moveset(Moves.GEOMANCY) - .battleType("single") + .battleStyle("single") .startingLevel(100) .enemySpecies(Species.SNORLAX) .enemyLevel(100) diff --git a/test/moves/gigaton_hammer.test.ts b/test/moves/gigaton_hammer.test.ts index a6f7438a0a2..6275e5d2dcb 100644 --- a/test/moves/gigaton_hammer.test.ts +++ b/test/moves/gigaton_hammer.test.ts @@ -22,7 +22,7 @@ describe("Moves - Gigaton Hammer", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .starterSpecies(Species.FEEBAS) .moveset([Moves.GIGATON_HAMMER]) diff --git a/test/moves/glaive_rush.test.ts b/test/moves/glaive_rush.test.ts index d3531b172e2..3c2bcea7884 100644 --- a/test/moves/glaive_rush.test.ts +++ b/test/moves/glaive_rush.test.ts @@ -23,7 +23,7 @@ describe("Moves - Glaive Rush", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/growth.test.ts b/test/moves/growth.test.ts index 926593a4f72..37cd84638ba 100644 --- a/test/moves/growth.test.ts +++ b/test/moves/growth.test.ts @@ -24,7 +24,7 @@ describe("Moves - Growth", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemyAbility(Abilities.MOXIE); game.override.ability(Abilities.INSOMNIA); game.override.moveset([Moves.GROWTH]); diff --git a/test/moves/grudge.test.ts b/test/moves/grudge.test.ts index 161fa38edd2..ecde5351d6d 100644 --- a/test/moves/grudge.test.ts +++ b/test/moves/grudge.test.ts @@ -25,7 +25,7 @@ describe("Moves - Grudge", () => { game.override .moveset([Moves.EMBER, Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.SHEDINJA) .enemyAbility(Abilities.WONDER_GUARD) diff --git a/test/moves/guard_split.test.ts b/test/moves/guard_split.test.ts index 5db07e4e82c..d182e94b203 100644 --- a/test/moves/guard_split.test.ts +++ b/test/moves/guard_split.test.ts @@ -24,7 +24,7 @@ describe("Moves - Guard Split", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.NONE) .enemySpecies(Species.MEW) .enemyLevel(200) diff --git a/test/moves/guard_swap.test.ts b/test/moves/guard_swap.test.ts index be824672f32..2076f92ccb1 100644 --- a/test/moves/guard_swap.test.ts +++ b/test/moves/guard_swap.test.ts @@ -24,7 +24,7 @@ describe("Moves - Guard Swap", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.INDEEDEE) diff --git a/test/moves/hard_press.test.ts b/test/moves/hard_press.test.ts index 8891f0bf0e2..8fe768cb8e4 100644 --- a/test/moves/hard_press.test.ts +++ b/test/moves/hard_press.test.ts @@ -27,7 +27,7 @@ describe("Moves - Hard Press", () => { beforeEach(() => { moveToCheck = allMoves[Moves.HARD_PRESS]; game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.BALL_FETCH); game.override.enemySpecies(Species.MUNCHLAX); game.override.enemyAbility(Abilities.BALL_FETCH); diff --git a/test/moves/haze.test.ts b/test/moves/haze.test.ts index d890678b466..4ddb6d1c7c5 100644 --- a/test/moves/haze.test.ts +++ b/test/moves/haze.test.ts @@ -23,7 +23,7 @@ describe("Moves - Haze", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.RATTATA); game.override.enemyLevel(100); diff --git a/test/moves/heal_bell.test.ts b/test/moves/heal_bell.test.ts index 4c0148bfd04..8ffb602c24f 100644 --- a/test/moves/heal_bell.test.ts +++ b/test/moves/heal_bell.test.ts @@ -26,7 +26,7 @@ describe("Moves - Heal Bell", () => { game.override .moveset([Moves.HEAL_BELL, Moves.SPLASH]) .statusEffect(StatusEffect.BURN) - .battleType("double") + .battleStyle("double") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); }); diff --git a/test/moves/heart_swap.test.ts b/test/moves/heart_swap.test.ts index a3d892cd518..009db731951 100644 --- a/test/moves/heart_swap.test.ts +++ b/test/moves/heart_swap.test.ts @@ -24,7 +24,7 @@ describe("Moves - Heart Swap", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.INDEEDEE) diff --git a/test/moves/hyper_beam.test.ts b/test/moves/hyper_beam.test.ts index 5cd54e9b46a..5b370f49e4c 100644 --- a/test/moves/hyper_beam.test.ts +++ b/test/moves/hyper_beam.test.ts @@ -26,7 +26,7 @@ describe("Moves - Hyper Beam", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.BALL_FETCH); game.override.enemySpecies(Species.SNORLAX); game.override.enemyAbility(Abilities.BALL_FETCH); diff --git a/test/moves/imprison.test.ts b/test/moves/imprison.test.ts index 89ef9981040..cefbaa52cad 100644 --- a/test/moves/imprison.test.ts +++ b/test/moves/imprison.test.ts @@ -23,7 +23,7 @@ describe("Moves - Imprison", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset([Moves.IMPRISON, Moves.SPLASH, Moves.GROWL]) .enemySpecies(Species.SHUCKLE) diff --git a/test/moves/instruct.test.ts b/test/moves/instruct.test.ts index 079c8803ddc..dd25db4ec90 100644 --- a/test/moves/instruct.test.ts +++ b/test/moves/instruct.test.ts @@ -32,7 +32,7 @@ describe("Moves - Instruct", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SHUCKLE) .enemyAbility(Abilities.NO_GUARD) .enemyLevel(100) @@ -89,7 +89,7 @@ describe("Moves - Instruct", () => { }); it("should repeat ally's attack on enemy", async () => { - game.override.battleType("double").enemyMoveset(Moves.SPLASH); + game.override.battleStyle("double").enemyMoveset(Moves.SPLASH); await game.classicMode.startBattle([Species.AMOONGUSS, Species.SHUCKLE]); const [amoonguss, shuckle] = game.scene.getPlayerField(); @@ -122,7 +122,7 @@ describe("Moves - Instruct", () => { }); it("should add moves to move queue for copycat", async () => { - game.override.battleType("double").moveset(Moves.INSTRUCT).enemyLevel(5); + game.override.battleStyle("double").moveset(Moves.INSTRUCT).enemyLevel(5); await game.classicMode.startBattle([Species.AMOONGUSS]); const [enemy1, enemy2] = game.scene.getEnemyField()!; @@ -179,7 +179,7 @@ describe("Moves - Instruct", () => { }); it("should redirect attacking moves if enemy faints", async () => { - game.override.battleType("double").enemyMoveset(Moves.SPLASH).enemySpecies(Species.MAGIKARP).enemyLevel(1); + game.override.battleStyle("double").enemyMoveset(Moves.SPLASH).enemySpecies(Species.MAGIKARP).enemyLevel(1); await game.classicMode.startBattle([Species.HISUI_ELECTRODE, Species.KOMMO_O]); const [electrode, kommo_o] = game.scene.getPlayerField()!; @@ -201,7 +201,7 @@ describe("Moves - Instruct", () => { expect(karp2.isFainted()).toBe(true); }); it("should allow for dancer copying of instructed dance move", async () => { - game.override.battleType("double").enemyMoveset([Moves.INSTRUCT, Moves.SPLASH]).enemyLevel(1000); + game.override.battleStyle("double").enemyMoveset([Moves.INSTRUCT, Moves.SPLASH]).enemyLevel(1000); await game.classicMode.startBattle([Species.ORICORIO, Species.VOLCARONA]); const [oricorio, volcarona] = game.scene.getPlayerField(); @@ -228,7 +228,7 @@ describe("Moves - Instruct", () => { const amoonguss = game.scene.getPlayerPokemon()!; game.move.changeMoveset(amoonguss, Moves.SEED_BOMB); - amoonguss.battleSummonData.moveHistory = [ + amoonguss.summonData.moveHistory = [ { move: Moves.SEED_BOMB, targets: [BattlerIndex.ENEMY], @@ -256,7 +256,7 @@ describe("Moves - Instruct", () => { }); it("should attempt to call enemy's disabled move, but move use itself should fail", async () => { - game.override.moveset([Moves.INSTRUCT, Moves.DISABLE]).battleType("double"); + game.override.moveset([Moves.INSTRUCT, Moves.DISABLE]).battleStyle("double"); await game.classicMode.startBattle([Species.AMOONGUSS, Species.DROWZEE]); const [enemy1, enemy2] = game.scene.getEnemyField(); @@ -301,7 +301,7 @@ describe("Moves - Instruct", () => { const player = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; - enemy.battleSummonData.moveHistory = [ + enemy.summonData.moveHistory = [ { move: Moves.SONIC_BOOM, targets: [BattlerIndex.PLAYER], @@ -350,7 +350,7 @@ describe("Moves - Instruct", () => { await game.classicMode.startBattle([Species.LUCARIO, Species.BANETTE]); const enemyPokemon = game.scene.getEnemyPokemon()!; - enemyPokemon.battleSummonData.moveHistory = [ + enemyPokemon.summonData.moveHistory = [ { move: Moves.WHIRLWIND, targets: [BattlerIndex.PLAYER], @@ -372,7 +372,7 @@ describe("Moves - Instruct", () => { it("should respect moves' original priority for psychic terrain", async () => { game.override - .battleType("double") + .battleStyle("double") .moveset([Moves.QUICK_ATTACK, Moves.SPLASH, Moves.INSTRUCT]) .enemyMoveset([Moves.SPLASH, Moves.PSYCHIC_TERRAIN]); await game.classicMode.startBattle([Species.BANETTE, Species.KLEFKI]); @@ -395,7 +395,7 @@ describe("Moves - Instruct", () => { }); it("should still work w/ prankster in psychic terrain", async () => { - game.override.battleType("double").enemyMoveset([Moves.SPLASH, Moves.PSYCHIC_TERRAIN]); + game.override.battleStyle("double").enemyMoveset([Moves.SPLASH, Moves.PSYCHIC_TERRAIN]); await game.classicMode.startBattle([Species.BANETTE, Species.KLEFKI]); const [banette, klefki] = game.scene.getPlayerField()!; @@ -419,7 +419,7 @@ describe("Moves - Instruct", () => { it("should cause spread moves to correctly hit targets in doubles after singles", async () => { game.override - .battleType("even-doubles") + .battleStyle("even-doubles") .moveset([Moves.BREAKING_SWIPE, Moves.INSTRUCT, Moves.SPLASH]) .enemyMoveset(Moves.SONIC_BOOM) .enemySpecies(Species.AXEW) @@ -446,7 +446,7 @@ describe("Moves - Instruct", () => { it("should cause AoE moves to correctly hit everyone in doubles after singles", async () => { game.override - .battleType("even-doubles") + .battleStyle("even-doubles") .moveset([Moves.BRUTAL_SWING, Moves.INSTRUCT, Moves.SPLASH]) .enemySpecies(Species.AXEW) .enemyMoveset(Moves.SONIC_BOOM) @@ -504,7 +504,7 @@ describe("Moves - Instruct", () => { it("should cause multi-hit moves to hit the appropriate number of times in doubles", async () => { game.override - .battleType("double") + .battleStyle("double") .enemyAbility(Abilities.SKILL_LINK) .moveset([Moves.SPLASH, Moves.INSTRUCT]) .enemyMoveset([Moves.BULLET_SEED, Moves.SPLASH]) diff --git a/test/moves/jaw_lock.test.ts b/test/moves/jaw_lock.test.ts index fc71397e624..71896dc3b62 100644 --- a/test/moves/jaw_lock.test.ts +++ b/test/moves/jaw_lock.test.ts @@ -29,7 +29,7 @@ describe("Moves - Jaw Lock", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.INSOMNIA) .enemyMoveset(Moves.SPLASH) @@ -107,7 +107,7 @@ describe("Moves - Jaw Lock", () => { }); it("should not trap other targets after the first target is trapped", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.startBattle([Species.CHARMANDER, Species.BULBASAUR]); diff --git a/test/moves/lash_out.test.ts b/test/moves/lash_out.test.ts index 8395633f5c0..c80a8ce348a 100644 --- a/test/moves/lash_out.test.ts +++ b/test/moves/lash_out.test.ts @@ -24,7 +24,7 @@ describe("Moves - Lash Out", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.FUR_COAT) diff --git a/test/moves/last-resort.test.ts b/test/moves/last-resort.test.ts new file mode 100644 index 00000000000..a7b462f3ca4 --- /dev/null +++ b/test/moves/last-resort.test.ts @@ -0,0 +1,166 @@ +import { BattlerIndex } from "#app/battle"; +import { MoveResult } from "#app/field/pokemon"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Last Resort", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + function expectLastResortFail() { + expect(game.scene.getPlayerPokemon()?.getLastXMoves()[0]).toEqual( + expect.objectContaining({ + move: Moves.LAST_RESORT, + result: MoveResult.FAIL, + }), + ); + } + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should fail unless all other moves (excluding itself) has been used at least once", async () => { + game.override.moveset([Moves.LAST_RESORT, Moves.SPLASH, Moves.GROWL, Moves.GROWTH]); + await game.classicMode.startBattle([Species.BLISSEY]); + + const blissey = game.scene.getPlayerPokemon()!; + expect(blissey).toBeDefined(); + + // Last resort by itself + game.move.select(Moves.LAST_RESORT); + await game.phaseInterceptor.to("TurnEndPhase"); + expectLastResortFail(); + + // Splash (1/3) + blissey.pushMoveHistory({ move: Moves.SPLASH, targets: [BattlerIndex.PLAYER] }); + game.move.select(Moves.LAST_RESORT); + await game.phaseInterceptor.to("TurnEndPhase"); + expectLastResortFail(); + + // Growl (2/3) + blissey.pushMoveHistory({ move: Moves.GROWL, targets: [BattlerIndex.ENEMY] }); + game.move.select(Moves.LAST_RESORT); + await game.phaseInterceptor.to("TurnEndPhase"); + expectLastResortFail(); // Were last resort itself counted, it would error here + + // Growth (3/3) + blissey.pushMoveHistory({ move: Moves.GROWTH, targets: [BattlerIndex.PLAYER] }); + game.move.select(Moves.LAST_RESORT); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(game.scene.getPlayerPokemon()?.getLastXMoves()[0]).toEqual( + expect.objectContaining({ + move: Moves.LAST_RESORT, + result: MoveResult.SUCCESS, + }), + ); + }); + + it("should disregard virtually invoked moves", async () => { + game.override + .moveset([Moves.LAST_RESORT, Moves.SWORDS_DANCE, Moves.ABSORB, Moves.MIRROR_MOVE]) + .enemyMoveset([Moves.SWORDS_DANCE, Moves.ABSORB]) + .ability(Abilities.DANCER) + .enemySpecies(Species.ABOMASNOW); // magikarp has 50% chance to be okho'd on absorb crit + await game.classicMode.startBattle([Species.BLISSEY]); + + // use mirror move normally to trigger absorb virtually + game.move.select(Moves.MIRROR_MOVE); + await game.forceEnemyMove(Moves.ABSORB); + await game.toNextTurn(); + + game.move.select(Moves.LAST_RESORT); + await game.forceEnemyMove(Moves.SWORDS_DANCE); // goes first to proc dancer ahead of time + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.phaseInterceptor.to("TurnEndPhase"); + expectLastResortFail(); + }); + + it("should fail if no other moves in moveset", async () => { + game.override.moveset(Moves.LAST_RESORT); + await game.classicMode.startBattle([Species.BLISSEY]); + + game.move.select(Moves.LAST_RESORT); + await game.phaseInterceptor.to("TurnEndPhase"); + + expectLastResortFail(); + }); + + it("should work if invoked virtually when all other moves have been used", async () => { + game.override.moveset([Moves.LAST_RESORT, Moves.SLEEP_TALK]).ability(Abilities.COMATOSE); + await game.classicMode.startBattle([Species.KOMALA]); + + game.move.select(Moves.SLEEP_TALK); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.scene.getPlayerPokemon()?.getLastXMoves(-1)).toEqual([ + expect.objectContaining({ + move: Moves.LAST_RESORT, + result: MoveResult.SUCCESS, + virtual: true, + }), + expect.objectContaining({ + move: Moves.SLEEP_TALK, + result: MoveResult.SUCCESS, + }), + ]); + }); + + it("should preserve usability status on reload", async () => { + game.override.moveset([Moves.LAST_RESORT, Moves.SPLASH]).ability(Abilities.COMATOSE); + await game.classicMode.startBattle([Species.BLISSEY]); + + game.move.select(Moves.SPLASH); + await game.doKillOpponents(); + await game.toNextWave(); + + const oldMoveHistory = game.scene.getPlayerPokemon()?.summonData.moveHistory; + await game.reload.reloadSession(); + + const newMoveHistory = game.scene.getPlayerPokemon()?.summonData.moveHistory; + expect(oldMoveHistory).toEqual(newMoveHistory); + + // use last resort and it should kill the karp just fine + game.move.select(Moves.LAST_RESORT); + game.scene.getEnemyPokemon()!.hp = 1; + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.isVictory()).toBe(true); + }); + + it("should fail if used while not in moveset", async () => { + game.override.moveset(Moves.MIRROR_MOVE).enemyMoveset([Moves.ABSORB, Moves.LAST_RESORT]); + await game.classicMode.startBattle([Species.BLISSEY]); + + // ensure enemy last resort succeeds + game.move.select(Moves.MIRROR_MOVE); + await game.forceEnemyMove(Moves.ABSORB); + await game.phaseInterceptor.to("TurnEndPhase"); + game.move.select(Moves.MIRROR_MOVE); + await game.forceEnemyMove(Moves.LAST_RESORT); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.phaseInterceptor.to("TurnEndPhase"); + + expectLastResortFail(); + }); +}); diff --git a/test/moves/last_respects.test.ts b/test/moves/last_respects.test.ts index ccab8a43415..a69ecb2e989 100644 --- a/test/moves/last_respects.test.ts +++ b/test/moves/last_respects.test.ts @@ -31,7 +31,7 @@ describe("Moves - Last Respects", () => { move = allMoves[Moves.LAST_RESPECTS]; basePower = move.power; game.override - .battleType("single") + .battleStyle("single") .disableCrits() .moveset([Moves.LAST_RESPECTS, Moves.EXPLOSION, Moves.LUNAR_DANCE]) .ability(Abilities.BALL_FETCH) diff --git a/test/moves/light_screen.test.ts b/test/moves/light_screen.test.ts index 9cc6944ed3e..cea26f29542 100644 --- a/test/moves/light_screen.test.ts +++ b/test/moves/light_screen.test.ts @@ -6,7 +6,7 @@ import { Abilities } from "#app/enums/abilities"; import { ArenaTagType } from "#app/enums/arena-tag-type"; import type Pokemon from "#app/field/pokemon"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; -import { NumberHolder } from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; @@ -34,7 +34,7 @@ describe("Moves - Light Screen", () => { beforeEach(() => { game = new GameManager(phaserGame); globalScene = game.scene; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.NONE); game.override.moveset([Moves.ABSORB, Moves.DAZZLING_GLEAM, Moves.TACKLE]); game.override.enemyLevel(100); @@ -61,7 +61,7 @@ describe("Moves - Light Screen", () => { }); it("reduces damage of special attacks by a third in a double battle", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); const moveToUse = Moves.DAZZLING_GLEAM; await game.classicMode.startBattle([Species.SHUCKLE, Species.SHUCKLE]); diff --git a/test/moves/lucky_chant.test.ts b/test/moves/lucky_chant.test.ts index 21802574e79..e2a28a7bbe3 100644 --- a/test/moves/lucky_chant.test.ts +++ b/test/moves/lucky_chant.test.ts @@ -25,7 +25,7 @@ describe("Moves - Lucky Chant", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .moveset([Moves.LUCKY_CHANT, Moves.SPLASH, Moves.FOLLOW_ME]) .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.INSOMNIA) @@ -54,7 +54,7 @@ describe("Moves - Lucky Chant", () => { }); it("should prevent critical hits against the user's ally", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); diff --git a/test/moves/lunar_blessing.test.ts b/test/moves/lunar_blessing.test.ts index d97e6c978eb..ee35107fccd 100644 --- a/test/moves/lunar_blessing.test.ts +++ b/test/moves/lunar_blessing.test.ts @@ -22,7 +22,7 @@ describe("Moves - Lunar Blessing", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.enemySpecies(Species.SHUCKLE); game.override.enemyMoveset(Moves.SPLASH); diff --git a/test/moves/lunar_dance.test.ts b/test/moves/lunar_dance.test.ts index d3dceba087c..30abe765291 100644 --- a/test/moves/lunar_dance.test.ts +++ b/test/moves/lunar_dance.test.ts @@ -25,7 +25,7 @@ describe("Moves - Lunar Dance", () => { game = new GameManager(phaserGame); game.override .statusEffect(StatusEffect.BURN) - .battleType("double") + .battleStyle("double") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); }); diff --git a/test/moves/magic_coat.test.ts b/test/moves/magic_coat.test.ts index 2cc8dea8938..23deef97318 100644 --- a/test/moves/magic_coat.test.ts +++ b/test/moves/magic_coat.test.ts @@ -30,7 +30,7 @@ describe("Moves - Magic Coat", () => { game = new GameManager(phaserGame); game.override .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) @@ -82,7 +82,7 @@ describe("Moves - Magic Coat", () => { }); it("should individually bounce back multi-target moves when used by both targets in doubles", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.GROWL, Moves.SPLASH]); await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); @@ -95,7 +95,7 @@ describe("Moves - Magic Coat", () => { }); it("should bounce back a spread status move against both pokemon", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.GROWL, Moves.SPLASH]); game.override.enemyMoveset([Moves.SPLASH, Moves.MAGIC_COAT]); await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); @@ -121,7 +121,7 @@ describe("Moves - Magic Coat", () => { }); it("should not bounce back a move that was just bounced", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.ability(Abilities.MAGIC_BOUNCE); game.override.moveset([Moves.GROWL, Moves.MAGIC_COAT]); game.override.enemyMoveset([Moves.SPLASH, Moves.MAGIC_COAT]); @@ -159,7 +159,7 @@ describe("Moves - Magic Coat", () => { }); it("should only bounce spikes back once when both targets use magic coat in doubles", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.classicMode.startBattle([Species.MAGIKARP]); game.override.moveset([Moves.SPIKES]); @@ -206,7 +206,7 @@ describe("Moves - Magic Coat", () => { // TODO: stomping tantrum should consider moves that were bounced. it.todo("should cause stomping tantrum to double in power when the last move was bounced", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); await game.classicMode.startBattle([Species.MAGIKARP]); game.override.moveset([Moves.STOMPING_TANTRUM, Moves.CHARM]); diff --git a/test/moves/magnet_rise.test.ts b/test/moves/magnet_rise.test.ts index 725bbb99276..62ad0c88091 100644 --- a/test/moves/magnet_rise.test.ts +++ b/test/moves/magnet_rise.test.ts @@ -23,7 +23,7 @@ describe("Moves - Magnet Rise", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.starterSpecies(Species.MAGNEZONE); game.override.enemySpecies(Species.RATTATA); game.override.enemyMoveset([Moves.DRILL_RUN, Moves.DRILL_RUN, Moves.DRILL_RUN, Moves.DRILL_RUN]); diff --git a/test/moves/make_it_rain.test.ts b/test/moves/make_it_rain.test.ts index 38460d99e63..4d94537bcec 100644 --- a/test/moves/make_it_rain.test.ts +++ b/test/moves/make_it_rain.test.ts @@ -24,7 +24,7 @@ describe("Moves - Make It Rain", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.MAKE_IT_RAIN, Moves.SPLASH]); game.override.enemySpecies(Species.SNORLAX); game.override.enemyAbility(Abilities.INSOMNIA); @@ -48,7 +48,7 @@ describe("Moves - Make It Rain", () => { it("should apply effects even if the target faints", async () => { game.override.enemyLevel(1); // ensures the enemy will faint - game.override.battleType("single"); + game.override.battleStyle("single"); await game.startBattle([Species.CHARIZARD]); diff --git a/test/moves/mat_block.test.ts b/test/moves/mat_block.test.ts index ddfa29a53da..9ed0f497af9 100644 --- a/test/moves/mat_block.test.ts +++ b/test/moves/mat_block.test.ts @@ -26,7 +26,7 @@ describe("Moves - Mat Block", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.MAT_BLOCK, Moves.SPLASH]); diff --git a/test/moves/metal_burst.test.ts b/test/moves/metal_burst.test.ts index 2cbc999436f..7fa5434dc58 100644 --- a/test/moves/metal_burst.test.ts +++ b/test/moves/metal_burst.test.ts @@ -27,7 +27,7 @@ describe("Moves - Metal Burst", () => { .moveset([Moves.METAL_BURST, Moves.FISSURE, Moves.PRECIPICE_BLADES]) .ability(Abilities.PURE_POWER) .startingLevel(10) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.PICHU) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/metronome.test.ts b/test/moves/metronome.test.ts index 80f32a3a6fb..bf177fb1a93 100644 --- a/test/moves/metronome.test.ts +++ b/test/moves/metronome.test.ts @@ -30,7 +30,7 @@ describe("Moves - Metronome", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.METRONOME, Moves.SPLASH]) - .battleType("single") + .battleStyle("single") .startingLevel(100) .starterSpecies(Species.REGIELEKI) .enemyLevel(100) @@ -79,7 +79,7 @@ describe("Moves - Metronome", () => { }); it("should only target ally for Aromatic Mist", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.classicMode.startBattle([Species.REGIELEKI, Species.RATTATA]); const [leftPlayer, rightPlayer] = game.scene.getPlayerField(); const [leftOpp, rightOpp] = game.scene.getEnemyField(); diff --git a/test/moves/mirror_move.test.ts b/test/moves/mirror_move.test.ts index 9178410adb2..438c594d839 100644 --- a/test/moves/mirror_move.test.ts +++ b/test/moves/mirror_move.test.ts @@ -27,7 +27,7 @@ describe("Moves - Mirror Move", () => { game.override .moveset([Moves.MIRROR_MOVE, Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) @@ -35,7 +35,7 @@ describe("Moves - Mirror Move", () => { }); it("should use the last move that the target used on the user", async () => { - game.override.battleType("double").enemyMoveset([Moves.TACKLE, Moves.GROWL]); + game.override.battleStyle("double").enemyMoveset([Moves.TACKLE, Moves.GROWL]); await game.classicMode.startBattle([Species.FEEBAS, Species.MAGIKARP]); game.move.select(Moves.MIRROR_MOVE, 0, BattlerIndex.ENEMY); // target's last move is Tackle, enemy should receive damage from Mirror Move copying Tackle diff --git a/test/moves/mist.test.ts b/test/moves/mist.test.ts index 2deb6f9b90d..70cdf5b55a0 100644 --- a/test/moves/mist.test.ts +++ b/test/moves/mist.test.ts @@ -25,7 +25,7 @@ describe("Moves - Mist", () => { game.override .moveset([Moves.MIST, Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/moongeist_beam.test.ts b/test/moves/moongeist_beam.test.ts index 117fe513e17..82a2567377b 100644 --- a/test/moves/moongeist_beam.test.ts +++ b/test/moves/moongeist_beam.test.ts @@ -26,7 +26,7 @@ describe("Moves - Moongeist Beam", () => { .moveset([Moves.MOONGEIST_BEAM, Moves.METRONOME]) .ability(Abilities.BALL_FETCH) .startingLevel(200) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.STURDY) diff --git a/test/moves/multi_target.test.ts b/test/moves/multi_target.test.ts index 2b17929a5df..ad47d540a14 100644 --- a/test/moves/multi_target.test.ts +++ b/test/moves/multi_target.test.ts @@ -1,7 +1,7 @@ import { BattlerIndex } from "#app/battle"; import { Abilities } from "#app/enums/abilities"; import { Species } from "#app/enums/species"; -import * as Utils from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; import { Moves } from "#enums/moves"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; @@ -25,7 +25,7 @@ describe("Multi-target damage reduction", () => { game = new GameManager(phaserGame); game.override .disableCrits() - .battleType("double") + .battleStyle("double") .enemyLevel(100) .startingLevel(100) .enemySpecies(Species.POLIWAG) @@ -71,8 +71,8 @@ describe("Multi-target damage reduction", () => { // Single target moves don't get reduced expect(tackle1).toBe(tackle2); // Moves that target all enemies get reduced if there's more than one enemy - expect(gleam1).toBeLessThanOrEqual(Utils.toDmgValue(gleam2 * 0.75) + 1); - expect(gleam1).toBeGreaterThanOrEqual(Utils.toDmgValue(gleam2 * 0.75) - 1); + expect(gleam1).toBeLessThanOrEqual(toDmgValue(gleam2 * 0.75) + 1); + expect(gleam1).toBeGreaterThanOrEqual(toDmgValue(gleam2 * 0.75) - 1); }); it("should reduce earthquake when more than one pokemon other than user is not fainted", async () => { @@ -122,7 +122,7 @@ describe("Multi-target damage reduction", () => { const damageEnemy1Turn3 = enemy1.getMaxHp() - enemy1.hp; // Turn 3: 1 target, should be no damage reduction - expect(damageEnemy1Turn1).toBeLessThanOrEqual(Utils.toDmgValue(damageEnemy1Turn3 * 0.75) + 1); - expect(damageEnemy1Turn1).toBeGreaterThanOrEqual(Utils.toDmgValue(damageEnemy1Turn3 * 0.75) - 1); + expect(damageEnemy1Turn1).toBeLessThanOrEqual(toDmgValue(damageEnemy1Turn3 * 0.75) + 1); + expect(damageEnemy1Turn1).toBeGreaterThanOrEqual(toDmgValue(damageEnemy1Turn3 * 0.75) - 1); }); }); diff --git a/test/moves/nightmare.test.ts b/test/moves/nightmare.test.ts index e1cef0084ee..044856ae33d 100644 --- a/test/moves/nightmare.test.ts +++ b/test/moves/nightmare.test.ts @@ -24,7 +24,7 @@ describe("Moves - Nightmare", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.RATTATA) .enemyMoveset(Moves.SPLASH) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/obstruct.test.ts b/test/moves/obstruct.test.ts index d8e3a949f08..f35a5964bcb 100644 --- a/test/moves/obstruct.test.ts +++ b/test/moves/obstruct.test.ts @@ -22,7 +22,7 @@ describe("Moves - Obstruct", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyMoveset(Moves.TACKLE) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/octolock.test.ts b/test/moves/octolock.test.ts index c9c5fd42f7e..fb57d0bfad5 100644 --- a/test/moves/octolock.test.ts +++ b/test/moves/octolock.test.ts @@ -25,7 +25,7 @@ describe("Moves - Octolock", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyMoveset(Moves.SPLASH) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/order_up.test.ts b/test/moves/order_up.test.ts index 516f7f625a3..b5df5bfba41 100644 --- a/test/moves/order_up.test.ts +++ b/test/moves/order_up.test.ts @@ -29,7 +29,7 @@ describe("Moves - Order Up", () => { game.override .moveset(Moves.ORDER_UP) .ability(Abilities.COMMANDER) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) @@ -81,7 +81,7 @@ describe("Moves - Order Up", () => { await game.phaseInterceptor.to("BerryPhase", false); - expect(dondozo.battleData.abilitiesApplied.includes(Abilities.SHEER_FORCE)).toBeTruthy(); + expect(dondozo.waveData.abilitiesApplied.has(Abilities.SHEER_FORCE)).toBeTruthy(); expect(dondozo.getStatStage(Stat.ATK)).toBe(3); }); }); diff --git a/test/moves/parting_shot.test.ts b/test/moves/parting_shot.test.ts index 699d960f882..a65c1a5b3a5 100644 --- a/test/moves/parting_shot.test.ts +++ b/test/moves/parting_shot.test.ts @@ -26,7 +26,7 @@ describe("Moves - Parting Shot", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.moveset([Moves.PARTING_SHOT, Moves.SPLASH]); game.override.enemyMoveset(Moves.SPLASH); game.override.startingLevel(5); diff --git a/test/moves/plasma_fists.test.ts b/test/moves/plasma_fists.test.ts index fe19ab4a460..b6a5ceaed68 100644 --- a/test/moves/plasma_fists.test.ts +++ b/test/moves/plasma_fists.test.ts @@ -25,7 +25,7 @@ describe("Moves - Plasma Fists", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.PLASMA_FISTS, Moves.TACKLE]) - .battleType("double") + .battleStyle("double") .startingLevel(100) .enemySpecies(Species.DUSCLOPS) .enemyAbility(Abilities.BALL_FETCH) @@ -56,7 +56,7 @@ describe("Moves - Plasma Fists", () => { }); it("should not affect Normal-type attacks boosted by Pixilate", async () => { - game.override.battleType("single").enemyAbility(Abilities.PIXILATE); + game.override.battleStyle("single").enemyAbility(Abilities.PIXILATE); await game.classicMode.startBattle([Species.ONIX]); @@ -74,7 +74,7 @@ describe("Moves - Plasma Fists", () => { }); it("should affect moves that become Normal type due to Normalize", async () => { - game.override.battleType("single").enemyAbility(Abilities.NORMALIZE).enemyMoveset(Moves.WATER_GUN); + game.override.battleStyle("single").enemyAbility(Abilities.NORMALIZE).enemyMoveset(Moves.WATER_GUN); await game.classicMode.startBattle([Species.DUSCLOPS]); diff --git a/test/moves/pledge_moves.test.ts b/test/moves/pledge_moves.test.ts index c866d15357c..2bfd408e5fb 100644 --- a/test/moves/pledge_moves.test.ts +++ b/test/moves/pledge_moves.test.ts @@ -1,11 +1,11 @@ import { BattlerIndex } from "#app/battle"; -import { allAbilities } from "#app/data/ability"; +import { allAbilities } from "#app/data/data-lists"; import { ArenaTagSide } from "#app/data/arena-tag"; import { allMoves, FlinchAttr } from "#app/data/moves/move"; import { PokemonType } from "#enums/pokemon-type"; import { ArenaTagType } from "#enums/arena-tag-type"; import { Stat } from "#enums/stat"; -import { toDmgValue } from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -30,7 +30,7 @@ describe("Moves - Pledge Moves", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .startingLevel(100) .moveset([Moves.FIRE_PLEDGE, Moves.GRASS_PLEDGE, Moves.WATER_PLEDGE, Moves.SPLASH]) .enemySpecies(Species.SNORLAX) @@ -86,7 +86,7 @@ describe("Moves - Pledge Moves", () => { }); it("Fire Pledge - should not combine with an enemy's Pledge move", async () => { - game.override.battleType("single").enemyMoveset(Moves.GRASS_PLEDGE); + game.override.battleStyle("single").enemyMoveset(Moves.GRASS_PLEDGE); await game.classicMode.startBattle([Species.CHARIZARD]); diff --git a/test/moves/pollen_puff.test.ts b/test/moves/pollen_puff.test.ts index 3af3ea1f41d..31d5950b47d 100644 --- a/test/moves/pollen_puff.test.ts +++ b/test/moves/pollen_puff.test.ts @@ -25,7 +25,7 @@ describe("Moves - Pollen Puff", () => { game.override .moveset([Moves.POLLEN_PUFF]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) @@ -33,7 +33,7 @@ describe("Moves - Pollen Puff", () => { }); it("should not heal more than once when the user has a source of multi-hit", async () => { - game.override.battleType("double").moveset([Moves.POLLEN_PUFF, Moves.ENDURE]).ability(Abilities.PARENTAL_BOND); + game.override.battleStyle("double").moveset([Moves.POLLEN_PUFF, Moves.ENDURE]).ability(Abilities.PARENTAL_BOND); await game.classicMode.startBattle([Species.BULBASAUR, Species.OMANYTE]); const [_, rightPokemon] = game.scene.getPlayerField(); diff --git a/test/moves/powder.test.ts b/test/moves/powder.test.ts index 522b0b74ca7..457beb60f91 100644 --- a/test/moves/powder.test.ts +++ b/test/moves/powder.test.ts @@ -27,7 +27,7 @@ describe("Moves - Powder", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override .enemySpecies(Species.SNORLAX) @@ -146,11 +146,11 @@ describe("Moves - Powder", () => { await game.phaseInterceptor.to(BerryPhase, false); expect(enemyPokemon.getLastXMoves()[0].result).toBe(MoveResult.FAIL); expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp()); - expect(enemyPokemon.summonData?.types).not.toBe(PokemonType.FIRE); + expect(enemyPokemon.summonData.types).not.toBe(PokemonType.FIRE); }); it("should cancel Fire-type moves generated by the target's Dancer ability", async () => { - game.override.battleType("double").enemySpecies(Species.BLASTOISE).enemyAbility(Abilities.DANCER); + game.override.battleStyle("double").enemySpecies(Species.BLASTOISE).enemyAbility(Abilities.DANCER); await game.classicMode.startBattle([Species.CHARIZARD, Species.CHARIZARD]); @@ -227,7 +227,7 @@ describe("Moves - Powder", () => { }); it("should cancel Grass Pledge if used after ally's Fire Pledge", async () => { - game.override.enemyMoveset([Moves.FIRE_PLEDGE, Moves.GRASS_PLEDGE]).battleType("double"); + game.override.enemyMoveset([Moves.FIRE_PLEDGE, Moves.GRASS_PLEDGE]).battleStyle("double"); await game.classicMode.startBattle([Species.CHARIZARD, Species.CHARIZARD]); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -244,7 +244,7 @@ describe("Moves - Powder", () => { }); it("should cancel Fire Pledge if used before ally's Water Pledge", async () => { - game.override.enemyMoveset([Moves.FIRE_PLEDGE, Moves.WATER_PLEDGE]).battleType("double"); + game.override.enemyMoveset([Moves.FIRE_PLEDGE, Moves.WATER_PLEDGE]).battleStyle("double"); await game.classicMode.startBattle([Species.CHARIZARD, Species.CHARIZARD]); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -261,7 +261,7 @@ describe("Moves - Powder", () => { }); it("should NOT cancel Fire Pledge if used after ally's Water Pledge", async () => { - game.override.enemyMoveset([Moves.FIRE_PLEDGE, Moves.WATER_PLEDGE]).battleType("double"); + game.override.enemyMoveset([Moves.FIRE_PLEDGE, Moves.WATER_PLEDGE]).battleStyle("double"); await game.classicMode.startBattle([Species.CHARIZARD, Species.CHARIZARD]); const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/test/moves/power_shift.test.ts b/test/moves/power_shift.test.ts index fbc6d732d30..0fee044f5ad 100644 --- a/test/moves/power_shift.test.ts +++ b/test/moves/power_shift.test.ts @@ -23,7 +23,7 @@ describe("Moves - Power Shift", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.POWER_SHIFT, Moves.BULK_UP]) - .battleType("single") + .battleStyle("single") .ability(Abilities.BALL_FETCH) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); diff --git a/test/moves/power_split.test.ts b/test/moves/power_split.test.ts index 9150a707ad5..f15275fce9e 100644 --- a/test/moves/power_split.test.ts +++ b/test/moves/power_split.test.ts @@ -24,7 +24,7 @@ describe("Moves - Power Split", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.NONE) .enemySpecies(Species.MEW) .enemyLevel(200) diff --git a/test/moves/power_swap.test.ts b/test/moves/power_swap.test.ts index d6f5e782e66..5f6aa022a51 100644 --- a/test/moves/power_swap.test.ts +++ b/test/moves/power_swap.test.ts @@ -24,7 +24,7 @@ describe("Moves - Power Swap", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.INDEEDEE) diff --git a/test/moves/power_trick.test.ts b/test/moves/power_trick.test.ts index 0cd849bbcc5..181eeca81bc 100644 --- a/test/moves/power_trick.test.ts +++ b/test/moves/power_trick.test.ts @@ -25,7 +25,7 @@ describe("Moves - Power Trick", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.MEW) diff --git a/test/moves/protect.test.ts b/test/moves/protect.test.ts index d50c490f7d3..183430f8654 100644 --- a/test/moves/protect.test.ts +++ b/test/moves/protect.test.ts @@ -27,7 +27,7 @@ describe("Moves - Protect", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.moveset([Moves.PROTECT]); game.override.enemySpecies(Species.SNORLAX); diff --git a/test/moves/psycho_shift.test.ts b/test/moves/psycho_shift.test.ts index 0a82189d201..678742906c7 100644 --- a/test/moves/psycho_shift.test.ts +++ b/test/moves/psycho_shift.test.ts @@ -26,7 +26,7 @@ describe("Moves - Psycho Shift", () => { .moveset([Moves.PSYCHO_SHIFT]) .ability(Abilities.BALL_FETCH) .statusEffect(StatusEffect.POISON) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyLevel(20) diff --git a/test/moves/purify.test.ts b/test/moves/purify.test.ts index 30d9df8ff67..191539d8cec 100644 --- a/test/moves/purify.test.ts +++ b/test/moves/purify.test.ts @@ -25,7 +25,7 @@ describe("Moves - Purify", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.starterSpecies(Species.PYUKUMUKU); game.override.startingLevel(10); diff --git a/test/moves/quash.test.ts b/test/moves/quash.test.ts index f85dbd89517..5bf8271320b 100644 --- a/test/moves/quash.test.ts +++ b/test/moves/quash.test.ts @@ -25,7 +25,7 @@ describe("Moves - Quash", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .enemyLevel(1) .enemySpecies(Species.SLOWPOKE) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/quick_guard.test.ts b/test/moves/quick_guard.test.ts index 22d4a5078ac..d9970ce64fa 100644 --- a/test/moves/quick_guard.test.ts +++ b/test/moves/quick_guard.test.ts @@ -25,7 +25,7 @@ describe("Moves - Quick Guard", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.QUICK_GUARD, Moves.SPLASH, Moves.FOLLOW_ME]); @@ -84,7 +84,7 @@ describe("Moves - Quick Guard", () => { }); test("should fail if the user is the last to move in the turn", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemyMoveset([Moves.QUICK_GUARD]); await game.classicMode.startBattle([Species.CHARIZARD]); diff --git a/test/moves/rage_fist.test.ts b/test/moves/rage_fist.test.ts index f44901c5aba..f215c5955c6 100644 --- a/test/moves/rage_fist.test.ts +++ b/test/moves/rage_fist.test.ts @@ -7,6 +7,7 @@ import type Move from "#app/data/moves/move"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { BattleType } from "#enums/battle-type"; describe("Moves - Rage Fist", () => { let phaserGame: Phaser.Game; @@ -27,20 +28,19 @@ describe("Moves - Rage Fist", () => { move = allMoves[Moves.RAGE_FIST]; game = new GameManager(phaserGame); game.override - .battleType("single") - .moveset([Moves.RAGE_FIST, Moves.SPLASH, Moves.SUBSTITUTE]) + .battleStyle("single") + .moveset([Moves.RAGE_FIST, Moves.SPLASH, Moves.SUBSTITUTE, Moves.TIDY_UP]) .startingLevel(100) .enemyLevel(1) + .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.DOUBLE_KICK); vi.spyOn(move, "calculateBattlePower"); }); - it("should have 100 more power if hit twice before calling Rage Fist", async () => { - game.override.enemySpecies(Species.MAGIKARP); - - await game.classicMode.startBattle([Species.MAGIKARP]); + it("should gain power per hit taken", async () => { + await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.RAGE_FIST); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); @@ -49,51 +49,95 @@ describe("Moves - Rage Fist", () => { expect(move.calculateBattlePower).toHaveLastReturnedWith(150); }); - it("should maintain its power during next battle if it is within the same arena encounter", async () => { - game.override.enemySpecies(Species.MAGIKARP).startingWave(1); + it("caps at 6 hits taken", async () => { + await game.classicMode.startBattle([Species.FEEBAS]); - await game.classicMode.startBattle([Species.MAGIKARP]); + // spam splash against magikarp hitting us 2 times per turn + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + game.move.select(Moves.RAGE_FIST); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.phaseInterceptor.to("TurnEndPhase"); + + // hit 8 times, but nothing else + expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(8); + expect(move.calculateBattlePower).toHaveLastReturnedWith(350); + }); + + it("should not count substitute hits or confusion damage", async () => { + game.override.enemySpecies(Species.SHUCKLE).enemyMoveset([Moves.CONFUSE_RAY, Moves.DOUBLE_KICK]); + + await game.classicMode.startBattle([Species.REGIROCK]); + + game.move.select(Moves.SUBSTITUTE); + await game.forceEnemyMove(Moves.DOUBLE_KICK); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.toNextTurn(); + + // no increase due to substitute + expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(0); + + // remove substitute and get confused + game.move.select(Moves.TIDY_UP); + await game.forceEnemyMove(Moves.CONFUSE_RAY); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.toNextTurn(); + + game.move.select(Moves.RAGE_FIST); + await game.forceEnemyMove(Moves.CONFUSE_RAY); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.move.forceConfusionActivation(true); + await game.toNextTurn(); + + // didn't go up from hitting ourself + expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(0); + }); + + it("should maintain hits recieved between wild waves", async () => { + await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.RAGE_FIST); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextWave(); + expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(2); + game.move.select(Moves.RAGE_FIST); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); - await game.phaseInterceptor.to("BerryPhase", false); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(4); expect(move.calculateBattlePower).toHaveLastReturnedWith(250); }); - it("should reset the hitRecCounter if we enter new trainer battle", async () => { - game.override.enemySpecies(Species.MAGIKARP).startingWave(4); + it("should reset hits recieved before trainer battles", async () => { + await game.classicMode.startBattle([Species.IRON_HANDS]); - await game.classicMode.startBattle([Species.MAGIKARP]); + const ironHands = game.scene.getPlayerPokemon()!; + expect(ironHands).toBeDefined(); + // beat up a magikarp game.move.select(Moves.RAGE_FIST); + await game.forceEnemyMove(Moves.DOUBLE_KICK); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.isVictory()).toBe(true); + expect(ironHands.battleData.hitCount).toBe(2); + expect(move.calculateBattlePower).toHaveLastReturnedWith(150); + + game.override.battleType(BattleType.TRAINER); await game.toNextWave(); - game.move.select(Moves.RAGE_FIST); - await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); - await game.phaseInterceptor.to("BerryPhase", false); - - expect(move.calculateBattlePower).toHaveLastReturnedWith(150); + expect(ironHands.battleData.hitCount).toBe(0); }); - it("should not increase the hitCounter if Substitute is hit", async () => { - game.override.enemySpecies(Species.MAGIKARP).startingWave(4); - - await game.classicMode.startBattle([Species.MAGIKARP]); - - game.move.select(Moves.SUBSTITUTE); - await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); - await game.phaseInterceptor.to("MoveEffectPhase"); - - expect(game.scene.getPlayerPokemon()?.customPokemonData.hitsRecCount).toBe(0); - }); - - it("should reset the hitRecCounter if we enter new biome", async () => { + it("should reset hits recieved before new biome", async () => { game.override.enemySpecies(Species.MAGIKARP).startingWave(10); await game.classicMode.startBattle([Species.MAGIKARP]); @@ -109,25 +153,50 @@ describe("Moves - Rage Fist", () => { expect(move.calculateBattlePower).toHaveLastReturnedWith(150); }); - it("should not reset the hitRecCounter if switched out", async () => { - game.override.enemySpecies(Species.MAGIKARP).startingWave(1).enemyMoveset(Moves.TACKLE); + it("should not reset if switched out or on reload", async () => { + game.override.enemyMoveset(Moves.TACKLE); + + const getPartyHitCount = () => + game.scene + .getPlayerParty() + .filter(p => !!p) + .map(m => m.battleData.hitCount); await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + // Charizard hit game.move.select(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); + expect(getPartyHitCount()).toEqual([1, 0]); + // blastoise switched in & hit game.doSwitchPokemon(1); await game.toNextTurn(); + expect(getPartyHitCount()).toEqual([1, 1]); + // charizard switched in & hit game.doSwitchPokemon(1); await game.toNextTurn(); + expect(getPartyHitCount()).toEqual([2, 1]); + // Charizard rage fist game.move.select(Moves.RAGE_FIST); await game.phaseInterceptor.to("MoveEndPhase"); - expect(game.scene.getPlayerParty()[0].species.speciesId).toBe(Species.CHARIZARD); + const charizard = game.scene.getPlayerPokemon()!; + expect(charizard).toBeDefined(); + expect(charizard.species.speciesId).toBe(Species.CHARIZARD); + expect(move.calculateBattlePower).toHaveLastReturnedWith(150); + + // go to new wave, reload game and beat up another poor sap + await game.toNextWave(); + + await game.reload.reloadSession(); + + // outsped and oneshot means power rmains same as prior + game.move.select(Moves.RAGE_FIST); + await game.phaseInterceptor.to("MoveEndPhase"); expect(move.calculateBattlePower).toHaveLastReturnedWith(150); }); }); diff --git a/test/moves/rage_powder.test.ts b/test/moves/rage_powder.test.ts index ab05ae2e0bc..284b558f842 100644 --- a/test/moves/rage_powder.test.ts +++ b/test/moves/rage_powder.test.ts @@ -22,7 +22,7 @@ describe("Moves - Rage Powder", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.enemySpecies(Species.SNORLAX); game.override.startingLevel(100); game.override.enemyLevel(100); diff --git a/test/moves/reflect.test.ts b/test/moves/reflect.test.ts index ac879a7cc2b..b8338cea8cf 100644 --- a/test/moves/reflect.test.ts +++ b/test/moves/reflect.test.ts @@ -6,7 +6,7 @@ import { Abilities } from "#app/enums/abilities"; import { ArenaTagType } from "#app/enums/arena-tag-type"; import type Pokemon from "#app/field/pokemon"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; -import { NumberHolder } from "#app/utils"; +import { NumberHolder } from "#app/utils/common"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; @@ -34,7 +34,7 @@ describe("Moves - Reflect", () => { beforeEach(() => { game = new GameManager(phaserGame); globalScene = game.scene; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.ability(Abilities.NONE); game.override.moveset([Moves.ABSORB, Moves.ROCK_SLIDE, Moves.TACKLE]); game.override.enemyLevel(100); @@ -60,7 +60,7 @@ describe("Moves - Reflect", () => { }); it("reduces damage of physical attacks by a third in a double battle", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); const moveToUse = Moves.ROCK_SLIDE; await game.classicMode.startBattle([Species.SHUCKLE, Species.SHUCKLE]); diff --git a/test/moves/reflect_type.test.ts b/test/moves/reflect_type.test.ts index 78371d35475..efd58bfeadf 100644 --- a/test/moves/reflect_type.test.ts +++ b/test/moves/reflect_type.test.ts @@ -22,7 +22,7 @@ describe("Moves - Reflect Type", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.ability(Abilities.BALL_FETCH).battleType("single").disableCrits().enemyAbility(Abilities.BALL_FETCH); + game.override.ability(Abilities.BALL_FETCH).battleStyle("single").disableCrits().enemyAbility(Abilities.BALL_FETCH); }); it("will make the user Normal/Grass if targetting a typeless Pokemon affected by Forest's Curse", async () => { diff --git a/test/moves/relic_song.test.ts b/test/moves/relic_song.test.ts index d8f1373b4c0..86195e81a24 100644 --- a/test/moves/relic_song.test.ts +++ b/test/moves/relic_song.test.ts @@ -24,7 +24,7 @@ describe("Moves - Relic Song", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.RELIC_SONG, Moves.SPLASH]) - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.MAGIKARP) diff --git a/test/moves/retaliate.test.ts b/test/moves/retaliate.test.ts index e916c9ffeaa..9ad7cd7853b 100644 --- a/test/moves/retaliate.test.ts +++ b/test/moves/retaliate.test.ts @@ -26,7 +26,7 @@ describe("Moves - Retaliate", () => { retaliate = allMoves[Moves.RETALIATE]; game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SNORLAX) .enemyMoveset([Moves.RETALIATE, Moves.RETALIATE, Moves.RETALIATE, Moves.RETALIATE]) .enemyLevel(100) diff --git a/test/moves/revival_blessing.test.ts b/test/moves/revival_blessing.test.ts index 87be20f60ad..b36cd43eb83 100644 --- a/test/moves/revival_blessing.test.ts +++ b/test/moves/revival_blessing.test.ts @@ -1,6 +1,6 @@ import { BattlerIndex } from "#app/battle"; import { MoveResult } from "#app/field/pokemon"; -import { toDmgValue } from "#app/utils"; +import { toDmgValue } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -27,7 +27,7 @@ describe("Moves - Revival Blessing", () => { game.override .moveset([Moves.SPLASH, Moves.REVIVAL_BLESSING, Moves.MEMENTO]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) @@ -88,7 +88,7 @@ describe("Moves - Revival Blessing", () => { it("should revive a player pokemon and immediately send it back out if used in the same turn it fainted in doubles", async () => { game.override - .battleType("double") + .battleStyle("double") .enemyMoveset([Moves.SPLASH, Moves.FISSURE]) .enemyAbility(Abilities.NO_GUARD) .enemyLevel(100); @@ -116,7 +116,7 @@ describe("Moves - Revival Blessing", () => { }); it("should not summon multiple pokemon to the same slot when reviving the enemy ally in doubles", async () => { - game.override.battleType("double").enemyMoveset([Moves.REVIVAL_BLESSING]).moveset([Moves.SPLASH]).startingWave(25); // 2nd rival battle - must have 3+ pokemon + game.override.battleStyle("double").enemyMoveset([Moves.REVIVAL_BLESSING]).moveset([Moves.SPLASH]).startingWave(25); // 2nd rival battle - must have 3+ pokemon await game.classicMode.startBattle([Species.ARCEUS, Species.GIRATINA]); const enemyFainting = game.scene.getEnemyField()[0]; diff --git a/test/moves/role_play.test.ts b/test/moves/role_play.test.ts index 2a899b6e987..d4893212003 100644 --- a/test/moves/role_play.test.ts +++ b/test/moves/role_play.test.ts @@ -25,7 +25,7 @@ describe("Moves - Role Play", () => { game.override .moveset([Moves.SPLASH, Moves.ROLE_PLAY]) .ability(Abilities.ADAPTABILITY) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/rollout.test.ts b/test/moves/rollout.test.ts index 89270c2dfc7..b477fd8274f 100644 --- a/test/moves/rollout.test.ts +++ b/test/moves/rollout.test.ts @@ -24,7 +24,7 @@ describe("Moves - Rollout", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override.disableCrits(); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.starterSpecies(Species.RATTATA); game.override.ability(Abilities.BALL_FETCH); game.override.enemySpecies(Species.BIDOOF); diff --git a/test/moves/roost.test.ts b/test/moves/roost.test.ts index a52b81085c8..e55c76ca220 100644 --- a/test/moves/roost.test.ts +++ b/test/moves/roost.test.ts @@ -25,7 +25,7 @@ describe("Moves - Roost", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.RELICANTH); game.override.startingLevel(100); game.override.enemyLevel(100); diff --git a/test/moves/round.test.ts b/test/moves/round.test.ts index 82f080a25ea..a58efb730f8 100644 --- a/test/moves/round.test.ts +++ b/test/moves/round.test.ts @@ -27,7 +27,7 @@ describe("Moves - Round", () => { game.override .moveset([Moves.SPLASH, Moves.ROUND]) .ability(Abilities.BALL_FETCH) - .battleType("double") + .battleStyle("double") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/safeguard.test.ts b/test/moves/safeguard.test.ts index 2235b59e1af..7804b63f5c5 100644 --- a/test/moves/safeguard.test.ts +++ b/test/moves/safeguard.test.ts @@ -1,5 +1,6 @@ import { BattlerIndex } from "#app/battle"; -import { allAbilities, PostDefendContactApplyStatusEffectAbAttr } from "#app/data/ability"; +import { PostDefendContactApplyStatusEffectAbAttr } from "#app/data/abilities/ability"; +import { allAbilities } from "#app/data/data-lists"; import { Abilities } from "#app/enums/abilities"; import { StatusEffect } from "#app/enums/status-effect"; import GameManager from "#test/testUtils/gameManager"; @@ -25,7 +26,7 @@ describe("Moves - Safeguard", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.DRATINI) .enemyMoveset([Moves.SAFEGUARD]) .enemyAbility(Abilities.BALL_FETCH) @@ -70,7 +71,7 @@ describe("Moves - Safeguard", () => { }); it("protects ally from status", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.classicMode.startBattle(); diff --git a/test/moves/scale_shot.test.ts b/test/moves/scale_shot.test.ts index 2be632adb54..4731ccf9574 100644 --- a/test/moves/scale_shot.test.ts +++ b/test/moves/scale_shot.test.ts @@ -30,7 +30,7 @@ describe("Moves - Scale Shot", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.SCALE_SHOT]) - .battleType("single") + .battleStyle("single") .disableCrits() .ability(Abilities.NO_GUARD) .passiveAbility(Abilities.SKILL_LINK) diff --git a/test/moves/secret_power.test.ts b/test/moves/secret_power.test.ts index 37f1664251b..cbc0cded28b 100644 --- a/test/moves/secret_power.test.ts +++ b/test/moves/secret_power.test.ts @@ -11,7 +11,8 @@ import { StatusEffect } from "#enums/status-effect"; import { BattlerIndex } from "#app/battle"; import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagSide } from "#app/data/arena-tag"; -import { allAbilities, MoveEffectChanceMultiplierAbAttr } from "#app/data/ability"; +import { MoveEffectChanceMultiplierAbAttr } from "#app/data/abilities/ability"; +import { allAbilities } from "#app/data/data-lists"; describe("Moves - Secret Power", () => { let phaserGame: Phaser.Game; @@ -32,7 +33,7 @@ describe("Moves - Secret Power", () => { game.override .moveset([Moves.SECRET_POWER]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyLevel(60) @@ -64,7 +65,7 @@ describe("Moves - Secret Power", () => { .moveset([Moves.FIRE_PLEDGE, Moves.WATER_PLEDGE, Moves.SECRET_POWER, Moves.SPLASH]) .ability(Abilities.SERENE_GRACE) .enemyMoveset([Moves.SPLASH]) - .battleType("double"); + .battleStyle("double"); await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); const sereneGraceAttr = allAbilities[Abilities.SERENE_GRACE].getAttrs(MoveEffectChanceMultiplierAbAttr)[0]; diff --git a/test/moves/shed_tail.test.ts b/test/moves/shed_tail.test.ts index 6744c4e9ed8..845399f6c27 100644 --- a/test/moves/shed_tail.test.ts +++ b/test/moves/shed_tail.test.ts @@ -25,7 +25,7 @@ describe("Moves - Shed Tail", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.SHED_TAIL]) - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); diff --git a/test/moves/shell_side_arm.test.ts b/test/moves/shell_side_arm.test.ts index a5b065b76cb..e43bf6db037 100644 --- a/test/moves/shell_side_arm.test.ts +++ b/test/moves/shell_side_arm.test.ts @@ -30,7 +30,7 @@ describe("Moves - Shell Side Arm", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.SHELL_SIDE_ARM, Moves.SPLASH]) - .battleType("single") + .battleStyle("single") .startingLevel(100) .enemyLevel(100) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/shell_trap.test.ts b/test/moves/shell_trap.test.ts index 2df94cdb828..f6501c2cd9e 100644 --- a/test/moves/shell_trap.test.ts +++ b/test/moves/shell_trap.test.ts @@ -27,7 +27,7 @@ describe("Moves - Shell Trap", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .moveset([Moves.SHELL_TRAP, Moves.SPLASH, Moves.BULLDOZE]) .enemySpecies(Species.SNORLAX) .enemyMoveset([Moves.RAZOR_LEAF]) @@ -128,7 +128,7 @@ describe("Moves - Shell Trap", () => { }); it("should not activate from a subsequent physical attack", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); vi.spyOn(allMoves[Moves.RAZOR_LEAF], "priority", "get").mockReturnValue(-4); await game.startBattle([Species.CHARIZARD]); diff --git a/test/moves/simple_beam.test.ts b/test/moves/simple_beam.test.ts index ce86f42671e..225fda28083 100644 --- a/test/moves/simple_beam.test.ts +++ b/test/moves/simple_beam.test.ts @@ -24,7 +24,7 @@ describe("Moves - Simple Beam", () => { game.override .moveset([Moves.SPLASH, Moves.SIMPLE_BEAM]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/sketch.test.ts b/test/moves/sketch.test.ts index dfbf2eca713..c9755189a71 100644 --- a/test/moves/sketch.test.ts +++ b/test/moves/sketch.test.ts @@ -27,7 +27,7 @@ describe("Moves - Sketch", () => { game = new GameManager(phaserGame); game.override .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.SHUCKLE) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/skill_swap.test.ts b/test/moves/skill_swap.test.ts index f807a85eaf6..562e4bb56ed 100644 --- a/test/moves/skill_swap.test.ts +++ b/test/moves/skill_swap.test.ts @@ -25,7 +25,7 @@ describe("Moves - Skill Swap", () => { game.override .moveset([Moves.SPLASH, Moves.SKILL_SWAP]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/sleep_talk.test.ts b/test/moves/sleep_talk.test.ts index d31eff34a7a..cbe3b6d7d3a 100644 --- a/test/moves/sleep_talk.test.ts +++ b/test/moves/sleep_talk.test.ts @@ -28,7 +28,7 @@ describe("Moves - Sleep Talk", () => { .moveset([Moves.SPLASH, Moves.SLEEP_TALK]) .statusEffect(StatusEffect.SLEEP) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/solar_beam.test.ts b/test/moves/solar_beam.test.ts index dffd4f210e5..49605a70c66 100644 --- a/test/moves/solar_beam.test.ts +++ b/test/moves/solar_beam.test.ts @@ -27,7 +27,7 @@ describe("Moves - Solar Beam", () => { game = new GameManager(phaserGame); game.override .moveset(Moves.SOLAR_BEAM) - .battleType("single") + .battleStyle("single") .startingLevel(100) .enemySpecies(Species.SNORLAX) .enemyLevel(100) diff --git a/test/moves/sparkly_swirl.test.ts b/test/moves/sparkly_swirl.test.ts index 6cd357c7e0e..b9df302933c 100644 --- a/test/moves/sparkly_swirl.test.ts +++ b/test/moves/sparkly_swirl.test.ts @@ -34,7 +34,7 @@ describe("Moves - Sparkly Swirl", () => { }); it("should cure status effect of the user, its ally, and all party pokemon", async () => { - game.override.battleType("double").statusEffect(StatusEffect.BURN); + game.override.battleStyle("double").statusEffect(StatusEffect.BURN); await game.classicMode.startBattle([Species.RATTATA, Species.RATTATA, Species.RATTATA]); const [leftPlayer, rightPlayer, partyPokemon] = game.scene.getPlayerParty(); const leftOpp = game.scene.getEnemyPokemon()!; @@ -58,7 +58,7 @@ describe("Moves - Sparkly Swirl", () => { }); it("should not cure status effect of the target/target's allies", async () => { - game.override.battleType("double").enemyStatusEffect(StatusEffect.BURN); + game.override.battleStyle("double").enemyStatusEffect(StatusEffect.BURN); await game.classicMode.startBattle([Species.RATTATA, Species.RATTATA]); const [leftOpp, rightOpp] = game.scene.getEnemyField(); diff --git a/test/moves/spectral_thief.test.ts b/test/moves/spectral_thief.test.ts index 2e52b118a74..2654ab1ad8d 100644 --- a/test/moves/spectral_thief.test.ts +++ b/test/moves/spectral_thief.test.ts @@ -71,7 +71,7 @@ describe("Moves - Spectral Thief", () => { const player = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; const moveToCheck = allMoves[Moves.SPECTRAL_THIEF]; - const dmgBefore = enemy.getAttackDamage(player, moveToCheck, false, false, false, false).damage; + const dmgBefore = enemy.getAttackDamage({ source: player, move: moveToCheck }).damage; enemy.setStatStage(Stat.ATK, 6); @@ -80,7 +80,7 @@ describe("Moves - Spectral Thief", () => { game.move.select(Moves.SPECTRAL_THIEF); await game.phaseInterceptor.to(TurnEndPhase); - expect(dmgBefore).toBeLessThan(enemy.getAttackDamage(player, moveToCheck, false, false, false, false).damage); + expect(dmgBefore).toBeLessThan(enemy.getAttackDamage({ source: player, move: moveToCheck }).damage); }); it("should steal stat stages as a negative value with Contrary.", async () => { diff --git a/test/moves/speed_swap.test.ts b/test/moves/speed_swap.test.ts index a1385ce5386..2b010885e34 100644 --- a/test/moves/speed_swap.test.ts +++ b/test/moves/speed_swap.test.ts @@ -24,7 +24,7 @@ describe("Moves - Speed Swap", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.NONE) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.MEW) diff --git a/test/moves/spikes.test.ts b/test/moves/spikes.test.ts index 9bf0e5e1437..3dfa398d7d6 100644 --- a/test/moves/spikes.test.ts +++ b/test/moves/spikes.test.ts @@ -4,6 +4,7 @@ import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag"; describe("Moves - Spikes", () => { let phaserGame: Phaser.Game; @@ -22,7 +23,7 @@ describe("Moves - Spikes", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) .ability(Abilities.BALL_FETCH) @@ -77,4 +78,17 @@ describe("Moves - Spikes", () => { const enemy = game.scene.getEnemyParty()[0]; expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); }, 20000); + + it("should work when all targets fainted", async () => { + game.override.enemySpecies(Species.DIGLETT); + game.override.battleStyle("double"); + game.override.startingLevel(50); + await game.classicMode.startBattle([Species.RAYQUAZA, Species.ROWLET]); + + game.move.select(Moves.EARTHQUAKE); + game.move.select(Moves.SPIKES, 1); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.scene.arena.getTagOnSide(ArenaTrapTag, ArenaTagSide.ENEMY)).toBeDefined(); + }, 20000); }); diff --git a/test/moves/spit_up.test.ts b/test/moves/spit_up.test.ts index d71647bda52..c034117bc64 100644 --- a/test/moves/spit_up.test.ts +++ b/test/moves/spit_up.test.ts @@ -32,7 +32,7 @@ describe("Moves - Spit Up", () => { spitUp = allMoves[Moves.SPIT_UP]; game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.RATTATA); game.override.enemyMoveset(Moves.SPLASH); diff --git a/test/moves/spotlight.test.ts b/test/moves/spotlight.test.ts index 91705dbb2fa..2c4f652e408 100644 --- a/test/moves/spotlight.test.ts +++ b/test/moves/spotlight.test.ts @@ -22,7 +22,7 @@ describe("Moves - Spotlight", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.starterSpecies(Species.AMOONGUSS); game.override.enemySpecies(Species.SNORLAX); game.override.startingLevel(100); diff --git a/test/moves/steamroller.test.ts b/test/moves/steamroller.test.ts index ba96928e01d..b32b4551c81 100644 --- a/test/moves/steamroller.test.ts +++ b/test/moves/steamroller.test.ts @@ -25,7 +25,7 @@ describe("Moves - Steamroller", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.moveset([Moves.STEAMROLLER]).battleType("single").enemyAbility(Abilities.BALL_FETCH); + game.override.moveset([Moves.STEAMROLLER]).battleStyle("single").enemyAbility(Abilities.BALL_FETCH); }); it("should always hit a minimzed target with double damage", async () => { diff --git a/test/moves/stockpile.test.ts b/test/moves/stockpile.test.ts index 033f24d5229..4b8f51c32b2 100644 --- a/test/moves/stockpile.test.ts +++ b/test/moves/stockpile.test.ts @@ -27,7 +27,7 @@ describe("Moves - Stockpile", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.RATTATA); game.override.enemyMoveset(Moves.SPLASH); diff --git a/test/moves/struggle.test.ts b/test/moves/struggle.test.ts new file mode 100644 index 00000000000..61c6cd23e10 --- /dev/null +++ b/test/moves/struggle.test.ts @@ -0,0 +1,65 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Moves - Struggle", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should not have its power boosted by adaptability or stab", async () => { + game.override.moveset([Moves.STRUGGLE]).ability(Abilities.ADAPTABILITY); + await game.classicMode.startBattle([Species.RATTATA]); + + const enemy = game.scene.getEnemyPokemon()!; + game.move.select(Moves.STRUGGLE); + + const stabSpy = vi.spyOn(enemy, "calculateStabMultiplier"); + + await game.phaseInterceptor.to("BerryPhase"); + + expect(stabSpy).toHaveReturnedWith(1); + + stabSpy.mockRestore(); + }); + + it("should ignore type effectiveness", async () => { + game.override.moveset([Moves.STRUGGLE]); + await game.classicMode.startBattle([Species.GASTLY]); + + const enemy = game.scene.getEnemyPokemon()!; + game.move.select(Moves.STRUGGLE); + + const moveEffectivenessSpy = vi.spyOn(enemy, "getMoveEffectiveness"); + + await game.phaseInterceptor.to("BerryPhase"); + + expect(moveEffectivenessSpy).toHaveReturnedWith(1); + + moveEffectivenessSpy.mockRestore(); + }); +}); diff --git a/test/moves/substitute.test.ts b/test/moves/substitute.test.ts index 23f7f4af4b9..7f4a2e69f9e 100644 --- a/test/moves/substitute.test.ts +++ b/test/moves/substitute.test.ts @@ -6,7 +6,7 @@ import { MoveResult } from "#app/field/pokemon"; import type { CommandPhase } from "#app/phases/command-phase"; import GameManager from "#test/testUtils/gameManager"; import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Abilities } from "#enums/abilities"; import { ArenaTagType } from "#enums/arena-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type"; @@ -36,7 +36,7 @@ describe("Moves - Substitute", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .moveset([Moves.SUBSTITUTE, Moves.SWORDS_DANCE, Moves.TACKLE, Moves.SPLASH]) .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.INSOMNIA) @@ -398,7 +398,7 @@ describe("Moves - Substitute", () => { leadPokemon.addTag(BattlerTagType.SUBSTITUTE, 0, Moves.NONE, leadPokemon.id); // Simulate a Baton switch for the player this turn - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.POKEMON, 1, true); }); diff --git a/test/moves/swallow.test.ts b/test/moves/swallow.test.ts index baa03801079..d548522068b 100644 --- a/test/moves/swallow.test.ts +++ b/test/moves/swallow.test.ts @@ -27,7 +27,7 @@ describe("Moves - Swallow", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.RATTATA); game.override.enemyMoveset(Moves.SPLASH); diff --git a/test/moves/syrup_bomb.test.ts b/test/moves/syrup_bomb.test.ts index 1e193793d82..8e9134497d0 100644 --- a/test/moves/syrup_bomb.test.ts +++ b/test/moves/syrup_bomb.test.ts @@ -25,7 +25,7 @@ describe("Moves - SYRUP BOMB", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SNORLAX) .enemyAbility(Abilities.BALL_FETCH) .ability(Abilities.BALL_FETCH) diff --git a/test/moves/tackle.test.ts b/test/moves/tackle.test.ts index 44fc698ec62..162836cd181 100644 --- a/test/moves/tackle.test.ts +++ b/test/moves/tackle.test.ts @@ -24,7 +24,7 @@ describe("Moves - Tackle", () => { beforeEach(() => { game = new GameManager(phaserGame); const moveToUse = Moves.TACKLE; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.MAGIKARP); game.override.startingLevel(1); game.override.startingWave(97); diff --git a/test/moves/tail_whip.test.ts b/test/moves/tail_whip.test.ts index 41c39ab22ca..2d3ade2691d 100644 --- a/test/moves/tail_whip.test.ts +++ b/test/moves/tail_whip.test.ts @@ -25,7 +25,7 @@ describe("Moves - Tail whip", () => { beforeEach(() => { game = new GameManager(phaserGame); const moveToUse = Moves.TAIL_WHIP; - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.RATTATA); game.override.enemyAbility(Abilities.INSOMNIA); game.override.ability(Abilities.INSOMNIA); diff --git a/test/moves/tailwind.test.ts b/test/moves/tailwind.test.ts index 591b94408ce..40bae67b514 100644 --- a/test/moves/tailwind.test.ts +++ b/test/moves/tailwind.test.ts @@ -25,7 +25,7 @@ describe("Moves - Tailwind", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("double") + .battleStyle("double") .moveset([Moves.TAILWIND, Moves.SPLASH]) .enemyMoveset(Moves.SPLASH) .enemyAbility(Abilities.BALL_FETCH) @@ -54,7 +54,7 @@ describe("Moves - Tailwind", () => { }); it("lasts for 4 turns", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); await game.classicMode.startBattle([Species.MAGIKARP]); @@ -77,7 +77,7 @@ describe("Moves - Tailwind", () => { }); it("does not affect the opposing side", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); await game.classicMode.startBattle([Species.MAGIKARP]); diff --git a/test/moves/tar_shot.test.ts b/test/moves/tar_shot.test.ts index ac3ba534446..68f19e3ab51 100644 --- a/test/moves/tar_shot.test.ts +++ b/test/moves/tar_shot.test.ts @@ -24,7 +24,7 @@ describe("Moves - Tar Shot", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.TANGELA) diff --git a/test/moves/taunt.test.ts b/test/moves/taunt.test.ts index adc1434c7dd..e0bb13c61fb 100644 --- a/test/moves/taunt.test.ts +++ b/test/moves/taunt.test.ts @@ -23,7 +23,7 @@ describe("Moves - Taunt", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset([Moves.TAUNT, Moves.SPLASH]) .enemySpecies(Species.SHUCKLE) diff --git a/test/moves/telekinesis.test.ts b/test/moves/telekinesis.test.ts index 1355cb975f3..d11cc0861f0 100644 --- a/test/moves/telekinesis.test.ts +++ b/test/moves/telekinesis.test.ts @@ -27,7 +27,7 @@ describe("Moves - Telekinesis", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.TELEKINESIS, Moves.TACKLE, Moves.MUD_SHOT, Moves.SMACK_DOWN]) - .battleType("single") + .battleStyle("single") .enemySpecies(Species.SNORLAX) .enemyLevel(60) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/tera_blast.test.ts b/test/moves/tera_blast.test.ts index c1a2b999fa0..efdb75e8156 100644 --- a/test/moves/tera_blast.test.ts +++ b/test/moves/tera_blast.test.ts @@ -4,7 +4,6 @@ import { allMoves, TeraMoveCategoryAttr } from "#app/data/moves/move"; import type Move from "#app/data/moves/move"; import { PokemonType } from "#enums/pokemon-type"; import { Abilities } from "#app/enums/abilities"; -import { HitResult } from "#app/field/pokemon"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; @@ -34,7 +33,7 @@ describe("Moves - Tera Blast", () => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .starterSpecies(Species.FEEBAS) .moveset([Moves.TERA_BLAST]) @@ -49,9 +48,9 @@ describe("Moves - Tera Blast", () => { it("changes type to match user's tera type", async () => { game.override.enemySpecies(Species.FURRET); - await game.startBattle(); + await game.classicMode.startBattle(); const enemyPokemon = game.scene.getEnemyPokemon()!; - vi.spyOn(enemyPokemon, "apply"); + const spy = vi.spyOn(enemyPokemon, "getMoveEffectiveness"); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.teraType = PokemonType.FIGHTING; @@ -61,11 +60,11 @@ describe("Moves - Tera Blast", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("MoveEffectPhase"); - expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.SUPER_EFFECTIVE); + expect(spy).toHaveReturnedWith(2); }, 20000); it("increases power if user is Stellar tera type", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.teraType = PokemonType.STELLAR; @@ -76,28 +75,28 @@ describe("Moves - Tera Blast", () => { await game.phaseInterceptor.to("MoveEffectPhase"); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(100); - }, 20000); + }); it("is super effective against terastallized targets if user is Stellar tera type", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.teraType = PokemonType.STELLAR; playerPokemon.isTerastallized = true; const enemyPokemon = game.scene.getEnemyPokemon()!; - vi.spyOn(enemyPokemon, "apply"); + const spy = vi.spyOn(enemyPokemon, "getMoveEffectiveness"); enemyPokemon.isTerastallized = true; game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("MoveEffectPhase"); - expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.SUPER_EFFECTIVE); + expect(spy).toHaveReturnedWith(2); }); it("uses the higher ATK for damage calculation", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.stats[Stat.ATK] = 100; @@ -112,7 +111,7 @@ describe("Moves - Tera Blast", () => { }); it("uses the higher SPATK for damage calculation", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.stats[Stat.ATK] = 1; @@ -127,7 +126,7 @@ describe("Moves - Tera Blast", () => { it("should stay as a special move if ATK turns lower than SPATK mid-turn", async () => { game.override.enemyMoveset([Moves.CHARM]); - await game.startBattle(); + await game.classicMode.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.stats[Stat.ATK] = 51; @@ -145,7 +144,7 @@ describe("Moves - Tera Blast", () => { game.override .startingHeldItems([{ name: "SPECIES_STAT_BOOSTER", type: "THICK_CLUB" }]) .starterSpecies(Species.CUBONE); - await game.startBattle(); + await game.classicMode.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; @@ -163,7 +162,7 @@ describe("Moves - Tera Blast", () => { it("does not change its move category from stat changes due to abilities", async () => { game.override.ability(Abilities.HUGE_POWER); - await game.startBattle(); + await game.classicMode.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.stats[Stat.ATK] = 50; @@ -178,7 +177,7 @@ describe("Moves - Tera Blast", () => { }); it("causes stat drops if user is Stellar tera type", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.teraType = PokemonType.STELLAR; @@ -190,5 +189,33 @@ describe("Moves - Tera Blast", () => { expect(playerPokemon.getStatStage(Stat.SPATK)).toBe(-1); expect(playerPokemon.getStatStage(Stat.ATK)).toBe(-1); - }, 20000); + }); + + it.each([ + { ab: "galvanize", ty: "electric", ab_id: Abilities.GALVANIZE, ty_id: PokemonType.ELECTRIC }, + { ab: "refrigerate", ty: "ice", ab_id: Abilities.REFRIGERATE, ty_id: PokemonType.ICE }, + { ab: "pixilate", ty: "fairy", ab_id: Abilities.PIXILATE, ty_id: PokemonType.FAIRY }, + { ab: "aerilate", ty: "flying", ab_id: Abilities.AERILATE, ty_id: PokemonType.FLYING }, + ])("should be $ty type if the user has $ab", async ({ ab_id, ty_id }) => { + game.override.ability(ab_id).moveset([Moves.TERA_BLAST]).enemyAbility(Abilities.BALL_FETCH); + await game.classicMode.startBattle([Species.MAGIKARP]); + const playerPokemon = game.scene.getPlayerPokemon()!; + expect(playerPokemon.getMoveType(allMoves[Moves.TERA_BLAST])).toBe(ty_id); + }); + + it("should not be affected by normalize when the user is terastallized with tera normal", async () => { + game.override.moveset([Moves.TERA_BLAST]).ability(Abilities.NORMALIZE); + await game.classicMode.startBattle([Species.MAGIKARP]); + const playerPokemon = game.scene.getPlayerPokemon()!; + // override the tera state for the pokemon + playerPokemon.isTerastallized = true; + playerPokemon.teraType = PokemonType.NORMAL; + + const move = allMoves[Moves.TERA_BLAST]; + const powerSpy = vi.spyOn(move, "calculateBattlePower"); + + game.move.select(Moves.TERA_BLAST); + await game.phaseInterceptor.to("BerryPhase"); + expect(powerSpy).toHaveLastReturnedWith(move.power); + }); }); diff --git a/test/moves/tera_starstorm.test.ts b/test/moves/tera_starstorm.test.ts index 19fe58f4057..5ae0c575599 100644 --- a/test/moves/tera_starstorm.test.ts +++ b/test/moves/tera_starstorm.test.ts @@ -25,7 +25,7 @@ describe("Moves - Tera Starstorm", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.TERA_STARSTORM, Moves.SPLASH]) - .battleType("double") + .battleStyle("double") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) .enemyLevel(30) @@ -33,7 +33,7 @@ describe("Moves - Tera Starstorm", () => { }); it("changes type to Stellar when used by Terapagos in its Stellar Form", async () => { - game.override.battleType("single"); + game.override.battleStyle("single"); await game.classicMode.startBattle([Species.TERAPAGOS]); const terapagos = game.scene.getPlayerPokemon()!; @@ -69,6 +69,40 @@ describe("Moves - Tera Starstorm", () => { expect(enemyField.every(pokemon => pokemon.isFullHp())).toBe(false); }); + it("targets both opponents in a double battle when used by Terapagos immediately after terastallizing", async () => { + await game.classicMode.startBattle([Species.TERAPAGOS]); + + const terapagos = game.scene.getPlayerParty()[0]; + terapagos.isTerastallized = false; + + game.move.selectWithTera(Moves.TERA_STARSTORM, 0); + + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); + + const enemyField = game.scene.getEnemyField(); + + // Terapagos in Stellar Form should hit both targets + await game.phaseInterceptor.to("MoveEndPhase"); + expect(enemyField.some(pokemon => pokemon.isFullHp())).toBe(false); + }); + + it("targets only one opponent in a double battle when used by Terapagos without terastallizing", async () => { + await game.classicMode.startBattle([Species.TERAPAGOS]); + + const terapagos = game.scene.getPlayerParty()[0]; + terapagos.isTerastallized = false; + + game.move.select(Moves.TERA_STARSTORM, 0, BattlerIndex.ENEMY); + + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); + + const enemyField = game.scene.getEnemyField(); + + // Terapagos in Stellar Form should hit both targets + await game.phaseInterceptor.to("MoveEndPhase"); + expect(enemyField.some(pokemon => pokemon.isFullHp())).toBe(true); + }); + it("applies the effects when Terapagos in Stellar Form is fused with another Pokemon", async () => { await game.classicMode.startBattle([Species.TERAPAGOS, Species.CHARMANDER, Species.MAGIKARP]); diff --git a/test/moves/thousand_arrows.test.ts b/test/moves/thousand_arrows.test.ts index 109fc2c6936..7259fda8560 100644 --- a/test/moves/thousand_arrows.test.ts +++ b/test/moves/thousand_arrows.test.ts @@ -24,7 +24,7 @@ describe("Moves - Thousand Arrows", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.TOGETIC); game.override.startingLevel(100); game.override.enemyLevel(100); diff --git a/test/moves/throat_chop.test.ts b/test/moves/throat_chop.test.ts index 755e60fe425..aaae9c0f5bb 100644 --- a/test/moves/throat_chop.test.ts +++ b/test/moves/throat_chop.test.ts @@ -24,7 +24,7 @@ describe("Moves - Throat Chop", () => { game = new GameManager(phaserGame); game.override .moveset(Array(4).fill(Moves.GROWL)) - .battleType("single") + .battleStyle("single") .ability(Abilities.BALL_FETCH) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Array(4).fill(Moves.THROAT_CHOP)) diff --git a/test/moves/thunder_wave.test.ts b/test/moves/thunder_wave.test.ts index 9f907e38b62..abfb5828d3b 100644 --- a/test/moves/thunder_wave.test.ts +++ b/test/moves/thunder_wave.test.ts @@ -24,7 +24,7 @@ describe("Moves - Thunder Wave", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .starterSpecies(Species.PIKACHU) .moveset([Moves.THUNDER_WAVE]) .enemyMoveset(Moves.SPLASH); diff --git a/test/moves/tidy_up.test.ts b/test/moves/tidy_up.test.ts index 9d98feb13f5..ba7a1e07959 100644 --- a/test/moves/tidy_up.test.ts +++ b/test/moves/tidy_up.test.ts @@ -26,7 +26,7 @@ describe("Moves - Tidy Up", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.enemySpecies(Species.MAGIKARP); game.override.enemyAbility(Abilities.BALL_FETCH); game.override.enemyMoveset(Moves.SPLASH); diff --git a/test/moves/torment.test.ts b/test/moves/torment.test.ts index 75143053321..d06837d2806 100644 --- a/test/moves/torment.test.ts +++ b/test/moves/torment.test.ts @@ -24,7 +24,7 @@ describe("Moves - Torment", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset([Moves.TORMENT, Moves.SPLASH]) .enemySpecies(Species.SHUCKLE) diff --git a/test/moves/toxic.test.ts b/test/moves/toxic.test.ts index f2b1f82fe02..f908d27ec7e 100644 --- a/test/moves/toxic.test.ts +++ b/test/moves/toxic.test.ts @@ -23,7 +23,7 @@ describe("Moves - Toxic", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("single").moveset(Moves.TOXIC).enemySpecies(Species.MAGIKARP).enemyMoveset(Moves.SPLASH); + game.override.battleStyle("single").moveset(Moves.TOXIC).enemySpecies(Species.MAGIKARP).enemyMoveset(Moves.SPLASH); }); it("should be guaranteed to hit if user is Poison-type", async () => { diff --git a/test/moves/toxic_spikes.test.ts b/test/moves/toxic_spikes.test.ts index d457ec5cb56..b1fdc7f39c2 100644 --- a/test/moves/toxic_spikes.test.ts +++ b/test/moves/toxic_spikes.test.ts @@ -28,7 +28,7 @@ describe("Moves - Toxic Spikes", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .startingWave(5) .enemySpecies(Species.RATTATA) .enemyAbility(Abilities.BALL_FETCH) @@ -129,7 +129,7 @@ describe("Moves - Toxic Spikes", () => { await game.phaseInterceptor.to("BattleEndPhase"); await game.toNextWave(); - const sessionData: SessionSaveData = gameData["getSessionSaveData"](); + const sessionData: SessionSaveData = gameData.getSessionSaveData(); localStorage.setItem("sessionTestData", encrypt(JSON.stringify(sessionData), true)); const recoveredData: SessionSaveData = gameData.parseSessionData( decrypt(localStorage.getItem("sessionTestData")!, true), diff --git a/test/moves/transform.test.ts b/test/moves/transform.test.ts index d37decf28f4..8bfe7df688b 100644 --- a/test/moves/transform.test.ts +++ b/test/moves/transform.test.ts @@ -4,7 +4,7 @@ import GameManager from "#test/testUtils/gameManager"; import { Species } from "#enums/species"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Moves } from "#enums/moves"; -import { Stat, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat"; +import { Stat, EFFECTIVE_STATS } from "#enums/stat"; import { Abilities } from "#enums/abilities"; import { BattlerIndex } from "#app/battle"; @@ -26,7 +26,7 @@ describe("Moves - Transform", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MEW) .enemyLevel(200) .enemyAbility(Abilities.BEAST_BOOST) @@ -49,30 +49,18 @@ describe("Moves - Transform", () => { expect(player.getAbility()).toBe(enemy.getAbility()); expect(player.getGender()).toBe(enemy.getGender()); + // copies all stats except hp expect(player.getStat(Stat.HP, false)).not.toBe(enemy.getStat(Stat.HP)); for (const s of EFFECTIVE_STATS) { expect(player.getStat(s, false)).toBe(enemy.getStat(s, false)); } - for (const s of BATTLE_STATS) { - expect(player.getStatStage(s)).toBe(enemy.getStatStage(s)); - } + expect(player.getStatStages()).toEqual(enemy.getStatStages()); - const playerMoveset = player.getMoveset(); - const enemyMoveset = enemy.getMoveset(); + // move IDs are equal + expect(player.getMoveset().map(m => m.moveId)).toEqual(enemy.getMoveset().map(m => m.moveId)); - expect(playerMoveset.length).toBe(enemyMoveset.length); - for (let i = 0; i < playerMoveset.length && i < enemyMoveset.length; i++) { - expect(playerMoveset[i]?.moveId).toBe(enemyMoveset[i]?.moveId); - } - - const playerTypes = player.getTypes(); - const enemyTypes = enemy.getTypes(); - - expect(playerTypes.length).toBe(enemyTypes.length); - for (let i = 0; i < playerTypes.length && i < enemyTypes.length; i++) { - expect(playerTypes[i]).toBe(enemyTypes[i]); - } + expect(player.getTypes()).toEqual(enemy.getTypes()); }); it("should copy in-battle overridden stats", async () => { diff --git a/test/moves/trick_or_treat.test.ts b/test/moves/trick_or_treat.test.ts index 108028f3008..3b32e09f72d 100644 --- a/test/moves/trick_or_treat.test.ts +++ b/test/moves/trick_or_treat.test.ts @@ -25,7 +25,7 @@ describe("Moves - Trick Or Treat", () => { game.override .moveset([Moves.FORESTS_CURSE, Moves.TRICK_OR_TREAT]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/triple_arrows.test.ts b/test/moves/triple_arrows.test.ts index eb434b25815..58ce8a9c528 100644 --- a/test/moves/triple_arrows.test.ts +++ b/test/moves/triple_arrows.test.ts @@ -32,7 +32,7 @@ describe("Moves - Triple Arrows", () => { game.override .ability(Abilities.BALL_FETCH) .moveset([Moves.TRIPLE_ARROWS]) - .battleType("single") + .battleStyle("single") .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.STURDY) .enemyMoveset(Moves.SPLASH); diff --git a/test/moves/u_turn.test.ts b/test/moves/u_turn.test.ts index f1d212f3f47..4ceb6865be0 100644 --- a/test/moves/u_turn.test.ts +++ b/test/moves/u_turn.test.ts @@ -23,7 +23,7 @@ describe("Moves - U-turn", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .enemySpecies(Species.GENGAR) .startingLevel(90) .startingWave(97) @@ -65,7 +65,7 @@ describe("Moves - U-turn", () => { // assert const playerPkm = game.scene.getPlayerPokemon()!; expect(playerPkm.hp).not.toEqual(playerPkm.getMaxHp()); - expect(game.scene.getEnemyPokemon()!.battleData.abilityRevealed).toBe(true); // proxy for asserting ability activated + expect(game.scene.getEnemyPokemon()!.waveData.abilityRevealed).toBe(true); // proxy for asserting ability activated expect(playerPkm.species.speciesId).toEqual(Species.RAICHU); expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); }, 20000); @@ -84,7 +84,7 @@ describe("Moves - U-turn", () => { const playerPkm = game.scene.getPlayerPokemon()!; expect(playerPkm.status?.effect).toEqual(StatusEffect.POISON); expect(playerPkm.species.speciesId).toEqual(Species.RAICHU); - expect(game.scene.getEnemyPokemon()!.battleData.abilityRevealed).toBe(true); // proxy for asserting ability activated + expect(game.scene.getEnemyPokemon()!.waveData.abilityRevealed).toBe(true); // proxy for asserting ability activated expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); }, 20000); diff --git a/test/moves/upper_hand.test.ts b/test/moves/upper_hand.test.ts index ecfd9f0735c..66359a94ccb 100644 --- a/test/moves/upper_hand.test.ts +++ b/test/moves/upper_hand.test.ts @@ -26,7 +26,7 @@ describe("Moves - Upper Hand", () => { game.override .moveset(Moves.UPPER_HAND) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/moves/whirlwind.test.ts b/test/moves/whirlwind.test.ts index d6124b6c766..6b5133ec7b1 100644 --- a/test/moves/whirlwind.test.ts +++ b/test/moves/whirlwind.test.ts @@ -10,6 +10,9 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { Status } from "#app/data/status-effect"; import { StatusEffect } from "#enums/status-effect"; +import { BattlerIndex } from "#app/battle"; +import { BattleType } from "#enums/battle-type"; +import { TrainerType } from "#enums/trainer-type"; describe("Moves - Whirlwind", () => { let phaserGame: Phaser.Game; @@ -28,8 +31,8 @@ describe("Moves - Whirlwind", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") - .moveset(Moves.SPLASH) + .battleStyle("single") + .moveset([Moves.SPLASH]) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset([Moves.SPLASH, Moves.WHIRLWIND]) .enemySpecies(Species.PIDGEY); @@ -41,7 +44,8 @@ describe("Moves - Whirlwind", () => { { move: Moves.SKY_DROP, name: "Sky Drop" }, ])("should not hit a flying target: $name (=$move)", async ({ move }) => { game.override.moveset([move]); - await game.classicMode.startBattle([Species.STARAPTOR]); + // Must have a pokemon in the back so that the move misses instead of fails. + await game.classicMode.startBattle([Species.STARAPTOR, Species.MAGIKARP]); const staraptor = game.scene.getPlayerPokemon()!; @@ -156,4 +160,61 @@ describe("Moves - Whirlwind", () => { expect(lapras.isOnField()).toBe(true); expect(eevee.isOnField()).toBe(false); }); + + it("should not pull in the other trainer's pokemon in a partner trainer battle", async () => { + game.override + .startingWave(2) + .battleType(BattleType.TRAINER) + .randomTrainer({ + trainerType: TrainerType.BREEDER, + alwaysDouble: true, + }) + .enemyMoveset([Moves.SPLASH, Moves.LUNAR_DANCE]) + .moveset([Moves.WHIRLWIND, Moves.SPLASH]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.TOTODILE]); + + // expect the enemy to have at least 4 pokemon, necessary for this check to even work + expect(game.scene.getEnemyParty().length, "enemy must have exactly 4 pokemon").toBe(4); + + const user = game.scene.getPlayerPokemon()!; + + console.log(user.getMoveset(false)); + + game.move.select(Moves.SPLASH); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.MEMENTO); + await game.forceEnemyMove(Moves.SPLASH); + await game.toNextTurn(); + + // Get the enemy pokemon id so we can check if is the same after switch. + const enemy_id = game.scene.getEnemyPokemon()!.id; + + // Hit the enemy that fainted with whirlwind. + game.move.select(Moves.WHIRLWIND, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); + + await game.forceEnemyMove(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + + await game.toNextTurn(); + + // Expect the enemy pokemon to not have switched out. + expect(game.scene.getEnemyPokemon()!.id).toBe(enemy_id); + }); + + it("should force a wild pokemon to flee", async () => { + game.override + .battleType(BattleType.WILD) + .moveset([Moves.WHIRLWIND, Moves.SPLASH]) + .enemyMoveset(Moves.SPLASH) + .ability(Abilities.BALL_FETCH); + await game.classicMode.startBattle([Species.MAGIKARP]); + + const user = game.scene.getPlayerPokemon()!; + + game.move.select(Moves.WHIRLWIND); + await game.phaseInterceptor.to("BerryPhase"); + + expect(user.getLastXMoves(1)[0].result).toBe(MoveResult.SUCCESS); + }); }); diff --git a/test/moves/wide_guard.test.ts b/test/moves/wide_guard.test.ts index c466f104f67..85ebad806d7 100644 --- a/test/moves/wide_guard.test.ts +++ b/test/moves/wide_guard.test.ts @@ -25,7 +25,7 @@ describe("Moves - Wide Guard", () => { beforeEach(() => { game = new GameManager(phaserGame); - game.override.battleType("double"); + game.override.battleStyle("double"); game.override.moveset([Moves.WIDE_GUARD, Moves.SPLASH, Moves.SURF]); diff --git a/test/moves/will_o_wisp.test.ts b/test/moves/will_o_wisp.test.ts index 0d19fec954c..b4e4975896b 100644 --- a/test/moves/will_o_wisp.test.ts +++ b/test/moves/will_o_wisp.test.ts @@ -26,7 +26,7 @@ describe("Moves - Will-O-Wisp", () => { game.override .moveset([Moves.WILL_O_WISP, Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/mystery-encounter/encounter-test-utils.ts b/test/mystery-encounter/encounter-test-utils.ts index 8c54e0dd606..977f40bc90e 100644 --- a/test/mystery-encounter/encounter-test-utils.ts +++ b/test/mystery-encounter/encounter-test-utils.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/style/noNamespaceImport: Necessary for mocks import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { Status } from "#app/data/status-effect"; import { CommandPhase } from "#app/phases/command-phase"; @@ -13,8 +14,8 @@ import type MessageUiHandler from "#app/ui/message-ui-handler"; import type MysteryEncounterUiHandler from "#app/ui/mystery-encounter-ui-handler"; import type PartyUiHandler from "#app/ui/party-ui-handler"; import type OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; -import { Mode } from "#app/ui/ui"; -import { isNullOrUndefined } from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import { isNullOrUndefined } from "#app/utils/common"; import { Button } from "#enums/buttons"; import { StatusEffect } from "#enums/status-effect"; import type GameManager from "#test/testUtils/gameManager"; @@ -39,7 +40,7 @@ export async function runMysteryEncounterToEnd( // run the selected options phase game.onNextPrompt( "MysteryEncounterOptionSelectedPhase", - Mode.MESSAGE, + UiMode.MESSAGE, () => { const uiHandler = game.scene.ui.getHandler(); uiHandler.processInput(Button.ACTION); @@ -50,9 +51,9 @@ export async function runMysteryEncounterToEnd( if (isBattle) { game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - game.setMode(Mode.MESSAGE); + game.setMode(UiMode.MESSAGE); game.endPhase(); }, () => game.isCurrentPhase(CommandPhase), @@ -60,16 +61,16 @@ export async function runMysteryEncounterToEnd( game.onNextPrompt( "CheckSwitchPhase", - Mode.MESSAGE, + UiMode.MESSAGE, () => { - game.setMode(Mode.MESSAGE); + game.setMode(UiMode.MESSAGE); game.endPhase(); }, () => game.isCurrentPhase(CommandPhase), ); // If a battle is started, fast forward to end of the battle - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { game.scene.clearPhaseQueue(); game.scene.clearPhaseQueueSplice(); game.scene.unshiftPhase(new VictoryPhase(0)); @@ -77,13 +78,13 @@ export async function runMysteryEncounterToEnd( }); // Handle end of battle trainer messages - game.onNextPrompt("TrainerVictoryPhase", Mode.MESSAGE, () => { + game.onNextPrompt("TrainerVictoryPhase", UiMode.MESSAGE, () => { const uiHandler = game.scene.ui.getHandler(); uiHandler.processInput(Button.ACTION); }); // Handle egg hatch dialogue - game.onNextPrompt("EggLapsePhase", Mode.MESSAGE, () => { + game.onNextPrompt("EggLapsePhase", UiMode.MESSAGE, () => { const uiHandler = game.scene.ui.getHandler(); uiHandler.processInput(Button.ACTION); }); @@ -102,7 +103,7 @@ export async function runSelectMysteryEncounterOption( // Handle any eventual queued messages (e.g. weather phase, etc.) game.onNextPrompt( "MessagePhase", - Mode.MESSAGE, + UiMode.MESSAGE, () => { const uiHandler = game.scene.ui.getHandler(); uiHandler.processInput(Button.ACTION); @@ -117,7 +118,7 @@ export async function runSelectMysteryEncounterOption( // dispose of intro messages game.onNextPrompt( "MysteryEncounterPhase", - Mode.MESSAGE, + UiMode.MESSAGE, () => { const uiHandler = game.scene.ui.getHandler(); uiHandler.processInput(Button.ACTION); @@ -156,7 +157,7 @@ export async function runSelectMysteryEncounterOption( async function handleSecondaryOptionSelect(game: GameManager, pokemonNo: number, optionNo?: number) { // Handle secondary option selections - const partyUiHandler = game.scene.ui.handlers[Mode.PARTY] as PartyUiHandler; + const partyUiHandler = game.scene.ui.handlers[UiMode.PARTY] as PartyUiHandler; vi.spyOn(partyUiHandler, "show"); const encounterUiHandler = game.scene.ui.getHandler(); @@ -176,7 +177,7 @@ async function handleSecondaryOptionSelect(game: GameManager, pokemonNo: number, // If there is a second choice to make after selecting a Pokemon if (!isNullOrUndefined(optionNo)) { // Wait for Summary menu to close and second options to spawn - const secondOptionUiHandler = game.scene.ui.handlers[Mode.OPTION_SELECT] as OptionSelectUiHandler; + const secondOptionUiHandler = game.scene.ui.handlers[UiMode.OPTION_SELECT] as OptionSelectUiHandler; vi.spyOn(secondOptionUiHandler, "show"); await vi.waitFor(() => expect(secondOptionUiHandler.show).toHaveBeenCalled()); @@ -205,6 +206,6 @@ export async function skipBattleRunMysteryEncounterRewardsPhase(game: GameManage }); game.scene.pushPhase(new VictoryPhase(0)); game.phaseInterceptor.superEndPhase(); - game.setMode(Mode.MESSAGE); + game.setMode(UiMode.MESSAGE); await game.phaseInterceptor.to(MysteryEncounterRewardsPhase, runRewardsPhase); } diff --git a/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts b/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts index 43d582c5b70..a4c043ad13f 100644 --- a/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts +++ b/test/mystery-encounter/encounters/a-trainers-test-encounter.test.ts @@ -117,10 +117,8 @@ describe("A Trainer's Test - Mystery Encounter", () => { i18next.t("trainerNames:marley"), i18next.t("trainerNames:mira"), i18next.t("trainerNames:riley"), - ] - .map(name => name.toLowerCase()) - .includes(scene.currentBattle.trainer!.config.name), - ).toBeTruthy(); + ].map(name => name.toLowerCase()), + ).toContain(scene.currentBattle.trainer!.config.name.toLowerCase()); expect(enemyField[0]).toBeDefined(); }); diff --git a/test/mystery-encounter/encounters/absolute-avarice-encounter.test.ts b/test/mystery-encounter/encounters/absolute-avarice-encounter.test.ts index e00ce03333c..36a284880c1 100644 --- a/test/mystery-encounter/encounters/absolute-avarice-encounter.test.ts +++ b/test/mystery-encounter/encounters/absolute-avarice-encounter.test.ts @@ -23,7 +23,7 @@ import i18next from "i18next"; const namespace = "mysteryEncounters/absoluteAvarice"; const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA]; -const defaultBiome = Biome.PLAINS; +const defaultBiome = Biome.TALL_GRASS; const defaultWave = 45; describe("Absolute Avarice - Mystery Encounter", () => { @@ -45,7 +45,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ - [Biome.PLAINS, [MysteryEncounterType.ABSOLUTE_AVARICE]], + [Biome.TALL_GRASS, [MysteryEncounterType.ABSOLUTE_AVARICE]], [Biome.VOLCANO, [MysteryEncounterType.MYSTERIOUS_CHALLENGERS]], ]), ); @@ -91,6 +91,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { game.override.startingHeldItems([ { name: "BERRY", count: 2, type: BerryType.SITRUS }, { name: "BERRY", count: 3, type: BerryType.GANLON }, + { name: "BERRY", count: 2, type: BerryType.APICOT }, ]); await game.runToMysteryEncounter(); @@ -102,6 +103,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { game.override.startingHeldItems([ { name: "BERRY", count: 2, type: BerryType.SITRUS }, { name: "BERRY", count: 3, type: BerryType.GANLON }, + { name: "BERRY", count: 2, type: BerryType.APICOT }, ]); await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty); @@ -138,7 +140,7 @@ describe("Absolute Avarice - Mystery Encounter", () => { expect(enemyField[0].species.speciesId).toBe(Species.GREEDENT); const moveset = enemyField[0].moveset.map(m => m.moveId); expect(moveset?.length).toBe(4); - expect(moveset).toEqual([Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.CRUNCH]); + expect(moveset).toEqual([Moves.THRASH, Moves.CRUNCH, Moves.BODY_PRESS, Moves.SLACK_OFF]); const movePhases = phaseSpy.mock.calls.filter(p => p[0] instanceof MovePhase).map(p => p[0]); expect(movePhases.length).toBe(1); diff --git a/test/mystery-encounter/encounters/berries-abound-encounter.test.ts b/test/mystery-encounter/encounters/berries-abound-encounter.test.ts index e19726f49fd..3f85b0b89d9 100644 --- a/test/mystery-encounter/encounters/berries-abound-encounter.test.ts +++ b/test/mystery-encounter/encounters/berries-abound-encounter.test.ts @@ -9,7 +9,7 @@ import { skipBattleRunMysteryEncounterRewardsPhase, } from "#test/mystery-encounter/encounter-test-utils"; import type BattleScene from "#app/battle-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { BerryModifier } from "#app/modifier/modifier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; @@ -153,7 +153,7 @@ describe("Berries Abound - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -238,7 +238,7 @@ describe("Berries Abound - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts b/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts index 9befe77e688..455a5d28194 100644 --- a/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts +++ b/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts @@ -12,7 +12,7 @@ import { import { Moves } from "#enums/moves"; import type BattleScene from "#app/battle-scene"; import { PokemonMove } from "#app/field/pokemon"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { initSceneWithoutEncounterPhase } from "#test/testUtils/gameManagerUtils"; @@ -118,24 +118,34 @@ const POOL_4_POKEMON = [Species.GENESECT, Species.SLITHER_WING, Species.BUZZWOLE const PHYSICAL_TUTOR_MOVES = [ Moves.MEGAHORN, - Moves.X_SCISSOR, Moves.ATTACK_ORDER, - Moves.PIN_MISSILE, + Moves.BUG_BITE, Moves.FIRST_IMPRESSION, + Moves.LUNGE ]; -const SPECIAL_TUTOR_MOVES = [Moves.SILVER_WIND, Moves.BUG_BUZZ, Moves.SIGNAL_BEAM, Moves.POLLEN_PUFF]; +const SPECIAL_TUTOR_MOVES = [ + Moves.SILVER_WIND, + Moves.SIGNAL_BEAM, + Moves.BUG_BUZZ, + Moves.POLLEN_PUFF, + Moves.STRUGGLE_BUG +]; -const STATUS_TUTOR_MOVES = [Moves.STRING_SHOT, Moves.STICKY_WEB, Moves.SILK_TRAP, Moves.RAGE_POWDER, Moves.HEAL_ORDER]; +const STATUS_TUTOR_MOVES = [ + Moves.STRING_SHOT, + Moves.DEFEND_ORDER, + Moves.RAGE_POWDER, + Moves.STICKY_WEB, + Moves.SILK_TRAP +]; const MISC_TUTOR_MOVES = [ - Moves.BUG_BITE, Moves.LEECH_LIFE, - Moves.DEFEND_ORDER, - Moves.QUIVER_DANCE, - Moves.TAIL_GLOW, - Moves.INFESTATION, Moves.U_TURN, + Moves.HEAL_ORDER, + Moves.QUIVER_DANCE, + Moves.INFESTATION, ]; describe("Bug-Type Superfan - Mystery Encounter", () => { @@ -364,7 +374,7 @@ describe("Bug-Type Superfan - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterRewardsPhase.name); game.phaseInterceptor["prompts"] = []; // Clear out prompt handlers - game.onNextPrompt("MysteryEncounterRewardsPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("MysteryEncounterRewardsPhase", UiMode.OPTION_SELECT, () => { game.phaseInterceptor.superEndPhase(); }); await game.phaseInterceptor.run(MysteryEncounterRewardsPhase); @@ -416,7 +426,7 @@ describe("Bug-Type Superfan - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -432,7 +442,7 @@ describe("Bug-Type Superfan - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -454,7 +464,7 @@ describe("Bug-Type Superfan - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -478,7 +488,7 @@ describe("Bug-Type Superfan - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -554,7 +564,7 @@ describe("Bug-Type Superfan - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/clowning-around-encounter.test.ts b/test/mystery-encounter/encounters/clowning-around-encounter.test.ts index 4bbe76e5c72..afc4a83e9bf 100644 --- a/test/mystery-encounter/encounters/clowning-around-encounter.test.ts +++ b/test/mystery-encounter/encounters/clowning-around-encounter.test.ts @@ -16,7 +16,7 @@ import { Moves } from "#enums/moves"; import type BattleScene from "#app/battle-scene"; import type Pokemon from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { initSceneWithoutEncounterPhase } from "#test/testUtils/gameManagerUtils"; @@ -206,14 +206,14 @@ describe("Clowning Around - Mystery Encounter", () => { await game.phaseInterceptor.run(SelectModifierPhase); const abilityToTrain = scene.currentBattle.mysteryEncounter?.misc.ability; - game.onNextPrompt("PostMysteryEncounterPhase", Mode.MESSAGE, () => { + game.onNextPrompt("PostMysteryEncounterPhase", UiMode.MESSAGE, () => { game.scene.ui.getHandler().processInput(Button.ACTION); }); // Run to ability train option selection - const optionSelectUiHandler = game.scene.ui.handlers[Mode.OPTION_SELECT] as OptionSelectUiHandler; + const optionSelectUiHandler = game.scene.ui.handlers[UiMode.OPTION_SELECT] as OptionSelectUiHandler; vi.spyOn(optionSelectUiHandler, "show"); - const partyUiHandler = game.scene.ui.handlers[Mode.PARTY] as PartyUiHandler; + const partyUiHandler = game.scene.ui.handlers[UiMode.PARTY] as PartyUiHandler; vi.spyOn(partyUiHandler, "show"); game.endPhase(); await game.phaseInterceptor.to(PostMysteryEncounterPhase); diff --git a/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts b/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts index 77cd65e51b9..873bed2f213 100644 --- a/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts +++ b/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts @@ -15,7 +15,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters"; import { Moves } from "#enums/moves"; import { DancingLessonsEncounter } from "#app/data/mystery-encounters/encounters/dancing-lessons-encounter"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { PokemonMove } from "#app/field/pokemon"; import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; @@ -132,7 +132,7 @@ describe("Dancing Lessons - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts b/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts index d4b0de30535..2488d12dad1 100644 --- a/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts +++ b/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts @@ -7,7 +7,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils"; import type BattleScene from "#app/battle-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { DepartmentStoreSaleEncounter } from "#app/data/mystery-encounters/encounters/department-store-sale-encounter"; import { CIVILIZATION_ENCOUNTER_BIOMES } from "#app/data/mystery-encounters/mystery-encounters"; @@ -98,7 +98,7 @@ describe("Department Store Sale - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -135,7 +135,7 @@ describe("Department Store Sale - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -175,7 +175,7 @@ describe("Department Store Sale - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -215,7 +215,7 @@ describe("Department Store Sale - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/field-trip-encounter.test.ts b/test/mystery-encounter/encounters/field-trip-encounter.test.ts index 8bd35d6013f..75a6fe77492 100644 --- a/test/mystery-encounter/encounters/field-trip-encounter.test.ts +++ b/test/mystery-encounter/encounters/field-trip-encounter.test.ts @@ -12,7 +12,7 @@ import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encount import { FieldTripEncounter } from "#app/data/mystery-encounters/encounters/field-trip-encounter"; import { Moves } from "#enums/moves"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import i18next from "i18next"; @@ -88,7 +88,7 @@ describe("Field Trip - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1, optionNo: 2 }); await game.phaseInterceptor.to(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -100,7 +100,7 @@ describe("Field Trip - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1, optionNo: 1 }); await game.phaseInterceptor.to(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -149,7 +149,7 @@ describe("Field Trip - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 2, { pokemonNo: 1, optionNo: 1 }); await game.phaseInterceptor.to(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -161,7 +161,7 @@ describe("Field Trip - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 2, { pokemonNo: 1, optionNo: 2 }); await game.phaseInterceptor.to(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -210,7 +210,7 @@ describe("Field Trip - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 3, { pokemonNo: 1, optionNo: 1 }); await game.phaseInterceptor.to(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -223,7 +223,7 @@ describe("Field Trip - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 3, { pokemonNo: 1, optionNo: 3 }); await game.phaseInterceptor.to(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts b/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts index d233e72932a..d47266268ee 100644 --- a/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts +++ b/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts @@ -12,7 +12,7 @@ import { import { Moves } from "#enums/moves"; import type BattleScene from "#app/battle-scene"; import { PokemonMove } from "#app/field/pokemon"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -126,7 +126,7 @@ describe("Fight or Flight - Mystery Encounter", () => { await game.phaseInterceptor.to(SelectModifierPhase, false); expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, @@ -186,7 +186,7 @@ describe("Fight or Flight - Mystery Encounter", () => { await game.phaseInterceptor.to(SelectModifierPhase, false); expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, diff --git a/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts b/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts index 4bb44c4d19e..f8375c1aa78 100644 --- a/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts +++ b/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts @@ -10,7 +10,7 @@ import { runSelectMysteryEncounterOption, } from "#test/mystery-encounter/encounter-test-utils"; import type BattleScene from "#app/battle-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { initSceneWithoutEncounterPhase } from "#test/testUtils/gameManagerUtils"; @@ -147,7 +147,7 @@ describe("Fun And Games! - Mystery Encounter", () => { expect(scene.getEnemyPokemon()?.ivs).toEqual([0, 0, 0, 0, 0, 0]); expect(scene.getEnemyPokemon()?.nature).toBe(Nature.MILD); - game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => { + game.onNextPrompt("MessagePhase", UiMode.MESSAGE, () => { game.endPhase(); }); @@ -173,7 +173,7 @@ describe("Fun And Games! - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1 }, true); expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); - game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => { + game.onNextPrompt("MessagePhase", UiMode.MESSAGE, () => { game.endPhase(); }); @@ -186,7 +186,7 @@ describe("Fun And Games! - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -200,7 +200,7 @@ describe("Fun And Games! - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1 }, true); expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); - game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => { + game.onNextPrompt("MessagePhase", UiMode.MESSAGE, () => { game.endPhase(); }); @@ -215,7 +215,7 @@ describe("Fun And Games! - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -230,7 +230,7 @@ describe("Fun And Games! - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1 }, true); expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); - game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => { + game.onNextPrompt("MessagePhase", UiMode.MESSAGE, () => { game.endPhase(); }); @@ -245,7 +245,7 @@ describe("Fun And Games! - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -260,7 +260,7 @@ describe("Fun And Games! - Mystery Encounter", () => { await runMysteryEncounterToEnd(game, 1, { pokemonNo: 1 }, true); expect(scene.getCurrentPhase()?.constructor.name).toBe(CommandPhase.name); - game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => { + game.onNextPrompt("MessagePhase", UiMode.MESSAGE, () => { game.endPhase(); }); @@ -275,7 +275,7 @@ describe("Fun And Games! - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts b/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts index f68561c2286..576e99c4e18 100644 --- a/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts +++ b/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts @@ -15,10 +15,10 @@ import { modifierTypes } from "#app/modifier/modifier-type"; import { GlobalTradeSystemEncounter } from "#app/data/mystery-encounters/encounters/global-trade-system-encounter"; import { CIVILIZATION_ENCOUNTER_BIOMES } from "#app/data/mystery-encounters/mystery-encounters"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { ModifierTier } from "#app/modifier/modifier-tier"; -import * as Utils from "#app/utils"; +import * as Utils from "#app/utils/common"; const namespace = "mysteryEncounters/globalTradeSystem"; const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA]; @@ -231,7 +231,7 @@ describe("Global Trade System - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts b/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts index f620cbd6c36..2c61d03b29d 100644 --- a/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts +++ b/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts @@ -10,7 +10,7 @@ import { skipBattleRunMysteryEncounterRewardsPhase, } from "#test/mystery-encounter/encounter-test-utils"; import type BattleScene from "#app/battle-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { initSceneWithoutEncounterPhase } from "#test/testUtils/gameManagerUtils"; @@ -166,7 +166,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -210,7 +210,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -267,7 +267,7 @@ describe("Mysterious Challengers - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts b/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts index 85c823038e8..4ff94c5a9bd 100644 --- a/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts +++ b/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts @@ -10,7 +10,7 @@ import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import GameManager from "#test/testUtils/gameManager"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { @@ -301,7 +301,7 @@ describe("Teleporting Hijinks - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts b/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts index a9e6a339d36..e3440aee9e0 100644 --- a/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts +++ b/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts @@ -18,7 +18,7 @@ import { Nature } from "#enums/nature"; import { BerryType } from "#enums/berry-type"; import { BattlerTagType } from "#enums/battler-tag-type"; import { PokemonMove } from "#app/field/pokemon"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { BerryModifier, PokemonBaseStatTotalModifier } from "#app/modifier/modifier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; @@ -236,7 +236,7 @@ describe("The Strong Stuff - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts b/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts index 94c8141aa1e..4cb712ce779 100644 --- a/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts +++ b/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts @@ -7,7 +7,7 @@ import GameManager from "#test/testUtils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils"; import type BattleScene from "#app/battle-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { initSceneWithoutEncounterPhase } from "#test/testUtils/gameManagerUtils"; @@ -299,7 +299,7 @@ describe("The Winstrate Challenge - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -341,7 +341,7 @@ describe("The Winstrate Challenge - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -359,7 +359,7 @@ describe("The Winstrate Challenge - Mystery Encounter", () => { async function skipBattleToNextBattle(game: GameManager, isFinalBattle = false) { game.scene.clearPhaseQueue(); game.scene.clearPhaseQueueSplice(); - const commandUiHandler = game.scene.ui.handlers[Mode.COMMAND]; + const commandUiHandler = game.scene.ui.handlers[UiMode.COMMAND]; commandUiHandler.clear(); game.scene.getEnemyParty().forEach(p => { p.hp = 0; diff --git a/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts b/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts index df7bbb9f424..2f910a9250f 100644 --- a/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts +++ b/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts @@ -20,8 +20,8 @@ import { CommandPhase } from "#app/phases/command-phase"; import { MovePhase } from "#app/phases/move-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; -import { Mode } from "#app/ui/ui"; -import * as Utils from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import * as Utils from "#app/utils/common"; import { Moves } from "#enums/moves"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -246,7 +246,7 @@ describe("Trash to Treasure - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/mystery-encounter/encounters/weird-dream-encounter.test.ts b/test/mystery-encounter/encounters/weird-dream-encounter.test.ts index fbb88e346a8..f51ab45e4d4 100644 --- a/test/mystery-encounter/encounters/weird-dream-encounter.test.ts +++ b/test/mystery-encounter/encounters/weird-dream-encounter.test.ts @@ -10,7 +10,7 @@ import { skipBattleRunMysteryEncounterRewardsPhase, } from "#test/mystery-encounter/encounter-test-utils"; import type BattleScene from "#app/battle-scene"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -144,7 +144,7 @@ describe("Weird Dream - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -200,7 +200,7 @@ describe("Weird Dream - Mystery Encounter", () => { expect(scene.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/phases/form-change-phase.test.ts b/test/phases/form-change-phase.test.ts index deac21ed0dd..974c64d9e5a 100644 --- a/test/phases/form-change-phase.test.ts +++ b/test/phases/form-change-phase.test.ts @@ -27,7 +27,7 @@ describe("Form Change Phase", () => { game.override .moveset([Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) diff --git a/test/phases/frenzy-move-reset.test.ts b/test/phases/frenzy-move-reset.test.ts index 2f628f8a8c4..6d3ec767722 100644 --- a/test/phases/frenzy-move-reset.test.ts +++ b/test/phases/frenzy-move-reset.test.ts @@ -25,7 +25,7 @@ describe("Frenzy Move Reset", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .battleType("single") + .battleStyle("single") .disableCrits() .starterSpecies(Species.MAGIKARP) .moveset(Moves.THRASH) diff --git a/test/phases/game-over-phase.test.ts b/test/phases/game-over-phase.test.ts index 438efc85167..40473a022cb 100644 --- a/test/phases/game-over-phase.test.ts +++ b/test/phases/game-over-phase.test.ts @@ -27,7 +27,7 @@ describe("Game Over Phase", () => { game.override .moveset([Moves.MEMENTO, Moves.ICE_BEAM, Moves.SPLASH]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) diff --git a/test/phases/learn-move-phase.test.ts b/test/phases/learn-move-phase.test.ts index 55b9d8b79d4..019b833d386 100644 --- a/test/phases/learn-move-phase.test.ts +++ b/test/phases/learn-move-phase.test.ts @@ -4,7 +4,7 @@ import GameManager from "#test/testUtils/gameManager"; import { Species } from "#enums/species"; import { Moves } from "#enums/moves"; import { LearnMovePhase } from "#app/phases/learn-move-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Button } from "#app/enums/buttons"; describe("Learn Move Phase", () => { @@ -52,10 +52,10 @@ describe("Learn Move Phase", () => { await game.doKillOpponents(); // queue up inputs to confirm dialog boxes - game.onNextPrompt("LearnMovePhase", Mode.CONFIRM, () => { + game.onNextPrompt("LearnMovePhase", UiMode.CONFIRM, () => { game.scene.ui.processInput(Button.ACTION); }); - game.onNextPrompt("LearnMovePhase", Mode.SUMMARY, () => { + game.onNextPrompt("LearnMovePhase", UiMode.SUMMARY, () => { for (let x = 0; x < moveSlotNum; x++) { game.scene.ui.processInput(Button.DOWN); } @@ -84,16 +84,16 @@ describe("Learn Move Phase", () => { await game.doKillOpponents(); // queue up inputs to confirm dialog boxes - game.onNextPrompt("LearnMovePhase", Mode.CONFIRM, () => { + game.onNextPrompt("LearnMovePhase", UiMode.CONFIRM, () => { game.scene.ui.processInput(Button.ACTION); }); - game.onNextPrompt("LearnMovePhase", Mode.SUMMARY, () => { + game.onNextPrompt("LearnMovePhase", UiMode.SUMMARY, () => { for (let x = 0; x < 4; x++) { game.scene.ui.processInput(Button.DOWN); // moves down 4 times to the 5th move slot } game.scene.ui.processInput(Button.ACTION); }); - game.onNextPrompt("LearnMovePhase", Mode.CONFIRM, () => { + game.onNextPrompt("LearnMovePhase", UiMode.CONFIRM, () => { game.scene.ui.processInput(Button.ACTION); }); await game.phaseInterceptor.to(LearnMovePhase); diff --git a/test/phases/mystery-encounter-phase.test.ts b/test/phases/mystery-encounter-phase.test.ts index f903932d2cb..34078b65039 100644 --- a/test/phases/mystery-encounter-phase.test.ts +++ b/test/phases/mystery-encounter-phase.test.ts @@ -3,7 +3,7 @@ import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { Species } from "#enums/species"; import { MysteryEncounterOptionSelectedPhase, MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Button } from "#enums/buttons"; import type MysteryEncounterUiHandler from "#app/ui/mystery-encounter-ui-handler"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; @@ -50,7 +50,7 @@ describe("Mystery Encounter Phases", () => { Species.VOLCARONA, ]); - game.onNextPrompt("MysteryEncounterPhase", Mode.MYSTERY_ENCOUNTER, () => { + game.onNextPrompt("MysteryEncounterPhase", UiMode.MYSTERY_ENCOUNTER, () => { // End phase early for test game.phaseInterceptor.superEndPhase(); }); @@ -61,7 +61,7 @@ describe("Mystery Encounter Phases", () => { MysteryEncounterType.MYSTERIOUS_CHALLENGERS, ); expect(game.scene.mysteryEncounterSaveData.encounteredEvents[0].tier).toEqual(MysteryEncounterTier.GREAT); - expect(game.scene.ui.getMode()).toBe(Mode.MYSTERY_ENCOUNTER); + expect(game.scene.ui.getMode()).toBe(UiMode.MYSTERY_ENCOUNTER); }); it("Selects an option for MysteryEncounterPhase", async () => { @@ -73,7 +73,7 @@ describe("Mystery Encounter Phases", () => { Species.VOLCARONA, ]); - game.onNextPrompt("MysteryEncounterPhase", Mode.MESSAGE, () => { + game.onNextPrompt("MysteryEncounterPhase", UiMode.MESSAGE, () => { const handler = game.scene.ui.getHandler() as MessageUiHandler; handler.processInput(Button.ACTION); }); @@ -89,7 +89,7 @@ describe("Mystery Encounter Phases", () => { await vi.waitFor(() => expect(game.scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterOptionSelectedPhase.name), ); - expect(ui.getMode()).toBe(Mode.MESSAGE); + expect(ui.getMode()).toBe(UiMode.MESSAGE); expect(ui.showDialogue).toHaveBeenCalledTimes(1); expect(ui.showText).toHaveBeenCalledTimes(2); expect(ui.showDialogue).toHaveBeenCalledWith( diff --git a/test/phases/phases.test.ts b/test/phases/phases.test.ts index 96225c9151c..2483cfb317f 100644 --- a/test/phases/phases.test.ts +++ b/test/phases/phases.test.ts @@ -2,7 +2,7 @@ import type BattleScene from "#app/battle-scene"; import { LoginPhase } from "#app/phases/login-phase"; import { TitlePhase } from "#app/phases/title-phase"; import { UnavailablePhase } from "#app/phases/unavailable-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -32,7 +32,7 @@ describe("Phases", () => { const loginPhase = new LoginPhase(); scene.unshiftPhase(loginPhase); await game.phaseInterceptor.to(LoginPhase); - expect(scene.ui.getMode()).to.equal(Mode.MESSAGE); + expect(scene.ui.getMode()).to.equal(UiMode.MESSAGE); }); }); @@ -41,7 +41,7 @@ describe("Phases", () => { const titlePhase = new TitlePhase(); scene.unshiftPhase(titlePhase); await game.phaseInterceptor.to(TitlePhase); - expect(scene.ui.getMode()).to.equal(Mode.TITLE); + expect(scene.ui.getMode()).to.equal(UiMode.TITLE); }); }); @@ -50,7 +50,7 @@ describe("Phases", () => { const unavailablePhase = new UnavailablePhase(); scene.unshiftPhase(unavailablePhase); await game.phaseInterceptor.to(UnavailablePhase); - expect(scene.ui.getMode()).to.equal(Mode.UNAVAILABLE); + expect(scene.ui.getMode()).to.equal(UiMode.UNAVAILABLE); }, 20000); }); }); diff --git a/test/phases/select-modifier-phase.test.ts b/test/phases/select-modifier-phase.test.ts index d352acea77a..85f8b472c4a 100644 --- a/test/phases/select-modifier-phase.test.ts +++ b/test/phases/select-modifier-phase.test.ts @@ -6,8 +6,8 @@ import type { CustomModifierSettings } from "#app/modifier/modifier-type"; import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; -import { Mode } from "#app/ui/ui"; -import { shiftCharCodes } from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import { shiftCharCodes } from "#app/utils/common"; import { Abilities } from "#enums/abilities"; import { Button } from "#enums/buttons"; import { Moves } from "#enums/moves"; @@ -51,7 +51,7 @@ describe("SelectModifierPhase", () => { scene.unshiftPhase(selectModifierPhase); await game.phaseInterceptor.to(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); }); it("should generate random modifiers", async () => { @@ -59,7 +59,7 @@ describe("SelectModifierPhase", () => { game.move.select(Moves.FISSURE); await game.phaseInterceptor.to("SelectModifierPhase"); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -97,7 +97,7 @@ describe("SelectModifierPhase", () => { // TODO: nagivate the ui to reroll somehow //const smphase = scene.getCurrentPhase() as SelectModifierPhase; - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -106,7 +106,7 @@ describe("SelectModifierPhase", () => { modifierSelectHandler.processInput(Button.ACTION); expect(scene.money).toBe(1000000 - 250); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); expect(modifierSelectHandler.options.length).toEqual(3); }); @@ -125,7 +125,7 @@ describe("SelectModifierPhase", () => { game.move.select(Moves.FISSURE); await game.phaseInterceptor.to("SelectModifierPhase"); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -134,7 +134,7 @@ describe("SelectModifierPhase", () => { // TODO: nagivate ui to reroll with lock capsule enabled - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); expect(modifierSelectHandler.options.length).toEqual(3); // Reroll with lock can still upgrade expect( @@ -168,7 +168,7 @@ describe("SelectModifierPhase", () => { game.move.select(Moves.SPLASH); await game.phaseInterceptor.to("SelectModifierPhase"); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -205,7 +205,7 @@ describe("SelectModifierPhase", () => { game.move.select(Moves.SPLASH); await game.phaseInterceptor.to("SelectModifierPhase"); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -244,7 +244,7 @@ describe("SelectModifierPhase", () => { game.move.select(Moves.SPLASH); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; @@ -268,7 +268,7 @@ describe("SelectModifierPhase", () => { game.move.select(Moves.SPLASH); await game.phaseInterceptor.run(SelectModifierPhase); - expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT); + expect(scene.ui.getMode()).to.equal(UiMode.MODIFIER_SELECT); const modifierSelectHandler = scene.ui.handlers.find( h => h instanceof ModifierSelectUiHandler, ) as ModifierSelectUiHandler; diff --git a/test/plugins/api/pokerogue-account-api.test.ts b/test/plugins/api/pokerogue-account-api.test.ts index e7e1b2d52b0..3c37451960a 100644 --- a/test/plugins/api/pokerogue-account-api.test.ts +++ b/test/plugins/api/pokerogue-account-api.test.ts @@ -2,7 +2,8 @@ import type { AccountInfoResponse } from "#app/@types/PokerogueAccountApi"; import { SESSION_ID_COOKIE_NAME } from "#app/constants"; import { PokerogueAccountApi } from "#app/plugins/api/pokerogue-account-api"; import { getApiBaseUrl } from "#test/testUtils/testUtils"; -import * as Utils from "#app/utils"; +import * as CookieUtils from "#app/utils/cookies"; +import * as cookies from "#app/utils/cookies"; import { http, HttpResponse } from "msw"; import { beforeAll, afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { initServerForApiTests } from "#test/testUtils/testFileInitialization"; @@ -98,13 +99,13 @@ describe("Pokerogue Account API", () => { const loginParams = { username: "test", password: "test" }; it("should return null and set the cookie on SUCCESS", async () => { - vi.spyOn(Utils, "setCookie"); + vi.spyOn(CookieUtils, "setCookie"); server.use(http.post(`${apiBase}/account/login`, () => HttpResponse.json({ token: "abctest" }))); const error = await accountApi.login(loginParams); expect(error).toBeNull(); - expect(Utils.setCookie).toHaveBeenCalledWith(SESSION_ID_COOKIE_NAME, "abctest"); + expect(cookies.setCookie).toHaveBeenCalledWith(SESSION_ID_COOKIE_NAME, "abctest"); }); it("should return error message and report a warning on FAILURE", async () => { @@ -130,16 +131,16 @@ describe("Pokerogue Account API", () => { describe("Logout", () => { beforeEach(() => { - vi.spyOn(Utils, "removeCookie"); + vi.spyOn(CookieUtils, "removeCookie"); }); it("should remove cookie on success", async () => { - vi.spyOn(Utils, "setCookie"); + vi.spyOn(CookieUtils, "setCookie"); server.use(http.get(`${apiBase}/account/logout`, () => new HttpResponse("", { status: 200 }))); await accountApi.logout(); - expect(Utils.removeCookie).toHaveBeenCalledWith(SESSION_ID_COOKIE_NAME); + expect(cookies.removeCookie).toHaveBeenCalledWith(SESSION_ID_COOKIE_NAME); }); it("should report a warning on and remove cookie on FAILURE", async () => { @@ -147,7 +148,7 @@ describe("Pokerogue Account API", () => { await accountApi.logout(); - expect(Utils.removeCookie).toHaveBeenCalledWith(SESSION_ID_COOKIE_NAME); + expect(cookies.removeCookie).toHaveBeenCalledWith(SESSION_ID_COOKIE_NAME); expect(console.warn).toHaveBeenCalledWith("Log out failed!", expect.any(Error)); }); @@ -156,7 +157,7 @@ describe("Pokerogue Account API", () => { await accountApi.logout(); - expect(Utils.removeCookie).toHaveBeenCalledWith(SESSION_ID_COOKIE_NAME); + expect(cookies.removeCookie).toHaveBeenCalledWith(SESSION_ID_COOKIE_NAME); expect(console.warn).toHaveBeenCalledWith("Log out failed!", expect.any(Error)); }); }); diff --git a/test/plugins/api/pokerogue-session-savedata-api.test.ts b/test/plugins/api/pokerogue-session-savedata-api.test.ts index d4c235ac51a..4d4774f2283 100644 --- a/test/plugins/api/pokerogue-session-savedata-api.test.ts +++ b/test/plugins/api/pokerogue-session-savedata-api.test.ts @@ -57,9 +57,7 @@ describe("Pokerogue Session Savedata API", () => { it("should return false and report a warning on ERROR", async () => { server.use(http.get(`${apiBase}/savedata/session/newclear`, () => HttpResponse.error())); - const success = await sessionSavedataApi.newclear(params); - - expect(success).toBe(false); + await expect(sessionSavedataApi.newclear(params)).rejects.toThrow("Could not newclear session!"); expect(console.warn).toHaveBeenCalledWith("Could not newclear session!", expect.any(Error)); }); }); diff --git a/test/reload.test.ts b/test/reload.test.ts index f54885eccfb..93823e06cce 100644 --- a/test/reload.test.ts +++ b/test/reload.test.ts @@ -1,7 +1,7 @@ import { GameModes } from "#app/game-mode"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import type OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Biome } from "#enums/biome"; import { Button } from "#enums/buttons"; import { Moves } from "#enums/moves"; @@ -48,7 +48,7 @@ describe("Reload", () => { it("should not have RNG inconsistencies after a biome switch", async () => { game.override .startingWave(10) - .battleType("single") + .battleStyle("single") .startingLevel(100) // Avoid levelling up .disableTrainerWaves() .moveset([Moves.SPLASH]) @@ -58,7 +58,7 @@ describe("Reload", () => { // Transition from Wave 10 to Wave 11 in order to trigger biome switch game.move.select(Moves.SPLASH); await game.doKillOpponents(); - game.onNextPrompt("SelectBiomePhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectBiomePhase", UiMode.OPTION_SELECT, () => { (game.scene.time as MockClock).overrideDelay = null; const optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; game.scene.time.delayedCall(1010, () => optionSelectUiHandler.processInput(Button.ACTION)); @@ -81,7 +81,7 @@ describe("Reload", () => { game.override .startingWave(10) .startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather - .battleType("single") + .battleStyle("single") .startingLevel(100) // Avoid levelling up .disableTrainerWaves() .moveset([Moves.SPLASH]) @@ -116,7 +116,7 @@ describe("Reload", () => { }, 20000); it("should not have RNG inconsistencies at a Daily run double battle", async () => { - game.override.battleType("double"); + game.override.battleStyle("double"); await game.dailyMode.startBattle(); const preReloadRngState = Phaser.Math.RND.state(); @@ -129,7 +129,7 @@ describe("Reload", () => { }, 20000); it("should not have RNG inconsistencies at a Daily run Gym Leader fight", async () => { - game.override.battleType("single").startingWave(40); + game.override.battleStyle("single").startingWave(40); await game.dailyMode.startBattle(); const preReloadRngState = Phaser.Math.RND.state(); @@ -142,7 +142,7 @@ describe("Reload", () => { }, 20000); it("should not have RNG inconsistencies at a Daily run regular trainer fight", async () => { - game.override.battleType("single").startingWave(45); + game.override.battleStyle("single").startingWave(45); await game.dailyMode.startBattle(); const preReloadRngState = Phaser.Math.RND.state(); @@ -155,7 +155,7 @@ describe("Reload", () => { }, 20000); it("should not have RNG inconsistencies at a Daily run wave 50 Boss fight", async () => { - game.override.battleType("single").startingWave(50); + game.override.battleStyle("single").startingWave(50); await game.runToFinalBossEncounter([Species.BULBASAUR], GameModes.DAILY); const preReloadRngState = Phaser.Math.RND.state(); diff --git a/test/settingMenu/rebinding_setting.test.ts b/test/settingMenu/rebinding_setting.test.ts index 28b5d73d7cc..20a1fe51484 100644 --- a/test/settingMenu/rebinding_setting.test.ts +++ b/test/settingMenu/rebinding_setting.test.ts @@ -2,7 +2,7 @@ import cfg_keyboard_qwerty from "#app/configs/inputs/cfg_keyboard_qwerty"; import { getKeyWithKeycode, getKeyWithSettingName } from "#app/configs/inputs/configHandler"; import type { InterfaceConfig } from "#app/inputs-controller"; import { SettingKeyboard } from "#app/system/settings/settings-keyboard"; -import { deepCopy } from "#app/utils"; +import { deepCopy } from "#app/utils/data"; import { Button } from "#enums/buttons"; import { Device } from "#enums/devices"; import { InGameManip } from "#test/settingMenu/helpers/inGameManip"; diff --git a/test/sprites/pokemonSprite.test.ts b/test/sprites/pokemonSprite.test.ts index 5bd08a58cda..a008b75b42e 100644 --- a/test/sprites/pokemonSprite.test.ts +++ b/test/sprites/pokemonSprite.test.ts @@ -3,8 +3,10 @@ import fs from "fs"; import path from "path"; import { beforeAll, describe, expect, it } from "vitest"; import _masterlist from "../../public/images/pokemon/variant/_masterlist.json"; +import _exp_masterlist from "../../public/images/pokemon/variant/_exp_masterlist.json"; type PokemonVariantMasterlist = typeof _masterlist; +type PokemonExpVariantMasterlist = typeof _exp_masterlist; const deepCopy = (data: any) => { return JSON.parse(JSON.stringify(data)); @@ -12,7 +14,7 @@ const deepCopy = (data: any) => { describe("check if every variant's sprite are correctly set", () => { let masterlist: PokemonVariantMasterlist; - let expVariant: PokemonVariantMasterlist["exp"]; + let expVariant: PokemonExpVariantMasterlist; let femaleVariant: PokemonVariantMasterlist["female"]; let backVariant: PokemonVariantMasterlist["back"]; let rootDir: string; @@ -20,13 +22,12 @@ describe("check if every variant's sprite are correctly set", () => { beforeAll(() => { rootDir = `${getAppRootDir()}${path.sep}public${path.sep}images${path.sep}pokemon${path.sep}variant${path.sep}`; masterlist = deepCopy(_masterlist); - expVariant = masterlist.exp; + expVariant = deepCopy(_exp_masterlist); femaleVariant = masterlist.female; backVariant = masterlist.back; - //@ts-ignore - delete masterlist.exp; //TODO: resolve ts-ignore - //@ts-ignore - delete masterlist.female; //TODO: resolve ts-ignore + + // @ts-ignore + delete masterlist.female; // TODO: resolve ts-ignore //@ts-ignore delete masterlist.back; //TODO: resolve ts-ignore }); diff --git a/test/system/game_data.test.ts b/test/system/game_data.test.ts index 93e615711c4..900fb672320 100644 --- a/test/system/game_data.test.ts +++ b/test/system/game_data.test.ts @@ -1,4 +1,4 @@ -import * as BattleScene from "#app/battle-scene"; +import * as bypassLoginModule from "#app/global-vars/bypass-login"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import type { SessionSaveData } from "#app/system/game-data"; import { Abilities } from "#enums/abilities"; @@ -22,7 +22,7 @@ describe("System - Game Data", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.SPLASH]) - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH); }); @@ -33,13 +33,13 @@ describe("System - Game Data", () => { describe("tryClearSession", () => { beforeEach(() => { - vi.spyOn(BattleScene, "bypassLogin", "get").mockReturnValue(false); + vi.spyOn(bypassLoginModule, "bypassLogin", "get").mockReturnValue(false); vi.spyOn(game.scene.gameData, "getSessionSaveData").mockReturnValue({} as SessionSaveData); vi.spyOn(account, "updateUserInfo").mockImplementation(async () => [true, 1]); }); it("should return [true, true] if bypassLogin is true", async () => { - vi.spyOn(BattleScene, "bypassLogin", "get").mockReturnValue(true); + vi.spyOn(bypassLoginModule, "bypassLogin", "get").mockReturnValue(true); const result = await game.scene.gameData.tryClearSession(0); diff --git a/test/testUtils/gameManager.ts b/test/testUtils/gameManager.ts index 390e71af126..8dd90decf1a 100644 --- a/test/testUtils/gameManager.ts +++ b/test/testUtils/gameManager.ts @@ -30,8 +30,8 @@ import type CommandUiHandler from "#app/ui/command-ui-handler"; import type ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import type PartyUiHandler from "#app/ui/party-ui-handler"; import type TargetSelectUiHandler from "#app/ui/target-select-ui-handler"; -import { Mode } from "#app/ui/ui"; -import { isNullOrUndefined } from "#app/utils"; +import { UiMode } from "#enums/ui-mode"; +import { isNullOrUndefined } from "#app/utils/common"; import { BattleStyle } from "#enums/battle-style"; import { Button } from "#enums/buttons"; import { ExpGainsSpeed } from "#enums/exp-gains-speed"; @@ -102,7 +102,7 @@ export default class GameManager { if (!firstTimeScene) { this.scene.reset(false, true); - (this.scene.ui.handlers[Mode.STARTER_SELECT] as StarterSelectUiHandler).clearStarterPreferences(); + (this.scene.ui.handlers[UiMode.STARTER_SELECT] as StarterSelectUiHandler).clearStarterPreferences(); this.scene.clearAllPhases(); // Must be run after phase interceptor has been initialized. @@ -135,7 +135,7 @@ export default class GameManager { * Sets the game mode. * @param mode - The mode to set. */ - setMode(mode: Mode) { + setMode(mode: UiMode) { this.scene.ui?.setMode(mode); } @@ -144,7 +144,7 @@ export default class GameManager { * @param mode - The mode to wait for. * @returns A promise that resolves when the mode is set. */ - waitMode(mode: Mode): Promise { + waitMode(mode: UiMode): Promise { return new Promise(async resolve => { await waitUntil(() => this.scene.ui?.getMode() === mode); return resolve(); @@ -168,7 +168,7 @@ export default class GameManager { */ onNextPrompt( phaseTarget: string, - mode: Mode, + mode: UiMode, callback: () => void, expireFn?: () => void, awaitingActionInput = false, @@ -208,7 +208,7 @@ export default class GameManager { console.log("===to final boss encounter==="); await this.runToTitle(); - this.onNextPrompt("TitlePhase", Mode.TITLE, () => { + this.onNextPrompt("TitlePhase", UiMode.TITLE, () => { this.scene.gameMode = getGameMode(mode); const starters = generateStarter(this.scene, species); const selectStarterPhase = new SelectStarterPhase(); @@ -243,7 +243,7 @@ export default class GameManager { this.onNextPrompt( "TitlePhase", - Mode.TITLE, + UiMode.TITLE, () => { this.scene.gameMode = getGameMode(GameModes.CLASSIC); const starters = generateStarter(this.scene, species); @@ -256,7 +256,7 @@ export default class GameManager { this.onNextPrompt( "EncounterPhase", - Mode.MESSAGE, + UiMode.MESSAGE, () => { const handler = this.scene.ui.getHandler() as BattleMessageUiHandler; handler.processInput(Button.ACTION); @@ -284,9 +284,9 @@ export default class GameManager { if (this.scene.battleStyle === BattleStyle.SWITCH) { this.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.setMode(Mode.MESSAGE); + this.setMode(UiMode.MESSAGE); this.endPhase(); }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase), @@ -294,9 +294,9 @@ export default class GameManager { this.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.setMode(Mode.MESSAGE); + this.setMode(UiMode.MESSAGE); this.endPhase(); }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase), @@ -310,13 +310,13 @@ export default class GameManager { /** * Emulate a player's target selection after a move is chosen, usually called automatically by {@linkcode MoveHelper.select}. * Will trigger during the next {@linkcode SelectTargetPhase} - * @param {BattlerIndex} targetIndex The index of the attack target, or `undefined` for multi-target attacks - * @param movePosition The index of the move in the pokemon's moveset array + * @param targetIndex - The {@linkcode BattlerIndex} of the attack target, or `undefined` for multi-target attacks + * @param movePosition - The 0-indexed position of the move in the pokemon's moveset array */ selectTarget(movePosition: number, targetIndex?: BattlerIndex) { this.onNextPrompt( "SelectTargetPhase", - Mode.TARGET_SELECT, + UiMode.TARGET_SELECT, () => { const handler = this.scene.ui.getHandler() as TargetSelectUiHandler; const move = (this.scene.getCurrentPhase() as SelectTargetPhase) @@ -347,11 +347,11 @@ export default class GameManager { } } - /** Emulate selecting a modifier (item) */ + /** Queue up button presses to skip taking an item on the next {@linkcode SelectModifierPhase} */ doSelectModifier() { this.onNextPrompt( "SelectModifierPhase", - Mode.MODIFIER_SELECT, + UiMode.MODIFIER_SELECT, () => { const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler; handler.processInput(Button.CANCEL); @@ -365,7 +365,7 @@ export default class GameManager { this.onNextPrompt( "SelectModifierPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler; handler.processInput(Button.ACTION); @@ -380,8 +380,9 @@ export default class GameManager { /** * Forces the next enemy selecting a move to use the given move in its moveset against the * given target (if applicable). - * @param moveId {@linkcode Moves} the move the enemy will use - * @param target {@linkcode BattlerIndex} the target on which the enemy will use the given move + * @param moveId - The {@linkcode Moves | move} the enemy will use + * @param target - The {@linkcode BattlerIndex} of the target against which the enemy will use the given move; + * will use normal target selection priorities if omitted. */ async forceEnemyMove(moveId: Moves, target?: BattlerIndex) { // Wait for the next EnemyCommandPhase to start @@ -421,15 +422,18 @@ export default class GameManager { await this.phaseInterceptor.to(CommandPhase); } - /** Emulate selecting a modifier (item) and transition to the next upcoming {@linkcode CommandPhase} */ + /** + * Queue up button presses to skip taking an item on the next {@linkcode SelectModifierPhase}, + * and then transition to the next {@linkcode CommandPhase}. + */ async toNextWave() { this.doSelectModifier(); this.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.setMode(Mode.MESSAGE); + this.setMode(UiMode.MESSAGE); this.endPhase(); }, () => this.isCurrentPhase(TurnInitPhase), @@ -439,8 +443,8 @@ export default class GameManager { } /** - * Checks if the player has won the battle. - * @returns True if the player has won, otherwise false. + * Check if the player has won the battle. + * @returns whether the player has won the battle (all opposing Pokemon have been fainted) */ isVictory() { return this.scene.currentBattle.enemyParty.every(pokemon => pokemon.isFainted()); @@ -449,7 +453,7 @@ export default class GameManager { /** * Checks if the current phase matches the target phase. * @param phaseTarget - The target phase. - * @returns True if the current phase matches the target phase, otherwise false. + * @returns Whether the current phase matches the target phase */ isCurrentPhase(phaseTarget) { const targetName = typeof phaseTarget === "string" ? phaseTarget : phaseTarget.name; @@ -458,10 +462,10 @@ export default class GameManager { /** * Checks if the current mode matches the target mode. - * @param mode - The target mode. - * @returns True if the current mode matches the target mode, otherwise false. + * @param mode - The target {@linkcode UiMode} to check. + * @returns Whether the current mode matches the target mode. */ - isCurrentMode(mode: Mode) { + isCurrentMode(mode: UiMode) { return this.scene.ui?.getMode() === mode; } @@ -499,7 +503,7 @@ export default class GameManager { /** * Faints a player or enemy pokemon instantly by setting their HP to 0. - * @param pokemon The player/enemy pokemon being fainted + * @param pokemon - The player/enemy pokemon being fainted * @returns A promise that resolves once the fainted pokemon's FaintPhase finishes running. */ async killPokemon(pokemon: PlayerPokemon | EnemyPokemon) { @@ -512,11 +516,12 @@ export default class GameManager { } /** - * Command an in-battle switch to another Pokemon via the main battle menu. - * @param pokemonIndex the index of the pokemon in your party to switch to + * Command an in-battle switch to another {@linkcode Pokemon} via the main battle menu. + * @param pokemonIndex - The 0-indexed position of the party pokemon to switch to. + * Should never be called with 0 as that will select the currently active pokemon and freeze. */ doSwitchPokemon(pokemonIndex: number) { - this.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + this.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { (this.scene.ui.getHandler() as CommandUiHandler).setCursor(2); (this.scene.ui.getHandler() as CommandUiHandler).processInput(Button.ACTION); }); @@ -526,7 +531,7 @@ export default class GameManager { /** * Revive pokemon, currently players only. - * @param pokemonIndex the index of the pokemon in your party to revive + * @param pokemonIndex - The 0-indexed position of the pokemon in your party to revive */ doRevivePokemon(pokemonIndex: number) { const party = this.scene.getPlayerParty(); @@ -536,16 +541,15 @@ export default class GameManager { } /** - * Select a pokemon from the party menu. Only really handles the basic cases - * of the party UI, where you just need to navigate to a party slot and press - * Action twice - navigating any menus that come up after you select a party member - * is not supported. - * @param slot the index of the pokemon in your party to switch to - * @param inPhase Which phase to expect the selection to occur in. Typically - * non-command switch actions happen in SwitchPhase. + * Select a pokemon from the party menu during the given phase. + * Only really handles the basic case of "navigate to party slot and press Action twice" - + * any menus that come up afterwards are ignored and must be handled separately by the caller. + * @param slot - The 0-indexed position of the pokemon in your party to switch to + * @param inPhase - Which phase to expect the selection to occur in. Defaults to `SwitchPhase` + * (which is where the majority of non-command switch operations occur). */ doSelectPartyPokemon(slot: number, inPhase = "SwitchPhase") { - this.onNextPrompt(inPhase, Mode.PARTY, () => { + this.onNextPrompt(inPhase, UiMode.PARTY, () => { const partyHandler = this.scene.ui.getHandler() as PartyUiHandler; partyHandler.setCursor(slot); @@ -557,15 +561,15 @@ export default class GameManager { /** * Select the BALL option from the command menu, then press Action; in the BALL * menu, select a pokéball type and press Action again to throw it. - * @param ballIndex the index of the pokeball to throw + * @param ballIndex - The index of the pokeball to throw */ public doThrowPokeball(ballIndex: number) { - this.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + this.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { (this.scene.ui.getHandler() as CommandUiHandler).setCursor(1); (this.scene.ui.getHandler() as CommandUiHandler).processInput(Button.ACTION); }); - this.onNextPrompt("CommandPhase", Mode.BALL, () => { + this.onNextPrompt("CommandPhase", UiMode.BALL, () => { const ballHandler = this.scene.ui.getHandler() as BallUiHandler; ballHandler.setCursor(ballIndex); ballHandler.processInput(Button.ACTION); // select ball and throw @@ -575,8 +579,8 @@ export default class GameManager { /** * Intercepts `TurnStartPhase` and mocks {@linkcode TurnStartPhase.getSpeedOrder}'s return value. * Used to manually modify Pokemon turn order. - * Note: This *DOES NOT* account for priority, only speed. - * @param {BattlerIndex[]} order The turn order to set + * Note: This *DOES NOT* account for priority. + * @param order - The turn order to set as an array of {@linkcode BattlerIndex}es. * @example * ```ts * await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]); diff --git a/test/testUtils/gameManagerUtils.ts b/test/testUtils/gameManagerUtils.ts index 11636bd66b4..9e9c8f15f96 100644 --- a/test/testUtils/gameManagerUtils.ts +++ b/test/testUtils/gameManagerUtils.ts @@ -1,4 +1,5 @@ -import Battle, { BattleType } from "#app/battle"; +import Battle from "#app/battle"; +import { BattleType } from "#enums/battle-type"; import type BattleScene from "#app/battle-scene"; import { getDailyRunStarters } from "#app/data/daily-run"; import { Gender } from "#app/data/gender"; diff --git a/test/testUtils/gameWrapper.ts b/test/testUtils/gameWrapper.ts index 388861e01c4..9264b68d421 100644 --- a/test/testUtils/gameWrapper.ts +++ b/test/testUtils/gameWrapper.ts @@ -1,8 +1,9 @@ // @ts-nocheck - TODO: remove this -import BattleScene, * as battleScene from "#app/battle-scene"; +import BattleScene from "#app/battle-scene"; import { MoveAnim } from "#app/data/battle-anims"; import Pokemon from "#app/field/pokemon"; -import * as Utils from "#app/utils"; +import { sessionIdKey } from "#app/utils/common"; +import { setCookie } from "#app/utils/cookies"; import { blobToString } from "#test/testUtils/gameManagerUtils"; import { MockClock } from "#test/testUtils/mocks/mockClock"; import { MockFetch } from "#test/testUtils/mocks/mockFetch"; @@ -20,6 +21,10 @@ import KeyboardPlugin = Phaser.Input.Keyboard.KeyboardPlugin; import GamepadPlugin = Phaser.Input.Gamepad.GamepadPlugin; import EventEmitter = Phaser.Events.EventEmitter; import UpdateList = Phaser.GameObjects.UpdateList; +import { PokedexMonContainer } from "#app/ui/pokedex-mon-container"; +import MockContainer from "./mocks/mocksContainer/mockContainer"; +// biome-ignore lint/style/noNamespaceImport: Necessary in order to mock the var +import * as bypassLoginModule from "#app/global-vars/bypass-login"; window.URL.createObjectURL = (blob: Blob) => { blobToString(blob).then((data: string) => { @@ -29,7 +34,7 @@ window.URL.createObjectURL = (blob: Blob) => { }; navigator.getGamepads = () => []; global.fetch = vi.fn(MockFetch); -Utils.setCookie(Utils.sessionIdKey, "fake_token"); +setCookie(sessionIdKey, "fake_token"); window.matchMedia = () => ({ matches: false, @@ -43,7 +48,7 @@ export default class GameWrapper { Phaser.Math.RND.sow(["test"]); // vi.spyOn(Utils, "apiFetch", "get").mockReturnValue(fetch); if (bypassLogin) { - vi.spyOn(battleScene, "bypassLogin", "get").mockReturnValue(true); + vi.spyOn(bypassLoginModule, "bypassLogin", "get").mockReturnValue(true); } this.game = phaserGame; MoveAnim.prototype.getAnim = () => ({ @@ -58,6 +63,10 @@ export default class GameWrapper { } }; BattleScene.prototype.addPokemonIcon = () => new Phaser.GameObjects.Container(this.scene); + + // Pokedex container is not actually mocking container, but the sprites they contain are mocked. + // We need to mock the remove function to not throw an error when removing a sprite. + PokedexMonContainer.prototype.remove = MockContainer.prototype.remove; } setScene(scene: BattleScene) { diff --git a/test/testUtils/helpers/challengeModeHelper.ts b/test/testUtils/helpers/challengeModeHelper.ts index 0b7826eda7e..3a4f2adcd09 100644 --- a/test/testUtils/helpers/challengeModeHelper.ts +++ b/test/testUtils/helpers/challengeModeHelper.ts @@ -3,7 +3,7 @@ import type { Species } from "#app/enums/species"; import overrides from "#app/overrides"; import { EncounterPhase } from "#app/phases/encounter-phase"; import { SelectStarterPhase } from "#app/phases/select-starter-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { generateStarter } from "../gameManagerUtils"; import { GameManagerHelper } from "./gameManagerHelper"; import type { Challenge } from "#app/data/challenge"; @@ -41,7 +41,7 @@ export class ChallengeModeHelper extends GameManagerHelper { this.game.override.shiny(false).enemyShiny(false); } - this.game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + this.game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { this.game.scene.gameMode.challenges = this.challenges; const starters = generateStarter(this.game.scene, species); const selectStarterPhase = new SelectStarterPhase(); @@ -66,9 +66,9 @@ export class ChallengeModeHelper extends GameManagerHelper { if (this.game.scene.battleStyle === BattleStyle.SWITCH) { this.game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.game.setMode(Mode.MESSAGE); + this.game.setMode(UiMode.MESSAGE); this.game.endPhase(); }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase), @@ -76,9 +76,9 @@ export class ChallengeModeHelper extends GameManagerHelper { this.game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.game.setMode(Mode.MESSAGE); + this.game.setMode(UiMode.MESSAGE); this.game.endPhase(); }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase), diff --git a/test/testUtils/helpers/classicModeHelper.ts b/test/testUtils/helpers/classicModeHelper.ts index 5b6a38f5747..8e1ac95c733 100644 --- a/test/testUtils/helpers/classicModeHelper.ts +++ b/test/testUtils/helpers/classicModeHelper.ts @@ -6,7 +6,7 @@ import { CommandPhase } from "#app/phases/command-phase"; import { EncounterPhase } from "#app/phases/encounter-phase"; import { SelectStarterPhase } from "#app/phases/select-starter-phase"; import { TurnInitPhase } from "#app/phases/turn-init-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { generateStarter } from "../gameManagerUtils"; import { GameManagerHelper } from "./gameManagerHelper"; @@ -26,7 +26,7 @@ export class ClassicModeHelper extends GameManagerHelper { this.game.override.shiny(false).enemyShiny(false); } - this.game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + this.game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { this.game.scene.gameMode = getGameMode(GameModes.CLASSIC); const starters = generateStarter(this.game.scene, species); const selectStarterPhase = new SelectStarterPhase(); @@ -51,9 +51,9 @@ export class ClassicModeHelper extends GameManagerHelper { if (this.game.scene.battleStyle === BattleStyle.SWITCH) { this.game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.game.setMode(Mode.MESSAGE); + this.game.setMode(UiMode.MESSAGE); this.game.endPhase(); }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase), @@ -61,9 +61,9 @@ export class ClassicModeHelper extends GameManagerHelper { this.game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.game.setMode(Mode.MESSAGE); + this.game.setMode(UiMode.MESSAGE); this.game.endPhase(); }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase), diff --git a/test/testUtils/helpers/dailyModeHelper.ts b/test/testUtils/helpers/dailyModeHelper.ts index 0f5bc84df68..8ee03ce5f89 100644 --- a/test/testUtils/helpers/dailyModeHelper.ts +++ b/test/testUtils/helpers/dailyModeHelper.ts @@ -6,7 +6,7 @@ import { EncounterPhase } from "#app/phases/encounter-phase"; import { TitlePhase } from "#app/phases/title-phase"; import { TurnInitPhase } from "#app/phases/turn-init-phase"; import type SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { GameManagerHelper } from "./gameManagerHelper"; /** @@ -24,12 +24,12 @@ export class DailyModeHelper extends GameManagerHelper { this.game.override.shiny(false).enemyShiny(false); } - this.game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + this.game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const titlePhase = new TitlePhase(); titlePhase.initDailyRun(); }); - this.game.onNextPrompt("TitlePhase", Mode.SAVE_SLOT, () => { + this.game.onNextPrompt("TitlePhase", UiMode.SAVE_SLOT, () => { const uihandler = this.game.scene.ui.getHandler(); uihandler.processInput(Button.ACTION); // select first slot. that's fine }); @@ -51,9 +51,9 @@ export class DailyModeHelper extends GameManagerHelper { if (this.game.scene.battleStyle === BattleStyle.SWITCH) { this.game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.game.setMode(Mode.MESSAGE); + this.game.setMode(UiMode.MESSAGE); this.game.endPhase(); }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase), @@ -61,9 +61,9 @@ export class DailyModeHelper extends GameManagerHelper { this.game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.game.setMode(Mode.MESSAGE); + this.game.setMode(UiMode.MESSAGE); this.game.endPhase(); }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase), diff --git a/test/testUtils/helpers/moveHelper.ts b/test/testUtils/helpers/moveHelper.ts index 543f46b2026..269cf65ea56 100644 --- a/test/testUtils/helpers/moveHelper.ts +++ b/test/testUtils/helpers/moveHelper.ts @@ -7,7 +7,7 @@ import type { CommandPhase } from "#app/phases/command-phase"; import { LearnMovePhase } from "#app/phases/learn-move-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Command } from "#app/ui/command-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Moves } from "#enums/moves"; import { getMovePosition } from "#test/testUtils/gameManagerUtils"; import { GameManagerHelper } from "#test/testUtils/helpers/gameManagerHelper"; @@ -18,29 +18,29 @@ import { vi } from "vitest"; */ export class MoveHelper extends GameManagerHelper { /** - * Intercepts {@linkcode MoveEffectPhase} and mocks the - * {@linkcode MoveEffectPhase.hitCheck | hitCheck}'s return value to `true`. - * Used to force a move to hit. + * Intercepts {@linkcode MoveEffectPhase} and mocks the phase's move's + * accuracy to -1, guaranteeing a hit. */ public async forceHit(): Promise { await this.game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + const moveEffectPhase = this.game.scene.getCurrentPhase() as MoveEffectPhase; + vi.spyOn(moveEffectPhase.move, "calculateBattleAccuracy").mockReturnValue(-1); } /** - * Intercepts {@linkcode MoveEffectPhase} and mocks the - * {@linkcode MoveEffectPhase.hitCheck | hitCheck}'s return value to `false`. - * Used to force a move to miss. + * Intercepts {@linkcode MoveEffectPhase} and mocks the phase's move's accuracy + * to 0, guaranteeing a miss. * @param firstTargetOnly - Whether the move should force miss on the first target only, in the case of multi-target moves. */ public async forceMiss(firstTargetOnly = false): Promise { await this.game.phaseInterceptor.to(MoveEffectPhase, false); - const hitCheck = vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck"); + const moveEffectPhase = this.game.scene.getCurrentPhase() as MoveEffectPhase; + const accuracy = vi.spyOn(moveEffectPhase.move, "calculateBattleAccuracy"); if (firstTargetOnly) { - hitCheck.mockReturnValueOnce(false); + accuracy.mockReturnValueOnce(0); } else { - hitCheck.mockReturnValue(false); + accuracy.mockReturnValue(0); } } @@ -53,10 +53,10 @@ export class MoveHelper extends GameManagerHelper { public select(move: Moves, pkmIndex: 0 | 1 = 0, targetIndex?: BattlerIndex | null) { const movePosition = getMovePosition(this.game.scene, pkmIndex, move); - this.game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - this.game.scene.ui.setMode(Mode.FIGHT, (this.game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); + this.game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { + this.game.scene.ui.setMode(UiMode.FIGHT, (this.game.scene.getCurrentPhase() as CommandPhase).getFieldIndex()); }); - this.game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + this.game.onNextPrompt("CommandPhase", UiMode.FIGHT, () => { (this.game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); @@ -65,6 +65,33 @@ export class MoveHelper extends GameManagerHelper { } } + /** + * Select the move to be used by the given Pokemon(-index), **which will also terastallize on this turn**. + * Triggers during the next {@linkcode CommandPhase} + * @param move - the move to use + * @param pkmIndex - the pokemon index. Relevant for double-battles only (defaults to 0) + * @param targetIndex - The {@linkcode BattlerIndex} of the Pokemon to target for single-target moves, or `null` if a manual call to `selectTarget()` is required + */ + public selectWithTera(move: Moves, pkmIndex: 0 | 1 = 0, targetIndex?: BattlerIndex | null) { + const movePosition = getMovePosition(this.game.scene, pkmIndex, move); + this.game.scene.getPlayerParty()[pkmIndex].isTerastallized = false; + + this.game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { + this.game.scene.ui.setMode( + UiMode.FIGHT, + (this.game.scene.getCurrentPhase() as CommandPhase).getFieldIndex(), + Command.TERA, + ); + }); + this.game.onNextPrompt("CommandPhase", UiMode.FIGHT, () => { + (this.game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.TERA, movePosition, false); + }); + + if (targetIndex !== null) { + this.game.selectTarget(movePosition, targetIndex); + } + } + /** * Forces the Paralysis or Freeze status to activate on the next move by temporarily mocking {@linkcode Overrides.STATUS_ACTIVATION_OVERRIDE}, * advancing to the next `MovePhase`, and then resetting the override to `null` @@ -76,6 +103,17 @@ export class MoveHelper extends GameManagerHelper { vi.spyOn(Overrides, "STATUS_ACTIVATION_OVERRIDE", "get").mockReturnValue(null); } + /** + * Forces the Confusion status to activate on the next move by temporarily mocking {@linkcode Overrides.CONFUSION_ACTIVATION_OVERRIDE}, + * advancing to the next `MovePhase`, and then resetting the override to `null` + * @param activated - `true` to force the Pokemon to hit themself, `false` to forcibly disable it + */ + public async forceConfusionActivation(activated: boolean): Promise { + vi.spyOn(Overrides, "CONFUSION_ACTIVATION_OVERRIDE", "get").mockReturnValue(activated); + await this.game.phaseInterceptor.to("MovePhase"); + vi.spyOn(Overrides, "CONFUSION_ACTIVATION_OVERRIDE", "get").mockReturnValue(null); + } + /** * Changes a pokemon's moveset to the given move(s). * Used when the normal moveset override can't be used (such as when it's necessary to check or update properties of the moveset). @@ -108,16 +146,16 @@ export class MoveHelper extends GameManagerHelper { // if slots are full, queue up inputs to replace existing moves if (this.game.scene.getPlayerParty()[partyIndex].moveset.filter(m => m).length === 4) { - this.game.onNextPrompt("LearnMovePhase", Mode.CONFIRM, () => { + this.game.onNextPrompt("LearnMovePhase", UiMode.CONFIRM, () => { this.game.scene.ui.processInput(Button.ACTION); // "Should a move be forgotten and replaced with XXX?" }); - this.game.onNextPrompt("LearnMovePhase", Mode.SUMMARY, () => { + this.game.onNextPrompt("LearnMovePhase", UiMode.SUMMARY, () => { for (let x = 0; x < (moveSlotIndex ?? 0); x++) { this.game.scene.ui.processInput(Button.DOWN); // Scrolling in summary pane to move position } this.game.scene.ui.processInput(Button.ACTION); if (moveSlotIndex === 4) { - this.game.onNextPrompt("LearnMovePhase", Mode.CONFIRM, () => { + this.game.onNextPrompt("LearnMovePhase", UiMode.CONFIRM, () => { this.game.scene.ui.processInput(Button.ACTION); // "Give up on learning XXX?" }); } diff --git a/test/testUtils/helpers/overridesHelper.ts b/test/testUtils/helpers/overridesHelper.ts index 9bb0369a31a..acc2e4d5cd0 100644 --- a/test/testUtils/helpers/overridesHelper.ts +++ b/test/testUtils/helpers/overridesHelper.ts @@ -1,4 +1,4 @@ -import type { Variant } from "#app/data/variant"; +import type { Variant } from "#app/sprites/variant"; import { Weather } from "#app/data/weather"; import { Abilities } from "#app/enums/abilities"; import type { ModifierOverride } from "#app/modifier/modifier-type"; @@ -14,7 +14,9 @@ import { StatusEffect } from "#enums/status-effect"; import type { WeatherType } from "#enums/weather-type"; import { expect, vi } from "vitest"; import { GameManagerHelper } from "./gameManagerHelper"; -import { shiftCharCodes } from "#app/utils"; +import { shiftCharCodes } from "#app/utils/common"; +import type { RandomTrainerOverride } from "#app/overrides"; +import type { BattleType } from "#enums/battle-type"; /** * Helper to handle overrides in tests @@ -28,7 +30,7 @@ export class OverridesHelper extends GameManagerHelper { /** * Override the starting biome * @warning Any event listeners that are attached to [NewArenaEvent](events\battle-scene.ts) may need to be handled down the line - * @param biome the biome to set + * @param biome - The biome to set */ public startingBiome(biome: Biome): this { this.game.scene.newArena(biome); @@ -37,8 +39,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the starting wave (index) - * @param wave the wave (index) to set. Classic: `1`-`200` + * Override the starting wave index + * @param wave - The wave to set. Classic: `1`-`200` * @returns `this` */ public startingWave(wave: number): this { @@ -48,8 +50,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the player (pokemon) starting level - * @param level the (pokemon) level to set + * Override the player pokemon's starting level + * @param level - The level to set * @returns `this` */ public startingLevel(level: Species | number): this { @@ -60,7 +62,7 @@ export class OverridesHelper extends GameManagerHelper { /** * Override the XP Multiplier - * @param value the XP multiplier to set + * @param value - The XP multiplier to set * @returns `this` */ public xpMultiplier(value: number): this { @@ -71,7 +73,7 @@ export class OverridesHelper extends GameManagerHelper { /** * Override the wave level cap - * @param cap the level cap value to set; 0 uses normal level caps and negative values + * @param cap - The level cap value to set; 0 uses normal level caps and negative values * disable it completely * @returns `this` */ @@ -90,8 +92,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the player (pokemon) starting held items - * @param items the items to hold + * Override the player pokemon's starting held items + * @param items - The items to hold * @returns `this` */ public startingHeldItems(items: ModifierOverride[]): this { @@ -101,8 +103,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the player (pokemon) {@linkcode Species | species} - * @param species the (pokemon) {@linkcode Species | species} to set + * Override the player pokemon's {@linkcode Species | species} + * @param species - The {@linkcode Species | species} to set * @returns `this` */ public starterSpecies(species: Species | number): this { @@ -112,7 +114,7 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the player (pokemon) to be a random fusion + * Override the player pokemon to be a random fusion * @returns `this` */ public enableStarterFusion(): this { @@ -122,8 +124,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the player (pokemon) fusion species - * @param species the fusion species to set + * Override the player pokemon's fusion species + * @param species - The fusion species to set * @returns `this` */ public starterFusionSpecies(species: Species | number): this { @@ -133,8 +135,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the player (pokemons) forms - * @param forms the (pokemon) forms to set + * Override the player pokemon's forms + * @param forms - The forms to set * @returns `this` */ public starterForms(forms: Partial>): this { @@ -148,7 +150,7 @@ export class OverridesHelper extends GameManagerHelper { /** * Override the player's starting modifiers - * @param modifiers the modifiers to set + * @param modifiers - The modifiers to set * @returns `this` */ public startingModifier(modifiers: ModifierOverride[]): this { @@ -158,8 +160,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the player (pokemon) {@linkcode Abilities | ability}. - * @param ability the (pokemon) {@linkcode Abilities | ability} to set + * Override the player pokemon's {@linkcode Abilities | ability}. + * @param ability - The {@linkcode Abilities | ability} to set * @returns `this` */ public ability(ability: Abilities): this { @@ -169,8 +171,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the player (pokemon) **passive** {@linkcode Abilities | ability} - * @param passiveAbility the (pokemon) **passive** {@linkcode Abilities | ability} to set + * Override the player pokemon's **passive** {@linkcode Abilities | ability} + * @param passiveAbility - The **passive** {@linkcode Abilities | ability} to set * @returns `this` */ public passiveAbility(passiveAbility: Abilities): this { @@ -180,8 +182,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Forces the status of the player (pokemon) **passive** {@linkcode Abilities | ability} - * @param hasPassiveAbility forces the passive to be active if `true`, inactive if `false` + * Forces the status of the player pokemon **passive** {@linkcode Abilities | ability} + * @param hasPassiveAbility - Forces the passive to be active if `true`, inactive if `false` * @returns `this` */ public hasPassiveAbility(hasPassiveAbility: boolean | null): this { @@ -194,8 +196,8 @@ export class OverridesHelper extends GameManagerHelper { return this; } /** - * Override the player (pokemon) {@linkcode Moves | moves}set - * @param moveset the {@linkcode Moves | moves}set to set + * Override the player pokemon's {@linkcode Moves | moves}set + * @param moveset - The {@linkcode Moves | moves}set to set * @returns `this` */ public moveset(moveset: Moves | Moves[]): this { @@ -209,8 +211,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the player (pokemon) {@linkcode StatusEffect | status-effect} - * @param statusEffect the {@linkcode StatusEffect | status-effect} to set + * Override the player pokemon's {@linkcode StatusEffect | status-effect} + * @param statusEffect - The {@linkcode StatusEffect | status-effect} to set * @returns */ public statusEffect(statusEffect: StatusEffect): this { @@ -229,6 +231,19 @@ export class OverridesHelper extends GameManagerHelper { return this; } + /** + * Override the trainer chosen when a random trainer is selected. + * + * Does not force the battle to be a trainer battle. + * @see {@linkcode setBattleType} + * @returns `this` + */ + public randomTrainer(trainer: RandomTrainerOverride | null): this { + vi.spyOn(Overrides, "RANDOM_TRAINER_OVERRIDE", "get").mockReturnValue(trainer); + this.log("Partner battle is forced!"); + return this; + } + /** * Override each wave to not have critical hits * @returns `this` @@ -240,8 +255,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the {@linkcode WeatherType | weather (type)} - * @param type {@linkcode WeatherType | weather type} to set + * Override the {@linkcode WeatherType | weather type} + * @param type - The {@linkcode WeatherType | weather type} to set * @returns `this` */ public weather(type: WeatherType): this { @@ -252,7 +267,7 @@ export class OverridesHelper extends GameManagerHelper { /** * Override the seed - * @param seed the seed to set + * @param seed - The seed to set * @returns `this` */ public seed(seed: string): this { @@ -264,20 +279,36 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the battle type (e.g., single or double). - * @see {@linkcode Overrides.BATTLE_TYPE_OVERRIDE} - * @param battleType battle type to set + * Override the battle style (e.g., single or double). + * @see {@linkcode Overrides.BATTLE_STYLE_OVERRIDE} + * @param battleStyle - The battle style to set * @returns `this` */ - public battleType(battleType: BattleStyle | null): this { - vi.spyOn(Overrides, "BATTLE_TYPE_OVERRIDE", "get").mockReturnValue(battleType); - this.log(battleType === null ? "Battle type override disabled!" : `Battle type set to ${battleType}!`); + public battleStyle(battleStyle: BattleStyle | null): this { + vi.spyOn(Overrides, "BATTLE_STYLE_OVERRIDE", "get").mockReturnValue(battleStyle); + this.log(battleStyle === null ? "Battle type override disabled!" : `Battle type set to ${battleStyle}!`); return this; } /** - * Override the enemy (pokemon) {@linkcode Species | species} - * @param species the (pokemon) {@linkcode Species | species} to set + * Override the battle type (e.g., WILD, or Trainer) for non-scripted battles. + * @see {@linkcode Overrides.BATTLE_TYPE_OVERRIDE} + * @param battleType - The battle type to set + * @returns `this` + */ + public battleType(battleType: Exclude): this { + vi.spyOn(Overrides, "BATTLE_TYPE_OVERRIDE", "get").mockReturnValue(battleType); + this.log( + battleType === null + ? "Battle type override disabled!" + : `Battle type set to ${battleType[battleType]} (=${battleType})!`, + ); + return this; + } + + /** + * Override the {@linkcode Species | species} of enemy pokemon + * @param species - The {@linkcode Species | species} to set * @returns `this` */ public enemySpecies(species: Species | number): this { @@ -287,7 +318,7 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the enemy (pokemon) to be a random fusion + * Override the enemy pokemon to be a random fusion * @returns `this` */ public enableEnemyFusion(): this { @@ -297,8 +328,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the enemy (pokemon) fusion species - * @param species the fusion species to set + * Override the enemy pokemon fusion species + * @param species - The fusion species to set * @returns `this` */ public enemyFusionSpecies(species: Species | number): this { @@ -308,8 +339,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the enemy (pokemon) {@linkcode Abilities | ability} - * @param ability the (pokemon) {@linkcode Abilities | ability} to set + * Override the {@linkcode Abilities | ability} of enemy pokemon + * @param ability - The {@linkcode Abilities | ability} to set * @returns `this` */ public enemyAbility(ability: Abilities): this { @@ -319,8 +350,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the enemy (pokemon) **passive** {@linkcode Abilities | ability} - * @param passiveAbility the (pokemon) **passive** {@linkcode Abilities | ability} to set + * Override the **passive** {@linkcode Abilities | ability} of enemy pokemon + * @param passiveAbility - The **passive** {@linkcode Abilities | ability} to set * @returns `this` */ public enemyPassiveAbility(passiveAbility: Abilities): this { @@ -330,8 +361,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Forces the status of the enemy (pokemon) **passive** {@linkcode Abilities | ability} - * @param hasPassiveAbility forces the passive to be active if `true`, inactive if `false` + * Forces the status of the enemy pokemon **passive** {@linkcode Abilities | ability} + * @param hasPassiveAbility - Forces the passive to be active if `true`, inactive if `false` * @returns `this` */ public enemyHasPassiveAbility(hasPassiveAbility: boolean | null): this { @@ -345,8 +376,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the enemy (pokemon) {@linkcode Moves | moves}set - * @param moveset the {@linkcode Moves | moves}set to set + * Override the {@linkcode Moves | move}set of enemy pokemon + * @param moveset - The {@linkcode Moves | move}set to set * @returns `this` */ public enemyMoveset(moveset: Moves | Moves[]): this { @@ -360,8 +391,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the enemy (pokemon) level - * @param level the level to set + * Override the level of enemy pokemon + * @param level - The level to set * @returns `this` */ public enemyLevel(level: number): this { @@ -371,8 +402,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the enemy (pokemon) {@linkcode StatusEffect | status-effect} - * @param statusEffect the {@linkcode StatusEffect | status-effect} to set + * Override the enemy {@linkcode StatusEffect | status-effect} for enemy pokemon + * @param statusEffect - The {@linkcode StatusEffect | status-effect} to set * @returns */ public enemyStatusEffect(statusEffect: StatusEffect): this { @@ -394,7 +425,7 @@ export class OverridesHelper extends GameManagerHelper { /** * Gives the player access to an Unlockable. - * @param unlockable The Unlockable(s) to enable. + * @param unlockable - The Unlockable(s) to enable. * @returns `this` */ public enableUnlockable(unlockable: Unlockables[]): this { @@ -405,7 +436,7 @@ export class OverridesHelper extends GameManagerHelper { /** * Override the items rolled at the end of a battle - * @param items the items to be rolled + * @param items - The items to be rolled * @returns `this` */ public itemRewards(items: ModifierOverride[]): this { @@ -463,8 +494,8 @@ export class OverridesHelper extends GameManagerHelper { } /** - * Override the enemy (Pokemon) to have the given amount of health segments - * @param healthSegments the number of segments to give + * Override the enemy Pokemon to have the given amount of health segments + * @param healthSegments - The number of segments to give * - `0` (default): the health segments will be handled like in the game based on wave, level and species * - `1`: the Pokemon will not be a boss * - `2`+: the Pokemon will be a boss with the given number of health segments @@ -491,9 +522,24 @@ export class OverridesHelper extends GameManagerHelper { return this; } + /** + * Override confusion to always or never activate + * @param activate - `true` to force activation, `false` to force no activation, `null` to disable the override + * @returns `this` + */ + public confusionActivation(activate: boolean | null): this { + vi.spyOn(Overrides, "CONFUSION_ACTIVATION_OVERRIDE", "get").mockReturnValue(activate); + if (activate !== null) { + this.log(`Confusion forced to ${activate ? "always" : "never"} activate!`); + } else { + this.log("Confusion activation override disabled!"); + } + return this; + } + /** * Override the encounter chance for a mystery encounter. - * @param percentage the encounter chance in % + * @param percentage - The encounter chance in % * @returns `this` */ public mysteryEncounterChance(percentage: number): this { diff --git a/test/testUtils/helpers/reloadHelper.ts b/test/testUtils/helpers/reloadHelper.ts index 842cd88b95c..4a9e5356968 100644 --- a/test/testUtils/helpers/reloadHelper.ts +++ b/test/testUtils/helpers/reloadHelper.ts @@ -1,6 +1,6 @@ import { GameManagerHelper } from "./gameManagerHelper"; import { TitlePhase } from "#app/phases/title-phase"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { vi } from "vitest"; import { BattleStyle } from "#app/enums/battle-style"; import { CommandPhase } from "#app/phases/command-phase"; @@ -46,6 +46,16 @@ export class ReloadHelper extends GameManagerHelper { scene.unshiftPhase(titlePhase); this.game.endPhase(); // End the currently ongoing battle + // remove all persistent mods before loading + // TODO: Look into why these aren't removed before load + if (this.game.scene.modifiers.length) { + console.log( + "Removing %d modifiers from scene on load...", + this.game.scene.modifiers.length, + this.game.scene.modifiers, + ); + this.game.scene.modifiers = []; + } titlePhase.loadSaveSlot(-1); // Load the desired session data this.game.phaseInterceptor.shift(); // Loading the save slot also ended TitlePhase, clean it up @@ -53,9 +63,9 @@ export class ReloadHelper extends GameManagerHelper { if (this.game.scene.battleStyle === BattleStyle.SWITCH) { this.game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.game.setMode(Mode.MESSAGE); + this.game.setMode(UiMode.MESSAGE); this.game.endPhase(); }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase), @@ -63,9 +73,9 @@ export class ReloadHelper extends GameManagerHelper { this.game.onNextPrompt( "CheckSwitchPhase", - Mode.CONFIRM, + UiMode.CONFIRM, () => { - this.game.setMode(Mode.MESSAGE); + this.game.setMode(UiMode.MESSAGE); this.game.endPhase(); }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase), @@ -73,6 +83,6 @@ export class ReloadHelper extends GameManagerHelper { } await this.game.phaseInterceptor.to(CommandPhase); - console.log("==================[New Turn]=================="); + console.log("==================[New Turn (Reloaded)]=================="); } } diff --git a/test/testUtils/mocks/mocksContainer/mockText.ts b/test/testUtils/mocks/mocksContainer/mockText.ts index 552f8ff3ff8..1f3f0ad792f 100644 --- a/test/testUtils/mocks/mocksContainer/mockText.ts +++ b/test/testUtils/mocks/mocksContainer/mockText.ts @@ -308,5 +308,14 @@ export default class MockText implements MockGameObject { return this.list; } + /** + * Runs the word wrap algorithm on the text, then returns an array of the lines + */ + getWrappedText() { + // Returns the wrapped text. + // return this.phaserText.getWrappedText(); + return this.runWordWrap(this.text).split("\n"); + } + on(_event: string | symbol, _fn: Function, _context?: any) {} } diff --git a/test/testUtils/phaseInterceptor.ts b/test/testUtils/phaseInterceptor.ts index 742a6bc8441..b1d76ecd4a6 100644 --- a/test/testUtils/phaseInterceptor.ts +++ b/test/testUtils/phaseInterceptor.ts @@ -43,7 +43,8 @@ import { TurnStartPhase } from "#app/phases/turn-start-phase"; import { UnavailablePhase } from "#app/phases/unavailable-phase"; import { VictoryPhase } from "#app/phases/victory-phase"; import { PartyHealPhase } from "#app/phases/party-heal-phase"; -import UI, { Mode } from "#app/ui/ui"; +import UI from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { SelectBiomePhase } from "#app/phases/select-biome-phase"; import { MysteryEncounterBattlePhase, @@ -64,7 +65,7 @@ import { RevivalBlessingPhase } from "#app/phases/revival-blessing-phase"; export interface PromptHandler { phaseTarget?: string; - mode?: Mode; + mode?: UiMode; callback?: () => void; expireFn?: () => void; awaitingActionInput?: boolean; @@ -204,6 +205,7 @@ export default class PhaseInterceptor { private phaseFrom; private inProgress; private originalSetMode; + private originalSetOverlayMode; private originalSuperEnd; /** @@ -441,6 +443,7 @@ export default class PhaseInterceptor { */ initPhases() { this.originalSetMode = UI.prototype.setMode; + this.originalSetOverlayMode = UI.prototype.setOverlayMode; this.originalSuperEnd = Phase.prototype.end; UI.prototype.setMode = (mode, ...args) => this.setMode.call(this, mode, ...args); Phase.prototype.end = () => this.superEndPhase.call(this); @@ -487,13 +490,13 @@ export default class PhaseInterceptor { /** * m2m to set mode. - * @param mode - The {@linkcode Mode} to set. + * @param mode - The {@linkcode UiMode} to set. * @param args - Additional arguments to pass to the original method. */ - setMode(mode: Mode, ...args: unknown[]): Promise { + setMode(mode: UiMode, ...args: unknown[]): Promise { const currentPhase = this.scene.getCurrentPhase(); const instance = this.scene.ui; - console.log("setMode", `${Mode[mode]} (=${mode})`, args); + console.log("setMode", `${UiMode[mode]} (=${mode})`, args); const ret = this.originalSetMode.apply(instance, [mode, ...args]); if (!this.phases[currentPhase.constructor.name]) { throw new Error( @@ -507,6 +510,18 @@ export default class PhaseInterceptor { return ret; } + /** + * mock to set overlay mode + * @param mode - The {@linkcode Mode} to set. + * @param args - Additional arguments to pass to the original method. + */ + setOverlayMode(mode: UiMode, ...args: unknown[]): Promise { + const instance = this.scene.ui; + console.log("setOverlayMode", `${UiMode[mode]} (=${mode})`, args); + const ret = this.originalSetOverlayMode.apply(instance, [mode, ...args]); + return ret; + } + /** * Method to start the prompt handler. */ @@ -546,7 +561,7 @@ export default class PhaseInterceptor { */ addToNextPrompt( phaseTarget: string, - mode: Mode, + mode: UiMode, callback: () => void, expireFn?: () => void, awaitingActionInput = false, @@ -571,6 +586,7 @@ export default class PhaseInterceptor { phase.prototype.start = this.phases[phase.name].start; } UI.prototype.setMode = this.originalSetMode; + UI.prototype.setOverlayMode = this.originalSetOverlayMode; Phase.prototype.end = this.originalSuperEnd; clearInterval(this.promptInterval); clearInterval(this.interval); diff --git a/test/testUtils/saves/data_pokedex_tests.prsv b/test/testUtils/saves/data_pokedex_tests.prsv new file mode 100644 index 00000000000..c55241760c4 --- /dev/null +++ b/test/testUtils/saves/data_pokedex_tests.prsv @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/test/testUtils/saves/data_pokedex_tests_v2.prsv b/test/testUtils/saves/data_pokedex_tests_v2.prsv new file mode 100644 index 00000000000..fff658d94d5 --- /dev/null +++ b/test/testUtils/saves/data_pokedex_tests_v2.prsv @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/test/testUtils/testFileInitialization.ts b/test/testUtils/testFileInitialization.ts index 2b41f3aa29a..15635289e6f 100644 --- a/test/testUtils/testFileInitialization.ts +++ b/test/testUtils/testFileInitialization.ts @@ -1,9 +1,9 @@ import { SESSION_ID_COOKIE_NAME } from "#app/constants"; import { initLoggedInUser } from "#app/account"; -import { initAbilities } from "#app/data/ability"; +import { initAbilities } from "#app/data/abilities/ability"; import { initBiomes } from "#app/data/balance/biomes"; import { initEggMoves } from "#app/data/balance/egg-moves"; -import { initPokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; +import { initPokemonPrevolutions, initPokemonStarters } from "#app/data/balance/pokemon-evolutions"; import { initMoves } from "#app/data/moves/move"; import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters"; import { initPokemonForms } from "#app/data/pokemon-forms"; @@ -11,7 +11,7 @@ import { initSpecies } from "#app/data/pokemon-species"; import { initAchievements } from "#app/system/achv"; import { initVouchers } from "#app/system/voucher"; import { initStatsKeys } from "#app/ui/game-stats-ui-handler"; -import { setCookie } from "#app/utils"; +import { setCookie } from "#app/utils/cookies"; import { blobToString } from "#test/testUtils/gameManagerUtils"; import { MockConsoleLog } from "#test/testUtils/mocks/mockConsoleLog"; import { mockContext } from "#test/testUtils/mocks/mockContextCanvas"; @@ -21,6 +21,7 @@ import Phaser from "phaser"; import InputText from "phaser3-rex-plugins/plugins/inputtext"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import { manageListeners } from "./listenersManager"; +import { initI18n } from "#app/plugins/i18n"; let wasInitialized = false; /** @@ -84,9 +85,9 @@ export function initTestFile() { HTMLCanvasElement.prototype.getContext = () => mockContext; // Initialize all of these things if and only if they have not been initialized yet - // initSpecies(); if (!wasInitialized) { wasInitialized = true; + initI18n(); initVouchers(); initAchievements(); initStatsKeys(); @@ -99,6 +100,8 @@ export function initTestFile() { initAbilities(); initLoggedInUser(); initMysteryEncounters(); + // init the pokemon starters for the pokedex + initPokemonStarters(); } manageListeners(); diff --git a/test/ui/battle_info.test.ts b/test/ui/battle_info.test.ts index 4c6274d5efb..c4548adc49c 100644 --- a/test/ui/battle_info.test.ts +++ b/test/ui/battle_info.test.ts @@ -32,7 +32,7 @@ describe("UI - Battle Info", () => { game = new GameManager(phaserGame); game.override .moveset([Moves.GUILLOTINE, Moves.SPLASH]) - .battleType("single") + .battleStyle("single") .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.SPLASH) .enemySpecies(Species.CATERPIE); diff --git a/test/ui/pokedex.test.ts b/test/ui/pokedex.test.ts new file mode 100644 index 00000000000..ff5ca116ba8 --- /dev/null +++ b/test/ui/pokedex.test.ts @@ -0,0 +1,547 @@ +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, type MockInstance, vi } from "vitest"; +import PokedexUiHandler from "#app/ui/pokedex-ui-handler"; +import { FilterTextRow } from "#app/ui/filter-text"; +import { allAbilities } from "#app/data/data-lists"; +import { Abilities } from "#enums/abilities"; +import { Species } from "#enums/species"; +import { allSpecies, getPokemonSpecies, type PokemonForm } from "#app/data/pokemon-species"; +import { Button } from "#enums/buttons"; +import { DropDownColumn } from "#app/ui/filter-bar"; +import type PokemonSpecies from "#app/data/pokemon-species"; +import { PokemonType } from "#enums/pokemon-type"; +import { UiMode } from "#enums/ui-mode"; +import PokedexPageUiHandler from "#app/ui/pokedex-page-ui-handler"; +import type { StarterAttributes } from "#app/system/game-data"; + +/* +Information for the `data_pokedex_tests.psrv`: + +Caterpie - Shiny 0 +Rattata - Shiny 1 +Ekans - Shiny 2 + +Chikorita has enough candies to unlock passive +Cyndaquil has first cost reduction unlocked, enough candies to buy the second +Totodile has first cost reduction unlocked, not enough candies to buy the second +Treecko has both cost reduction unlocked +Torchic has enough candies to do anything +Mudkip has passive unlocked +Turtwig has enough candies to purchase an egg +*/ + +/** + * Return all permutations of elements from an array + */ +function permutations(array: T[], length: number): T[][] { + if (length === 0) { + return [[]]; + } + return array.flatMap((item, index) => + permutations([...array.slice(0, index), ...array.slice(index + 1)], length - 1).map(perm => [item, ...perm]), + ); +} + +describe("UI - Pokedex", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + const mocks: MockInstance[] = []; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + while (mocks.length > 0) { + mocks.pop()?.mockRestore(); + } + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + }); + + /** + * Run the game to open the pokedex UI. + * @returns The handler for the pokedex UI. + */ + async function runToOpenPokedex(): Promise { + // Open the pokedex UI. + await game.runToTitle(); + + await game.phaseInterceptor.setOverlayMode(UiMode.POKEDEX); + + // Get the handler for the current UI. + const handler = game.scene.ui.getHandler(); + expect(handler).toBeInstanceOf(PokedexUiHandler); + + return handler as PokedexUiHandler; + } + + /** + * Run the game to open the pokedex UI. + * @returns The handler for the pokedex UI. + */ + async function runToPokedexPage( + species: PokemonSpecies, + starterAttributes: StarterAttributes = {}, + ): Promise { + // Open the pokedex UI. + await game.runToTitle(); + + await game.phaseInterceptor.setOverlayMode(UiMode.POKEDEX_PAGE, species, starterAttributes); + + // Get the handler for the current UI. + const handler = game.scene.ui.getHandler(); + expect(handler).toBeInstanceOf(PokedexPageUiHandler); + + return handler as PokedexPageUiHandler; + } + + /** + * Compute a set of pokemon that have a specific ability in allAbilities + * @param ability - The ability to filter for + */ + function getSpeciesWithAbility(ability: Abilities): Set { + const speciesSet = new Set(); + for (const pkmn of allSpecies) { + if ( + [pkmn.ability1, pkmn.ability2, pkmn.getPassiveAbility(), pkmn.abilityHidden].includes(ability) || + pkmn.forms.some(form => + [form.ability1, form.ability2, form.abilityHidden, form.getPassiveAbility()].includes(ability), + ) + ) { + speciesSet.add(pkmn.speciesId); + } + } + return speciesSet; + } + + /** + * Compute a set of pokemon that have one of the specified type(s) + * + * Includes all forms of the pokemon + * @param types - The types to filter for + */ + function getSpeciesWithType(...types: PokemonType[]): Set { + const speciesSet = new Set(); + const tySet = new Set(types); + + // get the pokemon and its forms + outer: for (const pkmn of allSpecies) { + // @ts-expect-error We know that type2 might be null. + if (tySet.has(pkmn.type1) || tySet.has(pkmn.type2)) { + speciesSet.add(pkmn.speciesId); + continue; + } + for (const form of pkmn.forms) { + // @ts-expect-error We know that type2 might be null. + if (tySet.has(form.type1) || tySet.has(form.type2)) { + speciesSet.add(pkmn.speciesId); + continue outer; + } + } + } + return speciesSet; + } + + /** + * Create mocks for the abilities of a species. + * This is used to set the abilities of a species to a specific value. + * All abilities are optional. Not providing one will set it to NONE. + * + * This will override the ability of the pokemon species only, unless set forms is true + * + * @param species - The species to set the abilities for + * @param ability - The ability to set for the first ability + * @param ability2 - The ability to set for the second ability + * @param hidden - The ability to set for the hidden ability + * @param passive - The ability to set for the passive ability + * @param setForms - Whether to also overwrite the abilities for each of the species' forms (defaults to `true`) + */ + function createAbilityMocks( + species: Species, + { + ability = Abilities.NONE, + ability2 = Abilities.NONE, + hidden = Abilities.NONE, + passive = Abilities.NONE, + setForms = true, + }: { + ability?: Abilities; + ability2?: Abilities; + hidden?: Abilities; + passive?: Abilities; + setForms?: boolean; + }, + ) { + const pokemon = getPokemonSpecies(species); + const checks: [PokemonSpecies | PokemonForm] = [pokemon]; + if (setForms) { + checks.push(...pokemon.forms); + } + for (const p of checks) { + mocks.push(vi.spyOn(p, "ability1", "get").mockReturnValue(ability)); + mocks.push(vi.spyOn(p, "ability2", "get").mockReturnValue(ability2)); + mocks.push(vi.spyOn(p, "abilityHidden", "get").mockReturnValue(hidden)); + mocks.push(vi.spyOn(p, "getPassiveAbility").mockReturnValue(passive)); + } + } + + /*************************** + * Tests for Filters * + ***************************/ + + it("should filter to show only the pokemon with an ability when filtering by ability", async () => { + // await game.importData("test/testUtils/saves/everything.prsv"); + const pokedexHandler = await runToOpenPokedex(); + + // Get name of overgrow + const overgrow = allAbilities[Abilities.OVERGROW].name; + + // @ts-expect-error `filterText` is private + pokedexHandler.filterText.setValue(FilterTextRow.ABILITY_1, overgrow); + + // filter all species to be the pokemon that have overgrow + const overgrowSpecies = getSpeciesWithAbility(Abilities.OVERGROW); + // @ts-expect-error - `filteredPokemonData` is private + const filteredSpecies = new Set(pokedexHandler.filteredPokemonData.map(pokemon => pokemon.species.speciesId)); + + expect(filteredSpecies).toEqual(overgrowSpecies); + }); + + it("should filter to show only pokemon with ability and passive when filtering by 2 abilities", async () => { + // Setup mocks for the ability and passive combinations + const whitelist: Species[] = []; + const blacklist: Species[] = []; + + const filter_ab1 = Abilities.OVERGROW; + const filter_ab2 = Abilities.ADAPTABILITY; + const ab1_instance = allAbilities[filter_ab1]; + const ab2_instance = allAbilities[filter_ab2]; + + // Create a species with passive set and each "ability" field + const baseObj = { + ability: Abilities.BALL_FETCH, + ability2: Abilities.NONE, + hidden: Abilities.BLAZE, + passive: Abilities.TORRENT, + }; + + // Mock pokemon to have the exhaustive combination of the two selected abilities + const attrs: (keyof typeof baseObj)[] = ["ability", "ability2", "hidden", "passive"]; + for (const [idx, value] of permutations(attrs, 2).entries()) { + createAbilityMocks(Species.BULBASAUR + idx, { + ...baseObj, + [value[0]]: filter_ab1, + [value[1]]: filter_ab2, + }); + if (value.includes("passive")) { + whitelist.push(Species.BULBASAUR + idx); + } else { + blacklist.push(Species.BULBASAUR + idx); + } + } + + const pokedexHandler = await runToOpenPokedex(); + + // @ts-expect-error `filterText` is private + pokedexHandler.filterText.setValue(FilterTextRow.ABILITY_1, ab1_instance.name); + // @ts-expect-error `filterText` is private + pokedexHandler.filterText.setValue(FilterTextRow.ABILITY_2, ab2_instance.name); + + let whiteListCount = 0; + // @ts-expect-error `filteredPokemonData` is private + for (const species of pokedexHandler.filteredPokemonData) { + expect(blacklist, "entry must have one of the abilities as a passive").not.toContain(species.species.speciesId); + + const rawAbility = [species.species.ability1, species.species.ability2, species.species.abilityHidden]; + const rawPassive = species.species.getPassiveAbility(); + + const c1 = rawPassive === ab1_instance.id && rawAbility.includes(ab2_instance.id); + const c2 = c1 || (rawPassive === ab2_instance.id && rawAbility.includes(ab1_instance.id)); + + expect(c2, "each filtered entry should have the ability and passive combination").toBe(true); + if (whitelist.includes(species.species.speciesId)) { + whiteListCount++; + } + } + + expect(whiteListCount).toBe(whitelist.length); + }); + + it("should filter to show only the pokemon with a type when filtering by a single type", async () => { + const pokedexHandler = await runToOpenPokedex(); + + // @ts-expect-error - `filterBar` is private + pokedexHandler.filterBar.getFilter(DropDownColumn.TYPES).toggleOptionState(PokemonType.NORMAL + 1); + + const expectedPokemon = getSpeciesWithType(PokemonType.NORMAL); + // @ts-expect-error - `filteredPokemonData` is private + const filteredPokemon = new Set(pokedexHandler.filteredPokemonData.map(pokemon => pokemon.species.speciesId)); + + expect(filteredPokemon).toEqual(expectedPokemon); + }); + + // Todo: Pokemon with a mega that adds a type do not show up in the filter, e.g. pinsir. + it.todo("should show only the pokemon with one of the types when filtering by multiple types", async () => { + const pokedexHandler = await runToOpenPokedex(); + + // @ts-expect-error - `filterBar` is private + pokedexHandler.filterBar.getFilter(DropDownColumn.TYPES).toggleOptionState(PokemonType.NORMAL + 1); + // @ts-expect-error - `filterBar` is private + pokedexHandler.filterBar.getFilter(DropDownColumn.TYPES).toggleOptionState(PokemonType.FLYING + 1); + + const expectedPokemon = getSpeciesWithType(PokemonType.NORMAL, PokemonType.FLYING); + // @ts-expect-error - `filteredPokemonData` is private + const filteredPokemon = new Set(pokedexHandler.filteredPokemonData.map(pokemon => pokemon.species.speciesId)); + + expect(filteredPokemon).toEqual(expectedPokemon); + }); + + it("filtering for unlockable cost reduction only shows species with sufficient candies", async () => { + // load the save file + await game.importData("./test/testUtils/saves/data_pokedex_tests.prsv"); + const pokedexHandler = await runToOpenPokedex(); + + // @ts-expect-error - `filterBar` is private + const filter = pokedexHandler.filterBar.getFilter(DropDownColumn.UNLOCKS); + + // Cycling 4 times to get to the "can unlock" for cost reduction + for (let i = 0; i < 4; i++) { + // index 1 is the cost reduction + filter.toggleOptionState(1); + } + + const expectedPokemon = new Set([ + Species.CHIKORITA, + Species.CYNDAQUIL, + Species.TORCHIC, + Species.TURTWIG, + Species.EKANS, + Species.MUDKIP, + ]); + expect( + // @ts-expect-error - `filteredPokemonData` is private + pokedexHandler.filteredPokemonData.every(pokemon => + expectedPokemon.has(pokedexHandler.getStarterSpeciesId(pokemon.species.speciesId)), + ), + ).toBe(true); + }); + + it("filtering by passive unlocked only shows species that have their passive", async () => { + await game.importData("./test/testUtils/saves/data_pokedex_tests.prsv"); + const pokedexHandler = await runToOpenPokedex(); + + // @ts-expect-error - `filterBar` is private + const filter = pokedexHandler.filterBar.getFilter(DropDownColumn.UNLOCKS); + + filter.toggleOptionState(0); // cycle to Passive: Yes + + expect( + // @ts-expect-error - `filteredPokemonData` is private + pokedexHandler.filteredPokemonData.every( + pokemon => pokedexHandler.getStarterSpeciesId(pokemon.species.speciesId) === Species.MUDKIP, + ), + ).toBe(true); + }); + + it("filtering for pokemon that can unlock passive shows only species with sufficient candies", async () => { + await game.importData("./test/testUtils/saves/data_pokedex_tests.prsv"); + const pokedexHandler = await runToOpenPokedex(); + + // @ts-expect-error - `filterBar` is private + const filter = pokedexHandler.filterBar.getFilter(DropDownColumn.UNLOCKS); + + // Cycling 4 times to get to the "can unlock" for passive + const expectedPokemon = new Set([ + Species.EKANS, + Species.CHIKORITA, + Species.CYNDAQUIL, + Species.TORCHIC, + Species.TURTWIG, + ]); + + // cycling twice to get to the "can unlock" for passive + filter.toggleOptionState(0); + filter.toggleOptionState(0); + + expect( + // @ts-expect-error - `filteredPokemonData` is private + pokedexHandler.filteredPokemonData.every(pokemon => + expectedPokemon.has(pokedexHandler.getStarterSpeciesId(pokemon.species.speciesId)), + ), + ).toBe(true); + }); + + it("filtering for pokemon that have any cost reduction shows only the species that have unlocked a cost reduction", async () => { + await game.importData("./test/testUtils/saves/data_pokedex_tests.prsv"); + const pokedexHandler = await runToOpenPokedex(); + + const expectedPokemon = new Set([Species.TREECKO, Species.CYNDAQUIL, Species.TOTODILE]); + + // @ts-expect-error - `filterBar` is private + const filter = pokedexHandler.filterBar.getFilter(DropDownColumn.UNLOCKS); + // Cycle 1 time for cost reduction + filter.toggleOptionState(1); + + expect( + // @ts-expect-error - `filteredPokemonData` is private + pokedexHandler.filteredPokemonData.every(pokemon => + expectedPokemon.has(pokedexHandler.getStarterSpeciesId(pokemon.species.speciesId)), + ), + ).toBe(true); + }); + + it("filtering for pokemon that have a single cost reduction shows only the species that have unlocked a single cost reduction", async () => { + await game.importData("./test/testUtils/saves/data_pokedex_tests.prsv"); + const pokedexHandler = await runToOpenPokedex(); + + const expectedPokemon = new Set([Species.CYNDAQUIL, Species.TOTODILE]); + + // @ts-expect-error - `filterBar` is private + const filter = pokedexHandler.filterBar.getFilter(DropDownColumn.UNLOCKS); + // Cycle 2 times for one cost reduction + filter.toggleOptionState(1); + filter.toggleOptionState(1); + + expect( + // @ts-expect-error - `filteredPokemonData` is private + pokedexHandler.filteredPokemonData.every(pokemon => + expectedPokemon.has(pokedexHandler.getStarterSpeciesId(pokemon.species.speciesId)), + ), + ).toBe(true); + }); + + it("filtering for pokemon that have two cost reductions sorts only shows the species that have unlocked both cost reductions", async () => { + await game.importData("./test/testUtils/saves/data_pokedex_tests.prsv"); + const pokedexHandler = await runToOpenPokedex(); + + // @ts-expect-error - `filterBar` is private + const filter = pokedexHandler.filterBar.getFilter(DropDownColumn.UNLOCKS); + // Cycle 3 time for two cost reductions + filter.toggleOptionState(1); + filter.toggleOptionState(1); + filter.toggleOptionState(1); + + expect( + // @ts-expect-error - `filteredPokemonData` is private + pokedexHandler.filteredPokemonData.every( + pokemon => pokedexHandler.getStarterSpeciesId(pokemon.species.speciesId) === Species.TREECKO, + ), + ).toBe(true); + }); + + it("filtering by shiny status shows the caught pokemon with the selected shiny tier", async () => { + await game.importData("./test/testUtils/saves/data_pokedex_tests.prsv"); + const pokedexHandler = await runToOpenPokedex(); + // @ts-expect-error - `filterBar` is private + const filter = pokedexHandler.filterBar.getFilter(DropDownColumn.CAUGHT); + filter.toggleOptionState(3); + + // @ts-expect-error - `filteredPokemonData` is private + let filteredPokemon = pokedexHandler.filteredPokemonData.map(pokemon => pokemon.species.speciesId); + + // Red shiny + expect(filteredPokemon.length).toBe(1); + expect(filteredPokemon[0], "tier 1 shiny").toBe(Species.CATERPIE); + + // tier 2 shiny + filter.toggleOptionState(3); + filter.toggleOptionState(2); + + // @ts-expect-error - `filteredPokemonData` is private + filteredPokemon = pokedexHandler.filteredPokemonData.map(pokemon => pokemon.species.speciesId); + expect(filteredPokemon.length).toBe(1); + expect(filteredPokemon[0], "tier 2 shiny").toBe(Species.RATTATA); + + filter.toggleOptionState(2); + filter.toggleOptionState(1); + // @ts-expect-error - `filteredPokemonData` is private + filteredPokemon = pokedexHandler.filteredPokemonData.map(pokemon => pokemon.species.speciesId); + expect(filteredPokemon.length).toBe(1); + expect(filteredPokemon[0], "tier 3 shiny").toBe(Species.EKANS); + + // filter by no shiny + filter.toggleOptionState(1); + filter.toggleOptionState(4); + + // @ts-expect-error - `filteredPokemonData` is private + filteredPokemon = pokedexHandler.filteredPokemonData.map(pokemon => pokemon.species.speciesId); + expect(filteredPokemon.length).toBe(27); + expect(filteredPokemon, "not shiny").not.toContain(Species.CATERPIE); + expect(filteredPokemon, "not shiny").not.toContain(Species.RATTATA); + expect(filteredPokemon, "not shiny").not.toContain(Species.EKANS); + }); + + /**************************** + * Tests for UI Input * + ****************************/ + + // TODO: fix cursor wrapping + it.todo( + "should wrap the cursor to the top when moving to an empty entry when there are more than 81 pokemon", + async () => { + const pokedexHandler = await runToOpenPokedex(); + + // Filter by gen 2 so we can pan a specific amount. + // @ts-expect-error `filterBar` is private + pokedexHandler.filterBar.getFilter(DropDownColumn.GEN).options[2].toggleOptionState(); + pokedexHandler.updateStarters(); + // @ts-expect-error - `filteredPokemonData` is private + expect(pokedexHandler.filteredPokemonData.length, "pokemon in gen2").toBe(100); + + // Let's try to pan to the right to see what the pokemon it points to is. + + // pan to the right once and down 11 times + pokedexHandler.processInput(Button.RIGHT); + // Nab the pokemon that is selected for comparison later. + + // @ts-expect-error - `lastSpecies` is private + const selectedPokemon = pokedexHandler.lastSpecies.speciesId; + for (let i = 0; i < 11; i++) { + pokedexHandler.processInput(Button.DOWN); + } + + // @ts-expect-error `lastSpecies` is private + expect(selectedPokemon).toEqual(pokedexHandler.lastSpecies.speciesId); + }, + ); + + /**************************** + * Tests for Pokédex Pages * + ****************************/ + + it("should show caught battle form as caught", async () => { + await game.importData("./test/testUtils/saves/data_pokedex_tests_v2.prsv"); + const pageHandler = await runToPokedexPage(getPokemonSpecies(Species.VENUSAUR), { form: 1 }); + + // @ts-expect-error - `species` is private + expect(pageHandler.species.speciesId).toEqual(Species.VENUSAUR); + + // @ts-expect-error - `formIndex` is private + expect(pageHandler.formIndex).toEqual(1); + + expect(pageHandler.isFormCaught()).toEqual(true); + expect(pageHandler.isSeen()).toEqual(true); + }); + + //TODO: check tint of the sprite + it("should show uncaught battle form as seen", async () => { + await game.importData("./test/testUtils/saves/data_pokedex_tests_v2.prsv"); + const pageHandler = await runToPokedexPage(getPokemonSpecies(Species.VENUSAUR), { form: 2 }); + + // @ts-expect-error - `species` is private + expect(pageHandler.species.speciesId).toEqual(Species.VENUSAUR); + + // @ts-expect-error - `formIndex` is private + expect(pageHandler.formIndex).toEqual(2); + + expect(pageHandler.isFormCaught()).toEqual(false); + expect(pageHandler.isSeen()).toEqual(true); + }); +}); diff --git a/test/ui/starter-select.test.ts b/test/ui/starter-select.test.ts index 1d523c3bbd5..b402e02e2d7 100644 --- a/test/ui/starter-select.test.ts +++ b/test/ui/starter-select.test.ts @@ -9,7 +9,7 @@ import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler" import type SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler"; import type OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; import type StarterSelectUiHandler from "#app/ui/starter-select-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import { Abilities } from "#enums/abilities"; import { Button } from "#enums/buttons"; import { Species } from "#enums/species"; @@ -44,12 +44,12 @@ describe("UI - Starter select", () => { }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); @@ -60,7 +60,7 @@ describe("UI - Starter select", () => { let options: OptionSelectItem[] = []; let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; options = optionSelectUiHandler.getOptionsWithScroll(); resolve(); @@ -74,15 +74,15 @@ describe("UI - Starter select", () => { optionSelectUiHandler?.processInput(Button.ACTION); await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.SUBMIT); }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.SAVE_SLOT, () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); resolve(); @@ -104,12 +104,12 @@ describe("UI - Starter select", () => { }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); @@ -121,7 +121,7 @@ describe("UI - Starter select", () => { let options: OptionSelectItem[] = []; let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; options = optionSelectUiHandler.getOptionsWithScroll(); resolve(); @@ -135,15 +135,15 @@ describe("UI - Starter select", () => { optionSelectUiHandler?.processInput(Button.ACTION); await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.SUBMIT); }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.SAVE_SLOT, () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); resolve(); @@ -166,12 +166,12 @@ describe("UI - Starter select", () => { }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); @@ -185,7 +185,7 @@ describe("UI - Starter select", () => { let options: OptionSelectItem[] = []; let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; options = optionSelectUiHandler.getOptionsWithScroll(); resolve(); @@ -199,15 +199,15 @@ describe("UI - Starter select", () => { optionSelectUiHandler?.processInput(Button.ACTION); await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.SUBMIT); }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.SAVE_SLOT, () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); resolve(); @@ -231,12 +231,12 @@ describe("UI - Starter select", () => { }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); @@ -248,7 +248,7 @@ describe("UI - Starter select", () => { let options: OptionSelectItem[] = []; let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; options = optionSelectUiHandler.getOptionsWithScroll(); resolve(); @@ -262,15 +262,15 @@ describe("UI - Starter select", () => { optionSelectUiHandler?.processInput(Button.ACTION); await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.SUBMIT); }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.SAVE_SLOT, () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); resolve(); @@ -292,12 +292,12 @@ describe("UI - Starter select", () => { }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); @@ -309,7 +309,7 @@ describe("UI - Starter select", () => { let options: OptionSelectItem[] = []; let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; options = optionSelectUiHandler.getOptionsWithScroll(); resolve(); @@ -323,15 +323,15 @@ describe("UI - Starter select", () => { optionSelectUiHandler?.processInput(Button.ACTION); await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.SUBMIT); }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.SAVE_SLOT, () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); resolve(); @@ -352,12 +352,12 @@ describe("UI - Starter select", () => { }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); @@ -371,7 +371,7 @@ describe("UI - Starter select", () => { let options: OptionSelectItem[] = []; let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; options = optionSelectUiHandler.getOptionsWithScroll(); resolve(); @@ -385,15 +385,15 @@ describe("UI - Starter select", () => { optionSelectUiHandler?.processInput(Button.ACTION); await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.SUBMIT); }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.SAVE_SLOT, () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); resolve(); @@ -414,12 +414,12 @@ describe("UI - Starter select", () => { }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); @@ -432,7 +432,7 @@ describe("UI - Starter select", () => { let options: OptionSelectItem[] = []; let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; options = optionSelectUiHandler.getOptionsWithScroll(); resolve(); @@ -446,15 +446,15 @@ describe("UI - Starter select", () => { optionSelectUiHandler?.processInput(Button.ACTION); await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.SUBMIT); }); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.SAVE_SLOT, () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); resolve(); @@ -475,12 +475,12 @@ describe("UI - Starter select", () => { }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.RIGHT); @@ -492,7 +492,7 @@ describe("UI - Starter select", () => { let options: OptionSelectItem[] = []; let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; options = optionSelectUiHandler.getOptionsWithScroll(); resolve(); @@ -507,7 +507,7 @@ describe("UI - Starter select", () => { let starterSelectUiHandler: StarterSelectUiHandler; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { starterSelectUiHandler = game.scene.ui.getHandler() as StarterSelectUiHandler; starterSelectUiHandler.processInput(Button.SUBMIT); resolve(); @@ -519,11 +519,11 @@ describe("UI - Starter select", () => { // expect(starterSelectUiHandler.cursorObj.x).toBe(132 + 4 * 18); // expect(starterSelectUiHandler.cursorObj.y).toBe(10); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.SAVE_SLOT, () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); }); @@ -539,12 +539,12 @@ describe("UI - Starter select", () => { }).length; expect(caughtCount).toBe(Object.keys(allSpecies).length); await game.runToTitle(); - game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + game.onNextPrompt("TitlePhase", UiMode.TITLE, () => { const currentPhase = game.scene.getCurrentPhase() as TitlePhase; currentPhase.gameMode = GameModes.CLASSIC; currentPhase.end(); }); - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.RIGHT); @@ -557,7 +557,7 @@ describe("UI - Starter select", () => { let options: OptionSelectItem[] = []; let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; options = optionSelectUiHandler.getOptionsWithScroll(); resolve(); @@ -572,7 +572,7 @@ describe("UI - Starter select", () => { let starterSelectUiHandler: StarterSelectUiHandler | undefined; await new Promise(resolve => { - game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.STARTER_SELECT, () => { starterSelectUiHandler = game.scene.ui.getHandler() as StarterSelectUiHandler; starterSelectUiHandler.processInput(Button.SUBMIT); resolve(); @@ -585,11 +585,11 @@ describe("UI - Starter select", () => { expect(starterSelectUiHandler?.cursorObj.x).toBe(53); expect(starterSelectUiHandler?.cursorObj.y).toBe(31); - game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.ACTION); }); - game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => { + game.onNextPrompt("SelectStarterPhase", UiMode.SAVE_SLOT, () => { const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler; saveSlotSelectUiHandler.processInput(Button.ACTION); }); diff --git a/test/ui/transfer-item.test.ts b/test/ui/transfer-item.test.ts index 476f0744436..f0ea8f84005 100644 --- a/test/ui/transfer-item.test.ts +++ b/test/ui/transfer-item.test.ts @@ -4,7 +4,7 @@ import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import type BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; @@ -26,7 +26,7 @@ describe("UI - Transfer Items", () => { beforeEach(async () => { game = new GameManager(phaserGame); - game.override.battleType("single"); + game.override.battleStyle("single"); game.override.startingLevel(100); game.override.startingWave(1); game.override.startingHeldItems([ @@ -42,21 +42,21 @@ describe("UI - Transfer Items", () => { game.move.select(Moves.DRAGON_CLAW); - game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { + game.onNextPrompt("SelectModifierPhase", UiMode.MODIFIER_SELECT, () => { expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); const handler = game.scene.ui.getHandler() as ModifierSelectUiHandler; handler.setCursor(1); handler.processInput(Button.ACTION); - void game.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER); + void game.scene.ui.setModeWithoutClear(UiMode.PARTY, PartyUiMode.MODIFIER_TRANSFER); }); await game.phaseInterceptor.to("BattleEndPhase"); }); it("check red tint for held item limit in transfer menu", async () => { - game.onNextPrompt("SelectModifierPhase", Mode.PARTY, () => { + game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, () => { expect(game.scene.ui.getHandler()).toBeInstanceOf(PartyUiHandler); const handler = game.scene.ui.getHandler() as PartyUiHandler; @@ -79,7 +79,7 @@ describe("UI - Transfer Items", () => { }, 20000); it("check transfer option for pokemon to transfer to", async () => { - game.onNextPrompt("SelectModifierPhase", Mode.PARTY, () => { + game.onNextPrompt("SelectModifierPhase", UiMode.PARTY, () => { expect(game.scene.ui.getHandler()).toBeInstanceOf(PartyUiHandler); const handler = game.scene.ui.getHandler() as PartyUiHandler; diff --git a/test/ui/type-hints.test.ts b/test/ui/type-hints.test.ts index fa7532fb674..2051af76754 100644 --- a/test/ui/type-hints.test.ts +++ b/test/ui/type-hints.test.ts @@ -3,7 +3,7 @@ import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; import { CommandPhase } from "#app/phases/command-phase"; import FightUiHandler from "#app/ui/fight-ui-handler"; -import { Mode } from "#app/ui/ui"; +import { UiMode } from "#enums/ui-mode"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -27,12 +27,12 @@ describe("UI - Type Hints", () => { beforeEach(async () => { game = new GameManager(phaserGame); game.settings.typeHints(true); //activate type hints - game.override.battleType("single").startingLevel(100).startingWave(1).enemyMoveset(Moves.SPLASH); + game.override.battleStyle("single").startingLevel(100).startingWave(1).enemyMoveset(Moves.SPLASH); }); it("check immunity color", async () => { game.override - .battleType("single") + .battleStyle("single") .startingLevel(100) .startingWave(1) .enemySpecies(Species.FLORGES) @@ -40,16 +40,16 @@ describe("UI - Type Hints", () => { .moveset([Moves.DRAGON_CLAW]); game.settings.typeHints(true); //activate type hints - await game.startBattle([Species.RAYQUAZA]); + await game.classicMode.startBattle([Species.RAYQUAZA]); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { const { ui } = game.scene; const handler = ui.getHandler(); handler.processInput(Button.ACTION); // select "Fight" game.phaseInterceptor.unlock(); }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + game.onNextPrompt("CommandPhase", UiMode.FIGHT, () => { const { ui } = game.scene; const movesContainer = ui.getByName(FightUiHandler.MOVES_CONTAINER_NAME); const dragonClawText = movesContainer @@ -65,16 +65,16 @@ describe("UI - Type Hints", () => { it("check status move color", async () => { game.override.enemySpecies(Species.FLORGES).moveset([Moves.GROWL]); - await game.startBattle([Species.RAYQUAZA]); + await game.classicMode.startBattle([Species.RAYQUAZA]); - game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { + game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { const { ui } = game.scene; const handler = ui.getHandler(); handler.processInput(Button.ACTION); // select "Fight" game.phaseInterceptor.unlock(); }); - game.onNextPrompt("CommandPhase", Mode.FIGHT, () => { + game.onNextPrompt("CommandPhase", UiMode.FIGHT, () => { const { ui } = game.scene; const movesContainer = ui.getByName(FightUiHandler.MOVES_CONTAINER_NAME); const growlText = movesContainer @@ -86,4 +86,41 @@ describe("UI - Type Hints", () => { }); await game.phaseInterceptor.to(CommandPhase); }); + + it("should show the proper hint for a move in doubles after one of the enemy pokemon flees", async () => { + game.override + .enemySpecies(Species.ABRA) + .moveset([Moves.SPLASH, Moves.SHADOW_BALL, Moves.SOAK]) + .enemyMoveset([Moves.SPLASH, Moves.TELEPORT]) + .battleStyle("double"); + + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + game.move.select(Moves.SPLASH); + // Use soak to change type of remaining abra to water + game.move.select(Moves.SOAK, 1); + + await game.forceEnemyMove(Moves.SPLASH); + await game.forceEnemyMove(Moves.TELEPORT); + await game.toNextTurn(); + + game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { + const { ui } = game.scene; + const handler = ui.getHandler(); + handler.processInput(Button.ACTION); // select "Fight" + game.phaseInterceptor.unlock(); + }); + + game.onNextPrompt("CommandPhase", UiMode.FIGHT, () => { + const { ui } = game.scene; + const movesContainer = ui.getByName(FightUiHandler.MOVES_CONTAINER_NAME); + const shadowBallText = movesContainer + .getAll() + .find(text => text.text === i18next.t("move:shadowBall.name"))! as unknown as MockText; + expect.soft(shadowBallText).toBeDefined(); + + expect.soft(shadowBallText.color).toBe(undefined); + ui.getHandler().processInput(Button.ACTION); + }); + await game.phaseInterceptor.to(CommandPhase); + }); }); diff --git a/src/utils.test.ts b/test/utils.test.ts similarity index 50% rename from src/utils.test.ts rename to test/utils.test.ts index cc3f2bb1a04..fe93bdd6970 100644 --- a/src/utils.test.ts +++ b/test/utils.test.ts @@ -1,5 +1,6 @@ import { expect, describe, it, beforeAll } from "vitest"; -import { randomString, padInt } from "./utils"; +import { randomString, padInt } from "#app/utils/common"; +import { deepMergeSpriteData } from "#app/utils/data"; import Phaser from "phaser"; @@ -9,6 +10,7 @@ describe("utils", () => { type: Phaser.HEADLESS, }); }); + describe("randomString", () => { it("should return a string of the specified length", () => { const str = randomString(10); @@ -46,4 +48,33 @@ describe("utils", () => { expect(result).toBe("1"); }); }); + describe("deepMergeSpriteData", () => { + it("should merge two objects' common properties", () => { + const dest = { a: 1, b: 2 }; + const source = { a: 3, b: 3, e: 4 }; + deepMergeSpriteData(dest, source); + expect(dest).toEqual({ a: 3, b: 3 }); + }); + + it("does nothing for identical objects", () => { + const dest = { a: 1, b: 2 }; + const source = { a: 1, b: 2 }; + deepMergeSpriteData(dest, source); + expect(dest).toEqual({ a: 1, b: 2 }); + }); + + it("should preserve missing and mistyped properties", () => { + const dest = { a: 1, c: 56, d: "test" }; + const source = { a: "apple", b: 3, d: "no hablo español" }; + deepMergeSpriteData(dest, source); + expect(dest).toEqual({ a: 1, c: 56, d: "no hablo español" }); + }); + + it("should copy arrays verbatim even with mismatches", () => { + const dest = { a: 1, b: [{ d: 1 }, { d: 2 }, { d: 3 }] }; + const source = { a: 3, b: [{ c: [4, 5] }, { p: [7, 8] }], e: 4 }; + deepMergeSpriteData(dest, source); + expect(dest).toEqual({ a: 3, b: [{ c: [4, 5] }, { p: [7, 8] }] }); + }); + }); }); diff --git a/tsconfig.json b/tsconfig.json index 30e208745b9..6af3e9ce650 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "esModuleInterop": true, "strictNullChecks": true, "sourceMap": false, - "strict": false, + "strict": false, // TODO: Enable this eventually "rootDir": ".", "baseUrl": "./src", "paths": {