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 8b0e33a18c4..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-file: '.nvmrc' + 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/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/package-lock.json b/package-lock.json index 07fed79969e..66400b14459 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.8.4", + "version": "1.9.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.8.4", + "version": "1.9.4", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", @@ -39,10 +39,11 @@ "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" @@ -2161,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" ], @@ -2175,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" ], @@ -2189,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" ], @@ -2203,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" ], @@ -2217,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" ], @@ -2231,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" ], @@ -2245,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" ], @@ -2259,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" ], @@ -2273,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" ], @@ -2287,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" ], @@ -2301,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" ], @@ -2315,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" ], @@ -2329,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" ], @@ -2343,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" ], @@ -2357,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" ], @@ -2371,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" ], @@ -2385,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" ], @@ -2399,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" ], @@ -2413,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" ], @@ -2427,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" ], @@ -4427,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", @@ -6559,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": { @@ -6575,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" } }, @@ -7043,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", @@ -7413,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 938d362f263..7d1ba35154a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.8.5", + "version": "1.9.4", "type": "module", "scripts": { "start": "vite", @@ -48,7 +48,7 @@ "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" diff --git a/public/battle-anims/common-sandstorm.json b/public/battle-anims/common-sandstorm.json index b5b2d29f54c..fba90a08645 100644 --- a/public/battle-anims/common-sandstorm.json +++ b/public/battle-anims/common-sandstorm.json @@ -542,6 +542,79 @@ "volume": 100, "pitch": 55, "eventType": "AnimTimedSoundEvent" + }, + { + "frameIndex": 0, + "resourceName": "PRAS- Sandstorm", + "bgX": -50, + "bgY": 0, + "opacity": 0, + "duration": 5, + "eventType": "AnimTimedAddBgEvent" + }, + { + "frameIndex": 0, + "resourceName": "", + "bgX": -50, + "bgY": 0, + "opacity": 96, + "duration": 3, + "eventType": "AnimTimedUpdateBgEvent" + } + ], + "3": [ + { + "frameIndex": 3, + "resourceName": "", + "bgX": -25, + "bgY": 0, + "opacity": 128, + "duration": 3, + "eventType": "AnimTimedUpdateBgEvent" + } + ], + "6": [ + { + "frameIndex": 6, + "resourceName": "", + "bgX": 0, + "bgY": 0, + "opacity": 192, + "duration": 3, + "eventType": "AnimTimedUpdateBgEvent" + } + ], + "9": [ + { + "frameIndex": 9, + "resourceName": "", + "bgX": 25, + "bgY": 0, + "opacity": 128, + "duration": 3, + "eventType": "AnimTimedUpdateBgEvent" + } + ], + "12": [ + { + "frameIndex": 12, + "resourceName": "", + "bgX": 50, + "bgY": 0, + "opacity": 96, + "duration": 3, + "eventType": "AnimTimedUpdateBgEvent" + } + ], + "15": [ + { + "frameIndex": 15, + "resourceName": "", + "bgX": 50, + "bgY": 0, + "opacity": 0, + "duration": 3, + "eventType": "AnimTimedUpdateBgEvent" } ] }, diff --git a/public/battle-anims/psychic.json b/public/battle-anims/psychic.json index 5ad4898de5a..72161ff9aff 100644 --- a/public/battle-anims/psychic.json +++ b/public/battle-anims/psychic.json @@ -1,6 +1,6 @@ { "id": 94, - "graphic": "PRAS- PsychicBG", + "graphic": "PRAS- Psychic BG", "frames": [ [ { diff --git a/public/images/events/spr25event-fr.png b/public/images/events/spr25event-fr.png index e7089eee4a1..7730e16d4a3 100644 Binary files a/public/images/events/spr25event-fr.png and b/public/images/events/spr25event-fr.png differ diff --git a/public/images/events/spr25event-zh-CN.png b/public/images/events/spr25event-zh-CN.png new file mode 100644 index 00000000000..1d8ad35c166 Binary files /dev/null and b/public/images/events/spr25event-zh-CN.png differ diff --git a/public/images/pokemon/692.json b/public/images/pokemon/692.json index a06bb0c77b7..125642a01f1 100644 --- a/public/images/pokemon/692.json +++ b/public/images/pokemon/692.json @@ -1,41 +1,20 @@ -{ - "textures": [ - { - "image": "692.png", - "format": "RGBA8888", - "size": { - "w": 56, - "h": 56 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 56, - "h": 35 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 56, - "h": 35 - }, - "frame": { - "x": 0, - "y": 0, - "w": 56, - "h": 35 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:031fb8fbcf9162adb44c0a90fd2cc110:44a2bd195c730b2d35c3ad898e1b3672:2880def858c84cd859bedf13b0b49a33$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 121, "y": 36, "w": 56, "h": 35 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 0, "w": 56, "h": 35 }, + "sourceSize": { "w": 63, "h": 35 }, + "duration": 50 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.12-x64", + "image": "692.png", + "format": "I8", + "size": { "w": 239, "h": 106 }, + "scale": "1" + } } diff --git a/public/images/pokemon/692.png b/public/images/pokemon/692.png index ce0cb4d3243..a22655931a8 100644 Binary files a/public/images/pokemon/692.png and b/public/images/pokemon/692.png differ diff --git a/public/images/pokemon/782.json b/public/images/pokemon/782.json index 2a08877c58b..938568ed74a 100644 --- a/public/images/pokemon/782.json +++ b/public/images/pokemon/782.json @@ -5,7 +5,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -14,7 +14,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -23,7 +23,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -32,7 +32,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -41,7 +41,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -50,7 +50,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -59,7 +59,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -68,7 +68,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -77,7 +77,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -86,7 +86,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -95,7 +95,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -104,7 +104,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -113,7 +113,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -122,7 +122,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -131,7 +131,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -140,7 +140,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -149,7 +149,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -158,7 +158,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -167,7 +167,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -176,7 +176,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -185,7 +185,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -194,7 +194,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -203,7 +203,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -212,7 +212,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -221,7 +221,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -230,7 +230,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -239,7 +239,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -248,7 +248,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -257,7 +257,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -266,7 +266,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -275,7 +275,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -284,7 +284,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -293,7 +293,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -302,7 +302,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -311,7 +311,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -320,7 +320,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -329,7 +329,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -338,7 +338,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -347,7 +347,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -356,7 +356,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -365,7 +365,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -374,7 +374,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -383,7 +383,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -392,7 +392,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -401,7 +401,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -410,7 +410,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -419,7 +419,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -428,7 +428,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -437,7 +437,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -446,7 +446,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -455,7 +455,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -464,7 +464,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -473,7 +473,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -482,7 +482,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -491,7 +491,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -500,7 +500,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -509,7 +509,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -518,7 +518,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -527,7 +527,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -536,7 +536,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -545,7 +545,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -554,7 +554,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -563,7 +563,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -572,7 +572,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -581,7 +581,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -590,7 +590,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -599,7 +599,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -608,7 +608,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -617,7 +617,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -626,7 +626,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 46, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -635,7 +635,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -644,7 +644,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -653,7 +653,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -662,7 +662,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 26, "y": 27, "w": 47, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -671,7 +671,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -680,7 +680,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 27, "w": 46, "h": 47 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -689,7 +689,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -698,7 +698,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 27, "y": 25, "w": 47, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -707,7 +707,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -716,7 +716,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -725,7 +725,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -734,7 +734,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -743,7 +743,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -752,7 +752,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -761,7 +761,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -770,7 +770,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -779,7 +779,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -788,7 +788,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -797,7 +797,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -806,7 +806,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -815,7 +815,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -824,7 +824,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -833,7 +833,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -842,7 +842,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -851,7 +851,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -860,7 +860,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -869,7 +869,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -878,7 +878,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -887,7 +887,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -896,7 +896,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -905,7 +905,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -914,7 +914,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -923,7 +923,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -932,7 +932,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -941,7 +941,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 45, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -950,7 +950,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -959,7 +959,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -968,7 +968,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -977,7 +977,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -986,7 +986,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -995,7 +995,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 28, "y": 23, "w": 47, "h": 51 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 } ], diff --git a/public/images/pokemon/back/692.json b/public/images/pokemon/back/692.json index bce3c7e1b49..e83252f8486 100644 --- a/public/images/pokemon/back/692.json +++ b/public/images/pokemon/back/692.json @@ -1,41 +1,20 @@ -{ - "textures": [ - { - "image": "692.png", - "format": "RGBA8888", - "size": { - "w": 56, - "h": 56 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 56, - "h": 35 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 56, - "h": 35 - }, - "frame": { - "x": 0, - "y": 0, - "w": 56, - "h": 35 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:0a35aa3345ff8a4432ecda2feb4d64c0:d3698e869432ff55b6d6cefbe02ef068:2880def858c84cd859bedf13b0b49a33$" - } +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 121, "y": 36, "w": 56, "h": 35 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 0, "w": 56, "h": 35 }, + "sourceSize": { "w": 63, "h": 35 }, + "duration": 50 + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.12-x64", + "image": "692.png", + "format": "I8", + "size": { "w": 181, "h": 106 }, + "scale": "1" + } } diff --git a/public/images/pokemon/back/692.png b/public/images/pokemon/back/692.png index c61c905353f..33059d53c05 100644 Binary files a/public/images/pokemon/back/692.png and b/public/images/pokemon/back/692.png differ diff --git a/public/images/pokemon/back/782.json b/public/images/pokemon/back/782.json index 564a0c4f13a..6cefb281b7b 100644 --- a/public/images/pokemon/back/782.json +++ b/public/images/pokemon/back/782.json @@ -5,7 +5,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -14,7 +14,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -23,7 +23,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -32,7 +32,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -41,7 +41,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -50,7 +50,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -59,7 +59,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -68,7 +68,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -77,7 +77,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -86,7 +86,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -95,7 +95,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -104,7 +104,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -113,7 +113,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -122,7 +122,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -131,7 +131,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -140,7 +140,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -149,7 +149,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -158,7 +158,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -167,7 +167,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -176,7 +176,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -185,7 +185,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -194,7 +194,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -203,7 +203,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -212,7 +212,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -221,7 +221,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -230,7 +230,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -239,7 +239,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -248,7 +248,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -257,7 +257,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -266,7 +266,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -275,7 +275,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -284,7 +284,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -293,7 +293,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -302,7 +302,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -311,7 +311,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -320,7 +320,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -329,7 +329,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -338,7 +338,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -347,7 +347,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -356,7 +356,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -365,7 +365,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -374,7 +374,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -383,7 +383,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -392,7 +392,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -401,7 +401,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -410,7 +410,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -419,7 +419,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -428,7 +428,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -437,7 +437,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -446,7 +446,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -455,7 +455,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -464,7 +464,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -473,7 +473,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -482,7 +482,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -491,7 +491,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -500,7 +500,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -509,7 +509,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -518,7 +518,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -527,7 +527,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -536,7 +536,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -545,7 +545,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -554,7 +554,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -563,7 +563,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -572,7 +572,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -581,7 +581,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -590,7 +590,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -599,7 +599,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -608,7 +608,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -617,7 +617,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -626,7 +626,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -635,7 +635,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -644,7 +644,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -653,7 +653,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -662,7 +662,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 26, "w": 46, "h": 48 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -671,7 +671,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -680,7 +680,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 25, "w": 45, "h": 49 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -689,7 +689,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -698,7 +698,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 25, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -707,7 +707,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -716,7 +716,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 24, "y": 24, "w": 45, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -725,7 +725,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -734,7 +734,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 24, "w": 46, "h": 50 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -743,7 +743,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -752,7 +752,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -761,7 +761,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -770,7 +770,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -779,7 +779,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -788,7 +788,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -797,7 +797,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -806,7 +806,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -815,7 +815,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -824,7 +824,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -833,7 +833,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -842,7 +842,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -851,7 +851,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -860,7 +860,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -869,7 +869,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -878,7 +878,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -887,7 +887,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -896,7 +896,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -905,7 +905,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -914,7 +914,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -923,7 +923,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -932,7 +932,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -941,7 +941,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 22, "w": 47, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -950,7 +950,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -959,7 +959,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -968,7 +968,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -977,7 +977,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 23, "y": 22, "w": 46, "h": 52 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -986,7 +986,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 }, { @@ -995,7 +995,7 @@ "rotated": false, "trimmed": true, "spriteSourceSize": { "x": 22, "y": 23, "w": 47, "h": 51 }, - "sourceSize": { "w": 96, "h": 96 }, + "sourceSize": { "w": 96, "h": 76 }, "duration": 50 } ], diff --git a/public/images/pokemon/exp/935.json b/public/images/pokemon/exp/935.json deleted file mode 100644 index 95df77f9c54..00000000000 --- a/public/images/pokemon/exp/935.json +++ /dev/null @@ -1,440 +0,0 @@ -{ - "textures": [ - { - "image": "935.png", - "format": "RGBA8888", - "size": { - "w": 165, - "h": 165 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 70, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 105, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 70, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 70, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 105, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 105, - "y": 110, - "w": 35, - "h": 55 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:06750fe617b2ad66c1af576e0074e016:b59cf22eea90e9839062adc1f728c00a:077dcf06dc5fc347497b59afe6126a5e$" - } -} diff --git a/public/images/pokemon/exp/935.png b/public/images/pokemon/exp/935.png deleted file mode 100644 index 1ca019f8c11..00000000000 Binary files a/public/images/pokemon/exp/935.png and /dev/null differ diff --git a/public/images/pokemon/exp/936.json b/public/images/pokemon/exp/936.json deleted file mode 100644 index b7dff5e8393..00000000000 --- a/public/images/pokemon/exp/936.json +++ /dev/null @@ -1,524 +0,0 @@ -{ - "textures": [ - { - "image": "936.png", - "format": "RGBA8888", - "size": { - "w": 323, - "h": 323 - }, - "scale": 1, - "frames": [ - { - "filename": "0016.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 76, - "h": 99 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 198, - "w": 76, - "h": 99 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 76, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 152, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 228, - "y": 0, - "w": 70, - "h": 99 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 76, - "y": 98, - "w": 70, - "h": 99 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 194, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 264, - "y": 99, - "w": 59, - "h": 99 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 253, - "y": 198, - "w": 59, - "h": 98 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2943281264e8142bbdb55f3a34167d72:322e92870c690e237c7a5e4a4a5f8e84:1a0490303f9626f92e787c567cd10feb$" - } -} diff --git a/public/images/pokemon/exp/936.png b/public/images/pokemon/exp/936.png deleted file mode 100644 index dce770dca44..00000000000 Binary files a/public/images/pokemon/exp/936.png and /dev/null differ diff --git a/public/images/pokemon/exp/937.json b/public/images/pokemon/exp/937.json deleted file mode 100644 index 9eba0e32900..00000000000 --- a/public/images/pokemon/exp/937.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "textures": [ - { - "image": "937.png", - "format": "RGBA8888", - "size": { - "w": 247, - "h": 247 - }, - "scale": 1, - "frames": [ - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 83, - "h": 98 - }, - "frame": { - "x": 0, - "y": 0, - "w": 83, - "h": 98 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 81, - "h": 99 - }, - "frame": { - "x": 83, - "y": 0, - "w": 81, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 83, - "h": 99 - }, - "frame": { - "x": 164, - "y": 0, - "w": 83, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 86, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 86, - "y": 99, - "w": 86, - "h": 99 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:492182e4e32e5cddaa9dfc2c2c08b684:084d0317f824a0d082ba0ffcfebc407b:1d4b4f8d62307c37457ba974879b47d0$" - } -} diff --git a/public/images/pokemon/exp/937.png b/public/images/pokemon/exp/937.png deleted file mode 100644 index 6e8b5b34268..00000000000 Binary files a/public/images/pokemon/exp/937.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/935.json b/public/images/pokemon/exp/back/935.json deleted file mode 100644 index 26aa6c572c3..00000000000 --- a/public/images/pokemon/exp/back/935.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "935.png", - "format": "RGBA8888", - "size": { - "w": 133, - "h": 133 - }, - "scale": 1, - "frames": [ - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 27, - "h": 48 - }, - "frame": { - "x": 28, - "y": 49, - "w": 27, - "h": 48 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 25, - "h": 45 - }, - "frame": { - "x": 108, - "y": 49, - "w": 25, - "h": 45 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2880dad5e3c550bb25e02ab0ab8d58c8:9dc0340440df25f20b3f006422b7a238:077dcf06dc5fc347497b59afe6126a5e$" - } -} diff --git a/public/images/pokemon/exp/back/935.png b/public/images/pokemon/exp/back/935.png deleted file mode 100644 index 64fc37a4a33..00000000000 Binary files a/public/images/pokemon/exp/back/935.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/936.json b/public/images/pokemon/exp/back/936.json deleted file mode 100644 index 79ff3ce5c33..00000000000 --- a/public/images/pokemon/exp/back/936.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "936.png", - "format": "RGBA8888", - "size": { - "w": 283, - "h": 283 - }, - "scale": 1, - "frames": [ - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 58, - "h": 94 - }, - "frame": { - "x": 175, - "y": 95, - "w": 58, - "h": 94 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 10, - "y": 3, - "w": 57, - "h": 94 - }, - "frame": { - "x": 175, - "y": 189, - "w": 57, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:973448a7633a4dceb9828d95556ed3c2:09d8ad02433d8015e4665464587b1259:1a0490303f9626f92e787c567cd10feb$" - } -} diff --git a/public/images/pokemon/exp/back/936.png b/public/images/pokemon/exp/back/936.png deleted file mode 100644 index 14b0c1c7bf2..00000000000 Binary files a/public/images/pokemon/exp/back/936.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/937.json b/public/images/pokemon/exp/back/937.json deleted file mode 100644 index 9cdf9b93093..00000000000 --- a/public/images/pokemon/exp/back/937.json +++ /dev/null @@ -1,650 +0,0 @@ -{ - "textures": [ - { - "image": "937.png", - "format": "RGBA8888", - "size": { - "w": 382, - "h": 382 - }, - "scale": 1, - "frames": [ - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 91, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:25759b98c1f7867fe6c4ff54c797c3e2:0076c777d18a4f3d780937118dfb6388:1d4b4f8d62307c37457ba974879b47d0$" - } -} diff --git a/public/images/pokemon/exp/back/937.png b/public/images/pokemon/exp/back/937.png deleted file mode 100644 index 676950a1999..00000000000 Binary files a/public/images/pokemon/exp/back/937.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/shiny/935.json b/public/images/pokemon/exp/back/shiny/935.json deleted file mode 100644 index 2bdf2b2a155..00000000000 --- a/public/images/pokemon/exp/back/shiny/935.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "935.png", - "format": "RGBA8888", - "size": { - "w": 133, - "h": 133 - }, - "scale": 1, - "frames": [ - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 27, - "h": 48 - }, - "frame": { - "x": 28, - "y": 49, - "w": 27, - "h": 48 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 25, - "h": 45 - }, - "frame": { - "x": 108, - "y": 49, - "w": 25, - "h": 45 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:039aaaf52028b39c07e4909a88a5e8bb:1e66e8f98dd44fa06a53d364e32b154b:077dcf06dc5fc347497b59afe6126a5e$" - } -} diff --git a/public/images/pokemon/exp/back/shiny/935.png b/public/images/pokemon/exp/back/shiny/935.png deleted file mode 100644 index bdd1ef192ad..00000000000 Binary files a/public/images/pokemon/exp/back/shiny/935.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/shiny/936.json b/public/images/pokemon/exp/back/shiny/936.json deleted file mode 100644 index 295267305ad..00000000000 --- a/public/images/pokemon/exp/back/shiny/936.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "936.png", - "format": "RGBA8888", - "size": { - "w": 283, - "h": 283 - }, - "scale": 1, - "frames": [ - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 58, - "h": 94 - }, - "frame": { - "x": 175, - "y": 95, - "w": 58, - "h": 94 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 10, - "y": 3, - "w": 57, - "h": 94 - }, - "frame": { - "x": 175, - "y": 189, - "w": 57, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:28e584ed8d8aaebb8c9edc4517b84f45:09d8ad02433d8015e4665464587b1259:1a0490303f9626f92e787c567cd10feb$" - } -} diff --git a/public/images/pokemon/exp/back/shiny/936.png b/public/images/pokemon/exp/back/shiny/936.png deleted file mode 100644 index 14b0c1c7bf2..00000000000 Binary files a/public/images/pokemon/exp/back/shiny/936.png and /dev/null differ diff --git a/public/images/pokemon/exp/back/shiny/937.json b/public/images/pokemon/exp/back/shiny/937.json deleted file mode 100644 index 1a94f5525d2..00000000000 --- a/public/images/pokemon/exp/back/shiny/937.json +++ /dev/null @@ -1,650 +0,0 @@ -{ - "textures": [ - { - "image": "937.png", - "format": "RGBA8888", - "size": { - "w": 382, - "h": 382 - }, - "scale": 1, - "frames": [ - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 91, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:d3ac9f14a29e2d6136e96b1fbd1551c7:0076c777d18a4f3d780937118dfb6388:1d4b4f8d62307c37457ba974879b47d0$" - } -} diff --git a/public/images/pokemon/exp/back/shiny/937.png b/public/images/pokemon/exp/back/shiny/937.png deleted file mode 100644 index 676950a1999..00000000000 Binary files a/public/images/pokemon/exp/back/shiny/937.png and /dev/null differ diff --git a/public/images/pokemon/exp/shiny/935.json b/public/images/pokemon/exp/shiny/935.json deleted file mode 100644 index 3b7326364a9..00000000000 --- a/public/images/pokemon/exp/shiny/935.json +++ /dev/null @@ -1,440 +0,0 @@ -{ - "textures": [ - { - "image": "935.png", - "format": "RGBA8888", - "size": { - "w": 165, - "h": 165 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 70, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 105, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 70, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 70, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 105, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 105, - "y": 110, - "w": 35, - "h": 55 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:f58bc6c5ab628b520de90b88937784eb:2cb222a4a62936135e43a7f74d7bb852:077dcf06dc5fc347497b59afe6126a5e$" - } -} diff --git a/public/images/pokemon/exp/shiny/935.png b/public/images/pokemon/exp/shiny/935.png deleted file mode 100644 index ce821b4f870..00000000000 Binary files a/public/images/pokemon/exp/shiny/935.png and /dev/null differ diff --git a/public/images/pokemon/exp/shiny/936.json b/public/images/pokemon/exp/shiny/936.json deleted file mode 100644 index 550894878b6..00000000000 --- a/public/images/pokemon/exp/shiny/936.json +++ /dev/null @@ -1,524 +0,0 @@ -{ - "textures": [ - { - "image": "936.png", - "format": "RGBA8888", - "size": { - "w": 323, - "h": 323 - }, - "scale": 1, - "frames": [ - { - "filename": "0016.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 76, - "h": 99 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 198, - "w": 76, - "h": 99 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 76, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 152, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 228, - "y": 0, - "w": 70, - "h": 99 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 76, - "y": 98, - "w": 70, - "h": 99 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 194, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 264, - "y": 99, - "w": 59, - "h": 99 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 253, - "y": 198, - "w": 59, - "h": 98 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:244cdd3e42481041b59c3b67b0c2744d:204f377b772d27af90e7fcb35c29932a:1a0490303f9626f92e787c567cd10feb$" - } -} diff --git a/public/images/pokemon/exp/shiny/936.png b/public/images/pokemon/exp/shiny/936.png deleted file mode 100644 index 97856ebb8cc..00000000000 Binary files a/public/images/pokemon/exp/shiny/936.png and /dev/null differ diff --git a/public/images/pokemon/exp/shiny/937.json b/public/images/pokemon/exp/shiny/937.json deleted file mode 100644 index be7f920f7cd..00000000000 --- a/public/images/pokemon/exp/shiny/937.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "textures": [ - { - "image": "937.png", - "format": "RGBA8888", - "size": { - "w": 247, - "h": 247 - }, - "scale": 1, - "frames": [ - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 83, - "h": 98 - }, - "frame": { - "x": 0, - "y": 0, - "w": 83, - "h": 98 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 81, - "h": 99 - }, - "frame": { - "x": 83, - "y": 0, - "w": 81, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 83, - "h": 99 - }, - "frame": { - "x": 164, - "y": 0, - "w": 83, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 86, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 86, - "y": 99, - "w": 86, - "h": 99 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:d042040d151bc1a4b99bc43297e01fa6:d31a38624e1e937eaab1670f078bcfd7:1d4b4f8d62307c37457ba974879b47d0$" - } -} diff --git a/public/images/pokemon/exp/shiny/937.png b/public/images/pokemon/exp/shiny/937.png deleted file mode 100644 index fbf34a76cc2..00000000000 Binary files a/public/images/pokemon/exp/shiny/937.png and /dev/null 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/7/746-school_1.png b/public/images/pokemon/icons/variant/7/746-school_1.png deleted file mode 100644 index a7a2854bea0..00000000000 Binary files a/public/images/pokemon/icons/variant/7/746-school_1.png and /dev/null 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_1.png b/public/images/pokemon/icons/variant/7/746_1.png deleted file mode 100644 index d4897e0acf3..00000000000 Binary files a/public/images/pokemon/icons/variant/7/746_1.png and /dev/null differ diff --git a/public/images/pokemon/icons/variant/7/746_2.png b/public/images/pokemon/icons/variant/7/746_2.png index 8746a45310d..d4897e0acf3 100644 Binary files a/public/images/pokemon/icons/variant/7/746_2.png 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/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_1.png b/public/images/pokemon/icons/variant/8/871_1.png deleted file mode 100644 index ff77c60cea2..00000000000 Binary files a/public/images/pokemon/icons/variant/8/871_1.png and /dev/null differ diff --git a/public/images/pokemon/icons/variant/8/871_2.png b/public/images/pokemon/icons/variant/8/871_2.png index bfefb010219..719ee1eb3a9 100644 Binary files a/public/images/pokemon/icons/variant/8/871_2.png 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/variant/_exp_masterlist.json b/public/images/pokemon/variant/_exp_masterlist.json index e588be59073..88c6f4a95c1 100644 --- a/public/images/pokemon/variant/_exp_masterlist.json +++ b/public/images/pokemon/variant/_exp_masterlist.json @@ -256,9 +256,6 @@ "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], @@ -593,9 +590,6 @@ "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], @@ -675,4 +669,4 @@ "6215": [0, 1, 1] } } -} \ No newline at end of file +} diff --git a/public/images/pokemon/variant/exp/935.json b/public/images/pokemon/variant/exp/935.json deleted file mode 100644 index 8aa02017aca..00000000000 --- a/public/images/pokemon/variant/exp/935.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "0": { - "3681e4": "cfac07", - "df00df": "b168ca", - "82afee": "fdcd0d", - "ff51ff": "e589b5", - "ca0d33": "5ba0cc", - "ee0d23": "93d6b7", - "801313": "212982", - "b33630": "4861a5", - "0f0f0f": "0f0f0f", - "464444": "4d3467", - "636161": "885aa3", - "f38f07": "b885d6", - "8c8a8a": "c79ace", - "f32e42": "93d6b7", - "1b2123": "1b2123", - "c77505": "795bd3", - "f3bd03": "a59fdf", - "ffffff": "ffffff", - "bbb9b9": "bbb9b9", - "5c5d64": "5c5d64" - }, - "1": { - "3681e4": "a3bfcc", - "df00df": "88a0cc", - "82afee": "dbf5ff", - "ff51ff": "bbccea", - "ca0d33": "41accd", - "ee0d23": "96f5ff", - "801313": "0b3060", - "b33630": "205b82", - "0f0f0f": "0f0f0f", - "464444": "2d2c35", - "636161": "3b4149", - "f38f07": "e0734c", - "8c8a8a": "888989", - "f32e42": "87c1e5", - "1b2123": "1b2123", - "c77505": "d33830", - "f3bd03": "f4b766", - "ffffff": "ffffff", - "bbb9b9": "bbb9b9", - "5c5d64": "5c5d64" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/935_1.png b/public/images/pokemon/variant/exp/935_1.png deleted file mode 100644 index 06c09657444..00000000000 Binary files a/public/images/pokemon/variant/exp/935_1.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/935_2.png b/public/images/pokemon/variant/exp/935_2.png deleted file mode 100644 index 87d88ad2a74..00000000000 Binary files a/public/images/pokemon/variant/exp/935_2.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/935_3.json b/public/images/pokemon/variant/exp/935_3.json deleted file mode 100644 index 019ec7ab1de..00000000000 --- a/public/images/pokemon/variant/exp/935_3.json +++ /dev/null @@ -1,440 +0,0 @@ -{ - "textures": [ - { - "image": "935_3.png", - "format": "RGBA8888", - "size": { - "w": 165, - "h": 165 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 0, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 35, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 70, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 105, - "y": 0, - "w": 35, - "h": 55 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 70, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 70, - "y": 110, - "w": 35, - "h": 55 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 105, - "y": 55, - "w": 35, - "h": 55 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 35, - "h": 55 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 35, - "h": 55 - }, - "frame": { - "x": 105, - "y": 110, - "w": 35, - "h": 55 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:06750fe617b2ad66c1af576e0074e016:b59cf22eea90e9839062adc1f728c00a:077dcf06dc5fc347497b59afe6126a5e$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/935_3.png b/public/images/pokemon/variant/exp/935_3.png deleted file mode 100644 index 2ffcbac799e..00000000000 Binary files a/public/images/pokemon/variant/exp/935_3.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/936_1.json b/public/images/pokemon/variant/exp/936_1.json deleted file mode 100644 index f3c45278c91..00000000000 --- a/public/images/pokemon/variant/exp/936_1.json +++ /dev/null @@ -1,524 +0,0 @@ -{ - "textures": [ - { - "image": "936_1.png", - "format": "RGBA8888", - "size": { - "w": 323, - "h": 323 - }, - "scale": 1, - "frames": [ - { - "filename": "0016.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 76, - "h": 99 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 198, - "w": 76, - "h": 99 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 76, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 152, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 228, - "y": 0, - "w": 70, - "h": 99 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 76, - "y": 98, - "w": 70, - "h": 99 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 194, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 264, - "y": 99, - "w": 59, - "h": 99 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 253, - "y": 198, - "w": 59, - "h": 98 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2943281264e8142bbdb55f3a34167d72:322e92870c690e237c7a5e4a4a5f8e84:1a0490303f9626f92e787c567cd10feb$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/936_1.png b/public/images/pokemon/variant/exp/936_1.png deleted file mode 100644 index cdc333ab841..00000000000 Binary files a/public/images/pokemon/variant/exp/936_1.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/936_2.json b/public/images/pokemon/variant/exp/936_2.json deleted file mode 100644 index dfe48120a67..00000000000 --- a/public/images/pokemon/variant/exp/936_2.json +++ /dev/null @@ -1,524 +0,0 @@ -{ - "textures": [ - { - "image": "936_2.png", - "format": "RGBA8888", - "size": { - "w": 323, - "h": 323 - }, - "scale": 1, - "frames": [ - { - "filename": "0016.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 76, - "h": 99 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 198, - "w": 76, - "h": 99 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 76, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 152, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 228, - "y": 0, - "w": 70, - "h": 99 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 76, - "y": 98, - "w": 70, - "h": 99 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 194, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 264, - "y": 99, - "w": 59, - "h": 99 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 253, - "y": 198, - "w": 59, - "h": 98 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2943281264e8142bbdb55f3a34167d72:322e92870c690e237c7a5e4a4a5f8e84:1a0490303f9626f92e787c567cd10feb$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/936_2.png b/public/images/pokemon/variant/exp/936_2.png deleted file mode 100644 index 4d5bfb25268..00000000000 Binary files a/public/images/pokemon/variant/exp/936_2.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/936_3.json b/public/images/pokemon/variant/exp/936_3.json deleted file mode 100644 index e80ca73deb5..00000000000 --- a/public/images/pokemon/variant/exp/936_3.json +++ /dev/null @@ -1,524 +0,0 @@ -{ - "textures": [ - { - "image": "936_3.png", - "format": "RGBA8888", - "size": { - "w": 323, - "h": 323 - }, - "scale": 1, - "frames": [ - { - "filename": "0016.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 76, - "h": 99 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 76, - "h": 99 - }, - "frame": { - "x": 0, - "y": 198, - "w": 76, - "h": 99 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 76, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 76, - "h": 98 - }, - "frame": { - "x": 152, - "y": 0, - "w": 76, - "h": 98 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 228, - "y": 0, - "w": 70, - "h": 99 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 70, - "h": 99 - }, - "frame": { - "x": 76, - "y": 98, - "w": 70, - "h": 99 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 146, - "y": 98, - "w": 59, - "h": 99 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 76, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 135, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 194, - "y": 197, - "w": 59, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 205, - "y": 99, - "w": 59, - "h": 98 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 0, - "w": 59, - "h": 99 - }, - "frame": { - "x": 264, - "y": 99, - "w": 59, - "h": 99 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 76, - "h": 99 - }, - "spriteSourceSize": { - "x": 9, - "y": 1, - "w": 59, - "h": 98 - }, - "frame": { - "x": 253, - "y": 198, - "w": 59, - "h": 98 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2943281264e8142bbdb55f3a34167d72:322e92870c690e237c7a5e4a4a5f8e84:1a0490303f9626f92e787c567cd10feb$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/936_3.png b/public/images/pokemon/variant/exp/936_3.png deleted file mode 100644 index 27874a25886..00000000000 Binary files a/public/images/pokemon/variant/exp/936_3.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/937_1.json b/public/images/pokemon/variant/exp/937_1.json deleted file mode 100644 index d8039af99c7..00000000000 --- a/public/images/pokemon/variant/exp/937_1.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "textures": [ - { - "image": "937_1.png", - "format": "RGBA8888", - "size": { - "w": 247, - "h": 247 - }, - "scale": 1, - "frames": [ - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 83, - "h": 98 - }, - "frame": { - "x": 0, - "y": 0, - "w": 83, - "h": 98 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 81, - "h": 99 - }, - "frame": { - "x": 83, - "y": 0, - "w": 81, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 83, - "h": 99 - }, - "frame": { - "x": 164, - "y": 0, - "w": 83, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 86, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 86, - "y": 99, - "w": 86, - "h": 99 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:492182e4e32e5cddaa9dfc2c2c08b684:084d0317f824a0d082ba0ffcfebc407b:1d4b4f8d62307c37457ba974879b47d0$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/937_1.png b/public/images/pokemon/variant/exp/937_1.png deleted file mode 100644 index 82fa70b0c5b..00000000000 Binary files a/public/images/pokemon/variant/exp/937_1.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/937_2.json b/public/images/pokemon/variant/exp/937_2.json deleted file mode 100644 index 58792129101..00000000000 --- a/public/images/pokemon/variant/exp/937_2.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "textures": [ - { - "image": "937_2.png", - "format": "RGBA8888", - "size": { - "w": 247, - "h": 247 - }, - "scale": 1, - "frames": [ - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 83, - "h": 98 - }, - "frame": { - "x": 0, - "y": 0, - "w": 83, - "h": 98 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 81, - "h": 99 - }, - "frame": { - "x": 83, - "y": 0, - "w": 81, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 83, - "h": 99 - }, - "frame": { - "x": 164, - "y": 0, - "w": 83, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 86, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 86, - "y": 99, - "w": 86, - "h": 99 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:492182e4e32e5cddaa9dfc2c2c08b684:084d0317f824a0d082ba0ffcfebc407b:1d4b4f8d62307c37457ba974879b47d0$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/937_2.png b/public/images/pokemon/variant/exp/937_2.png deleted file mode 100644 index 43e2b060319..00000000000 Binary files a/public/images/pokemon/variant/exp/937_2.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/937_3.json b/public/images/pokemon/variant/exp/937_3.json deleted file mode 100644 index 213c017c1e0..00000000000 --- a/public/images/pokemon/variant/exp/937_3.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "textures": [ - { - "image": "937_3.png", - "format": "RGBA8888", - "size": { - "w": 247, - "h": 247 - }, - "scale": 1, - "frames": [ - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 83, - "h": 98 - }, - "frame": { - "x": 0, - "y": 0, - "w": 83, - "h": 98 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 81, - "h": 99 - }, - "frame": { - "x": 83, - "y": 0, - "w": 81, - "h": 99 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 83, - "h": 99 - }, - "frame": { - "x": 164, - "y": 0, - "w": 83, - "h": 99 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 0, - "y": 99, - "w": 86, - "h": 99 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 86, - "h": 99 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 86, - "h": 99 - }, - "frame": { - "x": 86, - "y": 99, - "w": 86, - "h": 99 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:492182e4e32e5cddaa9dfc2c2c08b684:084d0317f824a0d082ba0ffcfebc407b:1d4b4f8d62307c37457ba974879b47d0$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/937_3.png b/public/images/pokemon/variant/exp/937_3.png deleted file mode 100644 index 9a208ba1457..00000000000 Binary files a/public/images/pokemon/variant/exp/937_3.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/back/935_1.json b/public/images/pokemon/variant/exp/back/935_1.json deleted file mode 100644 index 8f78d4f4569..00000000000 --- a/public/images/pokemon/variant/exp/back/935_1.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "935_1.png", - "format": "RGBA8888", - "size": { - "w": 133, - "h": 133 - }, - "scale": 1, - "frames": [ - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 27, - "h": 48 - }, - "frame": { - "x": 28, - "y": 49, - "w": 27, - "h": 48 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 25, - "h": 45 - }, - "frame": { - "x": 108, - "y": 49, - "w": 25, - "h": 45 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2880dad5e3c550bb25e02ab0ab8d58c8:9dc0340440df25f20b3f006422b7a238:077dcf06dc5fc347497b59afe6126a5e$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/935_1.png b/public/images/pokemon/variant/exp/back/935_1.png deleted file mode 100644 index 6f98dfa371e..00000000000 Binary files a/public/images/pokemon/variant/exp/back/935_1.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/back/935_2.json b/public/images/pokemon/variant/exp/back/935_2.json deleted file mode 100644 index 44fc56f8621..00000000000 --- a/public/images/pokemon/variant/exp/back/935_2.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "935_2.png", - "format": "RGBA8888", - "size": { - "w": 133, - "h": 133 - }, - "scale": 1, - "frames": [ - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 27, - "h": 48 - }, - "frame": { - "x": 28, - "y": 49, - "w": 27, - "h": 48 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 25, - "h": 45 - }, - "frame": { - "x": 108, - "y": 49, - "w": 25, - "h": 45 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2880dad5e3c550bb25e02ab0ab8d58c8:9dc0340440df25f20b3f006422b7a238:077dcf06dc5fc347497b59afe6126a5e$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/935_2.png b/public/images/pokemon/variant/exp/back/935_2.png deleted file mode 100644 index 08789758184..00000000000 Binary files a/public/images/pokemon/variant/exp/back/935_2.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/back/935_3.json b/public/images/pokemon/variant/exp/back/935_3.json deleted file mode 100644 index b2d13ca9909..00000000000 --- a/public/images/pokemon/variant/exp/back/935_3.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "935_3.png", - "format": "RGBA8888", - "size": { - "w": 133, - "h": 133 - }, - "scale": 1, - "frames": [ - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 29, - "h": 49 - }, - "frame": { - "x": 29, - "y": 0, - "w": 29, - "h": 49 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 58, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 28, - "h": 49 - }, - "frame": { - "x": 86, - "y": 0, - "w": 28, - "h": 49 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 28, - "h": 48 - }, - "frame": { - "x": 0, - "y": 49, - "w": 28, - "h": 48 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 27, - "h": 48 - }, - "frame": { - "x": 28, - "y": 49, - "w": 27, - "h": 48 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 5, - "y": 2, - "w": 27, - "h": 47 - }, - "frame": { - "x": 55, - "y": 49, - "w": 27, - "h": 47 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 6, - "y": 3, - "w": 26, - "h": 46 - }, - "frame": { - "x": 82, - "y": 49, - "w": 26, - "h": 46 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 49 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 25, - "h": 45 - }, - "frame": { - "x": 108, - "y": 49, - "w": 25, - "h": 45 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2880dad5e3c550bb25e02ab0ab8d58c8:9dc0340440df25f20b3f006422b7a238:077dcf06dc5fc347497b59afe6126a5e$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/935_3.png b/public/images/pokemon/variant/exp/back/935_3.png deleted file mode 100644 index e58a17ead33..00000000000 Binary files a/public/images/pokemon/variant/exp/back/935_3.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/back/936_1.json b/public/images/pokemon/variant/exp/back/936_1.json deleted file mode 100644 index ca0f37cffb2..00000000000 --- a/public/images/pokemon/variant/exp/back/936_1.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "936_1.png", - "format": "RGBA8888", - "size": { - "w": 283, - "h": 283 - }, - "scale": 1, - "frames": [ - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 58, - "h": 94 - }, - "frame": { - "x": 175, - "y": 95, - "w": 58, - "h": 94 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 10, - "y": 3, - "w": 57, - "h": 94 - }, - "frame": { - "x": 175, - "y": 189, - "w": 57, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:973448a7633a4dceb9828d95556ed3c2:09d8ad02433d8015e4665464587b1259:1a0490303f9626f92e787c567cd10feb$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/936_1.png b/public/images/pokemon/variant/exp/back/936_1.png deleted file mode 100644 index 154c4e86364..00000000000 Binary files a/public/images/pokemon/variant/exp/back/936_1.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/back/936_2.json b/public/images/pokemon/variant/exp/back/936_2.json deleted file mode 100644 index 282d9823ab7..00000000000 --- a/public/images/pokemon/variant/exp/back/936_2.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "936_2.png", - "format": "RGBA8888", - "size": { - "w": 283, - "h": 283 - }, - "scale": 1, - "frames": [ - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 58, - "h": 94 - }, - "frame": { - "x": 175, - "y": 95, - "w": 58, - "h": 94 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 10, - "y": 3, - "w": 57, - "h": 94 - }, - "frame": { - "x": 175, - "y": 189, - "w": 57, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:973448a7633a4dceb9828d95556ed3c2:09d8ad02433d8015e4665464587b1259:1a0490303f9626f92e787c567cd10feb$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/936_2.png b/public/images/pokemon/variant/exp/back/936_2.png deleted file mode 100644 index 442abc72971..00000000000 Binary files a/public/images/pokemon/variant/exp/back/936_2.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/back/936_3.json b/public/images/pokemon/variant/exp/back/936_3.json deleted file mode 100644 index 24eeb8e705e..00000000000 --- a/public/images/pokemon/variant/exp/back/936_3.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "textures": [ - { - "image": "936_3.png", - "format": "RGBA8888", - "size": { - "w": 283, - "h": 283 - }, - "scale": 1, - "frames": [ - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 0, - "y": 97, - "w": 59, - "h": 97 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 59, - "h": 97 - }, - "frame": { - "x": 59, - "y": 0, - "w": 59, - "h": 97 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 59, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 58, - "h": 97 - }, - "frame": { - "x": 117, - "y": 97, - "w": 58, - "h": 97 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 1, - "w": 57, - "h": 96 - }, - "frame": { - "x": 118, - "y": 0, - "w": 57, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 58, - "h": 95 - }, - "frame": { - "x": 175, - "y": 0, - "w": 58, - "h": 95 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 3, - "w": 58, - "h": 94 - }, - "frame": { - "x": 175, - "y": 95, - "w": 58, - "h": 94 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 67, - "h": 97 - }, - "spriteSourceSize": { - "x": 10, - "y": 3, - "w": 57, - "h": 94 - }, - "frame": { - "x": 175, - "y": 189, - "w": 57, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:973448a7633a4dceb9828d95556ed3c2:09d8ad02433d8015e4665464587b1259:1a0490303f9626f92e787c567cd10feb$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/936_3.png b/public/images/pokemon/variant/exp/back/936_3.png deleted file mode 100644 index db67191d73e..00000000000 Binary files a/public/images/pokemon/variant/exp/back/936_3.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/back/937_1.json b/public/images/pokemon/variant/exp/back/937_1.json deleted file mode 100644 index f7f0201b676..00000000000 --- a/public/images/pokemon/variant/exp/back/937_1.json +++ /dev/null @@ -1,650 +0,0 @@ -{ - "textures": [ - { - "image": "937_1.png", - "format": "RGBA8888", - "size": { - "w": 382, - "h": 382 - }, - "scale": 1, - "frames": [ - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 91, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:25759b98c1f7867fe6c4ff54c797c3e2:0076c777d18a4f3d780937118dfb6388:1d4b4f8d62307c37457ba974879b47d0$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/937_1.png b/public/images/pokemon/variant/exp/back/937_1.png deleted file mode 100644 index 2d0d58b0912..00000000000 Binary files a/public/images/pokemon/variant/exp/back/937_1.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/back/937_2.json b/public/images/pokemon/variant/exp/back/937_2.json deleted file mode 100644 index cda51714b93..00000000000 --- a/public/images/pokemon/variant/exp/back/937_2.json +++ /dev/null @@ -1,650 +0,0 @@ -{ - "textures": [ - { - "image": "937_2.png", - "format": "RGBA8888", - "size": { - "w": 382, - "h": 382 - }, - "scale": 1, - "frames": [ - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 91, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:25759b98c1f7867fe6c4ff54c797c3e2:0076c777d18a4f3d780937118dfb6388:1d4b4f8d62307c37457ba974879b47d0$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/937_2.png b/public/images/pokemon/variant/exp/back/937_2.png deleted file mode 100644 index 7ba1aa09b97..00000000000 Binary files a/public/images/pokemon/variant/exp/back/937_2.png and /dev/null differ diff --git a/public/images/pokemon/variant/exp/back/937_3.json b/public/images/pokemon/variant/exp/back/937_3.json deleted file mode 100644 index c5fff6bd743..00000000000 --- a/public/images/pokemon/variant/exp/back/937_3.json +++ /dev/null @@ -1,650 +0,0 @@ -{ - "textures": [ - { - "image": "937_3.png", - "format": "RGBA8888", - "size": { - "w": 382, - "h": 382 - }, - "scale": 1, - "frames": [ - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 91, - "h": 96 - }, - "frame": { - "x": 91, - "y": 0, - "w": 91, - "h": 96 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 90, - "h": 96 - }, - "frame": { - "x": 182, - "y": 0, - "w": 90, - "h": 96 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 89, - "h": 96 - }, - "frame": { - "x": 272, - "y": 0, - "w": 89, - "h": 96 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 91, - "h": 95 - }, - "frame": { - "x": 0, - "y": 96, - "w": 91, - "h": 95 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 4, - "y": 1, - "w": 89, - "h": 95 - }, - "frame": { - "x": 91, - "y": 96, - "w": 89, - "h": 95 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 180, - "y": 96, - "w": 88, - "h": 96 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 0, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 88, - "h": 96 - }, - "frame": { - "x": 88, - "y": 191, - "w": 88, - "h": 96 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 7, - "y": 0, - "w": 87, - "h": 96 - }, - "frame": { - "x": 176, - "y": 192, - "w": 87, - "h": 96 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 85, - "h": 95 - }, - "frame": { - "x": 0, - "y": 287, - "w": 85, - "h": 95 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 1, - "y": 3, - "w": 85, - "h": 94 - }, - "frame": { - "x": 85, - "y": 287, - "w": 85, - "h": 94 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 82, - "h": 96 - }, - "frame": { - "x": 263, - "y": 192, - "w": 82, - "h": 96 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 8, - "y": 3, - "w": 85, - "h": 93 - }, - "frame": { - "x": 268, - "y": 96, - "w": 85, - "h": 93 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 81, - "h": 94 - }, - "frame": { - "x": 170, - "y": 288, - "w": 81, - "h": 94 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 95, - "h": 97 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 80, - "h": 94 - }, - "frame": { - "x": 251, - "y": 288, - "w": 80, - "h": 94 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:25759b98c1f7867fe6c4ff54c797c3e2:0076c777d18a4f3d780937118dfb6388:1d4b4f8d62307c37457ba974879b47d0$" - } -} \ No newline at end of file diff --git a/public/images/pokemon/variant/exp/back/937_3.png b/public/images/pokemon/variant/exp/back/937_3.png deleted file mode 100644 index ee875356334..00000000000 Binary files a/public/images/pokemon/variant/exp/back/937_3.png and /dev/null differ diff --git a/public/images/pokemon_icons_4v.json b/public/images/pokemon_icons_4v.json index bbaca92c7c7..ffc36e945c4 100644 --- a/public/images/pokemon_icons_4v.json +++ b/public/images/pokemon_icons_4v.json @@ -1312,7 +1312,7 @@ } }, { - "filename": "418_2", + "filename": "417_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -1332,6 +1332,48 @@ "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 + } + }, + { + "filename": "418_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": "418_3", "rotated": false, @@ -1347,8 +1389,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 120, + "x": 0, + "y": 150, "w": 40, "h": 30 } @@ -1368,8 +1410,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 120, + "x": 40, + "y": 150, "w": 40, "h": 30 } @@ -1389,7 +1431,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 150, "w": 40, "h": 30 @@ -1410,7 +1452,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 150, "w": 40, "h": 30 @@ -1431,7 +1473,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 150, "w": 40, "h": 30 @@ -1452,7 +1494,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 150, "w": 40, "h": 30 @@ -1473,7 +1515,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 150, "w": 40, "h": 30 @@ -1494,7 +1536,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 150, "w": 40, "h": 30 @@ -1515,7 +1557,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 150, "w": 40, "h": 30 @@ -1536,7 +1578,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 150, "w": 40, "h": 30 @@ -1557,7 +1599,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 150, "w": 40, "h": 30 @@ -1578,7 +1620,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 150, "w": 40, "h": 30 @@ -1599,7 +1641,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 150, "w": 40, "h": 30 @@ -1620,8 +1662,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 150, + "x": 0, + "y": 180, "w": 40, "h": 30 } @@ -1641,8 +1683,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 150, + "x": 40, + "y": 180, "w": 40, "h": 30 } @@ -1662,7 +1704,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 180, "w": 40, "h": 30 @@ -1683,7 +1725,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 180, "w": 40, "h": 30 @@ -1704,7 +1746,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 180, "w": 40, "h": 30 @@ -1725,7 +1767,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 180, "w": 40, "h": 30 @@ -1746,7 +1788,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 180, "w": 40, "h": 30 @@ -1767,7 +1809,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 180, "w": 40, "h": 30 @@ -1788,7 +1830,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 180, "w": 40, "h": 30 @@ -1809,7 +1851,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 180, "w": 40, "h": 30 @@ -1830,7 +1872,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 180, "w": 40, "h": 30 @@ -1851,7 +1893,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 180, "w": 40, "h": 30 @@ -1872,7 +1914,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 180, "w": 40, "h": 30 @@ -1893,8 +1935,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 180, + "x": 0, + "y": 210, "w": 40, "h": 30 } @@ -1914,8 +1956,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 180, + "x": 40, + "y": 210, "w": 40, "h": 30 } @@ -1935,7 +1977,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 210, "w": 40, "h": 30 @@ -1956,7 +1998,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 210, "w": 40, "h": 30 @@ -1977,7 +2019,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 210, "w": 40, "h": 30 @@ -1998,7 +2040,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 210, "w": 40, "h": 30 @@ -2019,7 +2061,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 210, "w": 40, "h": 30 @@ -2040,7 +2082,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 210, "w": 40, "h": 30 @@ -2061,7 +2103,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 210, "w": 40, "h": 30 @@ -2082,7 +2124,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 210, "w": 40, "h": 30 @@ -2103,7 +2145,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 210, "w": 40, "h": 30 @@ -2124,7 +2166,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 210, "w": 40, "h": 30 @@ -2145,7 +2187,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 210, "w": 40, "h": 30 @@ -2166,8 +2208,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 210, + "x": 0, + "y": 240, "w": 40, "h": 30 } @@ -2187,8 +2229,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 210, + "x": 40, + "y": 240, "w": 40, "h": 30 } @@ -2208,7 +2250,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 240, "w": 40, "h": 30 @@ -2229,7 +2271,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 240, "w": 40, "h": 30 @@ -2250,7 +2292,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 240, "w": 40, "h": 30 @@ -2271,7 +2313,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 240, "w": 40, "h": 30 @@ -2292,7 +2334,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 240, "w": 40, "h": 30 @@ -2313,7 +2355,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 240, "w": 40, "h": 30 @@ -2334,7 +2376,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 240, "w": 40, "h": 30 @@ -2355,7 +2397,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 240, "w": 40, "h": 30 @@ -2376,7 +2418,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 240, "w": 40, "h": 30 @@ -2397,7 +2439,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 240, "w": 40, "h": 30 @@ -2418,7 +2460,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 240, "w": 40, "h": 30 @@ -2439,8 +2481,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 240, + "x": 0, + "y": 270, "w": 40, "h": 30 } @@ -2460,8 +2502,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 240, + "x": 40, + "y": 270, "w": 40, "h": 30 } @@ -2481,7 +2523,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 270, "w": 40, "h": 30 @@ -2502,7 +2544,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 270, "w": 40, "h": 30 @@ -2523,7 +2565,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 270, "w": 40, "h": 30 @@ -2544,7 +2586,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 270, "w": 40, "h": 30 @@ -2565,7 +2607,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 270, "w": 40, "h": 30 @@ -2586,7 +2628,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 270, "w": 40, "h": 30 @@ -2607,7 +2649,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 270, "w": 40, "h": 30 @@ -2628,7 +2670,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 270, "w": 40, "h": 30 @@ -2649,7 +2691,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 270, "w": 40, "h": 30 @@ -2670,7 +2712,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 270, "w": 40, "h": 30 @@ -2691,7 +2733,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 270, "w": 40, "h": 30 @@ -2712,8 +2754,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 270, + "x": 0, + "y": 300, "w": 40, "h": 30 } @@ -2733,8 +2775,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 270, + "x": 40, + "y": 300, "w": 40, "h": 30 } @@ -2754,7 +2796,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 300, "w": 40, "h": 30 @@ -2775,7 +2817,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 300, "w": 40, "h": 30 @@ -2796,7 +2838,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 300, "w": 40, "h": 30 @@ -2817,7 +2859,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 300, "w": 40, "h": 30 @@ -2838,7 +2880,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 300, "w": 40, "h": 30 @@ -2859,7 +2901,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 300, "w": 40, "h": 30 @@ -2880,7 +2922,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 300, "w": 40, "h": 30 @@ -2901,7 +2943,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 300, "w": 40, "h": 30 @@ -2922,7 +2964,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 300, "w": 40, "h": 30 @@ -2943,7 +2985,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 300, "w": 40, "h": 30 @@ -2964,7 +3006,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 300, "w": 40, "h": 30 @@ -2985,8 +3027,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 300, + "x": 0, + "y": 330, "w": 40, "h": 30 } @@ -3006,8 +3048,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 300, + "x": 40, + "y": 330, "w": 40, "h": 30 } @@ -3027,7 +3069,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 330, "w": 40, "h": 30 @@ -3048,7 +3090,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 330, "w": 40, "h": 30 @@ -3069,7 +3111,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 330, "w": 40, "h": 30 @@ -3090,7 +3132,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 330, "w": 40, "h": 30 @@ -3111,7 +3153,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 330, "w": 40, "h": 30 @@ -3132,7 +3174,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 330, "w": 40, "h": 30 @@ -3153,7 +3195,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 330, "w": 40, "h": 30 @@ -3174,7 +3216,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 330, "w": 40, "h": 30 @@ -3195,7 +3237,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 330, "w": 40, "h": 30 @@ -3216,7 +3258,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 330, "w": 40, "h": 30 @@ -3237,7 +3279,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 330, "w": 40, "h": 30 @@ -3258,8 +3300,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 330, + "x": 0, + "y": 360, "w": 40, "h": 30 } @@ -3279,8 +3321,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 330, + "x": 40, + "y": 360, "w": 40, "h": 30 } @@ -3300,7 +3342,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 360, "w": 40, "h": 30 @@ -3321,7 +3363,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 360, "w": 40, "h": 30 @@ -3342,7 +3384,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 360, "w": 40, "h": 30 @@ -3363,7 +3405,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 360, "w": 40, "h": 30 @@ -3384,7 +3426,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 360, "w": 40, "h": 30 @@ -3405,7 +3447,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 360, "w": 40, "h": 30 @@ -3426,7 +3468,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 360, "w": 40, "h": 30 @@ -3447,7 +3489,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 360, "w": 40, "h": 30 @@ -3468,7 +3510,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 360, "w": 40, "h": 30 @@ -3489,7 +3531,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 360, "w": 40, "h": 30 @@ -3510,7 +3552,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 360, "w": 40, "h": 30 @@ -3531,8 +3573,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 360, + "x": 0, + "y": 390, "w": 40, "h": 30 } @@ -3552,8 +3594,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 360, + "x": 40, + "y": 390, "w": 40, "h": 30 } @@ -3573,7 +3615,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 390, "w": 40, "h": 30 @@ -3594,7 +3636,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 390, "w": 40, "h": 30 @@ -3615,7 +3657,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 390, "w": 40, "h": 30 @@ -3636,7 +3678,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 390, "w": 40, "h": 30 @@ -3657,7 +3699,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 390, "w": 40, "h": 30 @@ -3678,7 +3720,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 390, "w": 40, "h": 30 @@ -3699,7 +3741,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 390, "w": 40, "h": 30 @@ -3720,7 +3762,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 390, "w": 40, "h": 30 @@ -3741,7 +3783,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 390, "w": 40, "h": 30 @@ -3762,7 +3804,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 390, "w": 40, "h": 30 @@ -3783,7 +3825,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 390, "w": 40, "h": 30 @@ -3804,8 +3846,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 390, + "x": 0, + "y": 420, "w": 40, "h": 30 } @@ -3825,8 +3867,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 390, + "x": 40, + "y": 420, "w": 40, "h": 30 } @@ -3846,7 +3888,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 420, "w": 40, "h": 30 @@ -3867,7 +3909,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 420, "w": 40, "h": 30 @@ -3888,7 +3930,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 420, "w": 40, "h": 30 @@ -3909,7 +3951,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 420, "w": 40, "h": 30 @@ -3930,7 +3972,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 420, "w": 40, "h": 30 @@ -3951,7 +3993,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 420, "w": 40, "h": 30 @@ -3972,7 +4014,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 420, "w": 40, "h": 30 @@ -3993,7 +4035,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 420, "w": 40, "h": 30 @@ -4014,7 +4056,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 420, "w": 40, "h": 30 @@ -4035,7 +4077,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 420, "w": 40, "h": 30 @@ -4056,7 +4098,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 420, "w": 40, "h": 30 @@ -4077,8 +4119,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 420, + "x": 0, + "y": 450, "w": 40, "h": 30 } @@ -4098,8 +4140,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 420, + "x": 40, + "y": 450, "w": 40, "h": 30 } @@ -4119,7 +4161,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 450, "w": 40, "h": 30 @@ -4140,7 +4182,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 450, "w": 40, "h": 30 @@ -4161,7 +4203,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 450, "w": 40, "h": 30 @@ -4182,7 +4224,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 450, "w": 40, "h": 30 @@ -4203,7 +4245,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 450, "w": 40, "h": 30 @@ -4224,7 +4266,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 450, "w": 40, "h": 30 @@ -4245,7 +4287,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 450, "w": 40, "h": 30 @@ -4266,7 +4308,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 450, "w": 40, "h": 30 @@ -4287,7 +4329,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 450, "w": 40, "h": 30 @@ -4308,7 +4350,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 450, "w": 40, "h": 30 @@ -4329,7 +4371,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 450, "w": 40, "h": 30 @@ -4350,8 +4392,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 450, + "x": 0, + "y": 480, "w": 40, "h": 30 } @@ -4371,8 +4413,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 450, + "x": 40, + "y": 480, "w": 40, "h": 30 } @@ -4392,7 +4434,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 80, "y": 480, "w": 40, "h": 30 @@ -4413,7 +4455,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 120, "y": 480, "w": 40, "h": 30 @@ -4434,7 +4476,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 160, "y": 480, "w": 40, "h": 30 @@ -4455,7 +4497,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 200, "y": 480, "w": 40, "h": 30 @@ -4476,7 +4518,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 240, "y": 480, "w": 40, "h": 30 @@ -4497,7 +4539,7 @@ "h": 30 }, "frame": { - "x": 200, + "x": 280, "y": 480, "w": 40, "h": 30 @@ -4518,7 +4560,7 @@ "h": 30 }, "frame": { - "x": 240, + "x": 320, "y": 480, "w": 40, "h": 30 @@ -4539,7 +4581,7 @@ "h": 30 }, "frame": { - "x": 280, + "x": 360, "y": 480, "w": 40, "h": 30 @@ -4560,7 +4602,7 @@ "h": 30 }, "frame": { - "x": 320, + "x": 400, "y": 480, "w": 40, "h": 30 @@ -4581,7 +4623,7 @@ "h": 30 }, "frame": { - "x": 360, + "x": 440, "y": 480, "w": 40, "h": 30 @@ -4602,7 +4644,7 @@ "h": 30 }, "frame": { - "x": 400, + "x": 480, "y": 480, "w": 40, "h": 30 @@ -4622,48 +4664,6 @@ "w": 40, "h": 30 }, - "frame": { - "x": 440, - "y": 480, - "w": 40, - "h": 30 - } - }, - { - "filename": "489_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": "489_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, "frame": { "x": 0, "y": 510, @@ -4672,7 +4672,7 @@ } }, { - "filename": "490_1", + "filename": "489_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4693,7 +4693,7 @@ } }, { - "filename": "490_2", + "filename": "489_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4714,7 +4714,7 @@ } }, { - "filename": "490_3", + "filename": "490_1", "rotated": false, "trimmed": false, "sourceSize": { @@ -4735,7 +4735,7 @@ } }, { - "filename": "491_2", + "filename": "490_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4756,7 +4756,7 @@ } }, { - "filename": "491_3", + "filename": "490_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4777,7 +4777,7 @@ } }, { - "filename": "492-land_2", + "filename": "491_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4798,7 +4798,7 @@ } }, { - "filename": "492-land_3", + "filename": "491_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4819,7 +4819,7 @@ } }, { - "filename": "492-sky_2", + "filename": "492-land_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4840,7 +4840,7 @@ } }, { - "filename": "492-sky_3", + "filename": "492-land_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4859,6 +4859,48 @@ "w": 40, "h": 30 } + }, + { + "filename": "492-sky_2", + "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 + } + }, + { + "filename": "492-sky_3", + "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 + } } ] } @@ -4866,6 +4908,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:52236a80fa87dc64d12684ac85cf8440:2809a2ce37dd2c24fc872d083bf5a2aa:ebc3f8ec5b2480b298192d752b6e57dc$" + "smartupdate": "$TexturePacker:SmartUpdate:00a4e5499c11f3abdf9f56423bbf4561:6f365ccd1246c9b5ae27e0e440695926:ebc3f8ec5b2480b298192d752b6e57dc$" } } diff --git a/public/images/pokemon_icons_4v.png b/public/images/pokemon_icons_4v.png index 43938ed5095..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_7v.json b/public/images/pokemon_icons_7v.json index d82cc4e3210..6a353fffe94 100644 --- a/public/images/pokemon_icons_7v.json +++ b/public/images/pokemon_icons_7v.json @@ -304,7 +304,7 @@ } }, { - "filename": "746-school_1", + "filename": "746-school_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -325,7 +325,7 @@ } }, { - "filename": "746-school_2", + "filename": "746-school_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -346,7 +346,7 @@ } }, { - "filename": "746_1", + "filename": "746_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -367,7 +367,7 @@ } }, { - "filename": "746_2", + "filename": "746_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3312,6 +3312,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:57eaade41c16d492ffda5339ea142c4d:b96a0f88bd707a9967af73e7bdf13031:d5975df27e1e94206a68aa1fd3c2c8d0$" + "smartupdate": "$TexturePacker:SmartUpdate:0780b00fda53c3fbd0b6e554e89a6818:b96a0f88bd707a9967af73e7bdf13031:d5975df27e1e94206a68aa1fd3c2c8d0$" } } diff --git a/public/images/pokemon_icons_8v.json b/public/images/pokemon_icons_8v.json index 0693e76e9d1..4b1877878a5 100644 --- a/public/images/pokemon_icons_8v.json +++ b/public/images/pokemon_icons_8v.json @@ -514,7 +514,7 @@ } }, { - "filename": "850_2", + "filename": "840_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -535,7 +535,7 @@ } }, { - "filename": "850_3", + "filename": "840_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -556,7 +556,7 @@ } }, { - "filename": "851-gigantamax", + "filename": "841-gigantamax_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -576,6 +576,216 @@ "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, + "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": "850_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": "851-gigantamax", + "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": "851-gigantamax_2", "rotated": false, @@ -591,7 +801,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 360, "y": 60, "w": 40, "h": 30 @@ -612,7 +822,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 400, "y": 60, "w": 40, "h": 30 @@ -633,7 +843,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 440, "y": 60, "w": 40, "h": 30 @@ -654,7 +864,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 480, "y": 60, "w": 40, "h": 30 @@ -675,8 +885,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 60, + "x": 0, + "y": 90, "w": 40, "h": 30 } @@ -696,8 +906,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 60, + "x": 40, + "y": 90, "w": 40, "h": 30 } @@ -717,8 +927,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 60, + "x": 80, + "y": 90, "w": 40, "h": 30 } @@ -738,8 +948,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 60, + "x": 120, + "y": 90, "w": 40, "h": 30 } @@ -759,8 +969,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 60, + "x": 160, + "y": 90, "w": 40, "h": 30 } @@ -780,8 +990,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 60, + "x": 200, + "y": 90, "w": 40, "h": 30 } @@ -801,8 +1011,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 60, + "x": 240, + "y": 90, "w": 40, "h": 30 } @@ -822,8 +1032,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 60, + "x": 280, + "y": 90, "w": 40, "h": 30 } @@ -843,7 +1053,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 320, "y": 90, "w": 40, "h": 30 @@ -864,7 +1074,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 360, "y": 90, "w": 40, "h": 30 @@ -885,7 +1095,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 400, "y": 90, "w": 40, "h": 30 @@ -906,7 +1116,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 440, "y": 90, "w": 40, "h": 30 @@ -927,7 +1137,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 480, "y": 90, "w": 40, "h": 30 @@ -948,8 +1158,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 90, + "x": 0, + "y": 120, "w": 40, "h": 30 } @@ -969,8 +1179,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 90, + "x": 40, + "y": 120, "w": 40, "h": 30 } @@ -990,8 +1200,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 90, + "x": 80, + "y": 120, "w": 40, "h": 30 } @@ -1011,8 +1221,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 90, + "x": 120, + "y": 120, "w": 40, "h": 30 } @@ -1032,8 +1242,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 90, + "x": 160, + "y": 120, "w": 40, "h": 30 } @@ -1053,8 +1263,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 90, + "x": 200, + "y": 120, "w": 40, "h": 30 } @@ -1074,8 +1284,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 90, + "x": 240, + "y": 120, "w": 40, "h": 30 } @@ -1095,8 +1305,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 90, + "x": 280, + "y": 120, "w": 40, "h": 30 } @@ -1116,7 +1326,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 320, "y": 120, "w": 40, "h": 30 @@ -1137,7 +1347,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 360, "y": 120, "w": 40, "h": 30 @@ -1158,7 +1368,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 400, "y": 120, "w": 40, "h": 30 @@ -1179,7 +1389,7 @@ "h": 30 }, "frame": { - "x": 120, + "x": 440, "y": 120, "w": 40, "h": 30 @@ -1200,7 +1410,7 @@ "h": 30 }, "frame": { - "x": 160, + "x": 480, "y": 120, "w": 40, "h": 30 @@ -1221,8 +1431,50 @@ "h": 30 }, "frame": { - "x": 200, - "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": 240, - "y": 120, + "x": 120, + "y": 150, "w": 40, "h": 30 } @@ -1263,8 +1515,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 120, + "x": 160, + "y": 150, "w": 40, "h": 30 } @@ -1284,8 +1536,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 120, + "x": 200, + "y": 150, "w": 40, "h": 30 } @@ -1305,8 +1557,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 120, + "x": 240, + "y": 150, "w": 40, "h": 30 } @@ -1326,8 +1578,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 120, + "x": 280, + "y": 150, "w": 40, "h": 30 } @@ -1347,8 +1599,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 120, + "x": 320, + "y": 150, "w": 40, "h": 30 } @@ -1368,8 +1620,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 120, + "x": 360, + "y": 150, "w": 40, "h": 30 } @@ -1389,7 +1641,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 150, "w": 40, "h": 30 @@ -1410,7 +1662,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 150, "w": 40, "h": 30 @@ -1431,7 +1683,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 150, "w": 40, "h": 30 @@ -1452,8 +1704,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 150, + "x": 0, + "y": 180, "w": 40, "h": 30 } @@ -1473,8 +1725,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 150, + "x": 40, + "y": 180, "w": 40, "h": 30 } @@ -1494,8 +1746,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 150, + "x": 80, + "y": 180, "w": 40, "h": 30 } @@ -1515,8 +1767,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 150, + "x": 120, + "y": 180, "w": 40, "h": 30 } @@ -1536,8 +1788,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 150, + "x": 160, + "y": 180, "w": 40, "h": 30 } @@ -1557,8 +1809,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 150, + "x": 200, + "y": 180, "w": 40, "h": 30 } @@ -1578,8 +1830,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 150, + "x": 240, + "y": 180, "w": 40, "h": 30 } @@ -1599,8 +1851,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 150, + "x": 280, + "y": 180, "w": 40, "h": 30 } @@ -1620,8 +1872,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 150, + "x": 320, + "y": 180, "w": 40, "h": 30 } @@ -1641,8 +1893,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 150, + "x": 360, + "y": 180, "w": 40, "h": 30 } @@ -1662,7 +1914,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 180, "w": 40, "h": 30 @@ -1683,7 +1935,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 180, "w": 40, "h": 30 @@ -1704,7 +1956,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 180, "w": 40, "h": 30 @@ -1725,8 +1977,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 180, + "x": 0, + "y": 210, "w": 40, "h": 30 } @@ -1746,8 +1998,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 180, + "x": 40, + "y": 210, "w": 40, "h": 30 } @@ -1767,8 +2019,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 180, + "x": 80, + "y": 210, "w": 40, "h": 30 } @@ -1788,8 +2040,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 180, + "x": 120, + "y": 210, "w": 40, "h": 30 } @@ -1809,8 +2061,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 180, + "x": 160, + "y": 210, "w": 40, "h": 30 } @@ -1830,8 +2082,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 180, + "x": 200, + "y": 210, "w": 40, "h": 30 } @@ -1851,8 +2103,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 180, + "x": 240, + "y": 210, "w": 40, "h": 30 } @@ -1872,8 +2124,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 180, + "x": 280, + "y": 210, "w": 40, "h": 30 } @@ -1893,8 +2145,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 180, + "x": 320, + "y": 210, "w": 40, "h": 30 } @@ -1914,8 +2166,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 180, + "x": 360, + "y": 210, "w": 40, "h": 30 } @@ -1935,7 +2187,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 210, "w": 40, "h": 30 @@ -1956,7 +2208,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 210, "w": 40, "h": 30 @@ -1977,7 +2229,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 210, "w": 40, "h": 30 @@ -1998,8 +2250,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 210, + "x": 0, + "y": 240, "w": 40, "h": 30 } @@ -2019,8 +2271,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 210, + "x": 40, + "y": 240, "w": 40, "h": 30 } @@ -2040,8 +2292,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 210, + "x": 80, + "y": 240, "w": 40, "h": 30 } @@ -2061,8 +2313,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 210, + "x": 120, + "y": 240, "w": 40, "h": 30 } @@ -2082,8 +2334,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 210, + "x": 160, + "y": 240, "w": 40, "h": 30 } @@ -2103,8 +2355,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 210, + "x": 200, + "y": 240, "w": 40, "h": 30 } @@ -2124,8 +2376,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 210, + "x": 240, + "y": 240, "w": 40, "h": 30 } @@ -2145,8 +2397,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 210, + "x": 280, + "y": 240, "w": 40, "h": 30 } @@ -2166,8 +2418,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 210, + "x": 320, + "y": 240, "w": 40, "h": 30 } @@ -2187,8 +2439,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 210, + "x": 360, + "y": 240, "w": 40, "h": 30 } @@ -2208,7 +2460,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 240, "w": 40, "h": 30 @@ -2229,7 +2481,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 240, "w": 40, "h": 30 @@ -2250,7 +2502,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 240, "w": 40, "h": 30 @@ -2271,8 +2523,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 240, + "x": 0, + "y": 270, "w": 40, "h": 30 } @@ -2292,8 +2544,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 240, + "x": 40, + "y": 270, "w": 40, "h": 30 } @@ -2313,8 +2565,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 240, + "x": 80, + "y": 270, "w": 40, "h": 30 } @@ -2334,8 +2586,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 240, + "x": 120, + "y": 270, "w": 40, "h": 30 } @@ -2355,8 +2607,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 240, + "x": 160, + "y": 270, "w": 40, "h": 30 } @@ -2376,8 +2628,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 240, + "x": 200, + "y": 270, "w": 40, "h": 30 } @@ -2397,8 +2649,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 240, + "x": 240, + "y": 270, "w": 40, "h": 30 } @@ -2418,8 +2670,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 240, + "x": 280, + "y": 270, "w": 40, "h": 30 } @@ -2439,8 +2691,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 240, + "x": 320, + "y": 270, "w": 40, "h": 30 } @@ -2460,8 +2712,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 240, + "x": 360, + "y": 270, "w": 40, "h": 30 } @@ -2481,7 +2733,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 270, "w": 40, "h": 30 @@ -2502,7 +2754,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 270, "w": 40, "h": 30 @@ -2523,7 +2775,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 270, "w": 40, "h": 30 @@ -2544,8 +2796,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 270, + "x": 0, + "y": 300, "w": 40, "h": 30 } @@ -2565,8 +2817,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 270, + "x": 40, + "y": 300, "w": 40, "h": 30 } @@ -2586,8 +2838,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 270, + "x": 80, + "y": 300, "w": 40, "h": 30 } @@ -2607,8 +2859,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 270, + "x": 120, + "y": 300, "w": 40, "h": 30 } @@ -2628,8 +2880,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 270, + "x": 160, + "y": 300, "w": 40, "h": 30 } @@ -2649,8 +2901,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 270, + "x": 200, + "y": 300, "w": 40, "h": 30 } @@ -2670,8 +2922,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 270, + "x": 240, + "y": 300, "w": 40, "h": 30 } @@ -2691,8 +2943,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 270, + "x": 280, + "y": 300, "w": 40, "h": 30 } @@ -2712,8 +2964,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 270, + "x": 320, + "y": 300, "w": 40, "h": 30 } @@ -2733,8 +2985,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 270, + "x": 360, + "y": 300, "w": 40, "h": 30 } @@ -2754,7 +3006,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 300, "w": 40, "h": 30 @@ -2775,7 +3027,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 300, "w": 40, "h": 30 @@ -2796,7 +3048,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 300, "w": 40, "h": 30 @@ -2817,8 +3069,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 300, + "x": 0, + "y": 330, "w": 40, "h": 30 } @@ -2838,8 +3090,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 300, + "x": 40, + "y": 330, "w": 40, "h": 30 } @@ -2859,8 +3111,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 300, + "x": 80, + "y": 330, "w": 40, "h": 30 } @@ -2880,8 +3132,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 300, + "x": 120, + "y": 330, "w": 40, "h": 30 } @@ -2901,8 +3153,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 300, + "x": 160, + "y": 330, "w": 40, "h": 30 } @@ -2922,8 +3174,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 300, + "x": 200, + "y": 330, "w": 40, "h": 30 } @@ -2943,8 +3195,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 300, + "x": 240, + "y": 330, "w": 40, "h": 30 } @@ -2964,8 +3216,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 300, + "x": 280, + "y": 330, "w": 40, "h": 30 } @@ -2985,8 +3237,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 300, + "x": 320, + "y": 330, "w": 40, "h": 30 } @@ -3006,8 +3258,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 300, + "x": 360, + "y": 330, "w": 40, "h": 30 } @@ -3027,7 +3279,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 330, "w": 40, "h": 30 @@ -3048,7 +3300,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 330, "w": 40, "h": 30 @@ -3069,7 +3321,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 330, "w": 40, "h": 30 @@ -3090,8 +3342,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 330, + "x": 0, + "y": 360, "w": 40, "h": 30 } @@ -3111,8 +3363,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 330, + "x": 40, + "y": 360, "w": 40, "h": 30 } @@ -3132,8 +3384,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 330, + "x": 80, + "y": 360, "w": 40, "h": 30 } @@ -3153,8 +3405,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 330, + "x": 120, + "y": 360, "w": 40, "h": 30 } @@ -3174,8 +3426,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 330, + "x": 160, + "y": 360, "w": 40, "h": 30 } @@ -3195,8 +3447,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 330, + "x": 200, + "y": 360, "w": 40, "h": 30 } @@ -3216,8 +3468,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 330, + "x": 240, + "y": 360, "w": 40, "h": 30 } @@ -3237,8 +3489,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 330, + "x": 280, + "y": 360, "w": 40, "h": 30 } @@ -3258,8 +3510,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 330, + "x": 320, + "y": 360, "w": 40, "h": 30 } @@ -3279,8 +3531,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 330, + "x": 360, + "y": 360, "w": 40, "h": 30 } @@ -3300,7 +3552,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 360, "w": 40, "h": 30 @@ -3321,7 +3573,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 360, "w": 40, "h": 30 @@ -3342,7 +3594,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 360, "w": 40, "h": 30 @@ -3363,8 +3615,8 @@ "h": 30 }, "frame": { - "x": 120, - "y": 360, + "x": 0, + "y": 390, "w": 40, "h": 30 } @@ -3384,8 +3636,8 @@ "h": 30 }, "frame": { - "x": 160, - "y": 360, + "x": 40, + "y": 390, "w": 40, "h": 30 } @@ -3405,8 +3657,8 @@ "h": 30 }, "frame": { - "x": 200, - "y": 360, + "x": 80, + "y": 390, "w": 40, "h": 30 } @@ -3426,8 +3678,8 @@ "h": 30 }, "frame": { - "x": 240, - "y": 360, + "x": 120, + "y": 390, "w": 40, "h": 30 } @@ -3447,8 +3699,8 @@ "h": 30 }, "frame": { - "x": 280, - "y": 360, + "x": 160, + "y": 390, "w": 40, "h": 30 } @@ -3468,8 +3720,8 @@ "h": 30 }, "frame": { - "x": 320, - "y": 360, + "x": 200, + "y": 390, "w": 40, "h": 30 } @@ -3489,8 +3741,8 @@ "h": 30 }, "frame": { - "x": 360, - "y": 360, + "x": 240, + "y": 390, "w": 40, "h": 30 } @@ -3510,8 +3762,8 @@ "h": 30 }, "frame": { - "x": 400, - "y": 360, + "x": 280, + "y": 390, "w": 40, "h": 30 } @@ -3531,8 +3783,8 @@ "h": 30 }, "frame": { - "x": 440, - "y": 360, + "x": 320, + "y": 390, "w": 40, "h": 30 } @@ -3552,8 +3804,8 @@ "h": 30 }, "frame": { - "x": 480, - "y": 360, + "x": 360, + "y": 390, "w": 40, "h": 30 } @@ -3573,7 +3825,7 @@ "h": 30 }, "frame": { - "x": 0, + "x": 400, "y": 390, "w": 40, "h": 30 @@ -3594,7 +3846,7 @@ "h": 30 }, "frame": { - "x": 40, + "x": 440, "y": 390, "w": 40, "h": 30 @@ -3615,7 +3867,7 @@ "h": 30 }, "frame": { - "x": 80, + "x": 480, "y": 390, "w": 40, "h": 30 @@ -3635,216 +3887,6 @@ "w": 40, "h": 30 }, - "frame": { - "x": 120, - "y": 390, - "w": 40, - "h": 30 - } - }, - { - "filename": "4562_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": "4562_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": "6100_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": "6100_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 - } - }, - { - "filename": "6101_2", - "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 - } - }, - { - "filename": "6101_3", - "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 - } - }, - { - "filename": "6215_2", - "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 - } - }, - { - "filename": "6215_3", - "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 - } - }, - { - "filename": "6503_2", - "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 - } - }, - { - "filename": "6503_3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 40, - "h": 30 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 40, - "h": 30 - }, "frame": { "x": 0, "y": 420, @@ -3853,7 +3895,7 @@ } }, { - "filename": "6549_2", + "filename": "4562_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3874,7 +3916,7 @@ } }, { - "filename": "6549_3", + "filename": "4562_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3895,7 +3937,7 @@ } }, { - "filename": "6570_2", + "filename": "6100_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3916,7 +3958,7 @@ } }, { - "filename": "6570_3", + "filename": "6100_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3937,7 +3979,7 @@ } }, { - "filename": "6571_2", + "filename": "6101_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -3958,7 +4000,7 @@ } }, { - "filename": "6571_3", + "filename": "6101_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -3979,7 +4021,7 @@ } }, { - "filename": "6705_2", + "filename": "6215_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4000,7 +4042,7 @@ } }, { - "filename": "6705_3", + "filename": "6215_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4021,7 +4063,7 @@ } }, { - "filename": "6706_2", + "filename": "6503_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4042,7 +4084,7 @@ } }, { - "filename": "6706_3", + "filename": "6503_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4063,7 +4105,7 @@ } }, { - "filename": "6713_2", + "filename": "6549_2", "rotated": false, "trimmed": false, "sourceSize": { @@ -4084,7 +4126,7 @@ } }, { - "filename": "6713_3", + "filename": "6549_3", "rotated": false, "trimmed": false, "sourceSize": { @@ -4105,45 +4147,213 @@ } }, { - "filename": "871_1", + "filename": "6570_2", "rotated": false, "trimmed": false, "sourceSize": { - "w": 43, - "h": 43 + "w": 40, + "h": 30 }, "spriteSourceSize": { "x": 0, "y": 0, - "w": 43, - "h": 43 + "w": 40, + "h": 30 }, "frame": { "x": 0, "y": 450, - "w": 43, - "h": 43 + "w": 40, + "h": 30 } }, { - "filename": "871_2", + "filename": "6570_3", "rotated": false, "trimmed": false, "sourceSize": { - "w": 43, - "h": 43 + "w": 40, + "h": 30 }, "spriteSourceSize": { "x": 0, "y": 0, - "w": 43, - "h": 43 + "w": 40, + "h": 30 }, "frame": { - "x": 43, + "x": 40, "y": 450, - "w": 43, - "h": 43 + "w": 40, + "h": 30 + } + }, + { + "filename": "6571_2", + "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 + } + }, + { + "filename": "6571_3", + "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 + } + }, + { + "filename": "6705_2", + "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": "6705_3", + "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": "6706_2", + "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": "6706_3", + "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": "6713_2", + "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": "6713_3", + "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 } } ] @@ -4152,6 +4362,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:b19669ded7d4ac74c9b66946a18a8ddb:63ad6fc80832ef3907fc171ae5297b3e:ec5f05e7f30cd98f74db0c2326109fd3$" + "smartupdate": "$TexturePacker:SmartUpdate:8408a38565cd946fb1dcfa1e942bfa70:5d4e77c515d77c2e94d454fb7c52d9fc:ec5f05e7f30cd98f74db0c2326109fd3$" } } diff --git a/public/images/pokemon_icons_8v.png b/public/images/pokemon_icons_8v.png index 1027406c9f1..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 57159a3fbfb..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:c01add1e11aabd2f8931110a67a9222b: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 f3530abe569..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 833dc40ec74..42cd5cf577f 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit 833dc40ec7409031fcea147ccbc45ec9c0ba0213 +Subproject commit 42cd5cf577f475c22bc82d55e7ca358eb4f3184f diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 8fe6c85263d..5835ee08af5 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -7,7 +7,6 @@ import type PokemonSpecies from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species"; import { fixedInt, - deepMergeObjects, getIvsFromId, randSeedInt, getEnumValues, @@ -19,6 +18,7 @@ import { BooleanHolder, type Constructor, } from "#app/utils/common"; +import { deepMergeSpriteData } from "#app/utils/data"; import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier"; import { ConsumableModifier, @@ -787,7 +787,7 @@ export default class BattleScene extends SceneBase { return; } const expVariantData = await this.cachedFetch("./images/pokemon/variant/_exp_masterlist.json").then(r => r.json()); - deepMergeObjects(variantData, expVariantData); + deepMergeSpriteData(variantData, expVariantData); } cachedFetch(url: string, init?: RequestInit): Promise { @@ -835,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. @@ -850,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` */ @@ -873,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); @@ -1044,32 +1045,33 @@ export default class BattleScene extends SceneBase { y: number, originX = 0.5, originY = 0.5, - ignoreOverride = false, + ignoreOverride = true, + useIllusion = false, ): Phaser.GameObjects.Container { const container = this.add.container(x, y); container.setName(`${pokemon.name}-icon`); - const icon = this.add.sprite(0, 0, pokemon.getIconAtlasKey(ignoreOverride)); + const icon = this.add.sprite(0, 0, pokemon.getIconAtlasKey(ignoreOverride, useIllusion)); icon.setName(`sprite-${pokemon.name}-icon`); - icon.setFrame(pokemon.getIconId(true)); + icon.setFrame(pokemon.getIconId(ignoreOverride, useIllusion)); // Temporary fix to show pokemon's default icon if variant icon doesn't exist - if (icon.frame.name !== pokemon.getIconId(true)) { + if (icon.frame.name !== pokemon.getIconId(ignoreOverride, useIllusion)) { console.log(`${pokemon.name}'s variant icon does not exist. Replacing with default.`); const temp = pokemon.shiny; pokemon.shiny = false; - icon.setTexture(pokemon.getIconAtlasKey(ignoreOverride)); - icon.setFrame(pokemon.getIconId(true)); + icon.setTexture(pokemon.getIconAtlasKey(ignoreOverride, useIllusion)); + icon.setFrame(pokemon.getIconId(true, useIllusion)); pokemon.shiny = temp; } icon.setOrigin(0.5, 0); container.add(icon); - if (pokemon.isFusion(true)) { - const fusionIcon = this.add.sprite(0, 0, pokemon.getFusionIconAtlasKey(ignoreOverride)); + if (pokemon.isFusion(useIllusion)) { + const fusionIcon = this.add.sprite(0, 0, pokemon.getFusionIconAtlasKey(ignoreOverride, useIllusion)); fusionIcon.setName("sprite-fusion-icon"); fusionIcon.setOrigin(0.5, 0); - fusionIcon.setFrame(pokemon.getFusionIconId(true)); + fusionIcon.setFrame(pokemon.getFusionIconId(ignoreOverride, useIllusion)); const originalWidth = icon.width; const originalHeight = icon.height; @@ -1307,14 +1309,13 @@ export default class BattleScene extends SceneBase { return isNewBiome; } - // TODO: ...this never actually returns `null`, right? 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; @@ -1496,7 +1497,7 @@ export default class BattleScene extends SceneBase { }); for (const pokemon of this.getPlayerParty()) { - pokemon.resetBattleData(); + pokemon.resetBattleAndWaveData(); pokemon.resetTera(); applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon); if ( @@ -2920,7 +2921,10 @@ export default class BattleScene extends SceneBase { instant?: boolean, cost?: number, ): boolean { - if (!modifier) { + // We check against modifier.type to stop a bug related to loading in a pokemon that has a form change item, which prior to some patch + // that changed form change modifiers worked, had previously set the `type` field to null. + // TODO: This is not the right place to check for this; it should ideally go in a session migrator. + if (!modifier || !modifier.type) { return false; } let success = false; @@ -3264,6 +3268,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++) { @@ -3316,8 +3321,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; diff --git a/src/data/abilities/ab-attrs/ab-attr.ts b/src/data/abilities/ab-attrs/ab-attr.ts index a653c3f372d..24fbb6dc338 100644 --- a/src/data/abilities/ab-attrs/ab-attr.ts +++ b/src/data/abilities/ab-attrs/ab-attr.ts @@ -6,6 +6,10 @@ 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; } diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 6e3f4c77f87..ff86937622b 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -43,10 +43,9 @@ 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 { 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"; @@ -60,6 +59,11 @@ 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"; // Type imports @@ -846,14 +850,14 @@ 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)]; + const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randBattleSeedInt(this.effects.length)]; return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && !attacker.status - && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance) + && (this.chance === -1 || pokemon.randBattleSeedInt(100) < this.chance) && attacker.canSetStatus(effect, true, false, pokemon); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { - const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; + const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randBattleSeedInt(this.effects.length)]; attacker.trySetStatus(effect, true, pokemon); } } @@ -887,7 +891,7 @@ 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.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && pokemon.randSeedInt(100) < this.chance + return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && pokemon.randBattleSeedInt(100) < this.chance && attacker.canAddTag(this.tagType); } @@ -1064,7 +1068,7 @@ 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.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance); + && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && (this.chance === -1 || pokemon.randBattleSeedInt(100) < this.chance); } override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { @@ -1737,7 +1741,7 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { const heldItems = this.getTargetHeldItems(defender).filter((i) => i.isTransferable); if (heldItems.length) { // Ensure that the stolen item in testing is the same as when the effect is applied - this.stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; + this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; if (globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon)) { return true; } @@ -1758,7 +1762,7 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { ): void { const heldItems = this.getTargetHeldItems(defender).filter((i) => i.isTransferable); if (!this.stolenItem) { - this.stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; + this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; } if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) { globalScene.queueMessage( @@ -1795,9 +1799,9 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr { if ( super.canApplyPostAttack(pokemon, passive, simulated, attacker, move, hitResult, args) && (simulated || !attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker - && (!this.contactRequired || move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) + && (!this.contactRequired || move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})) && pokemon.randBattleSeedInt(100) < this.chance && !pokemon.status) ) { - const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; + const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randBattleSeedInt(this.effects.length)]; return simulated || attacker.canSetStatus(effect, true, false, pokemon); } @@ -1805,7 +1809,7 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr { } applyPostAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): void { - const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; + const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randBattleSeedInt(this.effects.length)]; attacker.trySetStatus(effect, true, pokemon); } } @@ -1835,12 +1839,12 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr { return super.canApplyPostAttack(pokemon, passive, simulated, attacker, move, hitResult, args) && !attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker && (!this.contactRequired || move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})) && - pokemon.randSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status; + pokemon.randBattleSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status; } override applyPostAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): void { if (!simulated) { - const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; + const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randBattleSeedInt(this.effects.length)]; attacker.addTag(effect); } } @@ -1864,7 +1868,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { ) { const heldItems = this.getTargetHeldItems(attacker).filter((i) => i.isTransferable); if (heldItems.length) { - this.stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; + this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; if (globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon)) { return true; } @@ -1885,7 +1889,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { const heldItems = this.getTargetHeldItems(attacker).filter((i) => i.isTransferable); if (!this.stolenItem) { - this.stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; + this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; } if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) { globalScene.queueMessage( @@ -2675,7 +2679,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() { @@ -2710,7 +2714,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { const targets = pokemon.getOpponents(); const target = this.getTarget(targets); - if (!!target.summonData?.illusion) { + if (target.summonData.illusion) { return false; } @@ -3167,7 +3171,7 @@ export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr { */ override applyPostAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): void { if (!simulated) { - defender.addTag(BattlerTagType.CONFUSED, pokemon.randSeedIntRange(2, 5), move.id, defender.id); + defender.addTag(BattlerTagType.CONFUSED, pokemon.randBattleSeedIntRange(2, 5), move.id, defender.id); } } } @@ -3292,13 +3296,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; @@ -3315,7 +3319,7 @@ 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: BooleanHolder, args: [Pokemon, ...any]): boolean { const target = args[0]; @@ -3451,7 +3455,7 @@ export class BonusCritAbAttr extends AbAttr { /** * 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 @@ -3604,7 +3608,7 @@ export class PreWeatherEffectAbAttr extends AbAttr { args: any[]): boolean { return true; } - + applyPreWeatherEffect( pokemon: Pokemon, passive: boolean, @@ -3657,14 +3661,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; @@ -3675,7 +3675,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; @@ -3745,7 +3745,7 @@ function getAnticipationCondition(): AbAttrCondition { */ function getOncePerBattleCondition(ability: Abilities): AbAttrCondition { return (pokemon: Pokemon) => { - return !pokemon.battleData?.abilitiesApplied.includes(ability); + return !pokemon.waveData.abilitiesApplied.has(ability); }; } @@ -4034,7 +4034,7 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr { /** * 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; @@ -4066,79 +4066,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 = 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() { @@ -4161,12 +4235,12 @@ export class MoodyAbAttr extends PostTurnAbAttr { if (!simulated) { if (canRaise.length > 0) { - const raisedStat = canRaise[pokemon.randSeedInt(canRaise.length)]; + const raisedStat = canRaise[pokemon.randBattleSeedInt(canRaise.length)]; canLower = canRaise.filter(s => s !== raisedStat); globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ raisedStat ], 2)); } if (canLower.length > 0) { - const loweredStat = canLower[pokemon.randSeedInt(canLower.length)]; + const loweredStat = canLower[pokemon.randBattleSeedInt(canLower.length)]; globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ loweredStat ], -1)); } } @@ -4232,7 +4306,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 @@ -4414,7 +4488,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 { @@ -4503,8 +4577,19 @@ export class DoubleBerryEffectAbAttr extends AbAttr { } } +/** + * 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: 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; } } @@ -4526,17 +4611,19 @@ export class HealFromBerryUseAbAttr extends AbAttr { } 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(), - 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 ) ); - } } } @@ -4568,7 +4655,8 @@ export class CheckTrappedAbAttr extends AbAttr { simulated: boolean, trapped: BooleanHolder, otherPokemon: Pokemon, - args: any[]): boolean { + args: any[], + ): boolean { return true; } @@ -5091,7 +5179,7 @@ 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 */ @@ -5176,15 +5264,14 @@ export class IllusionPreSummonAbAttr extends PreSummonAbAttr { } override canApplyPreSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { - pokemon.initSummondata() - if(pokemon.hasTrainer()){ + 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 ( + if ( lastPokemon === pokemon || ((speciesId === Species.OGERPON || speciesId === Species.TERAPAGOS) && (lastPokemon.isTerastallized || pokemon.isTerastallized)) ) { @@ -5221,7 +5308,7 @@ export class PostDefendIllusionBreakAbAttr extends PostDefendAbAttr { 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 + return breakIllusion.includes(hitResult) && !!pokemon.summonData.illusion } } @@ -5262,7 +5349,7 @@ export class BypassSpeedChanceAbAttr extends AbAttr { const isCommandFight = turnCommand?.command === Command.FIGHT; const move = turnCommand?.move?.move ? allMoves[turnCommand.move.move] : null; const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL; - return !simulated && !bypassSpeed.value && pokemon.randSeedInt(100) < this.chance && isCommandFight && isDamageMove; + return !simulated && !bypassSpeed.value && pokemon.randBattleSeedInt(100) < this.chance && isCommandFight && isDamageMove; } /** @@ -5442,11 +5529,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(); @@ -5637,6 +5721,7 @@ export class PostDamageForceSwitchAbAttr extends PostDamageAbAttr { this.hpRatio = hpRatio; } + // TODO: Refactor to use more early returns public override canApplyPostDamage( pokemon: Pokemon, damage: number, @@ -5664,6 +5749,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 @@ -6326,17 +6412,14 @@ export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, 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 => @@ -6784,8 +6867,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) ) @@ -6824,6 +6906,8 @@ export function initAbilities() { .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() @@ -6907,7 +6991,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(), @@ -7153,7 +7237,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)), @@ -7368,7 +7452,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 ff9e4068292..19c94a8a045 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -768,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; } } @@ -962,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/egg-moves.ts b/src/data/balance/egg-moves.ts index 47898e9e885..289ac60bcc5 100644 --- a/src/data/balance/egg-moves.ts +++ b/src/data/balance/egg-moves.ts @@ -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.CLOSE_COMBAT, Moves.STONE_AXE, Moves.SWORDS_DANCE ], + [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 ], @@ -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,7 +436,7 @@ 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 ], diff --git a/src/data/balance/signature-species.ts b/src/data/balance/signature-species.ts index fb8f33d4435..04749a67521 100644 --- a/src/data/balance/signature-species.ts +++ b/src/data/balance/signature-species.ts @@ -8,11 +8,11 @@ export type SignatureSpecies = { * 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 `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. */ diff --git a/src/data/balance/tms.ts b/src/data/balance/tms.ts index 69aef9b135d..06d191c3b2a 100644 --- a/src/data/balance/tms.ts +++ b/src/data/balance/tms.ts @@ -19057,8 +19057,15 @@ export const tmSpecies: TmSpecies = { Species.SLAKING, Species.HARIYAMA, Species.NOSEPASS, + Species.ARON, + Species.LAIRON, + Species.AGGRON, + Species.ELECTRIKE, + Species.MANECTRIC, Species.GULPIN, Species.SWALOT, + Species.WAILMER, + Species.WAILORD, Species.NUMEL, Species.CAMERUPT, Species.TORKOAL, @@ -19067,18 +19074,28 @@ export const tmSpecies: TmSpecies = { Species.ZANGOOSE, Species.SEVIPER, Species.WHISCASH, + Species.LILEEP, + Species.CRADILY, + Species.ANORITH, + Species.ARMALDO, Species.SHUPPET, Species.BANETTE, Species.DUSKULL, Species.DUSCLOPS, Species.TROPIUS, Species.CHIMECHO, + Species.ABSOL, + Species.SPHEAL, + Species.SEALEO, + Species.WALREIN, Species.REGIROCK, Species.REGICE, Species.REGISTEEL, Species.TURTWIG, Species.GROTLE, Species.TORTERRA, + Species.BIDOOF, + Species.BIBAREL, Species.CRANIDOS, Species.RAMPARDOS, Species.SHIELDON, @@ -19120,6 +19137,11 @@ export const tmSpecies: TmSpecies = { Species.TEPIG, Species.PIGNITE, Species.EMBOAR, + Species.MUNNA, + Species.MUSHARNA, + Species.ROGGENROLA, + Species.BOLDORE, + Species.GIGALITH, Species.DRILBUR, Species.EXCADRILL, Species.TIMBURR, @@ -19128,28 +19150,44 @@ export const tmSpecies: TmSpecies = { Species.SANDILE, Species.KROKOROK, Species.KROOKODILE, + Species.DWEBBLE, + Species.CRUSTLE, Species.SCRAGGY, Species.SCRAFTY, Species.YAMASK, - Species.COFAGRIGUS, + Species.COFAGRIGUS, + Species.TRUBBISH, + Species.GARBODOR, Species.SAWSBUCK, + Species.FERROSEED, + Species.FERROTHORN, Species.LITWICK, Species.LAMPENT, Species.CHANDELURE, Species.BEARTIC, + Species.SHELMET, + Species.ACCELGOR, + Species.STUNFISK, Species.GOLETT, Species.GOLURK, + Species.HEATMOR, Species.CHESPIN, Species.QUILLADIN, Species.CHESNAUGHT, + Species.TYRUNT, + Species.TYRANTRUM, Species.SYLVEON, Species.GOOMY, Species.SLIGGOO, Species.GOODRA, Species.PHANTUMP, Species.TREVENANT, + Species.PUMPKABOO, + Species.GOURGEIST, Species.BERGMITE, Species.AVALUGG, + Species.ROWLET, + Species.DARTRIX, Species.DECIDUEYE, Species.GUMSHOOS, Species.MUDBRAY, @@ -19157,7 +19195,9 @@ export const tmSpecies: TmSpecies = { Species.PASSIMIAN, Species.SANDYGAST, Species.PALOSSAND, + Species.PYUKUMUKU, Species.KOMALA, + Species.TURTONATOR, Species.MIMIKYU, Species.SKWOVET, Species.GREEDENT, @@ -19169,6 +19209,7 @@ export const tmSpecies: TmSpecies = { Species.SINISTEA, Species.POLTEAGEIST, Species.PERRSERKER, + Species.CURSOLA, Species.RUNERIGUS, Species.PINCURCHIN, Species.STONJOURNER, @@ -19236,6 +19277,7 @@ export const tmSpecies: TmSpecies = { Species.GALAR_WEEZING, Species.GALAR_SLOWKING, Species.GALAR_YAMASK, + Species.GALAR_STUNFISK, Species.HISUI_ELECTRODE, Species.HISUI_TYPHLOSION, Species.HISUI_QWILFISH, @@ -67062,7 +67104,7 @@ export const tmSpecies: TmSpecies = { Species.CHEWTLE, Species.DREDNAW, Species.YAMPER, - Species.BOLTUND, + Species.BOLTUND, Species.ROLYCOLY, Species.CARKOL, Species.COALOSSAL, @@ -67079,7 +67121,7 @@ export const tmSpecies: TmSpecies = { Species.SIZZLIPEDE, Species.CENTISKORCH, Species.CLOBBOPUS, - Species.GRAPPLOCT, + Species.GRAPPLOCT, Species.SINISTEA, Species.POLTEAGEIST, Species.HATENNA, diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index 0999e9db6ff..454bd40130c 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -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; diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index ee41f0435b9..34fdd5409c8 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1,4 +1,5 @@ import { globalScene } from "#app/global-scene"; +import Overrides from "#app/overrides"; import { applyAbAttrs, BlockNonDirectDamageAbAttr, @@ -91,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; } @@ -108,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; @@ -120,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; @@ -140,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( @@ -746,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.randBattleSeedInt(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.randBattleSeedIntRange(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 { @@ -882,7 +890,7 @@ export class InfatuatedTag extends BattlerTag { ); globalScene.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT)); - if (pokemon.randSeedInt(2)) { + if (pokemon.randBattleSeedInt(2)) { globalScene.queueMessage( i18next.t("battlerTags:infatuatedLapseImmobilize", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), @@ -1111,14 +1119,14 @@ export class FrenzyTag extends BattlerTag { if (this.turnCount < 2) { // Only add CONFUSED tag if a disruption occurs on the final confusion-inducing turn of FRENZY - pokemon.addTag(BattlerTagType.CONFUSED, pokemon.randSeedIntRange(2, 4)); + pokemon.addTag(BattlerTagType.CONFUSED, pokemon.randBattleSeedIntRange(2, 4)); } } } /** - * 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; @@ -1133,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; diff --git a/src/data/berry.ts b/src/data/berry.ts index 22950c0beca..ecc3e92ca64 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -5,10 +5,8 @@ import { getStatusEffectHealText } from "./status-effect"; import { NumberHolder, toDmgValue, randSeedInt } from "#app/utils/common"; import { DoubleBerryEffectAbAttr, - PostItemLostAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs, - applyPostItemLostAbAttrs, } from "./abilities/ability"; import i18next from "i18next"; import { BattlerTagType } from "#enums/battler-tag-type"; @@ -70,97 +68,94 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate { } } -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 NumberHolder(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 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 = randSeedInt(Stat.SPD, Stat.ATK); - const stages = new 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 7388f397c7e..b4b8db2cc10 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -1,4 +1,5 @@ -import { BooleanHolder, type NumberHolder, randSeedItem, deepCopy } from "#app/utils/common"; +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"; diff --git a/src/data/custom-pokemon-data.ts b/src/data/custom-pokemon-data.ts index 704835e9dbc..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/common"; 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/egg.ts b/src/data/egg.ts index 55a253e843f..0b7733bf199 100644 --- a/src/data/egg.ts +++ b/src/data/egg.ts @@ -598,7 +598,7 @@ export class Egg { } private getEggTier(): EggTier { - return speciesEggTiers[this.species]; + return speciesEggTiers[this.species] ?? EggTier.COMMON; } //// diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 29542b54f6d..b190729621c 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -1591,7 +1591,7 @@ export class RandomLevelDamageAttr extends FixedDamageAttr { } getDamage(user: Pokemon, target: Pokemon, move: Move): number { - return toDmgValue(user.level * (user.randSeedIntRange(50, 150) * 0.01)); + return toDmgValue(user.level * (user.randBattleSeedIntRange(50, 150) * 0.01)); } } @@ -2352,7 +2352,7 @@ export class MultiHitAttr extends MoveAttr { switch (this.multiHitType) { case MultiHitType._2_TO_5: { - const rand = user.randSeedInt(20); + const rand = user.randBattleSeedInt(20); const hitValue = new NumberHolder(rand); applyAbAttrs(MaxMultiHitAbAttr, user, null, false, hitValue); if (hitValue.value >= 13) { @@ -2453,14 +2453,15 @@ export class StatusEffectAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true); - const statusCheck = moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance; + const statusCheck = moveChance < 0 || moveChance === 100 || user.randBattleSeedInt(100) < moveChance; + const quiet = move.category !== MoveCategory.STATUS; if (statusCheck) { const pokemon = this.selfTarget ? user : target; - if (user !== target && move.category === MoveCategory.STATUS && !target.canSetStatus(this.effect, false, false, user, true)) { + if (user !== target && move.category === MoveCategory.STATUS && !target.canSetStatus(this.effect, quiet, false, user, true)) { return false; } if (((!pokemon.status || this.overrideStatus) || (pokemon.status.effect === this.effect && moveChance < 0)) - && pokemon.trySetStatus(this.effect, true, user, this.turnsRemaining, null, this.overrideStatus, false)) { + && pokemon.trySetStatus(this.effect, true, user, this.turnsRemaining, null, this.overrideStatus, quiet)) { applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect); return true; } @@ -2532,10 +2533,10 @@ 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; @@ -2550,18 +2551,22 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { 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.randBattleSeedInt(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[] { @@ -2585,58 +2590,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) { + 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 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; } + // 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); // Check for abilities that block item theft + applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); - if (cancelled.value === true) { + if (cancelled.value) { 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.randBattleSeedInt(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; @@ -2662,17 +2671,18 @@ 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; + 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)) { @@ -2685,14 +2695,19 @@ export class EatBerryAttr extends MoveEffectAttr { if (heldBerries.length <= 0) { return false; } - this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)]; + + // pick a random berry to gobble and check if we preserve it + this.chosenBerry = heldBerries[user.randBattleSeedInt(heldBerries.length)]; const preserve = new BooleanHolder(false); // check for berry pouch preservation globalScene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), pokemon, preserve); if (!preserve.value) { this.reduceBerryModifier(pokemon); } - this.eatBerry(pokemon); + + // Don't update harvest for berries preserved via Berry pouch (no item dupes lol) + this.eatBerry(target, undefined, !preserve.value); + return true; } @@ -2708,46 +2723,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 + + /** + * 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(false); } + /** * User steals a random berry from the target and then eats it. - * @param user - Pokemon that used the move and will eat the stolen berry - * @param target - Pokemon that will have its berry stolen - * @param move - Move being used - * @param args Unused - * @returns 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 { + // check for abilities that block item theft const cancelled = new BooleanHolder(false); - applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // check for abilities that block item theft + 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 - this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)]; + + // pick a random berry and eat it + this.chosenBerry = heldBerries[user.randBattleSeedInt(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; } } @@ -3172,7 +3205,7 @@ export class StatStageChangeAttr extends MoveEffectAttr { } const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true); - if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) { + if (moveChance < 0 || moveChance === 100 || user.randBattleSeedInt(100) < moveChance) { const stages = this.getLevels(user); globalScene.unshiftPhase(new StatStageChangePhase((this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, stages, this.showMessage)); return true; @@ -3398,7 +3431,7 @@ export class AcupressureStatStageChangeAttr extends MoveEffectAttr { override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const randStats = BATTLE_STATS.filter((s) => target.getStatStage(s) < 6); if (randStats.length > 0) { - const boostStat = [ randStats[user.randSeedInt(randStats.length)] ]; + const boostStat = [ randStats[user.randBattleSeedInt(randStats.length)] ]; globalScene.unshiftPhase(new StatStageChangePhase(target.getBattlerIndex(), this.selfTarget, boostStat, 2)); return true; } @@ -3450,7 +3483,8 @@ export class CutHpStatStageBoostAttr extends StatStageChangeAttr { /** * Attribute implementing the stat boosting effect of {@link https://bulbapedia.bulbagarden.net/wiki/Order_Up_(move) | Order Up}. * If the user has a Pokemon with {@link https://bulbapedia.bulbagarden.net/wiki/Commander_(Ability) | Commander} in their mouth, - * one of the user's stats are increased by 1 stage, depending on the "commanding" Pokemon's form. + * one of the user's stats are increased by 1 stage, depending on the "commanding" Pokemon's form. This effect does not respect + * effect chance, but Order Up itself may be boosted by Sheer Force. */ export class OrderUpStatBoostAttr extends MoveEffectAttr { constructor() { @@ -4100,30 +4134,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; + /* 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]; - this.updateHitReceivedCount(user, hitCount, prevHitCount); - - basePower.value = 50 + (Math.min(user.customPokemonData.hitsRecCount, 6) * 50); - + 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; - } } /** @@ -4354,10 +4381,10 @@ export class LastMoveDoublePowerAttr extends VariablePowerAttr { const userAlly = user.getAlly(); const enemyAlly = enemy?.getAlly(); - if (!isNullOrUndefined(userAlly) && userAlly.turnData.acted) { + if (userAlly?.turnData.acted) { pokemonActed.push(userAlly); } - if (!isNullOrUndefined(enemyAlly) && enemyAlly.turnData.acted) { + if (enemyAlly?.turnData.acted) { pokemonActed.push(enemyAlly); } } @@ -4425,13 +4452,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 NumberHolder)) { - return false; - } - if (user.turnData?.joinedRound) { + if (user.turnData.joinedRound) { power.value *= 2; return true; } @@ -4799,7 +4823,7 @@ export class ShellSideArmCategoryAttr extends VariableMoveCategoryAttr { if (predictedPhysDmg > predictedSpecDmg) { category.value = MoveCategory.PHYSICAL; return true; - } else if (predictedPhysDmg === predictedSpecDmg && user.randSeedInt(2) === 0) { + } else if (predictedPhysDmg === predictedSpecDmg && user.randBattleSeedInt(2) === 0) { category.value = MoveCategory.PHYSICAL; return true; } @@ -5380,7 +5404,7 @@ export class FrenzyAttr extends MoveEffectAttr { } if (!user.getTag(BattlerTagType.FRENZY) && !user.getMoveQueue().length) { - const turnCount = user.randSeedIntRange(1, 2); + const turnCount = user.randBattleSeedIntRange(1, 2); new Array(turnCount).fill(null).map(() => user.getMoveQueue().push({ move: move.id, targets: [ target.getBattlerIndex() ], ignorePP: true })); user.addTag(BattlerTagType.FRENZY, turnCount, move.id, user.id); } else { @@ -5461,8 +5485,8 @@ export class AddBattlerTagAttr extends MoveEffectAttr { } const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true); - if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) { - return (this.selfTarget ? user : target).addTag(this.tagType, user.randSeedIntRange(this.turnCountMin, this.turnCountMax), move.id, user.id); + if (moveChance < 0 || moveChance === 100 || user.randBattleSeedInt(100) < moveChance) { + return (this.selfTarget ? user : target).addTag(this.tagType, user.randBattleSeedIntRange(this.turnCountMin, this.turnCountMax), move.id, user.id); } return false; @@ -5630,7 +5654,7 @@ export class JawLockAttr extends AddBattlerTagAttr { } const moveChance = this.getMoveChance(user, target, move, this.selfTarget); - if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) { + if (moveChance < 0 || moveChance === 100 || user.randBattleSeedInt(100) < moveChance) { /** * Add the tag to both the user and the target. * The target's tag source is considered to be the user and vice versa @@ -5768,7 +5792,7 @@ export class ProtectAttr extends AddBattlerTagAttr { timesUsed++; } if (timesUsed) { - return !user.randSeedInt(Math.pow(3, timesUsed)); + return !user.randBattleSeedInt(Math.pow(3, timesUsed)); } return true; }); @@ -5892,7 +5916,7 @@ export class AddArenaTagAttr extends MoveEffectAttr { return false; } - if ((move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) && user.getLastXMoves(1)[0]?.result === MoveResult.SUCCESS) { + if ((move.chance < 0 || move.chance === 100 || user.randBattleSeedInt(100) < move.chance) && user.getLastXMoves(1)[0]?.result === MoveResult.SUCCESS) { 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; @@ -5968,7 +5992,7 @@ export class AddArenaTrapTagHitAttr extends AddArenaTagAttr { const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true); const side = (this.selfSideTarget ? user : target).isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; const tag = globalScene.arena.getTagOnSide(this.tagType, side) as ArenaTrapTag; - if ((moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) && user.getLastXMoves(1)[0]?.result === MoveResult.SUCCESS) { + if ((moveChance < 0 || moveChance === 100 || user.randBattleSeedInt(100) < moveChance) && user.getLastXMoves(1)[0]?.result === MoveResult.SUCCESS) { globalScene.arena.addTag(this.tagType, 0, move.id, user.id, side); if (!tag) { return true; @@ -6143,7 +6167,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr { // If used by an enemy trainer with at least one fainted non-boss Pokemon, this // revives one of said Pokemon selected at random. const faintedPokemon = globalScene.getEnemyParty().filter((p) => p.isFainted() && !p.isBoss()); - const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length)]; + const pokemon = faintedPokemon[user.randBattleSeedInt(faintedPokemon.length)]; const slotIndex = globalScene.getEnemyParty().findIndex((p) => pokemon.id === p.id); pokemon.resetStatus(true, false, false, true); pokemon.heal(Math.min(toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); @@ -6239,7 +6263,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { if (switchOutTarget.hp > 0) { if (this.switchType === SwitchType.FORCE_SWITCH) { switchOutTarget.leaveField(true); - const slotIndex = eligibleNewIndices[user.randSeedInt(eligibleNewIndices.length)]; + const slotIndex = eligibleNewIndices[user.randBattleSeedInt(eligibleNewIndices.length)]; globalScene.prependToPhase( new SwitchSummonPhase( this.switchType, @@ -6282,7 +6306,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { if (switchOutTarget.hp > 0) { if (this.switchType === SwitchType.FORCE_SWITCH) { switchOutTarget.leaveField(true); - const slotIndex = eligibleNewIndices[user.randSeedInt(eligibleNewIndices.length)]; + const slotIndex = eligibleNewIndices[user.randBattleSeedInt(eligibleNewIndices.length)]; globalScene.prependToPhase( new SwitchSummonPhase( this.switchType, @@ -6701,7 +6725,7 @@ class CallMoveAttr extends OverrideMoveEffectAttr { } const targets = moveTargets.multiple || moveTargets.targets.length === 1 ? moveTargets.targets - : [ this.hasTarget ? target.getBattlerIndex() : moveTargets.targets[user.randSeedInt(moveTargets.targets.length)] ]; // account for Mirror Move having a target already + : [ this.hasTarget ? target.getBattlerIndex() : moveTargets.targets[user.randBattleSeedInt(moveTargets.targets.length)] ]; // account for Mirror Move having a target already user.getMoveQueue().push({ move: move.id, targets: targets, virtual: true, ignorePP: true }); globalScene.unshiftPhase(new LoadMoveAnimPhase(move.id)); globalScene.unshiftPhase(new MovePhase(user, targets, new PokemonMove(move.id, 0, 0, true), true, true)); @@ -6741,7 +6765,7 @@ export class RandomMoveAttr extends CallMoveAttr { 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)]; + moveId = this.getMoveOverride() ?? moveIds[user.randBattleSeedInt(moveIds.length)]; } while (moveId === Moves.NONE); return super.apply(user, target, allMoves[moveId], args); @@ -6793,7 +6817,7 @@ export class RandomMovesetMoveAttr extends CallMoveAttr { return false; } - this.moveId = moves[user.randSeedInt(moves.length)]!.moveId; + this.moveId = moves[user.randBattleSeedInt(moves.length)]!.moveId; return true; }; } @@ -7764,17 +7788,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)) }; } } @@ -7866,7 +7900,7 @@ const phaseForcedSlower = (phase: MovePhase, target: Pokemon, trickRoom: boolean let slower: boolean; // quashed pokemon still have speed ties if (phase.pokemon.getEffectiveStat(Stat.SPD) === target.getEffectiveStat(Stat.SPD)) { - slower = !!target.randSeedInt(2); + slower = !!target.randBattleSeedInt(2); } else { slower = !trickRoom ? phase.pokemon.getEffectiveStat(Stat.SPD) < target.getEffectiveStat(Stat.SPD) : phase.pokemon.getEffectiveStat(Stat.SPD) > target.getEffectiveStat(Stat.SPD); } @@ -7982,13 +8016,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; } } @@ -8013,10 +8052,10 @@ export class UpperHandCondition extends MoveCondition { } } -export class hitsSameTypeAttr extends VariableMoveTypeMultiplierAttr { +export class HitsSameTypeAttr extends VariableMoveTypeMultiplierAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const multiplier = args[0] as NumberHolder; - if (!user.getTypes().some(type => target.getTypes().includes(type))) { + if (!user.getTypes(true).some(type => target.getTypes(true).includes(type))) { multiplier.value = 0; return true; } @@ -8064,7 +8103,7 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr { if (!validTypes.length) { return false; } - const type = validTypes[user.randSeedInt(validTypes.length)]; + const type = validTypes[user.randBattleSeedInt(validTypes.length)]; user.summonData.types = [ type ]; globalScene.queueMessage(i18next.t("battle:transformedIntoType", { pokemonName: getPokemonNameWithAffix(user), type: toReadableString(PokemonType[type]) })); user.updateInfo(); @@ -8179,7 +8218,7 @@ export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveT multiple = moveTarget !== MoveTarget.NEAR_ENEMY; break; case MoveTarget.RANDOM_NEAR_ENEMY: - set = [ opponents[user.randSeedInt(opponents.length)] ]; + set = [ opponents[user.randBattleSeedInt(opponents.length)] ]; break; case MoveTarget.ATTACKER: return { targets: [ -1 as BattlerIndex ], multiple: false }; @@ -8626,7 +8665,7 @@ export function initMoves() { 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) + .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() @@ -8701,7 +8740,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) @@ -8991,6 +9033,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), @@ -9088,7 +9131,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), @@ -9276,7 +9322,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) @@ -9338,6 +9387,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) @@ -9415,7 +9469,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(), @@ -9701,7 +9756,7 @@ export function initMoves() { new AttackMove(Moves.SYNCHRONOISE, PokemonType.PSYCHIC, MoveCategory.SPECIAL, 120, 100, 10, -1, 0, 5) .target(MoveTarget.ALL_NEAR_OTHERS) .condition(unknownTypeCondition) - .attr(hitsSameTypeAttr), + .attr(HitsSameTypeAttr), new AttackMove(Moves.ELECTRO_BALL, PokemonType.ELECTRIC, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 5) .attr(ElectroBallPowerAttr) .ballBombMove(), @@ -9782,7 +9837,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) @@ -9957,7 +10014,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) => { @@ -10969,7 +11026,7 @@ export function initMoves() { .makesContact(false), new AttackMove(Moves.LUMINA_CRASH, PokemonType.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, 100, 0, 9) .attr(StatStageChangeAttr, [ Stat.SPDEF ], -2), - new AttackMove(Moves.ORDER_UP, PokemonType.DRAGON, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 9) + new AttackMove(Moves.ORDER_UP, PokemonType.DRAGON, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 9) .attr(OrderUpStatBoostAttr) .makesContact(false), new AttackMove(Moves.JET_PUNCH, PokemonType.WATER, MoveCategory.PHYSICAL, 60, 100, 15, -1, 1, 9) @@ -11083,7 +11140,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) diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts index e0486c83e77..acfc8cb16a1 100644 --- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts +++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts @@ -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/constants"; 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/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts index 001faf3a67f..87b223d5245 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -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 24c076f750e..ce5eb2cfdd1 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -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) { 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 b0721ddfee9..bb41bc7883c 100644 --- a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts +++ b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts @@ -684,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]; @@ -710,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/mysterious-chest-encounter.ts b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts index e9976ba04aa..e6c11378163 100644 --- a/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts +++ b/src/data/mystery-encounters/encounters/mysterious-chest-encounter.ts @@ -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/slumbering-snorlax-encounter.ts b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts index 41c20f35ba1..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/constants"; 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/the-expert-pokemon-breeder-encounter.ts b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts index 076171b3e5e..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 @@ -11,7 +11,6 @@ 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/constants"; 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 bab0c44db7d..25798de3b4a 100644 --- a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts @@ -88,7 +88,7 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui const r = randSeedInt(SHINY_MAGIKARP_WEIGHT); - const validEventEncounters = timedEventManager + let validEventEncounters = timedEventManager .getEventEncounters() .filter( s => @@ -116,18 +116,44 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui // If you roll 1%, give shiny Magikarp with random variant species = getPokemonSpecies(Species.MAGIKARP); pokemon = new PlayerPokemon(species, 5, 2, undefined, undefined, true); - } else if ( + } + else if ( (validEventEncounters.length > 0 && (r <= EVENT_THRESHOLD || (isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE))) ) { - // 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(); - } else { + 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-winstrate-challenge-encounter.ts b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts index bc7c570abca..3cbe42591d8 100644 --- a/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-winstrate-challenge-encounter.ts @@ -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/weird-dream-encounter.ts b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts index cd9ffefb516..cceda25fcb4 100644 --- a/src/data/mystery-encounters/encounters/weird-dream-encounter.ts +++ b/src/data/mystery-encounters/encounters/weird-dream-encounter.ts @@ -23,7 +23,6 @@ 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-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/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index 67904fc856c..0215928bbe8 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -10,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, @@ -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(); } diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index ed94a46ac18..a6a87b4ab9a 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -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 578c2efefdb..ebef47eac2d 100644 --- a/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts +++ b/src/data/mystery-encounters/utils/encounter-transformation-sequence.ts @@ -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/pokemon-species.ts b/src/data/pokemon-species.ts index 5a9a6ee9b3d..59167ba47f6 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -33,6 +33,7 @@ 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, @@ -485,10 +486,10 @@ export abstract class PokemonSpeciesForm { break; case Species.ZACIAN: case Species.ZAMAZENTA: + // biome-ignore lint/suspicious/noFallthroughSwitchClause: Falls through if (formSpriteKey.startsWith("behemoth")) { formSpriteKey = "crowned"; } - // biome-ignore lint/suspicious/no-fallthrough: Falls through default: ret += `-${formSpriteKey}`; break; @@ -749,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( () => { @@ -879,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 diff --git a/src/data/trainers/TrainerPartyTemplate.ts b/src/data/trainers/TrainerPartyTemplate.ts index 1952bcc179e..ccc494218e9 100644 --- a/src/data/trainers/TrainerPartyTemplate.ts +++ b/src/data/trainers/TrainerPartyTemplate.ts @@ -224,18 +224,19 @@ export const trainerPartyTemplates = { */ export function getEvilGruntPartyTemplate(): TrainerPartyTemplate { const waveIndex = globalScene.currentBattle?.waveIndex; - 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 <= ClassicFixedBossWaves.EVIL_GRUNT_1){ + return trainerPartyTemplates.TWO_AVG; } + if (waveIndex <= ClassicFixedBossWaves.EVIL_GRUNT_2){ + return trainerPartyTemplates.THREE_AVG; + } + if (waveIndex <= ClassicFixedBossWaves.EVIL_GRUNT_3){ + return trainerPartyTemplates.TWO_AVG_ONE_STRONG; + } + if (waveIndex <= ClassicFixedBossWaves.EVIL_ADMIN_1){ + 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[]) { diff --git a/src/data/trainers/trainer-config.ts b/src/data/trainers/trainer-config.ts index 50acf84efa6..839a1cdc0cc 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 { toReadableString, isNullOrUndefined, randSeedItem, randSeedInt } from "#app/utils/common"; +import { toReadableString, isNullOrUndefined, randSeedItem, randSeedInt, randSeedIntRange } 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"; @@ -2856,21 +2856,29 @@ export const trainerConfigs: TrainerConfigs = { .initForEliteFour(signatureSpecies["LORELEI"], false, PokemonType.ICE, 2) .setBattleBgm("battle_kanto_gym") .setMixedBattleBgm("battle_kanto_gym") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DEWGONG], TrainerSlot.TRAINER, true, p => { + .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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.LAPRAS], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -2880,9 +2888,13 @@ export const trainerConfigs: TrainerConfigs = { .setBattleBgm("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 + .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. + 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); } }), @@ -2901,16 +2913,22 @@ export const trainerConfigs: TrainerConfigs = { .setBattleBgm("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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.GENGAR], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -2921,16 +2939,22 @@ export const trainerConfigs: TrainerConfigs = { .setBattleBgm("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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.DRAGONITE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -2943,7 +2967,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.XATU], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -2952,7 +2978,9 @@ export const trainerConfigs: TrainerConfigs = { .initForEliteFour(signatureSpecies["KOGA"], true, PokemonType.POISON, 2) .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.VENOMOTH], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc( + 0, + getRandomPartyMemberFunc([Species.VENOMOTH], TrainerSlot.TRAINER, true, p => { p.abilityIndex = 1; // Tinted Lens p.generateAndPopulateMoveset(); }), @@ -2960,7 +2988,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.CROBAT], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -2970,16 +3000,22 @@ export const trainerConfigs: TrainerConfigs = { .setBattleBgm("battle_johto_gym") .setMixedBattleBgm("battle_johto_gym") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.UMBREON])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.GENGAR], TrainerSlot.TRAINER, true, p => { // Tera Dark Gengar + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.HOUNDOOM], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -2987,7 +3023,9 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.SIDNEY]: new TrainerConfig(++t) .initForEliteFour(signatureSpecies["SIDNEY"], true, PokemonType.DARK, 2) .setMixedBattleBgm("battle_hoenn_elite") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.MIGHTYENA], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc( + 0, + getRandomPartyMemberFunc([Species.MIGHTYENA], TrainerSlot.TRAINER, true, p => { p.abilityIndex = 0; // Intimidate p.generateAndPopulateMoveset(); }), @@ -3008,12 +3046,16 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.DUSKNOIR], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3021,7 +3063,9 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.GLACIA]: new TrainerConfig(++t) .initForEliteFour(signatureSpecies["GLACIA"], false, PokemonType.ICE, 2) .setMixedBattleBgm("battle_hoenn_elite") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ABOMASNOW], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc( + 0, + getRandomPartyMemberFunc([Species.ABOMASNOW], TrainerSlot.TRAINER, true, p => { p.abilityIndex = 0; // Snow Warning p.generateAndPopulateMoveset(); }), @@ -3029,7 +3073,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.WALREIN], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3038,16 +3084,22 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.SALAMENCE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3060,11 +3112,15 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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); } }), @@ -3074,14 +3130,19 @@ export const trainerConfigs: TrainerConfigs = { .setBattleBgm("battle_sinnoh_gym") .setMixedBattleBgm("battle_sinnoh_gym") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.WHISCASH])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.HIPPOWDON], TrainerSlot.TRAINER, true, p => { // Tera Ground Hippowdon + .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.RHYPERIOR], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.abilityIndex = 1; // Solid Rock p.generateAndPopulateMoveset(); @@ -3092,16 +3153,22 @@ export const trainerConfigs: TrainerConfigs = { .setBattleBgm("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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.MAGMORTAR], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3114,7 +3181,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.GALLADE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.abilityIndex = 1; // Sharpness p.generateAndPopulateMoveset(); @@ -3126,8 +3195,10 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.MISMAGIUS, Species.FROSLASS])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.CHANDELURE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3139,7 +3210,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.CONKELDURR], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3151,7 +3224,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.KINGAMBIT], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3161,7 +3236,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 3, + getRandomPartyMemberFunc([Species.GALLADE], TrainerSlot.TRAINER, true, p => { p.abilityIndex = 1; // Sharpness p.generateAndPopulateMoveset(); }), @@ -3177,19 +3254,25 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.MALVA]: new TrainerConfig(++t) .initForEliteFour(signatureSpecies["MALVA"], false, PokemonType.FIRE, 2) .setMixedBattleBgm("battle_kalos_elite") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PYROAR], TrainerSlot.TRAINER, true, p => { + .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 => { + .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.TALONFLAME], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3201,7 +3284,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.BARBARACLE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.abilityIndex = 1; // Tough Claws p.generateAndPopulateMoveset(); @@ -3211,16 +3296,22 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.AEGISLASH], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3232,7 +3323,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.NOIVERN], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3241,16 +3334,22 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.CRABOMINABLE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3262,7 +3361,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.ALOLA_DUGTRIO], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3270,7 +3371,9 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.OLIVIA]: new TrainerConfig(++t) .initForEliteFour(signatureSpecies["OLIVIA"], false, PokemonType.ROCK, 2) .setMixedBattleBgm("battle_alola_elite") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GIGALITH], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc( + 0, + getRandomPartyMemberFunc([Species.GIGALITH], TrainerSlot.TRAINER, true, p => { p.abilityIndex = 1; // Sand Stream p.generateAndPopulateMoveset(); }), @@ -3278,7 +3381,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.LYCANROC], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.formIndex = 1; p.generateAndPopulateMoveset(); @@ -3291,7 +3396,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.PALOSSAND], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3300,16 +3407,22 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.TOUCANNON], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3319,7 +3432,10 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. @@ -3329,7 +3445,9 @@ export const trainerConfigs: TrainerConfigs = { ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.SCRAFTY, Species.PANGORO])) .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.MORPEKO])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GRIMMSNARL], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.GRIMMSNARL], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3339,20 +3457,28 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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 => { + .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.DREDNAW], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3365,7 +3491,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.MACHAMP], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3378,7 +3506,9 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.GENGAR], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3388,17 +3518,23 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.ARCHALUDON], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3410,7 +3546,10 @@ export const trainerConfigs: TrainerConfigs = { .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 + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.CLODSIRE], TrainerSlot.TRAINER, true, p => { + // Tera Ground Clodsire p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3420,13 +3559,18 @@ export const trainerConfigs: TrainerConfigs = { .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 => { + .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 + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.TINKATON], TrainerSlot.TRAINER, true, p => { + // Tera Steel Tinkaton p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3439,7 +3583,10 @@ export const trainerConfigs: TrainerConfigs = { .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 + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.FLAMIGO], TrainerSlot.TRAINER, true, p => { + // Tera Flying Flamigo p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3451,7 +3598,10 @@ export const trainerConfigs: TrainerConfigs = { .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 + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.BAXCALIBUR], TrainerSlot.TRAINER, true, p => { + // Tera Dragon Baxcalibur p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3459,27 +3609,38 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.CRISPIN]: new TrainerConfig(++t) .initForEliteFour(signatureSpecies["CRISPIN"], true, PokemonType.FIRE, 2) .setMixedBattleBgm("battle_bb_elite") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ROTOM], TrainerSlot.TRAINER, true, p => { + .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 + .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. + 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 => { + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.BLAZIKEN], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3488,16 +3649,22 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.METAGROSS], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3509,10 +3676,14 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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); } }), @@ -3521,16 +3692,22 @@ export const trainerConfigs: TrainerConfigs = { .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 + .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. + 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 => { + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.ARCHALUDON], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); }), @@ -3545,18 +3722,29 @@ 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])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.ARCANINE, Species.EXEGGUTOR, Species.GYARADOS], TrainerSlot.TRAINER, true, p => { + .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(); @@ -3571,7 +3759,9 @@ 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(); @@ -3579,24 +3769,34 @@ 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) @@ -3606,20 +3806,26 @@ 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); @@ -3635,18 +3841,24 @@ 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(); @@ -3660,13 +3872,17 @@ 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(); @@ -3674,12 +3890,16 @@ 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); @@ -3692,22 +3912,35 @@ export const trainerConfigs: TrainerConfigs = { .setMixedBattleBgm("battle_sinnoh_champion") .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.generateAndPopulateMoveset(); - 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(); @@ -3723,28 +3956,47 @@ 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.generateAndPopulateMoveset(); - 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); @@ -3760,23 +4012,36 @@ 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.generateAndPopulateMoveset(); - 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; @@ -3787,28 +4052,38 @@ 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(); @@ -3819,29 +4094,45 @@ 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!; @@ -3853,24 +4144,32 @@ export const trainerConfigs: TrainerConfigs = { .setMixedBattleBgm("battle_alola_champion") .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; @@ -3882,18 +4181,29 @@ export const trainerConfigs: TrainerConfigs = { .setMixedBattleBgm("battle_galar_champion") .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(); @@ -3904,35 +4214,47 @@ 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 = 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 = randSeedInt(2, 2); // Random G-Max Urshifu + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([Species.URSHIFU], TrainerSlot.TRAINER, true, p => { + p.formIndex = randSeedIntRange(2, 3); // Random G-Max Urshifu p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.MALE; @@ -3943,21 +4265,27 @@ export const trainerConfigs: TrainerConfigs = { [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. @@ -3971,50 +4299,71 @@ 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])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.INCINEROAR, Species.GRIMMSNARL], TrainerSlot.TRAINER, true, p => { + .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 => { + .setPartyMemberFunc( + 4, + getRandomPartyMemberFunc([Species.OGERPON], TrainerSlot.TRAINER, true, p => { p.formIndex = randSeedInt(4); // Random Ogerpon Tera Mask p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; @@ -4024,7 +4373,9 @@ export const trainerConfigs: TrainerConfigs = { } }), ) - .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); 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/field/pokemon.ts b/src/field/pokemon.ts index 0c412e73b52..74ccb0c7f49 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -54,7 +54,7 @@ import { getStarterValueFriendshipCap, speciesStarterCosts, } from "#app/data/balance/starters"; -import { NumberHolder, randSeedInt, getIvsFromId, BooleanHolder, randSeedItem, isNullOrUndefined, getEnumValues, toDmgValue, fixedInt, rgbaToInt, rgbHexToRgba, rgbToHsv, deltaRgb, isBetween, type nil, type Constructor } from "#app/utils/common"; +import { NumberHolder, randSeedInt, getIvsFromId, BooleanHolder, randSeedItem, isNullOrUndefined, getEnumValues, toDmgValue, fixedInt, rgbaToInt, rgbHexToRgba, rgbToHsv, deltaRgb, isBetween, type nil, type Constructor, randSeedIntRange } from "#app/utils/common"; import type { TypeDamageMultiplier } from "#app/data/type"; import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type"; import { PokemonType } from "#enums/pokemon-type"; @@ -124,6 +124,7 @@ import { TarShotTag, AutotomizedTag, PowerTrickTag, + loadBattlerTag, type GrudgeTag, } from "../data/battler-tags"; import { WeatherType } from "#enums/weather-type"; @@ -185,6 +186,7 @@ import { applyAllyStatMultiplierAbAttrs, AllyStatMultiplierAbAttr, MoveAbilityBypassAbAttr, + PreSummonAbAttr, } from "#app/data/abilities/ability"; import { allAbilities } from "#app/data/data-lists"; import type PokemonData from "#app/system/pokemon-data"; @@ -305,6 +307,12 @@ type getBaseDamageParams = Omit 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; @@ -334,7 +342,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; @@ -350,13 +358,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; @@ -370,6 +388,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { private shinySparkle: Phaser.GameObjects.Sprite; + // TODO: Rework this eventually constructor( x: number, y: number, @@ -390,38 +409,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { throw `Cannot create a player Pokemon for species '${species.getName(formIndex)}'`; } - const hiddenAbilityChance = new 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 = !randSeedInt(hiddenAbilityChance.value); - const randAbilityIndex = 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; } @@ -437,6 +430,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; @@ -512,8 +506,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 { @@ -554,6 +546,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.stellarTypesBoosted = []; } + this.summonData = new PokemonSummonData(dataSource?.summonData); + this.battleData = new PokemonBattleData(dataSource?.battleData); + this.generateName(); if (!species.isObtainable()) { @@ -563,14 +558,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (!dataSource) { this.calculateStats(); } + } /** * @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; + 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 (nickname) { return decodeURIComponent(escape(atob(nickname))); @@ -584,7 +580,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { getPokeball(useIllusion = false){ if(useIllusion){ - return this.summonData?.illusion?.pokeball ?? this.pokeball + return this.summonData.illusion?.pokeball ?? this.pokeball } else { return this.pokeball } @@ -679,9 +675,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) { @@ -723,11 +720,38 @@ 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){ + if (this.summonData.illusion) { this.breakIllusion(); } if (this.hasTrainer()) { @@ -787,15 +811,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } breakIllusion(): boolean { - if (!this.summonData?.illusion) { + 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.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()) { @@ -825,13 +849,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { 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 = !!this.summonData?.illusion && useIllusion ? this.summonData?.illusion.formIndex : this.formIndex; + 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.getGender(useIllusion) === Gender.FEMALE, + formIndex, this.isShiny(useIllusion), this.getVariant(useIllusion) ), @@ -844,13 +868,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ); } if (this.getFusionSpeciesForm()) { - const fusionFormIndex = !!this.summonData?.illusion && useIllusion ? this.summonData?.illusion.fusionFormIndex : this.fusionFormIndex; - const fusionShiny = !!this.summonData?.illusion && !useIllusion ? this.summonData?.illusion.basePokemon!.fusionShiny : this.fusionShiny; - const fusionVariant = !!this.summonData?.illusion && !useIllusion ? this.summonData?.illusion.basePokemon!.fusionVariant : this.fusionVariant; + 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, + this.getFusionGender(false, useIllusion) === Gender.FEMALE, + fusionFormIndex, + fusionShiny, fusionVariant )); globalScene.loadPokemonAtlas( @@ -885,26 +909,29 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const originalWarn = console.warn; // Ignore warnings for missing frames, because there will be a lot console.warn = () => {}; - const battleFrameNames = globalScene.anims.generateFrameNames(this.getBattleSpriteKey(), { + const battleSpriteKey = this.getBattleSpriteKey(this.isPlayer(), ignoreOverride); + const battleFrameNames = globalScene.anims.generateFrameNames(battleSpriteKey, { zeroPad: 4, suffix: ".png", start: 1, end: 400, }); console.warn = originalWarn; - globalScene.anims.create({ - key: this.getBattleSpriteKey(), - frames: battleFrameNames, - frameRate: 10, - repeat: -1, - }); + if (!globalScene.anims.exists(battleSpriteKey)) { + globalScene.anims.create({ + key: battleSpriteKey, + 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) { + if (this.summonData.speciesForm) { this.updateFusionPalette(true); } } @@ -1014,11 +1041,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } getSpriteId(ignoreOverride?: boolean): string { - const formIndex: integer = !!this.summonData?.illusion ? this.summonData?.illusion.formIndex! : 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.getGender(ignoreOverride, true) === Gender.FEMALE, + formIndex, + this.shiny, this.variant ); } @@ -1028,13 +1055,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { back = this.isPlayer(); } - const formIndex: integer = !!this.summonData?.illusion ? this.summonData?.illusion.formIndex! : 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.getGender(ignoreOverride, true) === Gender.FEMALE, + formIndex, + this.shiny, + this.variant, back ); } @@ -1043,8 +1070,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.getSpeciesForm(ignoreOverride, false).getSpriteKey( this.getGender(ignoreOverride) === Gender.FEMALE, this.formIndex, - this.summonData?.illusion?.basePokemon.shiny ?? this.shiny, - this.summonData?.illusion?.basePokemon.variant ?? this.variant + this.summonData.illusion?.basePokemon.shiny ?? this.shiny, + this.summonData.illusion?.basePokemon.variant ?? this.variant ); } @@ -1053,11 +1080,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } getFusionSpriteId(ignoreOverride?: boolean): string { - const fusionFormIndex: integer = !!this.summonData?.illusion ? this.summonData?.illusion.fusionFormIndex! : 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.getFusionGender(ignoreOverride, true) === Gender.FEMALE, + fusionFormIndex, + this.fusionShiny, this.fusionVariant ); } @@ -1067,13 +1094,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { back = this.isPlayer(); } - const fusionFormIndex: integer = !!this.summonData?.illusion ? this.summonData?.illusion.fusionFormIndex! : 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.getFusionGender(ignoreOverride, true) === Gender.FEMALE, + fusionFormIndex, + this.fusionShiny, + this.fusionVariant, back ); } @@ -1092,53 +1119,62 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ); } - getIconAtlasKey(ignoreOverride?: boolean): string { - const formIndex: integer = !!this.summonData?.illusion ? this.summonData?.illusion.formIndex : this.formIndex; - return this.getSpeciesForm(ignoreOverride, true).getIconAtlasKey( - formIndex, - this.shiny, - this.variant + getIconAtlasKey(ignoreOverride?: boolean, useIllusion: boolean = true): string { + const formIndex = useIllusion && this.summonData.illusion?.formIndex ? this.summonData.illusion?.formIndex : this.formIndex; + const variant = !useIllusion && !!this.summonData.illusion ? this.summonData.illusion?.basePokemon.variant : this.variant; + return this.getSpeciesForm(ignoreOverride, useIllusion).getIconAtlasKey( + formIndex, + this.isBaseShiny(useIllusion), + variant ); } - getFusionIconAtlasKey(ignoreOverride?: boolean): string { - return this.getFusionSpeciesForm(ignoreOverride, true).getIconAtlasKey( - this.fusionFormIndex, - this.fusionShiny, - this.fusionVariant + getFusionIconAtlasKey(ignoreOverride?: boolean, useIllusion: boolean = true): string { + const fusionFormIndex = useIllusion && this.summonData.illusion?.fusionFormIndex ? this.summonData.illusion?.fusionFormIndex : this.fusionFormIndex; + const fusionVariant = !useIllusion && !!this.summonData.illusion ? this.summonData.illusion?.basePokemon.fusionVariant : this.fusionVariant; + return this.getFusionSpeciesForm(ignoreOverride, useIllusion).getIconAtlasKey( + fusionFormIndex, + this.isFusionShiny(), + fusionVariant ); } - getIconId(ignoreOverride?: boolean): string { - const formIndex: integer = !!this.summonData?.illusion ? this.summonData?.illusion.formIndex : this.formIndex; - return this.getSpeciesForm(ignoreOverride, true).getIconId( - this.getGender(ignoreOverride, true) === Gender.FEMALE, - formIndex, - this.shiny, - this.variant + getIconId(ignoreOverride?: boolean, useIllusion: boolean = true): string { + const formIndex = useIllusion && this.summonData.illusion?.formIndex ? this.summonData.illusion?.formIndex : this.formIndex; + const variant = !useIllusion && !!this.summonData.illusion ? this.summonData.illusion?.basePokemon.variant : this.variant; + return this.getSpeciesForm(ignoreOverride, useIllusion).getIconId( + this.getGender(ignoreOverride, useIllusion) === Gender.FEMALE, + formIndex, + this.isBaseShiny(), + variant ); } - getFusionIconId(ignoreOverride?: boolean): string { - const fusionFormIndex: integer = !!this.summonData?.illusion ? this.summonData?.illusion.fusionFormIndex! : this.fusionFormIndex; - return this.getFusionSpeciesForm(ignoreOverride, true).getIconId( - this.getFusionGender(ignoreOverride, true) === Gender.FEMALE, - fusionFormIndex, - this.fusionShiny, - this.fusionVariant + getFusionIconId(ignoreOverride?: boolean, useIllusion: boolean = true): string { + const fusionFormIndex = useIllusion && this.summonData.illusion?.fusionFormIndex ? this.summonData.illusion?.fusionFormIndex : this.fusionFormIndex; + const fusionVariant = !useIllusion && !!this.summonData.illusion ? this.summonData.illusion?.basePokemon.fusionVariant : this.fusionVariant; + return this.getFusionSpeciesForm(ignoreOverride, useIllusion).getIconId( + this.getFusionGender(ignoreOverride, useIllusion) === Gender.FEMALE, + fusionFormIndex, + this.isFusionShiny(), + fusionVariant ); } /** - * @param {boolean} useIllusion - Whether we want the speciesForm of the illusion or not. + * 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, useIllusion: boolean = false): PokemonSpeciesForm { - const species: PokemonSpecies = useIllusion && !!this.summonData?.illusion ? getPokemonSpecies(this.summonData?.illusion.species) : this.species; - const formIndex: integer = useIllusion && !!this.summonData?.illusion ? this.summonData?.illusion.formIndex : this.formIndex; - - if (!ignoreOverride && this.summonData?.speciesForm) { + getSpeciesForm(ignoreOverride: boolean = false, useIllusion: boolean = false): PokemonSpeciesForm { + if (!ignoreOverride && this.summonData.speciesForm) { return this.summonData.speciesForm; } + + 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]; } @@ -1150,14 +1186,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @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: integer = useIllusion && !!this.summonData?.illusion ? this.summonData?.illusion.fusionFormIndex! : this.fusionFormIndex; + 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?.speciesForm) { + if (!ignoreOverride && this.summonData.fusionSpeciesForm) { return this.summonData.fusionSpeciesForm; } if ( - !fusionSpecies?.forms?.length || + !fusionSpecies?.forms?.length || fusionFormIndex >= fusionSpecies?.forms.length ) { return fusionSpecies; @@ -1185,12 +1221,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 */ @@ -1384,12 +1423,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; @@ -1404,7 +1443,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]; @@ -1421,12 +1459,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; } } @@ -1455,20 +1495,17 @@ 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); } } /** * Calculate the critical-hit stage of a move used against this pokemon by * the given source - * - * @param source - The {@linkcode Pokemon} who using the move + * @param source - The {@linkcode Pokemon} using the move * @param move - The {@linkcode Move} being used * @returns The final critical-hit stage value */ @@ -1826,9 +1863,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @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 && this.summonData?.gender !== undefined) { + if (useIllusion && this.summonData.illusion) { + return this.summonData.illusion.gender; + } else if (!ignoreOverride && !isNullOrUndefined(this.summonData.gender)) { return this.summonData.gender; } return this.gender; @@ -1838,9 +1875,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @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) { - return this.summonData?.illusion.fusionGender!; - } else if (!ignoreOverride && this.summonData?.fusionGender !== undefined) { + 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; @@ -1850,21 +1887,37 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @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; + 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); } } + isBaseShiny(useIllusion: boolean = false){ + if (!useIllusion && this.summonData.illusion) { + return !!this.summonData.illusion.basePokemon?.shiny; + } else { + return this.shiny; + } + } + + isFusionShiny(useIllusion: boolean = false){ + if (!useIllusion && this.summonData.illusion) { + return !!this.summonData.illusion.basePokemon?.fusionShiny; + } else { + return this.isFusion(useIllusion) && this.fusionShiny; + } + } + /** - * + * * @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) { - return this.isFusion(false) && this.summonData?.illusion.basePokemon.shiny && this.summonData?.illusion.basePokemon.fusionShiny; + 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; } @@ -1874,25 +1927,23 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @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 + 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 + return !this.isFusion(true) + ? this.variant : Math.max(this.variant, this.fusionVariant) as Variant; } } getBaseVariant(doubleShiny: boolean): Variant { if (doubleShiny) { - return !!this.summonData?.illusion - ? this.summonData?.illusion.basePokemon!.variant - : this.variant; - } else { - return this.getVariant(); + return this.summonData.illusion?.basePokemon?.variant ?? this.variant; } + + return this.getVariant(); } getLuck(): number { @@ -1900,19 +1951,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } isFusion(useIllusion: boolean = false): boolean { - if (useIllusion && !!this.summonData?.illusion) { - return !!this.summonData?.illusion.fusionSpecies; - } else { - return !!this.fusionSpecies; + 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 && this.summonData?.illusion.basePokemon) - ? this.summonData?.illusion.basePokemon.name + return (!useIllusion && this.summonData.illusion?.basePokemon) + ? this.summonData.illusion.basePokemon.name : this.name; } @@ -1946,7 +1996,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; @@ -2028,14 +2078,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" + * @param useIllusion - `true` to return the types of the illusion instead of the actual types; Default: `false` * @returns array of {@linkcode PokemonType} */ public getTypes( - includeTeraType = false, - forDefend: boolean = false, - ignoreOverride?: boolean, - useIllusion: boolean | "AUTO" = "AUTO" + includeTeraType = false, + forDefend: boolean = false, + ignoreOverride: boolean = false, + useIllusion: boolean = false ): PokemonType[] { const types: PokemonType[] = []; @@ -2051,17 +2101,16 @@ 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?.illusion || !doIllusion) + !ignoreOverride && + this.summonData.types && + this.summonData.types.length > 0 && + (!this.summonData.illusion || !useIllusion) ) { this.summonData.types.forEach(t => types.push(t)); } else { - const speciesForm = this.getSpeciesForm(ignoreOverride, doIllusion); - const fusionSpeciesForm = this.getFusionSpeciesForm(ignoreOverride, doIllusion); + const speciesForm = this.getSpeciesForm(ignoreOverride, useIllusion); + const fusionSpeciesForm = this.getFusionSpeciesForm(ignoreOverride, useIllusion); const customTypes = this.customPokemonData.types?.length > 0; // First type, checking for "permanently changed" types from ME @@ -2137,10 +2186,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) ) { @@ -2183,7 +2231,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()) { @@ -2249,8 +2297,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( @@ -2362,7 +2410,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return false; } if ( - this.summonData?.abilitySuppressed && + this.summonData.abilitySuppressed && ability.isSuppressable ) { return false; @@ -2370,8 +2418,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const suppressAbilitiesTag = arena.getTag( ArenaTagType.NEUTRALIZING_GAS, ) as SuppressAbilitiesTag; + const suppressOffField = ability.hasAttr(PreSummonAbAttr); if ( - this.isOnField() && + (this.isOnField() || suppressOffField) && suppressAbilitiesTag && !suppressAbilitiesTag.isBeingRemoved() ) { @@ -2403,15 +2452,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 && @@ -2434,15 +2483,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()) && @@ -2641,14 +2690,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const moveType = source.getMoveType(move); const typeMultiplier = new NumberHolder( - move.category !== MoveCategory.STATUS || + move.category !== MoveCategory.STATUS || move.hasAttr(RespectAttackTypeImmunityAttr) ? this.getAttackTypeEffectiveness( - moveType, - source, - false, - simulated, - move, + moveType, + source, + false, + simulated, + move, useIllusion ) : 1); @@ -2759,11 +2808,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @returns a multiplier for the type effectiveness */ getAttackTypeEffectiveness( - moveType: PokemonType, - source?: Pokemon, - ignoreStrongWinds: boolean = false, - simulated: boolean = true, - move?: Move, + moveType: PokemonType, + source?: Pokemon, + ignoreStrongWinds: boolean = false, + simulated: boolean = true, + move?: Move, useIllusion: boolean = false ): TypeDamageMultiplier { if (moveType === PokemonType.STELLAR) { @@ -3143,7 +3192,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; } } @@ -3451,11 +3500,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } let weight = levelMove[0]; // Evolution Moves - if (weight === 0) { + if (weight === EVOLVE_MOVE) { weight = 50; } - // Assume level 1 moves with 80+ BP are "move reminder" moves and bump their weight - if (weight === 1 && allMoves[levelMove[1]].power >= 80) { + // Assume level 1 moves with 80+ BP are "move reminder" moves and bump their weight. Trainers use actual relearn moves. + if (weight === 1 && allMoves[levelMove[1]].power >= 80 || weight === RELEARN_MOVE && this.hasTrainer()) { weight = 40; } if ( @@ -3560,9 +3609,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { // Bosses never get self ko moves or Pain Split if (this.isBoss()) { - movePool = movePool.filter(m => !allMoves[m[0]].hasAttr(SacrificialAttr)); - movePool = movePool.filter(m => !allMoves[m[0]].hasAttr(HpSplitAttr)); + movePool = movePool.filter(m => !allMoves[m[0]].hasAttr(SacrificialAttr) && !allMoves[m[0]].hasAttr(HpSplitAttr)); } + // No one gets Memento or Final Gambit movePool = movePool.filter( m => !allMoves[m[0]].hasAttr(SacrificialAttrOnHit), ); @@ -3574,10 +3623,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { m[0], m[1] * (allMoves[m[0]].hasAttr(SacrificialAttr) ? 0.5 : 1), ]); - movePool = movePool.map(m => [ - m[0], - m[1] * (allMoves[m[0]].hasAttr(SacrificialAttrOnHit) ? 0.5 : 1), - ]); // Trainers get a weight bump to stat buffing moves movePool = movePool.map(m => [ m[0], @@ -3638,10 +3683,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ]); /** The higher this is the more the game weights towards higher level moves. At `0` all moves are equal weight. */ - let weightMultiplier = 0.9; - if (this.hasTrainer()) { - weightMultiplier += 0.7; - } + let weightMultiplier = 1.6; if (this.isBoss()) { weightMultiplier += 0.4; } @@ -3650,37 +3692,21 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { Math.ceil(Math.pow(m[1], weightMultiplier) * 100), ]); - // Trainers and bosses always force a stab move - if (this.hasTrainer() || this.isBoss()) { - const stabMovePool = baseWeights.filter( - m => - allMoves[m[0]].category !== MoveCategory.STATUS && - this.isOfType(allMoves[m[0]].type), - ); + // All Pokemon force a STAB move first + const stabMovePool = baseWeights.filter( + m => + allMoves[m[0]].category !== MoveCategory.STATUS && + this.isOfType(allMoves[m[0]].type), + ); - if (stabMovePool.length) { - const totalWeight = stabMovePool.reduce((v, m) => v + m[1], 0); - let rand = randSeedInt(totalWeight); - let index = 0; - while (rand > stabMovePool[index][1]) { - rand -= stabMovePool[index++][1]; - } - this.moveset.push(new PokemonMove(stabMovePool[index][0], 0, 0)); - } - } else { - // Normal wild pokemon just force a random damaging move - const attackMovePool = baseWeights.filter( - m => allMoves[m[0]].category !== MoveCategory.STATUS, - ); - if (attackMovePool.length) { - const totalWeight = attackMovePool.reduce((v, m) => v + m[1], 0); - let rand = randSeedInt(totalWeight); - let index = 0; - while (rand > attackMovePool[index][1]) { - rand -= attackMovePool[index++][1]; - } - this.moveset.push(new PokemonMove(attackMovePool[index][0], 0, 0)); + if (stabMovePool.length) { + const totalWeight = stabMovePool.reduce((v, m) => v + m[1], 0); + let rand = randSeedInt(totalWeight); + let index = 0; + while (rand > stabMovePool[index][1]) { + rand -= stabMovePool[index++][1]; } + this.moveset.push(new PokemonMove(stabMovePool[index][0], 0, 0)); } while ( @@ -3692,7 +3718,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { // Other damaging moves 2x weight if 0-1 damaging moves, 0.5x if 2, 0.125x if 3. These weights get 20x if STAB. // Status moves remain unchanged on weight, this encourages 1-2 movePool = baseWeights - .filter(m => !this.moveset.some(mo => m[0] === mo.moveId)) + .filter(m => !this.moveset.some( + mo => + m[0] === mo.moveId || + (allMoves[m[0]].hasAttr(SacrificialAttr) && mo.getMove().hasAttr(SacrificialAttr)) // Only one self-KO move allowed + )) .map(m => { let ret: number; if ( @@ -3723,7 +3753,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }); } else { // Non-trainer pokemon just use normal weights - movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo.moveId)); + movePool = baseWeights.filter(m => !this.moveset.some( + mo => + m[0] === mo.moveId || + (allMoves[m[0]].hasAttr(SacrificialAttr) && mo.getMove().hasAttr(SacrificialAttr)) // Only one self-KO move allowed + )); } const totalWeight = movePool.reduce((v, m) => v + m[1], 0); let rand = randSeedInt(totalWeight); @@ -3884,7 +3918,7 @@ 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; @@ -3892,7 +3926,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * 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[] { @@ -4202,12 +4236,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** 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 { @@ -4436,7 +4470,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { */ const randomMultiplier = simulated ? 1 - : this.randSeedIntRange(85, 100) / 100; + : this.randBattleSeedIntRange(85, 100) / 100; /** A damage multiplier for when the attack is of the attacker's type and/or Tera type. */ @@ -4602,7 +4636,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }; } - /** Calculate whether the given move critically hits this pokemon + /** 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`) @@ -4631,16 +4665,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { applyAbAttrs(BlockCritAbAttr, this, null, simulated, isCritical); return isCritical.value; - + } /** * 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, @@ -4653,6 +4687,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } 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); @@ -4696,7 +4731,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * 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. @@ -4708,25 +4743,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); @@ -4739,6 +4774,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { isIndirectDamage, ignoreFaintPhase, ); + // Ensure the battle-info bar's HP is updated, though only if the battle info is visible + // TODO: When battle-info UI is refactored, make this only update the HP bar + if (this.battleInfo.visible) { + this.updateInfo(); + } // Damage amount may have changed, but needed to be queued before calling damage function damagePhase.updateAmount(damage); /** @@ -4862,51 +4902,51 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { getTag(tagType: BattlerTagType.GRUDGE): GrudgeTag | nil; /** @overload */ - getTag(tagType: BattlerTagType): BattlerTag | nil; + getTag(tagType: BattlerTagType): BattlerTag | undefined; /** @overload */ - getTag(tagType: Constructor): T | nil; + getTag(tagType: Constructor): T | undefined; - getTag(tagType: BattlerTagType | Constructor): BattlerTag | nil { - if (!this.summonData) { - return null; - } + 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( @@ -4921,23 +4961,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) { @@ -4945,7 +4986,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 { @@ -4953,13 +4993,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; + } + }) } /** @@ -5075,7 +5113,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 { @@ -5373,7 +5411,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } const message = effect && this.status?.effect === effect ? getStatusEffectOverlapText(effect ?? StatusEffect.NONE, getPokemonNameWithAffix(this)) - : i18next.t("abilityTriggers:moveImmunity", { + : i18next.t("abilityTriggers:moveImmunity", { pokemonNameWithAffix: getPokemonNameWithAffix(this), }); globalScene.queueMessage(message); @@ -5518,9 +5556,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { sourcePokemon !== this && this.isSafeguarded(sourcePokemon) ) { - if(!quiet){ + if(!quiet){ globalScene.queueMessage( - i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(this) + i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(this) })); } return false; @@ -5576,7 +5614,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let sleepTurnsRemaining: NumberHolder; if (effect === StatusEffect.SLEEP) { - sleepTurnsRemaining = new NumberHolder(this.randSeedIntRange(2, 4)); + sleepTurnsRemaining = new NumberHolder(this.randBattleSeedIntRange(2, 4)); this.setFrameRate(4); @@ -5625,7 +5663,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * 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) { @@ -5667,65 +5705,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return false; } - primeSummonData(summonDataPrimer: PokemonSummonData): void { - this.summonDataPrimer = summonDataPrimer; - } - - // For PreSummonAbAttr to get access to summonData - initSummondata(): void { - this.summonData = this.summonData ?? this.summonDataPrimer ?? new PokemonSummonData() - } - - resetSummonData(): void { - const illusion: IllusionData | null = this.summonData?.illusion; - if (this.summonData?.speciesForm) { - this.summonData.speciesForm = null; - this.updateFusionPalette(); - } - this.summonData = new PokemonSummonData(); + /** + * Performs miscellaneous setup for when the Pokemon is summoned, like generating the substitute sprite + * @param resetSummonData - Whether to additionally reset the Pokemon's summon data (default: `false`) + */ + public fieldSetup(resetSummonData?: boolean): void { 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.summonData.illusion = illusion - 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, @@ -5733,6 +5718,62 @@ 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); + } + + if (resetSummonData) { + this.resetSummonData(); + } + } + + /** + * 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 { + 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.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 { @@ -5853,10 +5894,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; @@ -6213,10 +6254,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; }); @@ -6236,7 +6277,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param min The minimum integer to pick, default `0` * @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1) */ - randSeedInt(range: number, min = 0): number { + randBattleSeedInt(range: number, min = 0): number { return globalScene.currentBattle ? globalScene.randBattleSeedInt(range, min) : randSeedInt(range, min); @@ -6248,8 +6289,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param max The maximum integer to generate * @returns a random integer between {@linkcode min} and {@linkcode max} inclusive */ - randSeedIntRange(min: number, max: number): number { - return this.randSeedInt(max - min + 1, min); + randBattleSeedIntRange(min: number, max: number): number { + return globalScene.currentBattle + ? globalScene.randBattleSeedInt(max - min + 1, min) + : randSeedIntRange(min, max); } /** @@ -6269,7 +6312,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(); @@ -6339,7 +6382,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()); @@ -6347,10 +6393,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); } } @@ -6919,6 +6978,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, @@ -7028,7 +7089,6 @@ export class EnemyPokemon extends Pokemon { if (!dataSource) { this.generateAndPopulateMoveset(); - if (shinyLock || Overrides.OPP_SHINY_OVERRIDE === false) { this.shiny = false; } else { @@ -7069,7 +7129,7 @@ export class EnemyPokemon extends Pokemon { const { waveIndex } = globalScene.currentBattle; const ivs: number[] = []; while (ivs.length < 6) { - ivs.push(this.randSeedIntRange(Math.floor(waveIndex / 10), 31)); + ivs.push(randSeedIntRange(Math.floor(waveIndex / 10), 31)); } this.ivs = ivs; } @@ -7232,9 +7292,9 @@ export class EnemyPokemon extends Pokemon { p.getAttackDamage({ source: this, move, - ignoreAbility: !p.battleData.abilityRevealed, + ignoreAbility: !p.waveData.abilityRevealed, ignoreSourceAbility: false, - ignoreAllyAbility: !p.getAlly()?.battleData.abilityRevealed, + ignoreAllyAbility: !p.getAlly()?.waveData.abilityRevealed, ignoreSourceAllyAbility: false, isCritical, } @@ -7296,11 +7356,18 @@ export class EnemyPokemon extends Pokemon { ) { targetScore = -20; } else if (move instanceof AttackMove) { - /** - * 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, undefined, undefined, true); + /** + * 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.waveData.abilityRevealed, + undefined, + undefined, + true); + if (target.isPlayer() !== this.isPlayer()) { targetScore *= effectiveness; if (this.isOfType(move.type)) { @@ -7743,53 +7810,136 @@ 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 illusionBroken: boolean = false; + 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; -export class PokemonBattleData { - /** counts the hits the pokemon received */ - 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; - public berriesEaten: BerryType[] = []; - public abilitiesApplied: Abilities[] = []; - public abilityRevealed: boolean = false; -} + /** Array containing all berries eaten in the last turn; used by {@linkcode Abilities.CUD_CHEW} */ + public berriesEatenLast: BerryType[] = []; -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 */ + /** + * 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 === "moveset") { + this.moveset = value?.map((m: any) => PokemonMove.loadMove(m)); + 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 { + /** Counter tracking direct hits this Pokemon has received during this battle; used for {@linkcode Moves.RAGE_FIST} */ + public hitCount = 0; + /** 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[] = []; + + 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; +} + +/** + * 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 @@ -7813,6 +7963,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 { @@ -7850,8 +8006,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 */ @@ -7868,8 +8024,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. @@ -7940,9 +8096,9 @@ 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()); } @@ -7962,9 +8118,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/inputs-controller.ts b/src/inputs-controller.ts index 7fde0f2aca8..02a95f71ac4 100644 --- a/src/inputs-controller.ts +++ b/src/inputs-controller.ts @@ -1,5 +1,6 @@ import Phaser from "phaser"; -import { deepCopy, getEnumValues } from "#app/utils/common"; +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"; diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 110c19dfec0..608eca1157e 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -790,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 { @@ -3639,7 +3640,7 @@ function getNewModifierTypeOption( } tier += upgradeCount; } - } else if (retryCount === 10 && tier) { + } else if (retryCount >= 100 && tier) { retryCount = 0; tier--; } diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 549ce462c11..94bb0e3419a 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -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/abilities/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) { @@ -699,7 +710,7 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { if (!forSummary) { const pokemon = this.getPokemon(); if (pokemon) { - const pokemonIcon = globalScene.addPokemonIcon(pokemon, -2, 10, 0, 0.5); + const pokemonIcon = globalScene.addPokemonIcon(pokemon, -2, 10, 0, 0.5, undefined, true); container.add(pokemonIcon); container.setName(pokemon.id.toString()); } @@ -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; @@ -1537,7 +1548,7 @@ export class SurviveDamageModifier extends PokemonHeldItemModifier { * @returns `true` if the survive damage has been applied */ override apply(pokemon: Pokemon, surviveDamage: BooleanHolder): boolean { - if (!surviveDamage.value && pokemon.randSeedInt(10) < this.getStackCount()) { + if (!surviveDamage.value && pokemon.randBattleSeedInt(10) < this.getStackCount()) { surviveDamage.value = true; globalScene.queueMessage( @@ -1583,7 +1594,7 @@ export class BypassSpeedChanceModifier extends PokemonHeldItemModifier { * @returns `true` if {@linkcode BypassSpeedChanceModifier} has been applied */ override apply(pokemon: Pokemon, doBypassSpeed: BooleanHolder): boolean { - if (!doBypassSpeed.value && pokemon.randSeedInt(10) < this.getStackCount()) { + if (!doBypassSpeed.value && pokemon.randBattleSeedInt(10) < this.getStackCount()) { doBypassSpeed.value = true; const isCommandFight = globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()]?.command === Command.FIGHT; @@ -1639,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.randBattleSeedInt(100) < this.getStackCount() * this.chance) { flinched.value = true; return true; } @@ -1772,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(), @@ -1867,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; } @@ -1910,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.randBattleSeedInt(10) < this.getStackCount() * 3; return true; } @@ -3225,7 +3240,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { return false; } - const targetPokemon = opponents[pokemon.randSeedInt(opponents.length)]; + const targetPokemon = opponents[pokemon.randBattleSeedInt(opponents.length)]; const transferredItemCount = this.getTransferredItemCount(); if (!transferredItemCount) { @@ -3257,7 +3272,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { break; } } - const randItemIndex = pokemon.randSeedInt(itemModifiers.length); + const randItemIndex = pokemon.randBattleSeedInt(itemModifiers.length); const randItem = itemModifiers[randItemIndex]; if (globalScene.tryTransferHeldItemModifier(randItem, pokemon, false)) { transferredModifierTypes.push(randItem.type); @@ -3609,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); } @@ -3716,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.randBattleSeedInt(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 7e6a46f2f85..5bbd29b355f 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -104,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 diff --git a/src/phases/attempt-capture-phase.ts b/src/phases/attempt-capture-phase.ts index 795aa7010e1..8592cd98508 100644 --- a/src/phases/attempt-capture-phase.ts +++ b/src/phases/attempt-capture-phase.ts @@ -63,7 +63,7 @@ export class AttemptCapturePhase extends PokemonPhase { const modifiedCatchRate = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier); const shakeProbability = Math.round(65536 / Math.pow(255 / modifiedCatchRate, 0.1875)); // Formula taken from gen 6 const criticalCaptureChance = getCriticalCaptureChance(modifiedCatchRate); - const isCritical = pokemon.randSeedInt(256) < criticalCaptureChance; + const isCritical = pokemon.randBattleSeedInt(256) < criticalCaptureChance; const fpOffset = pokemon.getFieldPositionOffset(); const pokeballAtlasKey = getPokeballAtlasKey(this.pokeballType); @@ -135,14 +135,14 @@ export class AttemptCapturePhase extends PokemonPhase { pokeballMultiplier === -1 || isCritical || modifiedCatchRate >= 255 || - pokemon.randSeedInt(65536) < shakeProbability + pokemon.randBattleSeedInt(65536) < shakeProbability ) { globalScene.playSound("se/pb_move"); } else { shakeCounter.stop(); this.failCatch(shakeCount); } - } else if (isCritical && pokemon.randSeedInt(65536) >= shakeProbability) { + } else if (isCritical && pokemon.randBattleSeedInt(65536) >= shakeProbability) { // Above, perform the one shake check for critical captures after the ball shakes once shakeCounter.stop(); this.failCatch(shakeCount); diff --git a/src/phases/attempt-run-phase.ts b/src/phases/attempt-run-phase.ts index 274d3c40576..15c521c01fc 100644 --- a/src/phases/attempt-run-phase.ts +++ b/src/phases/attempt-run-phase.ts @@ -34,7 +34,7 @@ export class AttemptRunPhase extends PokemonPhase { applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance); - if (playerPokemon.randSeedInt(100) < escapeChance.value && !this.forceFailEscape) { + if (playerPokemon.randBattleSeedInt(100) < escapeChance.value && !this.forceFailEscape) { enemyField.forEach(enemyPokemon => applyPreLeaveFieldAbAttrs(PreLeaveFieldAbAttr, enemyPokemon)); globalScene.playSound("se/flee"); diff --git a/src/phases/battle-end-phase.ts b/src/phases/battle-end-phase.ts index 275a9017dfa..b4bb28fe55e 100644 --- a/src/phases/battle-end-phase.ts +++ b/src/phases/battle-end-phase.ts @@ -59,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; } } diff --git a/src/phases/berry-phase.ts b/src/phases/berry-phase.ts index b20b1736d4f..b027469ea5e 100644 --- a/src/phases/berry-phase.ts +++ b/src/phases/berry-phase.ts @@ -1,4 +1,9 @@ -import { applyAbAttrs, PreventBerryUseAbAttr, HealFromBerryUseAbAttr } from "#app/data/abilities/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"; @@ -8,47 +13,65 @@ 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 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 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/encounter-phase.ts b/src/phases/encounter-phase.ts index 20ed69119f9..3cfd2b9a901 100644 --- a/src/phases/encounter-phase.ts +++ b/src/phases/encounter-phase.ts @@ -113,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); @@ -140,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) @@ -153,7 +146,7 @@ export class EncounterPhase extends BattlePhase { const enemyPokemon = globalScene.getEnemyParty()[e]; if (e < (battle.double ? 2 : 1)) { enemyPokemon.setX(-66 + enemyPokemon.getFieldPositionOffset()[0]); - enemyPokemon.resetSummonData(); + enemyPokemon.fieldSetup(true); } if (!this.loaded) { @@ -195,7 +188,7 @@ 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( @@ -288,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, @@ -300,8 +294,8 @@ 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(UiMode.MESSAGE).then(() => { @@ -342,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(); } } @@ -558,7 +554,7 @@ export class EncounterPhase extends BattlePhase { 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/evolution-phase.ts b/src/phases/evolution-phase.ts index 7b013555f40..8fc8a8be031 100644 --- a/src/phases/evolution-phase.ts +++ b/src/phases/evolution-phase.ts @@ -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]; diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts index 4c99a609b11..1aa24d59fa0 100644 --- a/src/phases/faint-phase.ts +++ b/src/phases/faint-phase.ts @@ -118,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, @@ -136,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 ac7edadf244..5517fb0f402 100644 --- a/src/phases/form-change-phase.ts +++ b/src/phases/form-change-phase.ts @@ -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]; diff --git a/src/phases/message-phase.ts b/src/phases/message-phase.ts index f6777579857..b277d67de82 100644 --- a/src/phases/message-phase.ts +++ b/src/phases/message-phase.ts @@ -35,20 +35,22 @@ export class MessagePhase extends Phase { this.text = this.text.split(pokename[p]).join(repname[p]); } const pageIndex = this.text.indexOf("$"); - for (let p = 0; p < globalScene.getPlayerField().length; p++) { - this.text = this.text.split(repname[p]).join(pokename[p]); - } if (pageIndex !== -1) { + let page0 = this.text.slice(0, pageIndex); + let page1 = this.text.slice(pageIndex + 1); + // Pokemon names must be re-inserted _after_ the split, otherwise the index will be wrong + for (let p = 0; p < globalScene.getPlayerField().length; p++) { + page0 = page0.split(repname[p]).join(pokename[p]); + page1 = page1.split(repname[p]).join(pokename[p]); + } globalScene.unshiftPhase( - new MessagePhase( - this.text.slice(pageIndex + 1), - this.callbackDelay, - this.prompt, - this.promptDelay, - this.speaker, - ), + new MessagePhase(page1, this.callbackDelay, this.prompt, this.promptDelay, this.speaker), ); - this.text = this.text.slice(0, pageIndex).trim(); + this.text = page0.trim(); + } else { + for (let p = 0; p < globalScene.getPlayerField().length; p++) { + this.text = this.text.split(repname[p]).join(pokename[p]); + } } } diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 4b4e62db71b..e3773952214 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -206,11 +206,13 @@ export class MoveEffectPhase extends PokemonPhase { * @throws Error if there was an unexpected hit check result */ private applyToTargets(user: Pokemon, targets: Pokemon[]): void { + let firstHit = true; for (const [i, target] of targets.entries()) { const [hitCheckResult, effectiveness] = this.hitChecks[i]; switch (hitCheckResult) { case HitCheckResult.HIT: - this.applyMoveEffects(target, effectiveness); + this.applyMoveEffects(target, effectiveness, firstHit); + firstHit = false; if (isFieldTargeted(this.move)) { // Stop processing other targets if the move is a field move return; @@ -277,9 +279,6 @@ export class MoveEffectPhase extends PokemonPhase { super.end(); return; } - if (isNullOrUndefined(user.turnData)) { - user.resetTurnData(); - } } /** @@ -355,8 +354,8 @@ export class MoveEffectPhase extends PokemonPhase { 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), + // Some moves used in mystery encounters should be played even on an empty field + globalScene.currentBattle?.mysteryEncounter?.hasBattleAnimationsWithoutTargets ?? false, ).play(move.hitsSubstitute(user, firstTarget), () => this.postAnimCallback(user, targets)); return; @@ -595,7 +594,7 @@ export class MoveEffectPhase extends PokemonPhase { } const accuracyMultiplier = user.getAccuracyMultiplier(target, this.move); - const rand = user.randSeedInt(100); + const rand = user.randBattleSeedInt(100); if (rand < moveAccuracy * accuracyMultiplier) { return [HitCheckResult.HIT, effectiveness]; @@ -766,15 +765,12 @@ export class MoveEffectPhase extends PokemonPhase { * - 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}) + * @param target - the {@linkcode Pokemon} hit by this phase's move. + * @param effectiveness - The effectiveness of the move (as previously evaluated in {@linkcode hitCheck}) + * @param firstTarget - Whether this is the first target successfully struck by the move */ - protected applyMoveEffects(target: Pokemon, effectiveness: TypeDamageMultiplier): void { + protected applyMoveEffects(target: Pokemon, effectiveness: TypeDamageMultiplier, firstTarget: boolean): 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; } @@ -908,6 +904,14 @@ export class MoveEffectPhase extends PokemonPhase { target.destroySubstitute(); target.lapseTag(BattlerTagType.COMMANDED); + + // Force `lastHit` to be true if this is a multi hit move with hits left + // `hitsLeft` must be left as-is in order for the message displaying the number of hits + // to display the proper number. + // Note: When Dragon Darts' smart targeting is implemented, this logic may need to be adjusted. + if (!this.lastHit && user.turnData.hitsLeft > 1) { + this.lastHit = true; + } } /** @@ -947,7 +951,7 @@ export class MoveEffectPhase extends PokemonPhase { const result = this.applyMoveDamage(user, target, effectiveness); - if (user.turnData.hitsLeft === 1 && target.isFainted()) { + if (user.turnData.hitsLeft === 1 || target.isFainted()) { this.queueHitResultMessage(result); } diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index b24d7b61ebb..5d63fe6efea 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -232,7 +232,7 @@ export class MovePhase extends BattlePhase { switch (this.pokemon.status.effect) { case StatusEffect.PARALYSIS: activated = - (!this.pokemon.randSeedInt(4) || Overrides.STATUS_ACTIVATION_OVERRIDE === true) && + (!this.pokemon.randBattleSeedInt(4) || Overrides.STATUS_ACTIVATION_OVERRIDE === true) && Overrides.STATUS_ACTIVATION_OVERRIDE !== false; break; case StatusEffect.SLEEP: { @@ -258,7 +258,7 @@ export class MovePhase extends BattlePhase { .findAttr( attr => attr instanceof HealStatusEffectAttr && attr.selfTarget && attr.isOfEffect(StatusEffect.FREEZE), ) || - (!this.pokemon.randSeedInt(5) && Overrides.STATUS_ACTIVATION_OVERRIDE !== true) || + (!this.pokemon.randBattleSeedInt(5) && Overrides.STATUS_ACTIVATION_OVERRIDE !== true) || Overrides.STATUS_ACTIVATION_OVERRIDE === false; activated = !healed; @@ -618,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()); } diff --git a/src/phases/mystery-encounter-phases.ts b/src/phases/mystery-encounter-phases.ts index 011dd26db92..fd0c4ef7949 100644 --- a/src/phases/mystery-encounter-phases.ts +++ b/src/phases/mystery-encounter-phases.ts @@ -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( diff --git a/src/phases/new-biome-encounter-phase.ts b/src/phases/new-biome-encounter-phase.ts index 6a7afcb8da8..ef027bfd77a 100644 --- a/src/phases/new-biome-encounter-phase.ts +++ b/src/phases/new-biome-encounter-phase.ts @@ -7,17 +7,17 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase { 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 e5e61312c3b..30b4004363c 100644 --- a/src/phases/next-encounter-phase.ts +++ b/src/phases/next-encounter-phase.ts @@ -1,6 +1,10 @@ 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 { start() { super.start(); @@ -9,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/quiet-form-change-phase.ts b/src/phases/quiet-form-change-phase.ts index f476919a628..76411f62f77 100644 --- a/src/phases/quiet-form-change-phase.ts +++ b/src/phases/quiet-form-change-phase.ts @@ -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/select-biome-phase.ts b/src/phases/select-biome-phase.ts index 4811c4e6b8f..efd376eb5ba 100644 --- a/src/phases/select-biome-phase.ts +++ b/src/phases/select-biome-phase.ts @@ -13,6 +13,8 @@ export class SelectBiomePhase extends BattlePhase { start() { super.start(); + globalScene.resetSeed(); + const currentBiome = globalScene.arena.biomeType; const nextWaveIndex = globalScene.currentBattle.waveIndex + 1; 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/stat-stage-change-phase.ts b/src/phases/stat-stage-change-phase.ts index 9d64a81bbb4..6731e45025c 100644 --- a/src/phases/stat-stage-change-phase.ts +++ b/src/phases/stat-stage-change-phase.ts @@ -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-phase.ts b/src/phases/summon-phase.ts index ee27fc28247..c217583f163 100644 --- a/src/phases/summon-phase.ts +++ b/src/phases/summon-phase.ts @@ -177,11 +177,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { } globalScene.currentBattle.seenEnemyPartyMemberIds.add(pokemon.id); } - addPokeballOpenParticles( - pokemon.x, - pokemon.y - 16, - pokemon.getPokeball(true), - ); + addPokeballOpenParticles(pokemon.x, pokemon.y - 16, pokemon.getPokeball(true)); globalScene.updateModifiers(this.player); globalScene.updateFieldScale(); pokemon.showInfo(); @@ -200,9 +196,9 @@ export class SummonPhase extends PartyMemberPokemonPhase { onComplete: () => { pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); pokemon.getSprite().clearTint(); - pokemon.resetSummonData(); + pokemon.fieldSetup(); // necessary to stay transformed during wild waves - if (pokemon.summonData?.speciesForm) { + if (pokemon.summonData.speciesForm) { pokemon.loadAssets(false); } globalScene.time.delayedCall(1000, () => this.end()); @@ -266,7 +262,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { onComplete: () => { pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 }); pokemon.getSprite().clearTint(); - pokemon.resetSummonData(); + pokemon.fieldSetup(); globalScene.updateFieldScale(); globalScene.time.delayedCall(1000, () => this.end()); }, diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index f8728f3f9b9..a063b6e6863 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -33,10 +33,10 @@ export class SwitchSummonPhase extends SummonPhase { * @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 - (Optional) `true` if the switch is from the player + * @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; @@ -67,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; @@ -120,14 +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 => @@ -140,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, @@ -160,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.fieldSetup(true); } + this.summon(); + }; + + if (this.player) { + showTextAndSummon(); } else { - this.end(); + globalScene.time.delayedCall(1500, () => { + this.hideEnemyTrainer(); + globalScene.pbTrayEnemy.hide(); + showTextAndSummon(); + }); } } @@ -220,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) { @@ -240,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/turn-end-phase.ts b/src/phases/turn-end-phase.ts index fe16a4a864e..756c497802b 100644 --- a/src/phases/turn-end-phase.ts +++ b/src/phases/turn-end-phase.ts @@ -54,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-start-phase.ts b/src/phases/turn-start-phase.ts index 622b9cdcbd1..b802780bbb8 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -72,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 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; - }); + 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/system/game-data.ts b/src/system/game-data.ts index 8573c774054..0c5e0b349ed 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -118,15 +118,17 @@ export function getDataTypeKey(dataType: GameDataType, slotId = 0): string { } export function encrypt(data: string, bypassLogin: boolean): string { - return (bypassLogin ? (data: string) => btoa(data) : (data: string) => AES.encrypt(data, saveKey))( - data, - ) as unknown as string; // TODO: is this correct? + return (bypassLogin + ? (data: string) => btoa(encodeURIComponent(data)) + : (data: string) => AES.encrypt(data, saveKey))(data) as unknown as string; // TODO: is this correct? } export function decrypt(data: string, bypassLogin: boolean): string { - return (bypassLogin ? (data: string) => atob(data) : (data: string) => AES.decrypt(data, saveKey).toString(enc.Utf8))( - data, - ); + return ( + bypassLogin + ? (data: string) => decodeURIComponent(atob(data)) + : (data: string) => AES.decrypt(data, saveKey).toString(enc.Utf8) + )(data); } export interface SystemSaveData { @@ -1108,7 +1110,7 @@ export class GameData { for (const p of sessionData.party) { const pokemon = p.toPokemon() as PlayerPokemon; pokemon.setVisible(false); - loadPokemonAssets.push(pokemon.loadAssets()); + loadPokemonAssets.push(pokemon.loadAssets(false)); party.push(pokemon); } @@ -1145,7 +1147,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(); @@ -1198,13 +1200,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) { @@ -1342,68 +1347,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); @@ -1456,7 +1460,7 @@ export class GameData { encrypt(JSON.stringify(sessionData), bypassLogin), ); - console.debug("Session data saved"); + console.debug("Session data saved!"); if (!bypassLogin && sync) { pokerogueApi.savedata.updateAll(request).then(error => { diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index 00baad8cf12..00169678ed0 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -1,16 +1,15 @@ 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/sprites/variant"; -import { loadBattlerTag } from "../data/battler-tags"; 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,79 +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.summonData?.illusion ? sourcePokemon.summonData.illusion.basePokemon.nickname : 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 = sourcePokemon ? sourcePokemon.isShiny() : source.shiny; - this.variant = sourcePokemon ? sourcePokemon.getVariant() : source.variant; - this.pokeball = source.pokeball; + this.shiny = sourcePokemon?.summonData.illusion?.basePokemon.shiny ?? source.shiny; + this.variant = sourcePokemon?.summonData.illusion?.basePokemon.variant ?? 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 = sourcePokemon - ? (!!sourcePokemon.summonData?.illusion ? sourcePokemon.summonData.illusion.basePokemon.fusionShiny : sourcePokemon.fusionShiny) - : source.fusionShiny; - this.fusionVariant = sourcePokemon - ? (!!sourcePokemon.summonData?.illusion ? sourcePokemon.summonData.illusion.basePokemon.fusionVariant : sourcePokemon.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; @@ -143,52 +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; - this.summonData.illusionBroken = source.summonData.illusionBroken; - - 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 { @@ -223,30 +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) { + ret.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/version_migration/version_converter.ts b/src/system/version_migration/version_converter.ts index 1fdb9e93f88..798115e0395 100644 --- a/src/system/version_migration/version_converter.ts +++ b/src/system/version_migration/version_converter.ts @@ -59,6 +59,10 @@ import * as v1_7_0 from "./versions/v1_7_0"; // biome-ignore lint/style/noNamespaceImport: Convenience import * as v1_8_3 from "./versions/v1_8_3"; +// --- 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; @@ -80,6 +84,7 @@ systemMigrators.push(...v1_8_3.systemMigrators); 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[] = []; 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..c517896cf45 --- /dev/null +++ b/src/system/version_migration/versions/v1_9_0.ts @@ -0,0 +1,41 @@ +import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator"; +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) => { + // 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 3f5e0393ff7..163afdc098b 100644 --- a/src/timed-event-manager.ts +++ b/src/timed-event-manager.ts @@ -313,8 +313,8 @@ const timedEvents: TimedEvent[] = [ { name: "Shining Spring", eventType: EventType.SHINY, - startDate: new Date(Date.UTC(2025, 4, 2)), - endDate: new Date(Date.UTC(2025, 4, 12)), + 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"], @@ -340,7 +340,6 @@ const timedEvents: TimedEvent[] = [ { species: Species.DEERLING, formIndex: 0 }, // Spring Deerling { species: Species.CLAUNCHER }, { species: Species.WISHIWASHI }, - { species: Species.MUDBRAY }, { species: Species.DRAMPA }, { species: Species.JANGMO_O }, { species: Species.APPLIN }, @@ -351,7 +350,7 @@ const timedEvents: TimedEvent[] = [ { wave: 8, type: "CATCHING_CHARM" }, { wave: 25, type: "SHINY_CHARM" }, ], - } + }, ]; export class TimedEventManager { diff --git a/src/ui/ball-ui-handler.ts b/src/ui/ball-ui-handler.ts index abb106a6553..eb7c208662a 100644 --- a/src/ui/ball-ui-handler.ts +++ b/src/ui/ball-ui-handler.ts @@ -7,6 +7,7 @@ import { addWindow } from "./ui-theme"; import { Button } from "#enums/buttons"; import type { CommandPhase } from "#app/phases/command-phase"; import { globalScene } from "#app/global-scene"; +import i18next from "i18next"; export default class BallUiHandler extends UiHandler { private pokeballSelectContainer: Phaser.GameObjects.Container; @@ -31,7 +32,7 @@ export default class BallUiHandler extends UiHandler { for (let pb = 0; pb < Object.keys(globalScene.pokeballCounts).length; pb++) { optionsTextContent += `${getPokeballName(pb)}\n`; } - optionsTextContent += "Cancel"; + optionsTextContent += i18next.t("pokeball:cancel"); const optionsText = addTextObject(0, 0, optionsTextContent, TextStyle.WINDOW, { align: "right", maxLines: 6 }); const optionsTextWidth = optionsText.displayWidth; this.pokeballSelectContainer = globalScene.add.container( diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 99a91a9330e..2822e8364ec 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -465,7 +465,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.shinyIcon.setVisible(pokemon.isShiny()); - const types = pokemon.getTypes(true); + const types = pokemon.getTypes(true, false, undefined, true); this.type1Icon.setTexture(`pbinfo_${this.player ? "player" : "enemy"}_type${types.length > 1 ? "1" : ""}`); this.type1Icon.setFrame(PokemonType[types[0]].toLowerCase()); this.type2Icon.setVisible(types.length > 1); @@ -617,7 +617,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { return resolve(); } - const gender: Gender = pokemon.summonData?.illusion ? pokemon.summonData?.illusion.gender : pokemon.gender; + const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; this.genderText.setText(getGenderSymbol(gender)); this.genderText.setColor(getGenderColor(gender)); @@ -685,7 +685,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.statusIndicator.setVisible(!!this.lastStatus); } - const types = pokemon.getTypes(true); + const types = pokemon.getTypes(true, false, undefined, true); this.type1Icon.setTexture(`pbinfo_${this.player ? "player" : "enemy"}_type${types.length > 1 ? "1" : ""}`); this.type1Icon.setFrame(PokemonType[types[0]].toLowerCase()); this.type2Icon.setVisible(types.length > 1); @@ -727,6 +727,12 @@ export default class BattleInfo extends Phaser.GameObjects.Container { }, onComplete: () => { updateHpFrame(); + // If, after tweening, the hp is different from the original (due to rounding), force the hp number display + // to update to the correct value. + if (this.player && this.lastHp !== pokemon.hp) { + this.setHpNumbers(pokemon.hp, pokemon.getMaxHp()); + this.lastHp = pokemon.hp; + } resolve(); }, }); @@ -794,7 +800,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { const nameSizeTest = addTextObject(0, 0, displayName, TextStyle.BATTLE_INFO); nameTextWidth = nameSizeTest.displayWidth; - const gender: Gender = pokemon.summonData?.illusion ? pokemon.summonData?.illusion.gender : pokemon.gender; + const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; while ( nameTextWidth > (this.player || !this.boss ? 60 : 98) - diff --git a/src/ui/egg-gacha-ui-handler.ts b/src/ui/egg-gacha-ui-handler.ts index 5377cf3d283..1bb7124d935 100644 --- a/src/ui/egg-gacha-ui-handler.ts +++ b/src/ui/egg-gacha-ui-handler.ts @@ -108,7 +108,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { let pokemonIconX = -20; let pokemonIconY = 6; - if (["de", "es-ES", "fr", "ko", "pt-BR"].includes(currentLanguage)) { + if (["de", "es-ES", "es-MX", "fr", "ko", "pt-BR"].includes(currentLanguage)) { gachaTextStyle = TextStyle.SMALLER_WINDOW_ALT; gachaX = 2; gachaY = 2; @@ -116,7 +116,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { let legendaryLabelX = gachaX; let legendaryLabelY = gachaY; - if (["de", "es-ES"].includes(currentLanguage)) { + if (["de", "es-ES", "es-MX"].includes(currentLanguage)) { pokemonIconX = -25; pokemonIconY = 10; legendaryLabelX = -6; diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index e0a73d62934..5a0978a934d 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -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()); @@ -305,7 +305,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { const effectiveness = opponent.getMoveEffectiveness( pokemon, pokemonMove.getMove(), - !opponent.battleData?.abilityRevealed, + !opponent.waveData.abilityRevealed, undefined, undefined, true, @@ -356,7 +356,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { opponent.getMoveEffectiveness( pokemon, pokemonMove.getMove(), - !opponent.battleData.abilityRevealed, + !opponent.waveData.abilityRevealed, undefined, undefined, true, diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 7c3689e757c..6e947796d63 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1581,7 +1581,7 @@ class PartySlot extends Phaser.GameObjects.Container { fusionShinyStar.setOrigin(0, 0); fusionShinyStar.setPosition(shinyStar.x, shinyStar.y); fusionShinyStar.setTint( - getVariantTint(this.pokemon.summonData?.illusion?.basePokemon.fusionVariant ?? this.pokemon.fusionVariant), + getVariantTint(this.pokemon.summonData.illusion?.basePokemon.fusionVariant ?? this.pokemon.fusionVariant), ); slotInfoContainer.add(fusionShinyStar); diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index ddc16ab5a88..051d267259f 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -1888,7 +1888,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { if (!(passiveAttr & PassiveAttr.UNLOCKED)) { const passiveCost = getPassiveCandyCount(speciesStarterCosts[this.starterId]); options.push({ - label: `x${passiveCost} ${i18next.t("pokedexUiHandler:unlockPassive")} (${allAbilities[this.passive].name})`, + label: `x${passiveCost} ${i18next.t("pokedexUiHandler:unlockPassive")}`, handler: () => { if (Overrides.FREE_CANDY_UPGRADE_OVERRIDE || candyCount >= passiveCost) { starterData.passiveAttr |= PassiveAttr.UNLOCKED | PassiveAttr.ENABLED; diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/pokedex-ui-handler.ts index b1d0945de07..935c9adfeb8 100644 --- a/src/ui/pokedex-ui-handler.ts +++ b/src/ui/pokedex-ui-handler.ts @@ -873,6 +873,7 @@ export default class PokedexUiHandler extends MessageUiHandler { const tweenChain: Phaser.Types.Tweens.TweenChainBuilderConfig = { targets: icon, loop: -1, + paused: startPaused, // Make the initial bounce a little randomly delayed delay: randIntRange(0, 50) * 5, loopDelay: 1000, @@ -894,19 +895,14 @@ export default class PokedexUiHandler extends MessageUiHandler { ], }; - const isPassiveAvailable = this.isPassiveAvailable(species.speciesId); - const isValueReductionAvailable = this.isValueReductionAvailable(species.speciesId); - const isSameSpeciesEggAvailable = this.isSameSpeciesEggAvailable(species.speciesId); - - // 'Passives Only' mode - if (globalScene.candyUpgradeNotification === 1) { - if (isPassiveAvailable) { - globalScene.tweens.chain(tweenChain).paused = startPaused; - } - // 'On' mode - } else if (globalScene.candyUpgradeNotification === 2) { - if (isPassiveAvailable || isValueReductionAvailable || isSameSpeciesEggAvailable) { - globalScene.tweens.chain(tweenChain).paused = startPaused; + if ( + this.isPassiveAvailable(species.speciesId) || + (globalScene.candyUpgradeNotification === 2 && + (this.isValueReductionAvailable(species.speciesId) || this.isSameSpeciesEggAvailable(species.speciesId))) + ) { + const chain = globalScene.tweens.chain(tweenChain); + if (!startPaused) { + chain.play(); } } } @@ -2040,7 +2036,7 @@ export default class PokedexUiHandler extends MessageUiHandler { this.checkIconId(lastSpeciesIcon, container.species, props.female, props.formIndex, props.shiny, props.variant); this.iconAnimHandler.addOrUpdate(lastSpeciesIcon, PokemonIconAnimMode.NONE); // Resume the animation for the previously selected species - globalScene.tweens.getTweensOf(lastSpeciesIcon).forEach(tween => tween.resume()); + globalScene.tweens.getTweensOf(lastSpeciesIcon).forEach(tween => tween.play()); } } diff --git a/src/ui/registration-form-ui-handler.ts b/src/ui/registration-form-ui-handler.ts index 3d4613c21d6..a60a53a8e7a 100644 --- a/src/ui/registration-form-ui-handler.ts +++ b/src/ui/registration-form-ui-handler.ts @@ -102,9 +102,9 @@ export default class RegistrationFormUiHandler extends FormModalUiHandler { // Prevent overlapping overrides on action modification this.submitAction = originalRegistrationAction; this.sanitizeInputs(); - globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); + globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] }); const onFail = error => { - globalScene.ui.setMode(UiMode.REGISTRATION_FORM, Object.assign(config, { errorMessage: error?.trim() })); + globalScene.ui.setMode(UiMode.REGISTRATION_FORM, Object.assign(config, { errorMessage: error?.trim() })); globalScene.ui.playError(); const errorMessageFontSize = languageSettings[i18next.resolvedLanguage!]?.errorMessageFontSize; if (errorMessageFontSize) { diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 7c345f1735e..f24a3ff9265 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -145,12 +145,16 @@ const languageSettings: { [key: string]: LanguageSetting } = { starterInfoXPos: 33, }, ko: { - starterInfoTextSize: "52px", + starterInfoTextSize: "60px", instructionTextSize: "38px", + starterInfoYOffset: -0.5, + starterInfoXPos: 30, }, ja: { - starterInfoTextSize: "51px", + starterInfoTextSize: "62px", instructionTextSize: "38px", + starterInfoYOffset: 0.5, + starterInfoXPos: 33, }, "ca-ES": { starterInfoTextSize: "52px", @@ -1444,6 +1448,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const tweenChain: Phaser.Types.Tweens.TweenChainBuilderConfig = { targets: icon, + paused: startPaused, loop: -1, // Make the initial bounce a little randomly delayed delay: randIntRange(0, 50) * 5, @@ -1451,14 +1456,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { tweens: [ { targets: icon, - y: 2 - 5, + y: "-=5", duration: fixedInt(125), ease: "Cubic.easeOut", yoyo: true, }, { targets: icon, - y: 2 - 3, + y: "-=3", duration: fixedInt(150), ease: "Cubic.easeOut", yoyo: true, @@ -1466,19 +1471,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { ], }; - const isPassiveAvailable = this.isPassiveAvailable(species.speciesId); - const isValueReductionAvailable = this.isValueReductionAvailable(species.speciesId); - const isSameSpeciesEggAvailable = this.isSameSpeciesEggAvailable(species.speciesId); - - // 'Passives Only' mode - if (globalScene.candyUpgradeNotification === 1) { - if (isPassiveAvailable) { - globalScene.tweens.chain(tweenChain).paused = startPaused; - } - // 'On' mode - } else if (globalScene.candyUpgradeNotification === 2) { - if (isPassiveAvailable || isValueReductionAvailable || isSameSpeciesEggAvailable) { - globalScene.tweens.chain(tweenChain).paused = startPaused; + if ( + this.isPassiveAvailable(species.speciesId) || + (globalScene.candyUpgradeNotification === 2 && + (this.isValueReductionAvailable(species.speciesId) || this.isSameSpeciesEggAvailable(species.speciesId))) + ) { + const chain = globalScene.tweens.chain(tweenChain); + if (!startPaused) { + chain.play(); } } } @@ -2184,7 +2184,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (!(passiveAttr & PassiveAttr.UNLOCKED)) { const passiveCost = getPassiveCandyCount(speciesStarterCosts[this.lastSpecies.speciesId]); options.push({ - label: `x${passiveCost} ${i18next.t("starterSelectUiHandler:unlockPassive")} (${allAbilities[this.lastSpecies.getPassiveAbility()].name})`, + label: `x${passiveCost} ${i18next.t("starterSelectUiHandler:unlockPassive")}`, handler: () => { if (Overrides.FREE_CANDY_UPGRADE_OVERRIDE || candyCount >= passiveCost) { starterData.passiveAttr |= PassiveAttr.UNLOCKED | PassiveAttr.ENABLED; @@ -3478,7 +3478,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { // Resume the animation for the previously selected species const icon = this.starterContainers[speciesIndex].icon; - globalScene.tweens.getTweensOf(icon).forEach(tween => tween.resume()); + globalScene.tweens.getTweensOf(icon).forEach(tween => tween.play()); } this.lastSpecies = species!; // TODO: is this bang correct? diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index 877c342651f..f93a1826b3e 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -359,15 +359,15 @@ export default class SummaryUiHandler extends UiHandler { this.pokemonSprite.setPipelineData("spriteKey", this.pokemon.getSpriteKey()); this.pokemonSprite.setPipelineData( "shiny", - this.pokemon.summonData?.illusion?.basePokemon.shiny ?? this.pokemon.shiny, + this.pokemon.summonData.illusion?.basePokemon.shiny ?? this.pokemon.shiny, ); this.pokemonSprite.setPipelineData( "variant", - this.pokemon.summonData?.illusion?.basePokemon.variant ?? this.pokemon.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]; @@ -462,7 +462,7 @@ export default class SummaryUiHandler extends UiHandler { this.fusionShinyIcon.setVisible(doubleShiny); if (isFusion) { this.fusionShinyIcon.setTint( - getVariantTint(this.pokemon.summonData?.illusion?.basePokemon.fusionVariant ?? this.pokemon.fusionVariant), + getVariantTint(this.pokemon.summonData.illusion?.basePokemon.fusionVariant ?? this.pokemon.fusionVariant), ); } diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/target-select-ui-handler.ts index 0db2020c25a..5e14e5f7771 100644 --- a/src/ui/target-select-ui-handler.ts +++ b/src/ui/target-select-ui-handler.ts @@ -71,7 +71,7 @@ export default class TargetSelectUiHandler extends UiHandler { */ resetCursor(cursorN: number, user: Pokemon): void { if (!isNullOrUndefined(cursorN)) { - if ([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2].includes(cursorN) || user.battleSummonData.waveTurnCount === 1) { + 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; } diff --git a/src/utils/common.ts b/src/utils/common.ts index 6984840fb5c..b9111578e2f 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -99,6 +99,16 @@ export function randSeedInt(range: number, min = 0): number { return Phaser.Math.RND.integerInRange(min, range - 1 + min); } +/** + * Generates a random number using the global seed + * @param min The minimum integer to generate + * @param max The maximum integer to generate + * @returns a random integer between {@linkcode min} and {@linkcode max} inclusive + */ +export function randSeedIntRange(min: number, max: number): number { + return randSeedInt(max - min + 1, min); +} + /** * Returns a random integer between min and max (non-inclusive) * @param min The lowest number @@ -467,35 +477,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. @@ -579,25 +576,3 @@ export function animationFileName(move: Moves): string { export function camelCaseToKebabCase(str: string): string { return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (s, o) => (o ? "-" : "") + s.toLowerCase()); } - -/** - * Merges the two objects, such that for each property in `b` that matches a property in `a`, - * the value in `a` is replaced by the value in `b`. This is done recursively if the property is a non-array object - * - * If the property does not exist in `a` or its `typeof` evaluates differently, the property is skipped. - * If the value of the property is an array, the array is replaced. If it is any other object, the object is merged recursively. - */ -// biome-ignore lint/complexity/noBannedTypes: This function is designed to merge json objects -export function deepMergeObjects(a: Object, b: Object) { - for (const key in b) { - // !(key in a) is redundant here, yet makes it clear that we're explicitly interested in properties that exist in `a` - if (!(key in a) || typeof a[key] !== typeof b[key]) { - continue; - } - if (typeof b[key] === "object" && !Array.isArray(b[key])) { - deepMergeObjects(a[key], b[key]); - } else { - a[key] = b[key]; - } - } -} 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/test/abilities/cud_chew.test.ts b/test/abilities/cud_chew.test.ts new file mode 100644 index 00000000000..2f65ac5fd97 --- /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, "randBattleSeedInt").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/desolate-land.test.ts b/test/abilities/desolate-land.test.ts index d6f01f7aa5e..697bd0a4c48 100644 --- a/test/abilities/desolate-land.test.ts +++ b/test/abilities/desolate-land.test.ts @@ -139,7 +139,7 @@ describe("Abilities - Desolate Land", () => { await game.classicMode.startBattle([Species.MAGIKARP]); expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.HARSH_SUN); - vi.spyOn(game.scene.getPlayerPokemon()!, "randSeedInt").mockReturnValue(0); + vi.spyOn(game.scene.getPlayerPokemon()!, "randBattleSeedInt").mockReturnValue(0); const commandPhase = game.scene.getCurrentPhase() as CommandPhase; commandPhase.handleCommand(Command.RUN, 0); diff --git a/test/abilities/good_as_gold.test.ts b/test/abilities/good_as_gold.test.ts index 944c1d1bca1..09bdaafb11f 100644 --- a/test/abilities/good_as_gold.test.ts +++ b/test/abilities/good_as_gold.test.ts @@ -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); }); 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/illusion.test.ts b/test/abilities/illusion.test.ts index 1d8ce58ab38..8aae433b6c0 100644 --- a/test/abilities/illusion.test.ts +++ b/test/abilities/illusion.test.ts @@ -38,8 +38,8 @@ describe("Abilities - Illusion", () => { const zoroark = game.scene.getPlayerPokemon()!; const zorua = game.scene.getEnemyPokemon()!; - expect(!!zoroark.summonData?.illusion).equals(true); - expect(!!zorua.summonData?.illusion).equals(true); + expect(!!zoroark.summonData.illusion).equals(true); + expect(!!zorua.summonData.illusion).equals(true); }); it("break after receiving damaging move", async () => { @@ -50,7 +50,7 @@ describe("Abilities - Illusion", () => { const zorua = game.scene.getEnemyPokemon()!; - expect(!!zorua.summonData?.illusion).equals(false); + expect(!!zorua.summonData.illusion).equals(false); expect(zorua.name).equals("Zorua"); }); @@ -62,16 +62,30 @@ describe("Abilities - Illusion", () => { const zorua = game.scene.getEnemyPokemon()!; - expect(!!zorua.summonData?.illusion).equals(false); + expect(!!zorua.summonData.illusion).equals(false); }); - it("break with neutralizing gas", async () => { + it("breaks 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); + expect(!!zorua.summonData.illusion).equals(false); + }); + + it("does not activate if neutralizing gas is active", async () => { + game.override + .enemyAbility(Abilities.NEUTRALIZING_GAS) + .ability(Abilities.ILLUSION) + .moveset(Moves.SPLASH) + .enemyMoveset(Moves.SPLASH); + await game.classicMode.startBattle([Species.MAGIKARP, Species.FEEBAS, Species.MAGIKARP]); + + game.doSwitchPokemon(1); + await game.toNextTurn(); + + expect(game.scene.getPlayerPokemon()!.summonData.illusion).toBeFalsy(); }); it("causes enemy AI to consider the illusion's type instead of the actual type when considering move effectiveness", async () => { @@ -116,7 +130,7 @@ describe("Abilities - Illusion", () => { const zoroark = game.scene.getPlayerPokemon()!; - expect(!!zoroark.summonData?.illusion).equals(true); + expect(!!zoroark.summonData.illusion).equals(true); }); it("copies the the name, nickname, gender, shininess, and pokeball from the illusion source", async () => { diff --git a/test/abilities/infiltrator.test.ts b/test/abilities/infiltrator.test.ts index 48671e54020..1a9f802dd9c 100644 --- a/test/abilities/infiltrator.test.ts +++ b/test/abilities/infiltrator.test.ts @@ -68,7 +68,7 @@ describe("Abilities - Infiltrator", () => { 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/libero.test.ts b/test/abilities/libero.test.ts index 2e3668813c5..4adb828180e 100644 --- a/test/abilities/libero.test.ts +++ b/test/abilities/libero.test.ts @@ -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/neutralizing_gas.test.ts b/test/abilities/neutralizing_gas.test.ts index 32c61b72e4d..979583b7d97 100644 --- a/test/abilities/neutralizing_gas.test.ts +++ b/test/abilities/neutralizing_gas.test.ts @@ -164,7 +164,7 @@ describe("Abilities - Neutralizing Gas", () => { await game.classicMode.startBattle([Species.MAGIKARP]); expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined(); - vi.spyOn(game.scene.getPlayerPokemon()!, "randSeedInt").mockReturnValue(0); + vi.spyOn(game.scene.getPlayerPokemon()!, "randBattleSeedInt").mockReturnValue(0); const commandPhase = game.scene.getCurrentPhase() as CommandPhase; commandPhase.handleCommand(Command.RUN, 0); diff --git a/test/abilities/protean.test.ts b/test/abilities/protean.test.ts index efa6f33fe00..8f7633e1327 100644 --- a/test/abilities/protean.test.ts +++ b/test/abilities/protean.test.ts @@ -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/quick_draw.test.ts b/test/abilities/quick_draw.test.ts index 0d3171e947e..79a29b0ce77 100644 --- a/test/abilities/quick_draw.test.ts +++ b/test/abilities/quick_draw.test.ts @@ -54,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( @@ -76,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); }, ); @@ -96,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/wimp_out.test.ts b/test/abilities/wimp_out.test.ts index 463ec7587dc..f558efdb103 100644 --- a/test/abilities/wimp_out.test.ts +++ b/test/abilities/wimp_out.test.ts @@ -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"); diff --git a/test/battle/inverse_battle.test.ts b/test/battle/inverse_battle.test.ts index f8afa3518a9..799442bb603 100644 --- a/test/battle/inverse_battle.test.ts +++ b/test/battle/inverse_battle.test.ts @@ -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/battlerTags/substitute.test.ts b/test/battlerTags/substitute.test.ts index d2df5511c0a..c2a99299716 100644 --- a/test/battlerTags/substitute.test.ts +++ b/test/battlerTags/substitute.test.ts @@ -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; diff --git a/test/items/reviver_seed.test.ts b/test/items/reviver_seed.test.ts index c109794d3d2..3c67481a904 100644 --- a/test/items/reviver_seed.test.ts +++ b/test/items/reviver_seed.test.ts @@ -73,7 +73,7 @@ describe("Items - Reviver Seed", () => { const reviverSeed = player.getHeldItems()[0] as PokemonInstantReviveModifier; vi.spyOn(reviverSeed, "apply"); - vi.spyOn(player, "randSeedInt").mockReturnValue(0); // Force confusion self-hit + vi.spyOn(player, "randBattleSeedInt").mockReturnValue(0); // Force confusion self-hit game.move.select(Moves.TACKLE); await game.phaseInterceptor.to("BerryPhase"); diff --git a/test/moves/dive.test.ts b/test/moves/dive.test.ts index f33dc69b55f..95c3349c8a6 100644 --- a/test/moves/dive.test.ts +++ b/test/moves/dive.test.ts @@ -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/fake_out.test.ts b/test/moves/fake_out.test.ts index cbce16270e0..404473c8fa0 100644 --- a/test/moves/fake_out.test.ts +++ b/test/moves/fake_out.test.ts @@ -26,64 +26,71 @@ describe("Moves - Fake Out", () => { .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/instruct.test.ts b/test/moves/instruct.test.ts index c5650d7bbd5..dd25db4ec90 100644 --- a/test/moves/instruct.test.ts +++ b/test/moves/instruct.test.ts @@ -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], @@ -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], 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/order_up.test.ts b/test/moves/order_up.test.ts index 701d0489c25..b5df5bfba41 100644 --- a/test/moves/order_up.test.ts +++ b/test/moves/order_up.test.ts @@ -65,4 +65,23 @@ describe("Moves - Order Up", () => { affectedStats.forEach(st => expect(dondozo.getStatStage(st)).toBe(st === stat ? 3 : 2)); }, ); + + it("should be boosted by Sheer Force while still applying a stat boost", async () => { + game.override.passiveAbility(Abilities.SHEER_FORCE).starterForms({ [Species.TATSUGIRI]: 0 }); + + await game.classicMode.startBattle([Species.TATSUGIRI, Species.DONDOZO]); + + const [tatsugiri, dondozo] = game.scene.getPlayerField(); + + expect(game.scene.triggerPokemonBattleAnim).toHaveBeenLastCalledWith(tatsugiri, PokemonAnimType.COMMANDER_APPLY); + expect(dondozo.getTag(BattlerTagType.COMMANDED)).toBeDefined(); + + game.move.select(Moves.ORDER_UP, 1, BattlerIndex.ENEMY); + expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); + + await game.phaseInterceptor.to("BerryPhase", false); + + expect(dondozo.waveData.abilitiesApplied.has(Abilities.SHEER_FORCE)).toBeTruthy(); + expect(dondozo.getStatStage(Stat.ATK)).toBe(3); + }); }); diff --git a/test/moves/powder.test.ts b/test/moves/powder.test.ts index 6f7a6add054..457beb60f91 100644 --- a/test/moves/powder.test.ts +++ b/test/moves/powder.test.ts @@ -146,7 +146,7 @@ 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 () => { diff --git a/test/moves/rage_fist.test.ts b/test/moves/rage_fist.test.ts index 687d805da78..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; @@ -28,19 +29,18 @@ describe("Moves - Rage Fist", () => { game = new GameManager(phaserGame); game.override .battleStyle("single") - .moveset([Moves.RAGE_FIST, Moves.SPLASH, Moves.SUBSTITUTE]) + .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/synchronoise.test.ts b/test/moves/synchronoise.test.ts new file mode 100644 index 00000000000..0f59bce26b4 --- /dev/null +++ b/test/moves/synchronoise.test.ts @@ -0,0 +1,47 @@ +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 } from "vitest"; + +describe("Moves - Synchronoise", () => { + 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.SYNCHRONOISE]) + .ability(Abilities.BALL_FETCH) + .battleStyle("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should consider the user's tera type if it is terastallized", async () => { + await game.classicMode.startBattle([Species.BIDOOF]); + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + // force the player to be terastallized + playerPokemon.teraType = PokemonType.WATER; + playerPokemon.isTerastallized = true; + game.move.select(Moves.SYNCHRONOISE); + await game.phaseInterceptor.to("BerryPhase"); + expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp()); + }); +}); diff --git a/test/moves/toxic_spikes.test.ts b/test/moves/toxic_spikes.test.ts index 624db27bb92..b1fdc7f39c2 100644 --- a/test/moves/toxic_spikes.test.ts +++ b/test/moves/toxic_spikes.test.ts @@ -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 5bcb7c7ed4c..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"; @@ -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/u_turn.test.ts b/test/moves/u_turn.test.ts index 68bb7fe05c1..9dca29414a1 100644 --- a/test/moves/u_turn.test.ts +++ b/test/moves/u_turn.test.ts @@ -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); @@ -74,7 +74,7 @@ describe("Moves - U-turn", () => { // arrange game.override.enemyAbility(Abilities.POISON_POINT); await game.classicMode.startBattle([Species.RAICHU, Species.SHUCKLE]); - vi.spyOn(game.scene.getEnemyPokemon()!, "randSeedInt").mockReturnValue(0); + vi.spyOn(game.scene.getEnemyPokemon()!, "randBattleSeedInt").mockReturnValue(0); // act game.move.select(Moves.U_TURN); @@ -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/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/bug-type-superfan-encounter.test.ts b/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts index fc208ed7180..455a5d28194 100644 --- a/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts +++ b/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts @@ -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", () => { diff --git a/test/settingMenu/rebinding_setting.test.ts b/test/settingMenu/rebinding_setting.test.ts index 45c647248c4..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/common"; +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/testUtils/gameManager.ts b/test/testUtils/gameManager.ts index 39e65fba0e5..8dd90decf1a 100644 --- a/test/testUtils/gameManager.ts +++ b/test/testUtils/gameManager.ts @@ -579,9 +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. - * @param order - The turn order to set + * @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/helpers/moveHelper.ts b/test/testUtils/helpers/moveHelper.ts index 0f3d75c6268..269cf65ea56 100644 --- a/test/testUtils/helpers/moveHelper.ts +++ b/test/testUtils/helpers/moveHelper.ts @@ -103,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). diff --git a/test/testUtils/helpers/overridesHelper.ts b/test/testUtils/helpers/overridesHelper.ts index 6aa382ef59a..acc2e4d5cd0 100644 --- a/test/testUtils/helpers/overridesHelper.ts +++ b/test/testUtils/helpers/overridesHelper.ts @@ -522,6 +522,21 @@ 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 % diff --git a/test/testUtils/helpers/reloadHelper.ts b/test/testUtils/helpers/reloadHelper.ts index 4867a146aaf..4a9e5356968 100644 --- a/test/testUtils/helpers/reloadHelper.ts +++ b/test/testUtils/helpers/reloadHelper.ts @@ -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 @@ -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/utils.test.ts b/test/utils.test.ts index 33f7906738c..fe93bdd6970 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,5 +1,6 @@ import { expect, describe, it, beforeAll } from "vitest"; 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] }] }); + }); + }); });