diff --git a/.github/test-filters.yml b/.github/test-filters.yml index 89f4322adea..fc52e85082c 100644 --- a/.github/test-filters.yml +++ b/.github/test-filters.yml @@ -1,7 +1,8 @@ all: - - "src/**" - - "test/**" - - "public/**" + # Negations syntax from https://github.com/dorny/paths-filter/issues/184#issuecomment-2786521554 + - "src/**/!(*.{md,py,sh,gitkeep,gitignore})" + - "test/**/!(*.{md,py,sh,gitkeep,gitignore})" + - "public/**/!(*.{md,py,sh,gitkeep,gitignore})" # Workflows that can impact tests - ".github/workflows/test*.yml" - ".github/test-filters.yml" @@ -11,9 +12,4 @@ all: - "vite*" # vite.config.ts, vite.vitest.config.ts, vitest.workspace.ts - "tsconfig*.json" # tsconfig.json tweaking can impact compilation - "global.d.ts" - - ".env*" - # Blanket negations for files that cannot impact tests - - "!**/*.py" # No .py files - - "!**/*.sh" # No .sh files - - "!**/*.md" # No .md files - - "!**/.git*" # .gitkeep and family + - ".env*" \ No newline at end of file diff --git a/.github/workflows/test-shard-template.yml b/.github/workflows/test-shard-template.yml index a1146cb3497..98836bd335a 100644 --- a/.github/workflows/test-shard-template.yml +++ b/.github/workflows/test-shard-template.yml @@ -19,19 +19,20 @@ on: jobs: test: - name: Shard ${{ inputs.shard }} of ${{ inputs.totalShards }} + # We can't use dynmically named jobs until https://github.com/orgs/community/discussions/13261 is implemented + name: Shard runs-on: ubuntu-latest if: ${{ !inputs.skip }} steps: - name: Check out Git repository uses: actions/checkout@v4.2.2 with: - submodules: 'recursive' + submodules: "recursive" - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version-file: '.nvmrc' - cache: 'npm' + node-version-file: ".nvmrc" + cache: "npm" - name: Install Node.js dependencies run: npm ci - name: Run tests diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f04a1987eff..c3b9666caa9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,6 +25,7 @@ jobs: - name: checkout uses: actions/checkout@v4 - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 + id: filter with: filters: .github/test-filters.yml @@ -33,10 +34,10 @@ jobs: needs: check-path-change-filter strategy: matrix: - shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + shard: [1, 2, 3, 4, 5] uses: ./.github/workflows/test-shard-template.yml with: project: main shard: ${{ matrix.shard }} - totalShards: 10 - skip: ${{ needs.check-path-change-filter.outputs.all == 'false'}} + totalShards: 5 + skip: ${{ needs.check-path-change-filter.outputs.all != 'true'}} diff --git a/public/images/pokemon/332.png b/public/images/pokemon/332.png index a9979480673..44e374426b4 100644 Binary files a/public/images/pokemon/332.png and b/public/images/pokemon/332.png differ diff --git a/public/images/pokemon/646.png b/public/images/pokemon/646.png index 64b0af2d151..e54083bfc73 100644 Binary files a/public/images/pokemon/646.png and b/public/images/pokemon/646.png differ diff --git a/public/images/pokemon/back/332.png b/public/images/pokemon/back/332.png index a432b1af4b2..b251a35e468 100644 Binary files a/public/images/pokemon/back/332.png and b/public/images/pokemon/back/332.png differ diff --git a/public/images/pokemon/back/female/332.png b/public/images/pokemon/back/female/332.png index a432b1af4b2..b251a35e468 100644 Binary files a/public/images/pokemon/back/female/332.png and b/public/images/pokemon/back/female/332.png differ diff --git a/public/images/pokemon/female/332.png b/public/images/pokemon/female/332.png index 2100e4b9a10..c1f7c8ec3f0 100644 Binary files a/public/images/pokemon/female/332.png and b/public/images/pokemon/female/332.png differ diff --git a/public/images/pokemon/variant/332.json b/public/images/pokemon/variant/332.json index e9b487bca25..336ef4a22f3 100644 --- a/public/images/pokemon/variant/332.json +++ b/public/images/pokemon/variant/332.json @@ -1,34 +1,36 @@ { "1": { - "319452": "831a1f", - "4a7310": "982443", - "7ba563": "b44040", - "bdef84": "ec8c8c", "8cbd63": "c54b4b", - "215200": "710f2e", + "a5d670": "df5252", + "4aa552": "9f2f2c", "a5d674": "e16363", - "196b21": "891222", + "7aa953": "c54b4b", + "7ba563": "b44040", + "215200": "710f2e", "f7ce00": "7aa1df", "525252": "123a5a", - "63b56b": "b2332f", - "a5d673": "df5252", "8c6b3a": "448bc3", - "4aa552": "9f2f2c" + "bdef84": "ec8c8c", + "63b56b": "b2332f", + "319452": "831a1f", + "196b21": "891222", + "4a7310": "982443" }, "2": { - "319452": "b08d72", - "4a7310": "4f3956", - "7ba563": "704e7e", - "bdef84": "a779ba", "8cbd63": "e3d7a6", - "215200": "583823", + "a5d670": "d7cda7", + "4aa552": "c5a77f", "a5d674": "8c669b", - "196b21": "78582c", + "7aa953": "704e7e", + "7ba563": "704e7e", + "215200": "583823", "f7ce00": "f2aacd", "525252": "a53b6f", - "63b56b": "cfc191", - "a5d673": "d7cda7", "8c6b3a": "df87bb", - "4aa552": "c5a77f" + "bdef84": "a779ba", + "63b56b": "cfc191", + "319452": "b08d72", + "196b21": "78582c", + "4a7310": "4f3956" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/back/332.json b/public/images/pokemon/variant/back/332.json index c13c07c34b4..fbfb3705202 100644 --- a/public/images/pokemon/variant/back/332.json +++ b/public/images/pokemon/variant/back/332.json @@ -1,28 +1,28 @@ { "1": { + "196b21": "831a1f", + "7ba563": "b44040", + "215201": "630d28", + "215200": "710f2f", + "a5d674": "df5252", + "8cbd63": "c54b4b", + "63b56b": "b2332f", + "a5d670": "e16363", "319452": "831a1f", "4aa552": "9f2f2c", - "7ba563": "b44040", - "8cbd63": "c54b4b", - "215200": "710f2f", - "196b21": "831a1f", - "a5d674": "df5252", - "4a7310": "982443", - "a5d673": "e16363", - "63b56b": "b2332f", - "215201": "630d28" + "4a7310": "982443" }, "2": { + "196b21": "b08d72", + "7ba563": "704e7e", + "215201": "583823", + "215200": "3f3249", + "a5d674": "d7cda7", + "8cbd63": "e3d7a6", + "63b56b": "cfc191", + "a5d670": "8c669b", "319452": "b08d72", "4aa552": "c5a77f", - "7ba563": "704e7e", - "8cbd63": "e3d7a6", - "215200": "3f3249", - "196b21": "b08d72", - "a5d674": "d7cda7", - "4a7310": "4f3956", - "a5d673": "8c669b", - "63b56b": "cfc191", - "215201": "583823" + "4a7310": "4f3956" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/back/female/332.json b/public/images/pokemon/variant/back/female/332.json index 9ec50cb7e92..17f8d3c5f74 100644 --- a/public/images/pokemon/variant/back/female/332.json +++ b/public/images/pokemon/variant/back/female/332.json @@ -1,28 +1,28 @@ { "1": { + "196b21": "780d4a", + "7ba563": "b44040", + "215201": "710f2e", + "215200": "710f2f", + "a5d674": "de5b6f", + "8cbd63": "bf3d64", + "63b56b": "9e2056", + "a5d670": "e16363", "319452": "780d4a", "4aa552": "8a1652", - "7ba563": "b44040", - "8cbd63": "bf3d64", - "215200": "710f2f", - "196b21": "780d4a", - "a5d674": "de5b6f", - "4a7310": "982443", - "a5d673": "e16363", - "63b56b": "9e2056", - "215201": "710f2e" + "4a7310": "982443" }, "2": { + "196b21": "b59c72", + "7ba563": "805a9c", + "215201": "694d37", + "215200": "41334d", + "a5d674": "f6f7df", + "8cbd63": "ebe9ca", + "63b56b": "e3ddb8", + "a5d670": "a473ba", "319452": "b59c72", "4aa552": "c9b991", - "7ba563": "805a9c", - "8cbd63": "ebe9ca", - "215200": "41334d", - "196b21": "b59c72", - "a5d674": "f6f7df", - "4a7310": "4f3956", - "a5d673": "a473ba", - "63b56b": "e3ddb8", - "215201": "694d37" + "4a7310": "4f3956" } } \ No newline at end of file diff --git a/public/images/pokemon/variant/female/332.json b/public/images/pokemon/variant/female/332.json index c86429d13c4..7a1dc0f1457 100644 --- a/public/images/pokemon/variant/female/332.json +++ b/public/images/pokemon/variant/female/332.json @@ -1,34 +1,36 @@ { "1": { - "319452": "780d4a", - "4a7310": "982443", - "7ba563": "b44040", - "bdef84": "ec8c8c", "8cbd63": "bf3d64", - "215200": "710f2e", + "a5d670": "de5b6f", + "4aa552": "8a1652", "a5d674": "e16363", - "196b21": "7d1157", + "7aa953": "bf3d64", + "7ba563": "b44040", + "215200": "710f2e", "f7ce00": "5bcfc3", "525252": "20668c", - "63b56b": "9e2056", - "a5d673": "de5b6f", "8c6b3a": "33a3b0", - "4aa552": "8a1652" + "bdef84": "ec8c8c", + "63b56b": "9e2056", + "319452": "780d4a", + "196b21": "7d1157", + "4a7310": "982443" }, "2": { - "319452": "b59c72", - "4a7310": "4f3956", - "7ba563": "805a9c", - "bdef84": "c193cf", "8cbd63": "f6f7df", - "215200": "694d37", + "a5d670": "ebe9ca", + "4aa552": "c9b991", "a5d674": "a473ba", - "196b21": "9c805f", + "7aa953": "805a9c", + "7ba563": "805a9c", + "215200": "694d37", "f7ce00": "f2aab6", "525252": "983364", - "63b56b": "e3ddb8", - "a5d673": "ebe9ca", "8c6b3a": "df879f", - "4aa552": "c9b991" + "bdef84": "c193cf", + "63b56b": "e3ddb8", + "319452": "b59c72", + "196b21": "9c805f", + "4a7310": "4f3956" } } \ No newline at end of file diff --git a/public/images/statuses_ca-ES.json b/public/images/statuses_ca.json similarity index 98% rename from public/images/statuses_ca-ES.json rename to public/images/statuses_ca.json index be1b78e0e41..6ff0f74a73b 100644 --- a/public/images/statuses_ca-ES.json +++ b/public/images/statuses_ca.json @@ -1,7 +1,7 @@ { "textures": [ { - "image": "statuses_ca_ES.png", + "image": "statuses_ca.png", "format": "RGBA8888", "size": { "w": 22, diff --git a/public/images/statuses_ca-ES.png b/public/images/statuses_ca.png similarity index 100% rename from public/images/statuses_ca-ES.png rename to public/images/statuses_ca.png diff --git a/public/images/statuses_da.json b/public/images/statuses_da.json new file mode 100644 index 00000000000..b9bf56324de --- /dev/null +++ b/public/images/statuses_da.json @@ -0,0 +1,188 @@ +{ + "textures": [ + { + "image": "statuses_da.png", + "format": "RGBA8888", + "size": { + "w": 22, + "h": 64 + }, + "scale": 1, + "frames": [ + { + "filename": "pokerus", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 22, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 22, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 22, + "h": 8 + } + }, + { + "filename": "burn", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 8, + "w": 20, + "h": 8 + } + }, + { + "filename": "faint", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 16, + "w": 20, + "h": 8 + } + }, + { + "filename": "freeze", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 24, + "w": 20, + "h": 8 + } + }, + { + "filename": "paralysis", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 32, + "w": 20, + "h": 8 + } + }, + { + "filename": "poison", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 40, + "w": 20, + "h": 8 + } + }, + { + "filename": "sleep", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 48, + "w": 20, + "h": 8 + } + }, + { + "filename": "toxic", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 56, + "w": 20, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$" + } +} diff --git a/public/images/statuses_da.png b/public/images/statuses_da.png new file mode 100644 index 00000000000..02780bddd98 Binary files /dev/null and b/public/images/statuses_da.png differ diff --git a/public/images/statuses_ro.json b/public/images/statuses_ro.json new file mode 100644 index 00000000000..f85ebbb5213 --- /dev/null +++ b/public/images/statuses_ro.json @@ -0,0 +1,188 @@ +{ + "textures": [ + { + "image": "statuses_ro.png", + "format": "RGBA8888", + "size": { + "w": 22, + "h": 64 + }, + "scale": 1, + "frames": [ + { + "filename": "pokerus", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 22, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 22, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 22, + "h": 8 + } + }, + { + "filename": "burn", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 8, + "w": 20, + "h": 8 + } + }, + { + "filename": "faint", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 16, + "w": 20, + "h": 8 + } + }, + { + "filename": "freeze", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 24, + "w": 20, + "h": 8 + } + }, + { + "filename": "paralysis", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 32, + "w": 20, + "h": 8 + } + }, + { + "filename": "poison", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 40, + "w": 20, + "h": 8 + } + }, + { + "filename": "sleep", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 48, + "w": 20, + "h": 8 + } + }, + { + "filename": "toxic", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 56, + "w": 20, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$" + } +} diff --git a/public/images/statuses_ro.png b/public/images/statuses_ro.png new file mode 100644 index 00000000000..537b634c520 Binary files /dev/null and b/public/images/statuses_ro.png differ diff --git a/public/images/statuses_ru.json b/public/images/statuses_ru.json new file mode 100644 index 00000000000..5e4790b2874 --- /dev/null +++ b/public/images/statuses_ru.json @@ -0,0 +1,188 @@ +{ + "textures": [ + { + "image": "statuses_ru.png", + "format": "RGBA8888", + "size": { + "w": 22, + "h": 64 + }, + "scale": 1, + "frames": [ + { + "filename": "pokerus", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 22, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 22, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 22, + "h": 8 + } + }, + { + "filename": "burn", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 8, + "w": 20, + "h": 8 + } + }, + { + "filename": "faint", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 16, + "w": 20, + "h": 8 + } + }, + { + "filename": "freeze", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 24, + "w": 20, + "h": 8 + } + }, + { + "filename": "paralysis", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 32, + "w": 20, + "h": 8 + } + }, + { + "filename": "poison", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 40, + "w": 20, + "h": 8 + } + }, + { + "filename": "sleep", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 48, + "w": 20, + "h": 8 + } + }, + { + "filename": "toxic", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 56, + "w": 20, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$" + } +} diff --git a/public/images/statuses_ru.png b/public/images/statuses_ru.png new file mode 100644 index 00000000000..1da8b66a4f8 Binary files /dev/null and b/public/images/statuses_ru.png differ diff --git a/public/images/statuses_tr.json b/public/images/statuses_tr.json new file mode 100644 index 00000000000..d9530368cb7 --- /dev/null +++ b/public/images/statuses_tr.json @@ -0,0 +1,188 @@ +{ + "textures": [ + { + "image": "statuses_tr.png", + "format": "RGBA8888", + "size": { + "w": 22, + "h": 64 + }, + "scale": 1, + "frames": [ + { + "filename": "pokerus", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 22, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 22, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 22, + "h": 8 + } + }, + { + "filename": "burn", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 8, + "w": 20, + "h": 8 + } + }, + { + "filename": "faint", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 16, + "w": 20, + "h": 8 + } + }, + { + "filename": "freeze", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 24, + "w": 20, + "h": 8 + } + }, + { + "filename": "paralysis", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 32, + "w": 20, + "h": 8 + } + }, + { + "filename": "poison", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 40, + "w": 20, + "h": 8 + } + }, + { + "filename": "sleep", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 48, + "w": 20, + "h": 8 + } + }, + { + "filename": "toxic", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 20, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 20, + "h": 8 + }, + "frame": { + "x": 0, + "y": 56, + "w": 20, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$" + } +} diff --git a/public/images/statuses_tr.png b/public/images/statuses_tr.png new file mode 100644 index 00000000000..d372b989be9 Binary files /dev/null and b/public/images/statuses_tr.png differ diff --git a/public/images/types_ca-ES.json b/public/images/types_ca.json similarity index 99% rename from public/images/types_ca-ES.json rename to public/images/types_ca.json index fa3abaaf259..aaa04fbad36 100644 --- a/public/images/types_ca-ES.json +++ b/public/images/types_ca.json @@ -1,7 +1,7 @@ { "textures": [ { - "image": "types_ca-ES.png", + "image": "types_ca.png", "format": "RGBA8888", "size": { "w": 32, diff --git a/public/images/types_ca-ES.png b/public/images/types_ca.png similarity index 100% rename from public/images/types_ca-ES.png rename to public/images/types_ca.png diff --git a/public/images/types_da.json b/public/images/types_da.json new file mode 100644 index 00000000000..d1c01de1e0e --- /dev/null +++ b/public/images/types_da.json @@ -0,0 +1,440 @@ +{ + "textures": [ + { + "image": "types_da.png", + "format": "RGBA8888", + "size": { + "w": 32, + "h": 280 + }, + "scale": 1, + "frames": [ + { + "filename": "unknown", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + } + }, + { + "filename": "bug", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 14, + "w": 32, + "h": 14 + } + }, + { + "filename": "dark", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 28, + "w": 32, + "h": 14 + } + }, + { + "filename": "dragon", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 42, + "w": 32, + "h": 14 + } + }, + { + "filename": "electric", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 56, + "w": 32, + "h": 14 + } + }, + { + "filename": "fairy", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 70, + "w": 32, + "h": 14 + } + }, + { + "filename": "fighting", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 84, + "w": 32, + "h": 14 + } + }, + { + "filename": "fire", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 98, + "w": 32, + "h": 14 + } + }, + { + "filename": "flying", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 112, + "w": 32, + "h": 14 + } + }, + { + "filename": "ghost", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 126, + "w": 32, + "h": 14 + } + }, + { + "filename": "grass", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 140, + "w": 32, + "h": 14 + } + }, + { + "filename": "ground", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 154, + "w": 32, + "h": 14 + } + }, + { + "filename": "ice", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 168, + "w": 32, + "h": 14 + } + }, + { + "filename": "normal", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 182, + "w": 32, + "h": 14 + } + }, + { + "filename": "poison", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 196, + "w": 32, + "h": 14 + } + }, + { + "filename": "psychic", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 210, + "w": 32, + "h": 14 + } + }, + { + "filename": "rock", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 224, + "w": 32, + "h": 14 + } + }, + { + "filename": "steel", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 238, + "w": 32, + "h": 14 + } + }, + { + "filename": "water", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 252, + "w": 32, + "h": 14 + } + }, + { + "filename": "stellar", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 266, + "w": 32, + "h": 14 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:f14cf47d9a8f1d40c8e03aa6ba00fff3:6fc4227b57a95d429a1faad4280f7ec8:5961efbfbf4c56b8745347e7a663a32f$" + } +} diff --git a/public/images/types_da.png b/public/images/types_da.png new file mode 100644 index 00000000000..f2b7af8967a Binary files /dev/null and b/public/images/types_da.png differ diff --git a/public/images/types_ro.json b/public/images/types_ro.json new file mode 100644 index 00000000000..efdbeba38a0 --- /dev/null +++ b/public/images/types_ro.json @@ -0,0 +1,440 @@ +{ + "textures": [ + { + "image": "types_ro.png", + "format": "RGBA8888", + "size": { + "w": 32, + "h": 280 + }, + "scale": 1, + "frames": [ + { + "filename": "unknown", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + } + }, + { + "filename": "bug", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 14, + "w": 32, + "h": 14 + } + }, + { + "filename": "dark", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 28, + "w": 32, + "h": 14 + } + }, + { + "filename": "dragon", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 42, + "w": 32, + "h": 14 + } + }, + { + "filename": "electric", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 56, + "w": 32, + "h": 14 + } + }, + { + "filename": "fairy", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 70, + "w": 32, + "h": 14 + } + }, + { + "filename": "fighting", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 84, + "w": 32, + "h": 14 + } + }, + { + "filename": "fire", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 98, + "w": 32, + "h": 14 + } + }, + { + "filename": "flying", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 112, + "w": 32, + "h": 14 + } + }, + { + "filename": "ghost", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 126, + "w": 32, + "h": 14 + } + }, + { + "filename": "grass", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 140, + "w": 32, + "h": 14 + } + }, + { + "filename": "ground", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 154, + "w": 32, + "h": 14 + } + }, + { + "filename": "ice", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 168, + "w": 32, + "h": 14 + } + }, + { + "filename": "normal", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 182, + "w": 32, + "h": 14 + } + }, + { + "filename": "poison", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 196, + "w": 32, + "h": 14 + } + }, + { + "filename": "psychic", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 210, + "w": 32, + "h": 14 + } + }, + { + "filename": "rock", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 224, + "w": 32, + "h": 14 + } + }, + { + "filename": "steel", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 238, + "w": 32, + "h": 14 + } + }, + { + "filename": "water", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 252, + "w": 32, + "h": 14 + } + }, + { + "filename": "stellar", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 266, + "w": 32, + "h": 14 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:f14cf47d9a8f1d40c8e03aa6ba00fff3:6fc4227b57a95d429a1faad4280f7ec8:5961efbfbf4c56b8745347e7a663a32f$" + } +} diff --git a/public/images/types_ro.png b/public/images/types_ro.png new file mode 100644 index 00000000000..35b09a37035 Binary files /dev/null and b/public/images/types_ro.png differ diff --git a/public/images/types_ru.json b/public/images/types_ru.json new file mode 100644 index 00000000000..536a0e31929 --- /dev/null +++ b/public/images/types_ru.json @@ -0,0 +1,440 @@ +{ + "textures": [ + { + "image": "types_ru.png", + "format": "RGBA8888", + "size": { + "w": 32, + "h": 280 + }, + "scale": 1, + "frames": [ + { + "filename": "unknown", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + } + }, + { + "filename": "bug", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 14, + "w": 32, + "h": 14 + } + }, + { + "filename": "dark", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 28, + "w": 32, + "h": 14 + } + }, + { + "filename": "dragon", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 42, + "w": 32, + "h": 14 + } + }, + { + "filename": "electric", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 56, + "w": 32, + "h": 14 + } + }, + { + "filename": "fairy", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 70, + "w": 32, + "h": 14 + } + }, + { + "filename": "fighting", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 84, + "w": 32, + "h": 14 + } + }, + { + "filename": "fire", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 98, + "w": 32, + "h": 14 + } + }, + { + "filename": "flying", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 112, + "w": 32, + "h": 14 + } + }, + { + "filename": "ghost", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 126, + "w": 32, + "h": 14 + } + }, + { + "filename": "grass", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 140, + "w": 32, + "h": 14 + } + }, + { + "filename": "ground", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 154, + "w": 32, + "h": 14 + } + }, + { + "filename": "ice", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 168, + "w": 32, + "h": 14 + } + }, + { + "filename": "normal", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 182, + "w": 32, + "h": 14 + } + }, + { + "filename": "poison", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 196, + "w": 32, + "h": 14 + } + }, + { + "filename": "psychic", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 210, + "w": 32, + "h": 14 + } + }, + { + "filename": "rock", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 224, + "w": 32, + "h": 14 + } + }, + { + "filename": "steel", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 238, + "w": 32, + "h": 14 + } + }, + { + "filename": "water", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 252, + "w": 32, + "h": 14 + } + }, + { + "filename": "stellar", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 266, + "w": 32, + "h": 14 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:f14cf47d9a8f1d40c8e03aa6ba00fff3:6fc4227b57a95d429a1faad4280f7ec8:5961efbfbf4c56b8745347e7a663a32f$" + } +} diff --git a/public/images/types_ru.png b/public/images/types_ru.png new file mode 100644 index 00000000000..571e162e8dc Binary files /dev/null and b/public/images/types_ru.png differ diff --git a/public/images/types_tr.json b/public/images/types_tr.json new file mode 100644 index 00000000000..ee82cce3fb4 --- /dev/null +++ b/public/images/types_tr.json @@ -0,0 +1,440 @@ +{ + "textures": [ + { + "image": "types_tr.png", + "format": "RGBA8888", + "size": { + "w": 32, + "h": 280 + }, + "scale": 1, + "frames": [ + { + "filename": "unknown", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + } + }, + { + "filename": "bug", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 14, + "w": 32, + "h": 14 + } + }, + { + "filename": "dark", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 28, + "w": 32, + "h": 14 + } + }, + { + "filename": "dragon", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 42, + "w": 32, + "h": 14 + } + }, + { + "filename": "electric", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 56, + "w": 32, + "h": 14 + } + }, + { + "filename": "fairy", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 70, + "w": 32, + "h": 14 + } + }, + { + "filename": "fighting", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 84, + "w": 32, + "h": 14 + } + }, + { + "filename": "fire", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 98, + "w": 32, + "h": 14 + } + }, + { + "filename": "flying", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 112, + "w": 32, + "h": 14 + } + }, + { + "filename": "ghost", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 126, + "w": 32, + "h": 14 + } + }, + { + "filename": "grass", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 140, + "w": 32, + "h": 14 + } + }, + { + "filename": "ground", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 154, + "w": 32, + "h": 14 + } + }, + { + "filename": "ice", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 168, + "w": 32, + "h": 14 + } + }, + { + "filename": "normal", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 182, + "w": 32, + "h": 14 + } + }, + { + "filename": "poison", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 196, + "w": 32, + "h": 14 + } + }, + { + "filename": "psychic", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 210, + "w": 32, + "h": 14 + } + }, + { + "filename": "rock", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 224, + "w": 32, + "h": 14 + } + }, + { + "filename": "steel", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 238, + "w": 32, + "h": 14 + } + }, + { + "filename": "water", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 252, + "w": 32, + "h": 14 + } + }, + { + "filename": "stellar", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 32, + "h": 14 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 32, + "h": 14 + }, + "frame": { + "x": 0, + "y": 266, + "w": 32, + "h": 14 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:f14cf47d9a8f1d40c8e03aa6ba00fff3:6fc4227b57a95d429a1faad4280f7ec8:5961efbfbf4c56b8745347e7a663a32f$" + } +} diff --git a/public/images/types_tr.png b/public/images/types_tr.png new file mode 100644 index 00000000000..8b644f1041c Binary files /dev/null and b/public/images/types_tr.png differ diff --git a/public/locales b/public/locales index 42cd5cf577f..88c60b6f8d5 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit 42cd5cf577f475c22bc82d55e7ca358eb4f3184f +Subproject commit 88c60b6f8d5babfb0c157b31ceff22486712295c diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index b677dd2bd11..f49863639f0 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -7425,7 +7425,12 @@ export function initAbilities() { .uncopiable() .attr(NoTransformAbilityAbAttr), new Ability(Abilities.GOOD_AS_GOLD, 9) - .attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.category === MoveCategory.STATUS && ![ MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES, MoveTarget.USER_SIDE ].includes(move.moveTarget)) + .attr(MoveImmunityAbAttr, (pokemon, attacker, move) => + pokemon !== attacker + && move.category === MoveCategory.STATUS + && ![ MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES, MoveTarget.USER_SIDE ].includes(move.moveTarget) + ) + .edgeCase() // Heal Bell should not cure the status of a Pokemon with Good As Gold .ignorable(), new Ability(Abilities.VESSEL_OF_RUIN, 9) .attr(FieldMultiplyStatAbAttr, Stat.SPATK, 0.75) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 59167ba47f6..5c97f360094 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -1697,8 +1697,8 @@ export function initSpecies() { new PokemonSpecies(Species.CHINCHOU, 2, false, false, false, "Angler Pokémon", PokemonType.WATER, PokemonType.ELECTRIC, 0.5, 12, Abilities.VOLT_ABSORB, Abilities.ILLUMINATE, Abilities.WATER_ABSORB, 330, 75, 38, 38, 56, 56, 67, 190, 50, 66, GrowthRate.SLOW, 50, false), new PokemonSpecies(Species.LANTURN, 2, false, false, false, "Light Pokémon", PokemonType.WATER, PokemonType.ELECTRIC, 1.2, 22.5, Abilities.VOLT_ABSORB, Abilities.ILLUMINATE, Abilities.WATER_ABSORB, 460, 125, 58, 58, 76, 76, 67, 75, 50, 161, GrowthRate.SLOW, 50, false), new PokemonSpecies(Species.PICHU, 2, false, false, false, "Tiny Mouse Pokémon", PokemonType.ELECTRIC, null, 0.3, 2, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, GrowthRate.MEDIUM_FAST, 50, false, false, - new PokemonForm("Normal", "", PokemonType.ELECTRIC, null, 1.4, 61.5, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, false, null, true), - new PokemonForm("Spiky-Eared", "spiky", PokemonType.ELECTRIC, null, 1.4, 61.5, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, false, null, true), + new PokemonForm("Normal", "", PokemonType.ELECTRIC, null, 1.4, 2, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, false, null, true), + new PokemonForm("Spiky-Eared", "spiky", PokemonType.ELECTRIC, null, 1.4, 2, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 205, 20, 40, 15, 35, 35, 60, 190, 70, 41, false, null, true), ), new PokemonSpecies(Species.CLEFFA, 2, false, false, false, "Star Shape Pokémon", PokemonType.FAIRY, null, 0.3, 3, Abilities.CUTE_CHARM, Abilities.MAGIC_GUARD, Abilities.FRIEND_GUARD, 218, 50, 25, 28, 45, 55, 15, 150, 140, 44, GrowthRate.FAST, 25, false), new PokemonSpecies(Species.IGGLYBUFF, 2, false, false, false, "Balloon Pokémon", PokemonType.NORMAL, PokemonType.FAIRY, 0.3, 1, Abilities.CUTE_CHARM, Abilities.COMPETITIVE, Abilities.FRIEND_GUARD, 210, 90, 30, 15, 40, 20, 15, 170, 50, 42, GrowthRate.FAST, 25, false), @@ -3121,7 +3121,7 @@ export function initSpecies() { ), new PokemonSpecies(Species.WALKING_WAKE, 9, false, false, false, "Paradox Pokémon", PokemonType.WATER, PokemonType.DRAGON, 3.5, 280, Abilities.PROTOSYNTHESIS, Abilities.NONE, Abilities.NONE, 590, 99, 83, 91, 125, 83, 109, 10, 0, 295, GrowthRate.SLOW, null, false), //Custom Catchrate, matching Gouging Fire and Raging Bolt new PokemonSpecies(Species.IRON_LEAVES, 9, false, false, false, "Paradox Pokémon", PokemonType.GRASS, PokemonType.PSYCHIC, 1.5, 125, Abilities.QUARK_DRIVE, Abilities.NONE, Abilities.NONE, 590, 90, 130, 88, 70, 108, 104, 10, 0, 295, GrowthRate.SLOW, null, false), //Custom Catchrate, matching Iron Boulder and Iron Crown - new PokemonSpecies(Species.DIPPLIN, 9, false, false, false, "Candy Apple Pokémon", PokemonType.GRASS, PokemonType.DRAGON, 0.4, 9.7, Abilities.SUPERSWEET_SYRUP, Abilities.GLUTTONY, Abilities.STICKY_HOLD, 485, 80, 80, 110, 95, 80, 40, 45, 50, 170, GrowthRate.ERRATIC, 50, false), + new PokemonSpecies(Species.DIPPLIN, 9, false, false, false, "Candy Apple Pokémon", PokemonType.GRASS, PokemonType.DRAGON, 0.4, 4.4, Abilities.SUPERSWEET_SYRUP, Abilities.GLUTTONY, Abilities.STICKY_HOLD, 485, 80, 80, 110, 95, 80, 40, 45, 50, 170, GrowthRate.ERRATIC, 50, false), new PokemonSpecies(Species.POLTCHAGEIST, 9, false, false, false, "Matcha Pokémon", PokemonType.GRASS, PokemonType.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, GrowthRate.SLOW, null, false, false, new PokemonForm("Counterfeit Form", "counterfeit", PokemonType.GRASS, PokemonType.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, false, null, true), new PokemonForm("Artisan Form", "artisan", PokemonType.GRASS, PokemonType.GHOST, 0.1, 1.1, Abilities.HOSPITALITY, Abilities.NONE, Abilities.HEATPROOF, 308, 40, 45, 45, 74, 54, 50, 120, 50, 62, false, null, false, true), diff --git a/src/enums/drop-down-column.ts b/src/enums/drop-down-column.ts new file mode 100644 index 00000000000..b413d1f0bf4 --- /dev/null +++ b/src/enums/drop-down-column.ts @@ -0,0 +1,9 @@ +export enum DropDownColumn { + GEN, + TYPES, + BIOME, + CAUGHT, + UNLOCKS, + MISC, + SORT +} diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 85b003517a6..329ba06fd09 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -5,7 +5,9 @@ import { globalScene } from "#app/global-scene"; import type { Variant } from "#app/sprites/variant"; import { populateVariantColors, variantColorCache } from "#app/sprites/variant"; import { variantData } from "#app/sprites/variant"; -import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "#app/ui/battle-info"; +import BattleInfo from "#app/ui/battle-info/battle-info"; +import { EnemyBattleInfo } from "#app/ui/battle-info/enemy-battle-info"; +import { PlayerBattleInfo } from "#app/ui/battle-info/player-battle-info"; import type Move from "#app/data/moves/move"; import { HighCritAttr, @@ -3347,22 +3349,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.battleInfo.updateInfo(this, instant); } - /** - * Show or hide the type effectiveness multiplier window - * Passing undefined will hide the window - */ - updateEffectiveness(effectiveness?: string) { - this.battleInfo.updateEffectiveness(effectiveness); - } - toggleStats(visible: boolean): void { this.battleInfo.toggleStats(visible); } - toggleFlyout(visible: boolean): void { - this.battleInfo.toggleFlyout(visible); - } - /** * Adds experience to this PlayerPokemon, subject to wave based level caps. * @param exp The amount of experience to add @@ -5518,6 +5508,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } export class PlayerPokemon extends Pokemon { + protected battleInfo: PlayerBattleInfo; public compatibleTms: Moves[]; constructor( @@ -6038,6 +6029,7 @@ export class PlayerPokemon extends Pokemon { } export class EnemyPokemon extends Pokemon { + protected battleInfo: EnemyBattleInfo; public trainerSlot: TrainerSlot; public aiType: AiType; public bossSegments: number; @@ -6709,6 +6701,19 @@ export class EnemyPokemon extends Pokemon { return ret; } + + + /** + * Show or hide the type effectiveness multiplier window + * Passing undefined will hide the window + */ + updateEffectiveness(effectiveness?: string) { + this.battleInfo.updateEffectiveness(effectiveness); + } + + toggleFlyout(visible: boolean): void { + this.battleInfo.toggleFlyout(visible); + } } /** diff --git a/src/game-mode.ts b/src/game-mode.ts index ec7171b0024..97398d2b0a9 100644 --- a/src/game-mode.ts +++ b/src/game-mode.ts @@ -7,7 +7,7 @@ import type PokemonSpecies from "./data/pokemon-species"; import { allSpecies } from "./data/pokemon-species"; import type { Arena } from "./field/arena"; import Overrides from "#app/overrides"; -import { randSeedInt, randSeedItem } from "#app/utils/common"; +import { isNullOrUndefined, randSeedInt, randSeedItem } from "#app/utils/common"; import { Biome } from "#enums/biome"; import { Species } from "#enums/species"; import { Challenges } from "./enums/challenges"; @@ -124,16 +124,20 @@ export class GameMode implements GameModeConfig { /** * @returns either: - * - random biome for Daily mode * - override from overrides.ts + * - random biome for Daily mode * - Town */ getStartingBiome(): Biome { + if (!isNullOrUndefined(Overrides.STARTING_BIOME_OVERRIDE)) { + return Overrides.STARTING_BIOME_OVERRIDE; + } + switch (this.modeId) { case GameModes.DAILY: return getDailyStartingBiome(); default: - return Overrides.STARTING_BIOME_OVERRIDE || Biome.TOWN; + return Biome.TOWN; } } diff --git a/src/main.ts b/src/main.ts index 7db663d14c7..38bfcbe5636 100644 --- a/src/main.ts +++ b/src/main.ts @@ -29,7 +29,7 @@ window.addEventListener("unhandledrejection", event => { const setPositionRelative = function (guideObject: Phaser.GameObjects.GameObject, x: number, y: number) { const offsetX = guideObject.width * (-0.5 + (0.5 - guideObject.originX)); const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY)); - this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y); + return this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y); }; Phaser.GameObjects.Container.prototype.setPositionRelative = setPositionRelative; diff --git a/src/overrides.ts b/src/overrides.ts index 5bbd29b355f..95c758d7c43 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -73,7 +73,7 @@ class DefaultOverrides { */ readonly BATTLE_STYLE_OVERRIDE: BattleStyle | null = null; readonly STARTING_WAVE_OVERRIDE: number = 0; - readonly STARTING_BIOME_OVERRIDE: Biome = Biome.TOWN; + readonly STARTING_BIOME_OVERRIDE: Biome | null = null; readonly ARENA_TINT_OVERRIDE: TimeOfDay | null = null; /** Multiplies XP gained by this value including 0. Set to null to ignore the override. */ readonly XP_MULTIPLIER_OVERRIDE: number | null = null; diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index c61eb73118f..6bdbb66be14 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -125,6 +125,12 @@ export class SwitchSummonPhase extends SummonPhase { const switchedInPokemon: Pokemon | undefined = party[this.slotIndex]; this.lastPokemon = this.getPokemon(); + // Defensive programming: Overcome the bug where the summon data has somehow not been reset + // prior to switching in a new Pokemon. + // Force the switch to occur and load the assets for the new pokemon, ignoring override. + switchedInPokemon.resetSummonData(); + switchedInPokemon.loadAssets(true); + applyPreSummonAbAttrs(PreSummonAbAttr, switchedInPokemon); applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, this.lastPokemon); if (!switchedInPokemon) { @@ -132,6 +138,7 @@ export class SwitchSummonPhase extends SummonPhase { 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) => diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 63d3345b90d..c2d13badc01 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -65,14 +65,14 @@ const fonts: Array = [ unicodeRange: rangesByLanguage.chinese, }), extraOptions: { sizeAdjust: "70%", format: "woff2" }, - only: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca", "he"], + only: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca", "da", "tr", "ro", "ru", "he"], }, { face: new FontFace("pkmnems", "url(./fonts/unifont-15.1.05.subset.woff2)", { unicodeRange: rangesByLanguage.chinese, }), extraOptions: { format: "woff2" }, - only: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca", "he"], + only: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca", "da", "tr", "ro", "ru", "he"], }, // japanese { @@ -174,7 +174,7 @@ export async function initI18n(): Promise { "es-MX": ["es-ES", "en"], default: ["en"], }, - supportedLngs: ["en", "es-ES", "es-MX", "fr", "it", "de", "zh-CN", "zh-TW", "pt-BR", "ko", "ja", "ca-ES", "he"], + supportedLngs: ["en", "es-ES", "es-MX", "fr", "it", "de", "zh-CN", "zh-TW", "pt-BR", "ko", "ja", "ca", "da", "tr", "ro", "ru", "he"], backend: { loadPath(lng: string, [ns]: string[]) { let fileName: string; diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index 547dad30bc6..90b28ca9bc4 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -921,10 +921,6 @@ export function setSetting(setting: string, value: number): boolean { label: "Español (LATAM)", handler: () => changeLocaleHandler("es-MX"), }, - { - label: "Italiano", - handler: () => changeLocaleHandler("it"), - }, { label: "Français", handler: () => changeLocaleHandler("fr"), @@ -933,18 +929,14 @@ export function setSetting(setting: string, value: number): boolean { label: "Deutsch", handler: () => changeLocaleHandler("de"), }, + { + label: "Italiano", + handler: () => changeLocaleHandler("it"), + }, { label: "Português (BR)", handler: () => changeLocaleHandler("pt-BR"), }, - { - label: "简体中文", - handler: () => changeLocaleHandler("zh-CN"), - }, - { - label: "繁體中文", - handler: () => changeLocaleHandler("zh-TW"), - }, { label: "한국어", handler: () => changeLocaleHandler("ko"), @@ -954,8 +946,32 @@ export function setSetting(setting: string, value: number): boolean { handler: () => changeLocaleHandler("ja"), }, { - label: "Català", - handler: () => changeLocaleHandler("ca-ES"), + label: "简体中文", + handler: () => changeLocaleHandler("zh-CN"), + }, + { + label: "繁體中文", + handler: () => changeLocaleHandler("zh-TW"), + }, + { + label: "Català (Needs Help)", + handler: () => changeLocaleHandler("ca"), + }, + { + label: "Türkçe (Needs Help)", + handler: () => changeLocaleHandler("tr") + }, + { + label: "Русский (Needs Help)", + handler: () => changeLocaleHandler("ru"), + }, + { + label: "Dansk (Needs Help)", + handler: () => changeLocaleHandler("da") + }, + { + label: "Română (Needs Help)", + handler: () => changeLocaleHandler("ro") }, { label: "עברית", diff --git a/src/typings/phaser/index.d.ts b/src/typings/phaser/index.d.ts index f3665768cec..26fbcff75bd 100644 --- a/src/typings/phaser/index.d.ts +++ b/src/typings/phaser/index.d.ts @@ -20,37 +20,37 @@ declare module "phaser" { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface Sprite { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface Image { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface NineSlice { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface Text { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } interface Rectangle { /** * Sets this object's position relative to another object with a given offset */ - setPositionRelative(guideObject: any, x: number, y: number): void; + setPositionRelative(guideObject: any, x: number, y: number): this; } } diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index 0c13cdb9512..e4f11e1c93c 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -161,7 +161,7 @@ export class UiInputs { buttonInfo(pressed = true): void { if (globalScene.showMovesetFlyout) { - for (const p of globalScene.getField().filter(p => p?.isActive(true))) { + for (const p of globalScene.getEnemyField().filter(p => p?.isActive(true))) { p.toggleFlyout(pressed); } } diff --git a/src/ui/battle-flyout.ts b/src/ui/battle-flyout.ts index e590bebcf5a..f8ef5fc1ec4 100644 --- a/src/ui/battle-flyout.ts +++ b/src/ui/battle-flyout.ts @@ -1,4 +1,4 @@ -import type { default as Pokemon } from "../field/pokemon"; +import type { EnemyPokemon, default as Pokemon } from "../field/pokemon"; import { addTextObject, TextStyle } from "./text"; import { fixedInt } from "#app/utils/common"; import { globalScene } from "#app/global-scene"; @@ -126,7 +126,7 @@ export default class BattleFlyout extends Phaser.GameObjects.Container { * Links the given {@linkcode Pokemon} and subscribes to the {@linkcode BattleSceneEventType.MOVE_USED} event * @param pokemon {@linkcode Pokemon} to link to this flyout */ - initInfo(pokemon: Pokemon) { + initInfo(pokemon: EnemyPokemon) { this.pokemon = pokemon; this.name = `Flyout ${getPokemonNameWithAffix(this.pokemon)}`; diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts deleted file mode 100644 index 2822e8364ec..00000000000 --- a/src/ui/battle-info.ts +++ /dev/null @@ -1,986 +0,0 @@ -import type { EnemyPokemon, default as Pokemon } from "../field/pokemon"; -import { getLevelTotalExp, getLevelRelExp } from "../data/exp"; -import { getLocalizedSpriteKey, fixedInt } from "#app/utils/common"; -import { addTextObject, TextStyle } from "./text"; -import { getGenderSymbol, getGenderColor, Gender } from "../data/gender"; -import { StatusEffect } from "#enums/status-effect"; -import { globalScene } from "#app/global-scene"; -import { getTypeRgb } from "#app/data/type"; -import { PokemonType } from "#enums/pokemon-type"; -import { getVariantTint } from "#app/sprites/variant"; -import { Stat } from "#enums/stat"; -import BattleFlyout from "./battle-flyout"; -import { WindowVariant, addWindow } from "./ui-theme"; -import i18next from "i18next"; -import { ExpGainsSpeed } from "#app/enums/exp-gains-speed"; - -export default class BattleInfo extends Phaser.GameObjects.Container { - public static readonly EXP_GAINS_DURATION_BASE = 1650; - - private baseY: number; - - private player: boolean; - private mini: boolean; - private boss: boolean; - private bossSegments: number; - private offset: boolean; - private lastName: string | null; - private lastTeraType: PokemonType; - private lastStatus: StatusEffect; - private lastHp: number; - private lastMaxHp: number; - private lastHpFrame: string | null; - private lastExp: number; - private lastLevelExp: number; - private lastLevel: number; - private lastLevelCapped: boolean; - private lastStats: string; - - private box: Phaser.GameObjects.Sprite; - private nameText: Phaser.GameObjects.Text; - private genderText: Phaser.GameObjects.Text; - private ownedIcon: Phaser.GameObjects.Sprite; - private championRibbon: Phaser.GameObjects.Sprite; - private teraIcon: Phaser.GameObjects.Sprite; - private shinyIcon: Phaser.GameObjects.Sprite; - private fusionShinyIcon: Phaser.GameObjects.Sprite; - private splicedIcon: Phaser.GameObjects.Sprite; - private statusIndicator: Phaser.GameObjects.Sprite; - private levelContainer: Phaser.GameObjects.Container; - private hpBar: Phaser.GameObjects.Image; - private hpBarSegmentDividers: Phaser.GameObjects.Rectangle[]; - private levelNumbersContainer: Phaser.GameObjects.Container; - private hpNumbersContainer: Phaser.GameObjects.Container; - private type1Icon: Phaser.GameObjects.Sprite; - private type2Icon: Phaser.GameObjects.Sprite; - private type3Icon: Phaser.GameObjects.Sprite; - private expBar: Phaser.GameObjects.Image; - - // #region Type effectiveness hint objects - private effectivenessContainer: Phaser.GameObjects.Container; - private effectivenessWindow: Phaser.GameObjects.NineSlice; - private effectivenessText: Phaser.GameObjects.Text; - private currentEffectiveness?: string; - // #endregion - - public expMaskRect: Phaser.GameObjects.Graphics; - - private statsContainer: Phaser.GameObjects.Container; - private statsBox: Phaser.GameObjects.Sprite; - private statValuesContainer: Phaser.GameObjects.Container; - private statNumbers: Phaser.GameObjects.Sprite[]; - - public flyoutMenu?: BattleFlyout; - - private statOrder: Stat[]; - private readonly statOrderPlayer = [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.ACC, Stat.EVA, Stat.SPD]; - private readonly statOrderEnemy = [Stat.HP, Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.ACC, Stat.EVA, Stat.SPD]; - - constructor(x: number, y: number, player: boolean) { - super(globalScene, x, y); - this.baseY = y; - this.player = player; - this.mini = !player; - this.boss = false; - this.offset = false; - this.lastName = null; - this.lastTeraType = PokemonType.UNKNOWN; - this.lastStatus = StatusEffect.NONE; - this.lastHp = -1; - this.lastMaxHp = -1; - this.lastHpFrame = null; - this.lastExp = -1; - this.lastLevelExp = -1; - this.lastLevel = -1; - - // Initially invisible and shown via Pokemon.showInfo - this.setVisible(false); - - this.box = globalScene.add.sprite(0, 0, this.getTextureName()); - this.box.setName("box"); - this.box.setOrigin(1, 0.5); - this.add(this.box); - - this.nameText = addTextObject(player ? -115 : -124, player ? -15.2 : -11.2, "", TextStyle.BATTLE_INFO); - this.nameText.setName("text_name"); - this.nameText.setOrigin(0, 0); - this.add(this.nameText); - - this.genderText = addTextObject(0, 0, "", TextStyle.BATTLE_INFO); - this.genderText.setName("text_gender"); - this.genderText.setOrigin(0, 0); - this.genderText.setPositionRelative(this.nameText, 0, 2); - this.add(this.genderText); - - if (!this.player) { - this.ownedIcon = globalScene.add.sprite(0, 0, "icon_owned"); - this.ownedIcon.setName("icon_owned"); - this.ownedIcon.setVisible(false); - this.ownedIcon.setOrigin(0, 0); - this.ownedIcon.setPositionRelative(this.nameText, 0, 11.75); - this.add(this.ownedIcon); - - this.championRibbon = globalScene.add.sprite(0, 0, "champion_ribbon"); - this.championRibbon.setName("icon_champion_ribbon"); - this.championRibbon.setVisible(false); - this.championRibbon.setOrigin(0, 0); - this.championRibbon.setPositionRelative(this.nameText, 8, 11.75); - this.add(this.championRibbon); - } - - this.teraIcon = globalScene.add.sprite(0, 0, "icon_tera"); - this.teraIcon.setName("icon_tera"); - this.teraIcon.setVisible(false); - this.teraIcon.setOrigin(0, 0); - this.teraIcon.setScale(0.5); - this.teraIcon.setPositionRelative(this.nameText, 0, 2); - this.teraIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains); - this.add(this.teraIcon); - - this.shinyIcon = globalScene.add.sprite(0, 0, "shiny_star"); - this.shinyIcon.setName("icon_shiny"); - this.shinyIcon.setVisible(false); - this.shinyIcon.setOrigin(0, 0); - this.shinyIcon.setScale(0.5); - this.shinyIcon.setPositionRelative(this.nameText, 0, 2); - this.shinyIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains); - this.add(this.shinyIcon); - - this.fusionShinyIcon = globalScene.add.sprite(0, 0, "shiny_star_2"); - this.fusionShinyIcon.setName("icon_fusion_shiny"); - this.fusionShinyIcon.setVisible(false); - this.fusionShinyIcon.setOrigin(0, 0); - this.fusionShinyIcon.setScale(0.5); - this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); - this.add(this.fusionShinyIcon); - - this.splicedIcon = globalScene.add.sprite(0, 0, "icon_spliced"); - this.splicedIcon.setName("icon_spliced"); - this.splicedIcon.setVisible(false); - this.splicedIcon.setOrigin(0, 0); - this.splicedIcon.setScale(0.5); - this.splicedIcon.setPositionRelative(this.nameText, 0, 2); - this.splicedIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains); - this.add(this.splicedIcon); - - this.statusIndicator = globalScene.add.sprite(0, 0, getLocalizedSpriteKey("statuses")); - this.statusIndicator.setName("icon_status"); - this.statusIndicator.setVisible(false); - this.statusIndicator.setOrigin(0, 0); - this.statusIndicator.setPositionRelative(this.nameText, 0, 11.5); - this.add(this.statusIndicator); - - this.levelContainer = globalScene.add.container(player ? -41 : -50, player ? -10 : -5); - this.levelContainer.setName("container_level"); - this.add(this.levelContainer); - - const levelOverlay = globalScene.add.image(0, 0, "overlay_lv"); - this.levelContainer.add(levelOverlay); - - this.hpBar = globalScene.add.image(player ? -61 : -71, player ? -1 : 4.5, "overlay_hp"); - this.hpBar.setName("hp_bar"); - this.hpBar.setOrigin(0); - this.add(this.hpBar); - - this.hpBarSegmentDividers = []; - - this.levelNumbersContainer = globalScene.add.container(9.5, globalScene.uiTheme ? 0 : -0.5); - this.levelNumbersContainer.setName("container_level"); - this.levelContainer.add(this.levelNumbersContainer); - - if (this.player) { - this.hpNumbersContainer = globalScene.add.container(-15, 10); - this.hpNumbersContainer.setName("container_hp"); - this.add(this.hpNumbersContainer); - - const expBar = globalScene.add.image(-98, 18, "overlay_exp"); - expBar.setName("overlay_exp"); - expBar.setOrigin(0); - this.add(expBar); - - const expMaskRect = globalScene.make.graphics({}); - expMaskRect.setScale(6); - expMaskRect.fillStyle(0xffffff); - expMaskRect.beginPath(); - expMaskRect.fillRect(127, 126, 85, 2); - - const expMask = expMaskRect.createGeometryMask(); - - expBar.setMask(expMask); - - this.expBar = expBar; - this.expMaskRect = expMaskRect; - } - - this.statsContainer = globalScene.add.container(0, 0); - this.statsContainer.setName("container_stats"); - this.statsContainer.setAlpha(0); - this.add(this.statsContainer); - - this.statsBox = globalScene.add.sprite(0, 0, `${this.getTextureName()}_stats`); - this.statsBox.setName("box_stats"); - this.statsBox.setOrigin(1, 0.5); - this.statsContainer.add(this.statsBox); - - const statLabels: Phaser.GameObjects.Sprite[] = []; - this.statNumbers = []; - - this.statValuesContainer = globalScene.add.container(0, 0); - this.statsContainer.add(this.statValuesContainer); - - // this gives us a different starting location from the left of the label and padding between stats for a player vs enemy - // since the player won't have HP to show, it doesn't need to change from the current version - const startingX = this.player ? -this.statsBox.width + 8 : -this.statsBox.width + 5; - const paddingX = this.player ? 4 : 2; - const statOverflow = this.player ? 1 : 0; - this.statOrder = this.player ? this.statOrderPlayer : this.statOrderEnemy; // this tells us whether or not to use the player or enemy battle stat order - - this.statOrder.map((s, i) => { - // we do a check for i > statOverflow to see when the stat labels go onto the next column - // For enemies, we have HP (i=0) by itself then a new column, so we check for i > 0 - // For players, we don't have HP, so we start with i = 0 and i = 1 for our first column, and so need to check for i > 1 - const statX = - i > statOverflow - ? this.statNumbers[Math.max(i - 2, 0)].x + this.statNumbers[Math.max(i - 2, 0)].width + paddingX - : startingX; // we have the Math.max(i - 2, 0) in there so for i===1 to not return a negative number; since this is now based on anything >0 instead of >1, we need to allow for i-2 < 0 - - const baseY = -this.statsBox.height / 2 + 4; // this is the baseline for the y-axis - let statY: number; // this will be the y-axis placement for the labels - if (this.statOrder[i] === Stat.SPD || this.statOrder[i] === Stat.HP) { - statY = baseY + 5; - } else { - statY = baseY + (!!(i % 2) === this.player ? 10 : 0); // we compare i % 2 against this.player to tell us where to place the label; because this.battleStatOrder for enemies has HP, this.battleStatOrder[1]=ATK, but for players this.battleStatOrder[0]=ATK, so this comparing i % 2 to this.player fixes this issue for us - } - - const statLabel = globalScene.add.sprite(statX, statY, "pbinfo_stat", Stat[s]); - statLabel.setName("icon_stat_label_" + i.toString()); - statLabel.setOrigin(0, 0); - statLabels.push(statLabel); - this.statValuesContainer.add(statLabel); - - const statNumber = globalScene.add.sprite( - statX + statLabel.width, - statY, - "pbinfo_stat_numbers", - this.statOrder[i] !== Stat.HP ? "3" : "empty", - ); - statNumber.setName("icon_stat_number_" + i.toString()); - statNumber.setOrigin(0, 0); - this.statNumbers.push(statNumber); - this.statValuesContainer.add(statNumber); - - if (this.statOrder[i] === Stat.HP) { - statLabel.setVisible(false); - statNumber.setVisible(false); - } - }); - - if (!this.player) { - this.flyoutMenu = new BattleFlyout(this.player); - this.add(this.flyoutMenu); - - this.moveBelow(this.flyoutMenu, this.box); - } - - this.type1Icon = globalScene.add.sprite( - player ? -139 : -15, - player ? -17 : -15.5, - `pbinfo_${player ? "player" : "enemy"}_type1`, - ); - this.type1Icon.setName("icon_type_1"); - this.type1Icon.setOrigin(0, 0); - this.add(this.type1Icon); - - this.type2Icon = globalScene.add.sprite( - player ? -139 : -15, - player ? -1 : -2.5, - `pbinfo_${player ? "player" : "enemy"}_type2`, - ); - this.type2Icon.setName("icon_type_2"); - this.type2Icon.setOrigin(0, 0); - this.add(this.type2Icon); - - this.type3Icon = globalScene.add.sprite( - player ? -154 : 0, - player ? -17 : -15.5, - `pbinfo_${player ? "player" : "enemy"}_type`, - ); - this.type3Icon.setName("icon_type_3"); - this.type3Icon.setOrigin(0, 0); - this.add(this.type3Icon); - - if (!this.player) { - this.effectivenessContainer = globalScene.add.container(0, 0); - this.effectivenessContainer.setPositionRelative(this.type1Icon, 22, 4); - this.effectivenessContainer.setVisible(false); - this.add(this.effectivenessContainer); - - this.effectivenessText = addTextObject(5, 4.5, "", TextStyle.BATTLE_INFO); - this.effectivenessWindow = addWindow(0, 0, 0, 20, undefined, false, undefined, undefined, WindowVariant.XTHIN); - - this.effectivenessContainer.add(this.effectivenessWindow); - this.effectivenessContainer.add(this.effectivenessText); - } - } - - getStatsValueContainer(): Phaser.GameObjects.Container { - return this.statValuesContainer; - } - - initInfo(pokemon: Pokemon) { - this.updateNameText(pokemon); - const nameTextWidth = this.nameText.displayWidth; - - this.name = pokemon.getNameToRender(); - this.box.name = pokemon.getNameToRender(); - - this.flyoutMenu?.initInfo(pokemon); - - this.genderText.setText(getGenderSymbol(pokemon.gender)); - this.genderText.setColor(getGenderColor(pokemon.gender)); - this.genderText.setPositionRelative(this.nameText, nameTextWidth, 0); - - this.lastTeraType = pokemon.getTeraType(); - - this.teraIcon.setPositionRelative(this.nameText, nameTextWidth + this.genderText.displayWidth + 1, 2); - this.teraIcon.setVisible(pokemon.isTerastallized); - this.teraIcon.on("pointerover", () => { - if (pokemon.isTerastallized) { - globalScene.ui.showTooltip( - "", - i18next.t("fightUiHandler:teraHover", { - type: i18next.t(`pokemonInfo:Type.${PokemonType[this.lastTeraType]}`), - }), - ); - } - }); - this.teraIcon.on("pointerout", () => globalScene.ui.hideTooltip()); - - const isFusion = pokemon.isFusion(true); - - this.splicedIcon.setPositionRelative( - this.nameText, - nameTextWidth + this.genderText.displayWidth + 1 + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), - 2.5, - ); - this.splicedIcon.setVisible(isFusion); - if (this.splicedIcon.visible) { - this.splicedIcon.on("pointerover", () => - globalScene.ui.showTooltip( - "", - `${pokemon.species.getName(pokemon.formIndex)}/${pokemon.fusionSpecies?.getName(pokemon.fusionFormIndex)}`, - ), - ); - this.splicedIcon.on("pointerout", () => globalScene.ui.hideTooltip()); - } - - const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; - const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; - - this.shinyIcon.setPositionRelative( - this.nameText, - nameTextWidth + - this.genderText.displayWidth + - 1 + - (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) + - (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0), - 2.5, - ); - this.shinyIcon.setTexture(`shiny_star${doubleShiny ? "_1" : ""}`); - this.shinyIcon.setVisible(pokemon.isShiny()); - this.shinyIcon.setTint(getVariantTint(baseVariant)); - if (this.shinyIcon.visible) { - const shinyDescriptor = - doubleShiny || baseVariant - ? `${baseVariant === 2 ? i18next.t("common:epicShiny") : baseVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}${doubleShiny ? `/${pokemon.fusionVariant === 2 ? i18next.t("common:epicShiny") : pokemon.fusionVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}` : ""}` - : ""; - this.shinyIcon.on("pointerover", () => - globalScene.ui.showTooltip( - "", - `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, - ), - ); - this.shinyIcon.on("pointerout", () => globalScene.ui.hideTooltip()); - } - - this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); - this.fusionShinyIcon.setVisible(doubleShiny); - if (isFusion) { - this.fusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); - } - - if (!this.player) { - if (this.nameText.visible) { - this.nameText.on("pointerover", () => - globalScene.ui.showTooltip( - "", - i18next.t("battleInfo:generation", { - generation: i18next.t(`starterSelectUiHandler:gen${pokemon.species.generation}`), - }), - ), - ); - this.nameText.on("pointerout", () => globalScene.ui.hideTooltip()); - } - - const dexEntry = globalScene.gameData.dexData[pokemon.species.speciesId]; - this.ownedIcon.setVisible(!!dexEntry.caughtAttr); - const opponentPokemonDexAttr = pokemon.getDexAttr(); - if (globalScene.gameMode.isClassic) { - if ( - globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].classicWinCount > 0 && - globalScene.gameData.starterData[pokemon.species.getRootSpeciesId(true)].classicWinCount > 0 - ) { - this.championRibbon.setVisible(true); - } - } - - // Check if Player owns all genders and forms of the Pokemon - const missingDexAttrs = (dexEntry.caughtAttr & opponentPokemonDexAttr) < opponentPokemonDexAttr; - - const ownedAbilityAttrs = globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].abilityAttr; - - // Check if the player owns ability for the root form - const playerOwnsThisAbility = pokemon.checkIfPlayerHasAbilityOfStarter(ownedAbilityAttrs); - - if (missingDexAttrs || !playerOwnsThisAbility) { - this.ownedIcon.setTint(0x808080); - } - - if (this.boss) { - this.updateBossSegmentDividers(pokemon as EnemyPokemon); - } - } - - this.hpBar.setScale(pokemon.getHpRatio(true), 1); - this.lastHpFrame = this.hpBar.scaleX > 0.5 ? "high" : this.hpBar.scaleX > 0.25 ? "medium" : "low"; - this.hpBar.setFrame(this.lastHpFrame); - if (this.player) { - this.setHpNumbers(pokemon.hp, pokemon.getMaxHp()); - } - this.lastHp = pokemon.hp; - this.lastMaxHp = pokemon.getMaxHp(); - - this.setLevel(pokemon.level); - this.lastLevel = pokemon.level; - - this.shinyIcon.setVisible(pokemon.isShiny()); - - 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); - this.type3Icon.setVisible(types.length > 2); - if (types.length > 1) { - this.type2Icon.setFrame(PokemonType[types[1]].toLowerCase()); - } - if (types.length > 2) { - this.type3Icon.setFrame(PokemonType[types[2]].toLowerCase()); - } - - if (this.player) { - this.expMaskRect.x = (pokemon.levelExp / getLevelTotalExp(pokemon.level, pokemon.species.growthRate)) * 510; - this.lastExp = pokemon.exp; - this.lastLevelExp = pokemon.levelExp; - - this.statValuesContainer.setPosition(8, 7); - } - - const stats = this.statOrder.map(() => 0); - - this.lastStats = stats.join(""); - this.updateStats(stats); - } - - getTextureName(): string { - return `pbinfo_${this.player ? "player" : "enemy"}${!this.player && this.boss ? "_boss" : this.mini ? "_mini" : ""}`; - } - - setMini(mini: boolean): void { - if (this.mini === mini) { - return; - } - - this.mini = mini; - - this.box.setTexture(this.getTextureName()); - this.statsBox.setTexture(`${this.getTextureName()}_stats`); - - if (this.player) { - this.y -= 12 * (mini ? 1 : -1); - this.baseY = this.y; - } - - const offsetElements = [ - this.nameText, - this.genderText, - this.teraIcon, - this.splicedIcon, - this.shinyIcon, - this.statusIndicator, - this.levelContainer, - ]; - offsetElements.forEach(el => (el.y += 1.5 * (mini ? -1 : 1))); - - [this.type1Icon, this.type2Icon, this.type3Icon].forEach(el => { - el.x += 4 * (mini ? 1 : -1); - el.y += -8 * (mini ? 1 : -1); - }); - - this.statValuesContainer.x += 2 * (mini ? 1 : -1); - this.statValuesContainer.y += -7 * (mini ? 1 : -1); - - const toggledElements = [this.hpNumbersContainer, this.expBar]; - toggledElements.forEach(el => el.setVisible(!mini)); - } - - toggleStats(visible: boolean): void { - globalScene.tweens.add({ - targets: this.statsContainer, - duration: fixedInt(125), - ease: "Sine.easeInOut", - alpha: visible ? 1 : 0, - }); - } - - updateBossSegments(pokemon: EnemyPokemon): void { - const boss = !!pokemon.bossSegments; - - if (boss !== this.boss) { - this.boss = boss; - - [ - this.nameText, - this.genderText, - this.teraIcon, - this.splicedIcon, - this.shinyIcon, - this.ownedIcon, - this.championRibbon, - this.statusIndicator, - this.statValuesContainer, - ].map(e => (e.x += 48 * (boss ? -1 : 1))); - this.hpBar.x += 38 * (boss ? -1 : 1); - this.hpBar.y += 2 * (this.boss ? -1 : 1); - this.levelContainer.x += 2 * (boss ? -1 : 1); - this.hpBar.setTexture(`overlay_hp${boss ? "_boss" : ""}`); - this.box.setTexture(this.getTextureName()); - this.statsBox.setTexture(`${this.getTextureName()}_stats`); - } - - this.bossSegments = boss ? pokemon.bossSegments : 0; - this.updateBossSegmentDividers(pokemon); - } - - updateBossSegmentDividers(pokemon: EnemyPokemon): void { - while (this.hpBarSegmentDividers.length) { - this.hpBarSegmentDividers.pop()?.destroy(); - } - - if (this.boss && this.bossSegments > 1) { - const uiTheme = globalScene.uiTheme; - const maxHp = pokemon.getMaxHp(); - for (let s = 1; s < this.bossSegments; s++) { - const dividerX = (Math.round((maxHp / this.bossSegments) * s) / maxHp) * this.hpBar.width; - const divider = globalScene.add.rectangle( - 0, - 0, - 1, - this.hpBar.height - (uiTheme ? 0 : 1), - pokemon.bossSegmentIndex >= s ? 0xffffff : 0x404040, - ); - divider.setOrigin(0.5, 0); - divider.setName("hpBar_divider_" + s.toString()); - this.add(divider); - this.moveBelow(divider as Phaser.GameObjects.GameObject, this.statsContainer); - - divider.setPositionRelative(this.hpBar, dividerX, uiTheme ? 0 : 1); - this.hpBarSegmentDividers.push(divider); - } - } - } - - setOffset(offset: boolean): void { - if (this.offset === offset) { - return; - } - - this.offset = offset; - - this.x += 10 * (this.offset === this.player ? 1 : -1); - this.y += 27 * (this.offset ? 1 : -1); - this.baseY = this.y; - } - - updateInfo(pokemon: Pokemon, instant?: boolean): Promise { - return new Promise(resolve => { - if (!globalScene) { - return resolve(); - } - - const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; - - this.genderText.setText(getGenderSymbol(gender)); - this.genderText.setColor(getGenderColor(gender)); - - const nameUpdated = this.lastName !== pokemon.getNameToRender(); - - if (nameUpdated) { - this.updateNameText(pokemon); - this.genderText.setPositionRelative(this.nameText, this.nameText.displayWidth, 0); - } - - const teraType = pokemon.isTerastallized ? pokemon.getTeraType() : PokemonType.UNKNOWN; - const teraTypeUpdated = this.lastTeraType !== teraType; - - if (teraTypeUpdated) { - this.teraIcon.setVisible(teraType !== PokemonType.UNKNOWN); - this.teraIcon.setPositionRelative( - this.nameText, - this.nameText.displayWidth + this.genderText.displayWidth + 1, - 2, - ); - this.teraIcon.setTintFill(Phaser.Display.Color.GetColor(...getTypeRgb(teraType))); - this.lastTeraType = teraType; - } - - const isFusion = pokemon.isFusion(true); - - if (nameUpdated || teraTypeUpdated) { - this.splicedIcon.setVisible(isFusion); - - this.teraIcon.setPositionRelative( - this.nameText, - this.nameText.displayWidth + this.genderText.displayWidth + 1, - 2, - ); - this.splicedIcon.setPositionRelative( - this.nameText, - this.nameText.displayWidth + - this.genderText.displayWidth + - 1 + - (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), - 1.5, - ); - this.shinyIcon.setPositionRelative( - this.nameText, - this.nameText.displayWidth + - this.genderText.displayWidth + - 1 + - (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) + - (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0), - 2.5, - ); - } - - if (this.lastStatus !== (pokemon.status?.effect || StatusEffect.NONE)) { - this.lastStatus = pokemon.status?.effect || StatusEffect.NONE; - - if (this.lastStatus !== StatusEffect.NONE) { - this.statusIndicator.setFrame(StatusEffect[this.lastStatus].toLowerCase()); - } - - const offsetX = !this.player ? (this.ownedIcon.visible ? 8 : 0) + (this.championRibbon.visible ? 8 : 0) : 0; - this.statusIndicator.setPositionRelative(this.nameText, offsetX, 11.5); - - this.statusIndicator.setVisible(!!this.lastStatus); - } - - 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); - this.type3Icon.setVisible(types.length > 2); - if (types.length > 1) { - this.type2Icon.setFrame(PokemonType[types[1]].toLowerCase()); - } - if (types.length > 2) { - this.type3Icon.setFrame(PokemonType[types[2]].toLowerCase()); - } - - const updateHpFrame = () => { - const hpFrame = this.hpBar.scaleX > 0.5 ? "high" : this.hpBar.scaleX > 0.25 ? "medium" : "low"; - if (hpFrame !== this.lastHpFrame) { - this.hpBar.setFrame(hpFrame); - this.lastHpFrame = hpFrame; - } - }; - - const updatePokemonHp = () => { - let duration = !instant ? Phaser.Math.Clamp(Math.abs(this.lastHp - pokemon.hp) * 5, 250, 5000) : 0; - const speed = globalScene.hpBarSpeed; - if (speed) { - duration = speed >= 3 ? 0 : duration / Math.pow(2, speed); - } - globalScene.tweens.add({ - targets: this.hpBar, - ease: "Sine.easeOut", - scaleX: pokemon.getHpRatio(true), - duration: duration, - onUpdate: () => { - if (this.player && this.lastHp !== pokemon.hp) { - const tweenHp = Math.ceil(this.hpBar.scaleX * pokemon.getMaxHp()); - this.setHpNumbers(tweenHp, pokemon.getMaxHp()); - this.lastHp = tweenHp; - } - - updateHpFrame(); - }, - 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(); - }, - }); - if (!this.player) { - this.lastHp = pokemon.hp; - } - this.lastMaxHp = pokemon.getMaxHp(); - }; - - if (this.player) { - const isLevelCapped = pokemon.level >= globalScene.getMaxExpLevel(); - - if (this.lastExp !== pokemon.exp || this.lastLevel !== pokemon.level) { - const originalResolve = resolve; - const durationMultipler = Math.max( - Phaser.Tweens.Builders.GetEaseFunction("Cubic.easeIn")( - 1 - Math.min(pokemon.level - this.lastLevel, 10) / 10, - ), - 0.1, - ); - resolve = () => this.updatePokemonExp(pokemon, false, durationMultipler).then(() => originalResolve()); - } else if (isLevelCapped !== this.lastLevelCapped) { - this.setLevel(pokemon.level); - } - - this.lastLevelCapped = isLevelCapped; - } - - if (this.lastHp !== pokemon.hp || this.lastMaxHp !== pokemon.getMaxHp()) { - return updatePokemonHp(); - } - if (!this.player && this.lastLevel !== pokemon.level) { - this.setLevel(pokemon.level); - this.lastLevel = pokemon.level; - } - - const stats = pokemon.getStatStages(); - const statsStr = stats.join(""); - - if (this.lastStats !== statsStr) { - this.updateStats(stats); - this.lastStats = statsStr; - } - - this.shinyIcon.setVisible(pokemon.isShiny(true)); - - const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; - const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; - this.shinyIcon.setTint(getVariantTint(baseVariant)); - - this.fusionShinyIcon.setVisible(doubleShiny); - if (isFusion) { - this.fusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); - } - this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); - - resolve(); - }); - } - - updateNameText(pokemon: Pokemon): void { - let displayName = pokemon.getNameToRender().replace(/[♂♀]/g, ""); - let nameTextWidth: number; - - const nameSizeTest = addTextObject(0, 0, displayName, TextStyle.BATTLE_INFO); - nameTextWidth = nameSizeTest.displayWidth; - - const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; - while ( - nameTextWidth > - (this.player || !this.boss ? 60 : 98) - - ((gender !== Gender.GENDERLESS ? 6 : 0) + - (pokemon.fusionSpecies ? 8 : 0) + - (pokemon.isShiny() ? 8 : 0) + - (Math.min(pokemon.level.toString().length, 3) - 3) * 8) - ) { - displayName = `${displayName.slice(0, displayName.endsWith(".") ? -2 : -1).trimEnd()}.`; - nameSizeTest.setText(displayName); - nameTextWidth = nameSizeTest.displayWidth; - } - - nameSizeTest.destroy(); - - this.nameText.setText(displayName); - this.lastName = pokemon.getNameToRender(); - - if (this.nameText.visible) { - this.nameText.setInteractive( - new Phaser.Geom.Rectangle(0, 0, this.nameText.width, this.nameText.height), - Phaser.Geom.Rectangle.Contains, - ); - } - } - - updatePokemonExp(pokemon: Pokemon, instant?: boolean, levelDurationMultiplier = 1): Promise { - return new Promise(resolve => { - const levelUp = this.lastLevel < pokemon.level; - const relLevelExp = getLevelRelExp(this.lastLevel + 1, pokemon.species.growthRate); - const levelExp = levelUp ? relLevelExp : pokemon.levelExp; - let ratio = relLevelExp ? levelExp / relLevelExp : 0; - if (this.lastLevel >= globalScene.getMaxExpLevel(true)) { - if (levelUp) { - ratio = 1; - } else { - ratio = 0; - } - instant = true; - } - const durationMultiplier = Phaser.Tweens.Builders.GetEaseFunction("Sine.easeIn")( - 1 - Math.max(this.lastLevel - 100, 0) / 150, - ); - let duration = - this.visible && !instant - ? ((levelExp - this.lastLevelExp) / relLevelExp) * - BattleInfo.EXP_GAINS_DURATION_BASE * - durationMultiplier * - levelDurationMultiplier - : 0; - const speed = globalScene.expGainsSpeed; - if (speed && speed >= ExpGainsSpeed.DEFAULT) { - duration = speed >= ExpGainsSpeed.SKIP ? ExpGainsSpeed.DEFAULT : duration / Math.pow(2, speed); - } - if (ratio === 1) { - this.lastLevelExp = 0; - this.lastLevel++; - } else { - this.lastExp = pokemon.exp; - this.lastLevelExp = pokemon.levelExp; - } - if (duration) { - globalScene.playSound("se/exp"); - } - globalScene.tweens.add({ - targets: this.expMaskRect, - ease: "Sine.easeIn", - x: ratio * 510, - duration: duration, - onComplete: () => { - if (!globalScene) { - return resolve(); - } - if (duration) { - globalScene.sound.stopByKey("se/exp"); - } - if (ratio === 1) { - globalScene.playSound("se/level_up"); - this.setLevel(this.lastLevel); - globalScene.time.delayedCall(500 * levelDurationMultiplier, () => { - this.expMaskRect.x = 0; - this.updateInfo(pokemon, instant).then(() => resolve()); - }); - return; - } - resolve(); - }, - }); - }); - } - - setLevel(level: number): void { - const isCapped = level >= globalScene.getMaxExpLevel(); - this.levelNumbersContainer.removeAll(true); - const levelStr = level.toString(); - for (let i = 0; i < levelStr.length; i++) { - this.levelNumbersContainer.add( - globalScene.add.image(i * 8, 0, `numbers${isCapped && this.player ? "_red" : ""}`, levelStr[i]), - ); - } - this.levelContainer.setX((this.player ? -41 : -50) - 8 * Math.max(levelStr.length - 3, 0)); - } - - setHpNumbers(hp: number, maxHp: number): void { - if (!this.player || !globalScene) { - return; - } - this.hpNumbersContainer.removeAll(true); - const hpStr = hp.toString(); - const maxHpStr = maxHp.toString(); - let offset = 0; - for (let i = maxHpStr.length - 1; i >= 0; i--) { - this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", maxHpStr[i])); - } - this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", "/")); - for (let i = hpStr.length - 1; i >= 0; i--) { - this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", hpStr[i])); - } - } - - updateStats(stats: number[]): void { - this.statOrder.map((s, i) => { - if (s !== Stat.HP) { - this.statNumbers[i].setFrame(stats[s - 1].toString()); - } - }); - } - - /** - * Request the flyoutMenu to toggle if available and hides or shows the effectiveness window where necessary - */ - toggleFlyout(visible: boolean): void { - this.flyoutMenu?.toggleFlyout(visible); - - if (visible) { - this.effectivenessContainer?.setVisible(false); - } else { - this.updateEffectiveness(this.currentEffectiveness); - } - } - - /** - * Show or hide the type effectiveness multiplier window - * Passing undefined will hide the window - */ - updateEffectiveness(effectiveness?: string) { - if (this.player) { - return; - } - this.currentEffectiveness = effectiveness; - - if (!globalScene.typeHints || effectiveness === undefined || this.flyoutMenu?.flyoutVisible) { - this.effectivenessContainer.setVisible(false); - return; - } - - this.effectivenessText.setText(effectiveness); - this.effectivenessWindow.width = 10 + this.effectivenessText.displayWidth; - this.effectivenessContainer.setVisible(true); - } - - getBaseY(): number { - return this.baseY; - } - - resetY(): void { - this.y = this.baseY; - } -} - -export class PlayerBattleInfo extends BattleInfo { - constructor() { - super(Math.floor(globalScene.game.canvas.width / 6) - 10, -72, true); - } -} - -export class EnemyBattleInfo extends BattleInfo { - constructor() { - super(140, -141, false); - } - - setMini(_mini: boolean): void {} // Always mini -} diff --git a/src/ui/battle-info/battle-info.ts b/src/ui/battle-info/battle-info.ts new file mode 100644 index 00000000000..7e6cc12bd3d --- /dev/null +++ b/src/ui/battle-info/battle-info.ts @@ -0,0 +1,688 @@ +import type { default as Pokemon } from "../../field/pokemon"; +import { getLocalizedSpriteKey, fixedInt, getShinyDescriptor } from "#app/utils/common"; +import { addTextObject, TextStyle } from "../text"; +import { getGenderSymbol, getGenderColor, Gender } from "../../data/gender"; +import { StatusEffect } from "#enums/status-effect"; +import { globalScene } from "#app/global-scene"; +import { getTypeRgb } from "#app/data/type"; +import { PokemonType } from "#enums/pokemon-type"; +import { getVariantTint } from "#app/sprites/variant"; +import { Stat } from "#enums/stat"; +import i18next from "i18next"; + +/** + * Parameters influencing the position of elements within the battle info container + */ +export type BattleInfoParamList = { + /** X offset for the name text*/ + nameTextX: number; + /** Y offset for the name text */ + nameTextY: number; + /** X offset for the level container */ + levelContainerX: number; + /** Y offset for the level container */ + levelContainerY: number; + /** X offset for the hp bar */ + hpBarX: number; + /** Y offset for the hp bar */ + hpBarY: number; + /** Parameters for the stat box container */ + statBox: { + /** The starting offset from the left of the label for the entries in the stat box */ + xOffset: number; + /** The X padding between each number column */ + paddingX: number; + /** The index of the stat entries at which paddingX is used instead of startingX */ + statOverflow: number; + }; +}; + +export default abstract class BattleInfo extends Phaser.GameObjects.Container { + public static readonly EXP_GAINS_DURATION_BASE = 1650; + + protected baseY: number; + protected baseLvContainerX: number; + + protected player: boolean; + protected mini: boolean; + protected boss: boolean; + protected bossSegments: number; + protected offset: boolean; + protected lastName: string | null; + protected lastTeraType: PokemonType; + protected lastStatus: StatusEffect; + protected lastHp: number; + protected lastMaxHp: number; + protected lastHpFrame: string | null; + protected lastExp: number; + protected lastLevelExp: number; + protected lastLevel: number; + protected lastLevelCapped: boolean; + protected lastStats: string; + + protected box: Phaser.GameObjects.Sprite; + protected nameText: Phaser.GameObjects.Text; + protected genderText: Phaser.GameObjects.Text; + protected teraIcon: Phaser.GameObjects.Sprite; + protected shinyIcon: Phaser.GameObjects.Sprite; + protected fusionShinyIcon: Phaser.GameObjects.Sprite; + protected splicedIcon: Phaser.GameObjects.Sprite; + protected statusIndicator: Phaser.GameObjects.Sprite; + protected levelContainer: Phaser.GameObjects.Container; + protected hpBar: Phaser.GameObjects.Image; + protected levelNumbersContainer: Phaser.GameObjects.Container; + protected type1Icon: Phaser.GameObjects.Sprite; + protected type2Icon: Phaser.GameObjects.Sprite; + protected type3Icon: Phaser.GameObjects.Sprite; + protected expBar: Phaser.GameObjects.Image; + + public expMaskRect: Phaser.GameObjects.Graphics; + + protected statsContainer: Phaser.GameObjects.Container; + protected statsBox: Phaser.GameObjects.Sprite; + protected statValuesContainer: Phaser.GameObjects.Container; + protected statNumbers: Phaser.GameObjects.Sprite[]; + + get statOrder(): Stat[] { + return []; + } + + /** Helper method used by the constructor to create the tera and shiny icons next to the name */ + private constructIcons() { + const hitArea = new Phaser.Geom.Rectangle(0, 0, 12, 15); + const hitCallback = Phaser.Geom.Rectangle.Contains; + + this.teraIcon = globalScene.add + .sprite(0, 0, "icon_tera") + .setName("icon_tera") + .setVisible(false) + .setOrigin(0) + .setScale(0.5) + .setInteractive(hitArea, hitCallback) + .setPositionRelative(this.nameText, 0, 2); + + this.shinyIcon = globalScene.add + .sprite(0, 0, "shiny_star") + .setName("icon_shiny") + .setVisible(false) + .setOrigin(0) + .setScale(0.5) + .setInteractive(hitArea, hitCallback) + .setPositionRelative(this.nameText, 0, 2); + + this.fusionShinyIcon = globalScene.add + .sprite(0, 0, "shiny_star_2") + .setName("icon_fusion_shiny") + .setVisible(false) + .setOrigin(0) + .setScale(0.5) + .copyPosition(this.shinyIcon); + + this.splicedIcon = globalScene.add + .sprite(0, 0, "icon_spliced") + .setName("icon_spliced") + .setVisible(false) + .setOrigin(0) + .setScale(0.5) + .setInteractive(hitArea, hitCallback) + .setPositionRelative(this.nameText, 0, 2); + + this.add([this.teraIcon, this.shinyIcon, this.fusionShinyIcon, this.splicedIcon]); + } + + /** + * Submethod of the constructor that creates and adds the stats container to the battle info + */ + protected constructStatContainer({ xOffset, paddingX, statOverflow }: BattleInfoParamList["statBox"]): void { + this.statsContainer = globalScene.add.container(0, 0).setName("container_stats").setAlpha(0); + this.add(this.statsContainer); + + this.statsBox = globalScene.add + .sprite(0, 0, `${this.getTextureName()}_stats`) + .setName("box_stats") + .setOrigin(1, 0.5); + this.statsContainer.add(this.statsBox); + + const statLabels: Phaser.GameObjects.Sprite[] = []; + this.statNumbers = []; + + this.statValuesContainer = globalScene.add.container(); + this.statsContainer.add(this.statValuesContainer); + + const startingX = -this.statsBox.width + xOffset; + + // this gives us a different starting location from the left of the label and padding between stats for a player vs enemy + // since the player won't have HP to show, it doesn't need to change from the current version + + for (const [i, s] of this.statOrder.entries()) { + const isHp = s === Stat.HP; + // we do a check for i > statOverflow to see when the stat labels go onto the next column + // For enemies, we have HP (i=0) by itself then a new column, so we check for i > 0 + // For players, we don't have HP, so we start with i = 0 and i = 1 for our first column, and so need to check for i > 1 + const statX = + i > statOverflow + ? this.statNumbers[Math.max(i - 2, 0)].x + this.statNumbers[Math.max(i - 2, 0)].width + paddingX + : startingX; // we have the Math.max(i - 2, 0) in there so for i===1 to not return a negative number; since this is now based on anything >0 instead of >1, we need to allow for i-2 < 0 + + let statY = -this.statsBox.height / 2 + 4; // this is the baseline for the y-axis + if (isHp || s === Stat.SPD) { + statY += 5; + } else if (this.player === !!(i % 2)) { + // we compare i % 2 against this.player to tell us where to place the label + // because this.battleStatOrder for enemies has HP, this.battleStatOrder[1]=ATK, but for players + // this.battleStatOrder[0]=ATK, so this comparing i % 2 to this.player fixes this issue for us + statY += 10; + } + + const statLabel = globalScene.add + .sprite(statX, statY, "pbinfo_stat", Stat[s]) + .setName("icon_stat_label_" + i.toString()) + .setOrigin(0); + statLabels.push(statLabel); + this.statValuesContainer.add(statLabel); + + const statNumber = globalScene.add + .sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", !isHp ? "3" : "empty") + .setName("icon_stat_number_" + i.toString()) + .setOrigin(0); + this.statNumbers.push(statNumber); + this.statValuesContainer.add(statNumber); + + if (isHp) { + statLabel.setVisible(false); + statNumber.setVisible(false); + } + } + } + + /** + * Submethod of the constructor that creates and adds the pokemon type icons to the battle info + */ + protected abstract constructTypeIcons(): void; + + /** + * @param x - The x position of the battle info container + * @param y - The y position of the battle info container + * @param player - Whether this battle info belongs to a player or an enemy + * @param posParams - The parameters influencing the position of elements within the battle info container + */ + constructor(x: number, y: number, player: boolean, posParams: BattleInfoParamList) { + super(globalScene, x, y); + this.baseY = y; + this.player = player; + this.mini = !player; + this.boss = false; + this.offset = false; + this.lastName = null; + this.lastTeraType = PokemonType.UNKNOWN; + this.lastStatus = StatusEffect.NONE; + this.lastHp = -1; + this.lastMaxHp = -1; + this.lastHpFrame = null; + this.lastExp = -1; + this.lastLevelExp = -1; + this.lastLevel = -1; + this.baseLvContainerX = posParams.levelContainerX; + + // Initially invisible and shown via Pokemon.showInfo + this.setVisible(false); + + this.box = globalScene.add.sprite(0, 0, this.getTextureName()).setName("box").setOrigin(1, 0.5); + this.add(this.box); + + this.nameText = addTextObject(posParams.nameTextX, posParams.nameTextY, "", TextStyle.BATTLE_INFO) + .setName("text_name") + .setOrigin(0); + this.add(this.nameText); + + this.genderText = addTextObject(0, 0, "", TextStyle.BATTLE_INFO) + .setName("text_gender") + .setOrigin(0) + .setPositionRelative(this.nameText, 0, 2); + this.add(this.genderText); + + this.constructIcons(); + + this.statusIndicator = globalScene.add + .sprite(0, 0, getLocalizedSpriteKey("statuses")) + .setName("icon_status") + .setVisible(false) + .setOrigin(0) + .setPositionRelative(this.nameText, 0, 11.5); + this.add(this.statusIndicator); + + this.levelContainer = globalScene.add + .container(posParams.levelContainerX, posParams.levelContainerY) + .setName("container_level"); + this.add(this.levelContainer); + + const levelOverlay = globalScene.add.image(0, 0, "overlay_lv"); + this.levelContainer.add(levelOverlay); + + this.hpBar = globalScene.add.image(posParams.hpBarX, posParams.hpBarY, "overlay_hp").setName("hp_bar").setOrigin(0); + this.add(this.hpBar); + + this.levelNumbersContainer = globalScene.add + .container(9.5, globalScene.uiTheme ? 0 : -0.5) + .setName("container_level"); + this.levelContainer.add(this.levelNumbersContainer); + + this.constructStatContainer(posParams.statBox); + + this.constructTypeIcons(); + } + + getStatsValueContainer(): Phaser.GameObjects.Container { + return this.statValuesContainer; + } + + //#region Initialization methods + + initSplicedIcon(pokemon: Pokemon, baseWidth: number) { + this.splicedIcon.setPositionRelative( + this.nameText, + baseWidth + this.genderText.displayWidth + 1 + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), + 2.5, + ); + this.splicedIcon.setVisible(pokemon.isFusion(true)); + if (!this.splicedIcon.visible) { + return; + } + this.splicedIcon + .on("pointerover", () => + globalScene.ui.showTooltip( + "", + `${pokemon.species.getName(pokemon.formIndex)}/${pokemon.fusionSpecies?.getName(pokemon.fusionFormIndex)}`, + ), + ) + .on("pointerout", () => globalScene.ui.hideTooltip()); + } + + /** + * Called by {@linkcode initInfo} to initialize the shiny icon + * @param pokemon - The pokemon object attached to this battle info + * @param baseXOffset - The x offset to use for the shiny icon + * @param doubleShiny - Whether the pokemon is shiny and its fusion species is also shiny + */ + protected initShinyIcon(pokemon: Pokemon, xOffset: number, doubleShiny: boolean) { + const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; + + this.shinyIcon.setPositionRelative( + this.nameText, + xOffset + + this.genderText.displayWidth + + 1 + + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) + + (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0), + 2.5, + ); + this.shinyIcon + .setTexture(`shiny_star${doubleShiny ? "_1" : ""}`) + .setVisible(pokemon.isShiny()) + .setTint(getVariantTint(baseVariant)); + + if (!this.shinyIcon.visible) { + return; + } + + let shinyDescriptor = ""; + if (doubleShiny || baseVariant) { + shinyDescriptor = " (" + getShinyDescriptor(baseVariant); + if (doubleShiny) { + shinyDescriptor += "/" + getShinyDescriptor(pokemon.fusionVariant); + } + shinyDescriptor += ")"; + } + + this.shinyIcon + .on("pointerover", () => globalScene.ui.showTooltip("", i18next.t("common:shinyOnHover") + shinyDescriptor)) + .on("pointerout", () => globalScene.ui.hideTooltip()); + } + + initInfo(pokemon: Pokemon) { + this.updateNameText(pokemon); + const nameTextWidth = this.nameText.displayWidth; + + this.name = pokemon.getNameToRender(); + this.box.name = pokemon.getNameToRender(); + + this.genderText + .setText(getGenderSymbol(pokemon.gender)) + .setColor(getGenderColor(pokemon.gender)) + .setPositionRelative(this.nameText, nameTextWidth, 0); + + this.lastTeraType = pokemon.getTeraType(); + + this.teraIcon + .setVisible(pokemon.isTerastallized) + .on("pointerover", () => { + if (pokemon.isTerastallized) { + globalScene.ui.showTooltip( + "", + i18next.t("fightUiHandler:teraHover", { + type: i18next.t(`pokemonInfo:Type.${PokemonType[this.lastTeraType]}`), + }), + ); + } + }) + .on("pointerout", () => globalScene.ui.hideTooltip()) + .setPositionRelative(this.nameText, nameTextWidth + this.genderText.displayWidth + 1, 2); + + const isFusion = pokemon.isFusion(true); + this.initSplicedIcon(pokemon, nameTextWidth); + + const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; + this.initShinyIcon(pokemon, nameTextWidth, doubleShiny); + + this.fusionShinyIcon.setVisible(doubleShiny).copyPosition(this.shinyIcon); + if (isFusion) { + this.fusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); + } + + this.hpBar.setScale(pokemon.getHpRatio(true), 1); + this.lastHpFrame = this.hpBar.scaleX > 0.5 ? "high" : this.hpBar.scaleX > 0.25 ? "medium" : "low"; + this.hpBar.setFrame(this.lastHpFrame); + this.lastHp = pokemon.hp; + this.lastMaxHp = pokemon.getMaxHp(); + + this.setLevel(pokemon.level); + this.lastLevel = pokemon.level; + + this.shinyIcon.setVisible(pokemon.isShiny()); + + this.setTypes(pokemon.getTypes(true, false, undefined, true)); + + const stats = this.statOrder.map(() => 0); + + this.lastStats = stats.join(""); + this.updateStats(stats); + } + //#endregion + + /** + * Return the texture name of the battle info box + */ + abstract getTextureName(): string; + + setMini(_mini: boolean): void {} + + toggleStats(visible: boolean): void { + globalScene.tweens.add({ + targets: this.statsContainer, + duration: fixedInt(125), + ease: "Sine.easeInOut", + alpha: visible ? 1 : 0, + }); + } + + setOffset(offset: boolean): void { + if (this.offset === offset) { + return; + } + + this.offset = offset; + + this.x += 10 * (this.offset === this.player ? 1 : -1); + this.y += 27 * (this.offset ? 1 : -1); + this.baseY = this.y; + } + + //#region Update methods and helpers + + /** + * Update the status icon to match the pokemon's current status + * @param pokemon - The pokemon object attached to this battle info + * @param xOffset - The offset from the name text + */ + updateStatusIcon(pokemon: Pokemon, xOffset = 0) { + if (this.lastStatus !== (pokemon.status?.effect || StatusEffect.NONE)) { + this.lastStatus = pokemon.status?.effect || StatusEffect.NONE; + + if (this.lastStatus !== StatusEffect.NONE) { + this.statusIndicator.setFrame(StatusEffect[this.lastStatus].toLowerCase()); + } + + this.statusIndicator.setVisible(!!this.lastStatus).setPositionRelative(this.nameText, xOffset, 11.5); + } + } + + /** Update the pokemon name inside the container */ + protected updateName(name: string): boolean { + if (this.lastName === name) { + return false; + } + this.nameText.setText(name).setPositionRelative(this.box, -this.nameText.displayWidth, 0); + this.lastName = name; + + return true; + } + + protected updateTeraType(ty: PokemonType): boolean { + if (this.lastTeraType === ty) { + return false; + } + + this.teraIcon + .setVisible(ty !== PokemonType.UNKNOWN) + .setTintFill(Phaser.Display.Color.GetColor(...getTypeRgb(ty))) + .setPositionRelative(this.nameText, this.nameText.displayWidth + this.genderText.displayWidth + 1, 2); + this.lastTeraType = ty; + + return true; + } + + /** + * Update the type icons to match the pokemon's types + */ + setTypes(types: PokemonType[]): void { + this.type1Icon + .setTexture(`pbinfo_${this.player ? "player" : "enemy"}_type${types.length > 1 ? "1" : ""}`) + .setFrame(PokemonType[types[0]].toLowerCase()); + this.type2Icon.setVisible(types.length > 1); + this.type3Icon.setVisible(types.length > 2); + if (types.length > 1) { + this.type2Icon.setFrame(PokemonType[types[1]].toLowerCase()); + } + if (types.length > 2) { + this.type3Icon.setFrame(PokemonType[types[2]].toLowerCase()); + } + } + + /** + * Called by {@linkcode updateInfo} to update the position of the tera, spliced, and shiny icons + * @param isFusion - Whether the pokemon is a fusion or not + */ + protected updateIconDisplay(isFusion: boolean): void { + this.teraIcon.setPositionRelative(this.nameText, this.nameText.displayWidth + this.genderText.displayWidth + 1, 2); + this.splicedIcon + .setVisible(isFusion) + .setPositionRelative( + this.nameText, + this.nameText.displayWidth + + this.genderText.displayWidth + + 1 + + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), + 1.5, + ); + this.shinyIcon.setPositionRelative( + this.nameText, + this.nameText.displayWidth + + this.genderText.displayWidth + + 1 + + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0) + + (this.splicedIcon.visible ? this.splicedIcon.displayWidth + 1 : 0), + 2.5, + ); + } + + //#region Hp Bar Display handling + /** + * Called every time the hp frame is updated by the tween + * @param pokemon - The pokemon object attached to this battle info + */ + protected updateHpFrame(): void { + const hpFrame = this.hpBar.scaleX > 0.5 ? "high" : this.hpBar.scaleX > 0.25 ? "medium" : "low"; + if (hpFrame !== this.lastHpFrame) { + this.hpBar.setFrame(hpFrame); + this.lastHpFrame = hpFrame; + } + } + + /** + * Called by every frame in the hp animation tween created in {@linkcode updatePokemonHp} + * @param _pokemon - The pokemon the battle-info bar belongs to + */ + protected onHpTweenUpdate(_pokemon: Pokemon): void { + this.updateHpFrame(); + } + + /** Update the pokemonHp bar */ + protected updatePokemonHp(pokemon: Pokemon, resolve: (r: void | PromiseLike) => void, instant?: boolean): void { + let duration = !instant ? Phaser.Math.Clamp(Math.abs(this.lastHp - pokemon.hp) * 5, 250, 5000) : 0; + const speed = globalScene.hpBarSpeed; + if (speed) { + duration = speed >= 3 ? 0 : duration / Math.pow(2, speed); + } + globalScene.tweens.add({ + targets: this.hpBar, + ease: "Sine.easeOut", + scaleX: pokemon.getHpRatio(true), + duration: duration, + onUpdate: () => { + this.onHpTweenUpdate(pokemon); + }, + onComplete: () => { + this.updateHpFrame(); + resolve(); + }, + }); + this.lastMaxHp = pokemon.getMaxHp(); + } + + //#endregion + + async updateInfo(pokemon: Pokemon, instant?: boolean): Promise { + let resolve: (r: void | PromiseLike) => void = () => {}; + const promise = new Promise(r => (resolve = r)); + if (!globalScene) { + return resolve(); + } + + const gender: Gender = pokemon.summonData?.illusion?.gender ?? pokemon.gender; + + this.genderText.setText(getGenderSymbol(gender)).setColor(getGenderColor(gender)); + + const nameUpdated = this.updateName(pokemon.getNameToRender()); + + const teraTypeUpdated = this.updateTeraType(pokemon.isTerastallized ? pokemon.getTeraType() : PokemonType.UNKNOWN); + + const isFusion = pokemon.isFusion(true); + + if (nameUpdated || teraTypeUpdated) { + this.updateIconDisplay(isFusion); + } + + this.updateStatusIcon(pokemon); + + if (this.lastHp !== pokemon.hp || this.lastMaxHp !== pokemon.getMaxHp()) { + return this.updatePokemonHp(pokemon, resolve, instant); + } + if (!this.player && this.lastLevel !== pokemon.level) { + this.setLevel(pokemon.level); + this.lastLevel = pokemon.level; + } + + const stats = pokemon.getStatStages(); + const statsStr = stats.join(""); + + if (this.lastStats !== statsStr) { + this.updateStats(stats); + this.lastStats = statsStr; + } + + this.shinyIcon.setVisible(pokemon.isShiny(true)); + + const doubleShiny = isFusion && pokemon.shiny && pokemon.fusionShiny; + const baseVariant = !doubleShiny ? pokemon.getVariant(true) : pokemon.variant; + this.shinyIcon.setTint(getVariantTint(baseVariant)); + + this.fusionShinyIcon.setVisible(doubleShiny).setPosition(this.shinyIcon.x, this.shinyIcon.y); + if (isFusion) { + this.fusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); + } + + resolve(); + await promise; + } + //#endregion + + updateNameText(pokemon: Pokemon): void { + let displayName = pokemon.getNameToRender().replace(/[♂♀]/g, ""); + let nameTextWidth: number; + + const nameSizeTest = addTextObject(0, 0, displayName, TextStyle.BATTLE_INFO); + nameTextWidth = nameSizeTest.displayWidth; + + const gender = pokemon.summonData.illusion?.gender ?? pokemon.gender; + while ( + nameTextWidth > + (this.player || !this.boss ? 60 : 98) - + ((gender !== Gender.GENDERLESS ? 6 : 0) + + (pokemon.fusionSpecies ? 8 : 0) + + (pokemon.isShiny() ? 8 : 0) + + (Math.min(pokemon.level.toString().length, 3) - 3) * 8) + ) { + displayName = `${displayName.slice(0, displayName.endsWith(".") ? -2 : -1).trimEnd()}.`; + nameSizeTest.setText(displayName); + nameTextWidth = nameSizeTest.displayWidth; + } + + nameSizeTest.destroy(); + + this.nameText.setText(displayName); + this.lastName = pokemon.getNameToRender(); + + if (this.nameText.visible) { + this.nameText.setInteractive( + new Phaser.Geom.Rectangle(0, 0, this.nameText.width, this.nameText.height), + Phaser.Geom.Rectangle.Contains, + ); + } + } + + /** + * Set the level numbers container to display the provided level + * + * @remarks + * The numbers in the pokemon's level uses images for each number rather than a text object with a special font. + * This method sets the images for each digit of the level number and then positions the level container based + * on the number of digits. + * + * @param level - The level to display + * @param textureKey - The texture key for the level numbers + */ + setLevel(level: number, textureKey: "numbers" | "numbers_red" = "numbers"): void { + this.levelNumbersContainer.removeAll(true); + const levelStr = level.toString(); + for (let i = 0; i < levelStr.length; i++) { + this.levelNumbersContainer.add(globalScene.add.image(i * 8, 0, textureKey, levelStr[i])); + } + this.levelContainer.setX(this.baseLvContainerX - 8 * Math.max(levelStr.length - 3, 0)); + } + + updateStats(stats: number[]): void { + for (const [i, s] of this.statOrder.entries()) { + if (s !== Stat.HP) { + this.statNumbers[i].setFrame(stats[s - 1].toString()); + } + } + } + + getBaseY(): number { + return this.baseY; + } + + resetY(): void { + this.y = this.baseY; + } +} diff --git a/src/ui/battle-info/enemy-battle-info.ts b/src/ui/battle-info/enemy-battle-info.ts new file mode 100644 index 00000000000..7c16f01ac38 --- /dev/null +++ b/src/ui/battle-info/enemy-battle-info.ts @@ -0,0 +1,235 @@ +import { globalScene } from "#app/global-scene"; +import BattleFlyout from "../battle-flyout"; +import { addTextObject, TextStyle } from "#app/ui/text"; +import { addWindow, WindowVariant } from "#app/ui/ui-theme"; +import { Stat } from "#enums/stat"; +import i18next from "i18next"; +import type { EnemyPokemon } from "#app/field/pokemon"; +import type { GameObjects } from "phaser"; +import BattleInfo from "./battle-info"; +import type { BattleInfoParamList } from "./battle-info"; + +export class EnemyBattleInfo extends BattleInfo { + protected player: false = false; + protected championRibbon: Phaser.GameObjects.Sprite; + protected ownedIcon: Phaser.GameObjects.Sprite; + protected flyoutMenu: BattleFlyout; + + protected hpBarSegmentDividers: GameObjects.Rectangle[] = []; + + // #region Type effectiveness hint objects + protected effectivenessContainer: Phaser.GameObjects.Container; + protected effectivenessWindow: Phaser.GameObjects.NineSlice; + protected effectivenessText: Phaser.GameObjects.Text; + protected currentEffectiveness?: string; + // #endregion + + override get statOrder(): Stat[] { + return [Stat.HP, Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.ACC, Stat.EVA, Stat.SPD]; + } + + override getTextureName(): string { + return this.boss ? "pbinfo_enemy_boss" : "pbinfo_enemy_mini"; + } + + override constructTypeIcons(): void { + this.type1Icon = globalScene.add.sprite(-15, -15.5, "pbinfo_enemy_type1").setName("icon_type_1").setOrigin(0); + this.type2Icon = globalScene.add.sprite(-15, -2.5, "pbinfo_enemy_type2").setName("icon_type_2").setOrigin(0); + this.type3Icon = globalScene.add.sprite(0, 15.5, "pbinfo_enemy_type3").setName("icon_type_3").setOrigin(0); + this.add([this.type1Icon, this.type2Icon, this.type3Icon]); + } + + constructor() { + const posParams: BattleInfoParamList = { + nameTextX: -124, + nameTextY: -11.2, + levelContainerX: -50, + levelContainerY: -5, + hpBarX: -71, + hpBarY: 4.5, + statBox: { + xOffset: 5, + paddingX: 2, + statOverflow: 0, + }, + }; + + super(140, -141, false, posParams); + + this.ownedIcon = globalScene.add + .sprite(0, 0, "icon_owned") + .setName("icon_owned") + .setVisible(false) + .setOrigin(0, 0) + .setPositionRelative(this.nameText, 0, 11.75); + + this.championRibbon = globalScene.add + .sprite(0, 0, "champion_ribbon") + .setName("icon_champion_ribbon") + .setVisible(false) + .setOrigin(0, 0) + .setPositionRelative(this.nameText, 8, 11.75); + // Ensure these two icons are positioned below the stats container + this.addAt([this.ownedIcon, this.championRibbon], this.getIndex(this.statsContainer)); + + this.flyoutMenu = new BattleFlyout(this.player); + this.add(this.flyoutMenu); + + this.moveBelow(this.flyoutMenu, this.box); + + this.effectivenessContainer = globalScene.add + .container(0, 0) + .setVisible(false) + .setPositionRelative(this.type1Icon, 22, 4); + this.add(this.effectivenessContainer); + + this.effectivenessText = addTextObject(5, 4.5, "", TextStyle.BATTLE_INFO); + this.effectivenessWindow = addWindow(0, 0, 0, 20, undefined, false, undefined, undefined, WindowVariant.XTHIN); + + this.effectivenessContainer.add([this.effectivenessWindow, this.effectivenessText]); + } + + override initInfo(pokemon: EnemyPokemon): void { + this.flyoutMenu.initInfo(pokemon); + super.initInfo(pokemon); + + if (this.nameText.visible) { + this.nameText + .on("pointerover", () => + globalScene.ui.showTooltip( + "", + i18next.t("battleInfo:generation", { + generation: i18next.t(`starterSelectUiHandler:gen${pokemon.species.generation}`), + }), + ), + ) + .on("pointerout", () => globalScene.ui.hideTooltip()); + } + + const dexEntry = globalScene.gameData.dexData[pokemon.species.speciesId]; + this.ownedIcon.setVisible(!!dexEntry.caughtAttr); + const opponentPokemonDexAttr = pokemon.getDexAttr(); + if ( + globalScene.gameMode.isClassic && + globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].classicWinCount > 0 && + globalScene.gameData.starterData[pokemon.species.getRootSpeciesId(true)].classicWinCount > 0 + ) { + this.championRibbon.setVisible(true); + } + + // Check if Player owns all genders and forms of the Pokemon + const missingDexAttrs = (dexEntry.caughtAttr & opponentPokemonDexAttr) < opponentPokemonDexAttr; + + const ownedAbilityAttrs = globalScene.gameData.starterData[pokemon.species.getRootSpeciesId()].abilityAttr; + + // Check if the player owns ability for the root form + const playerOwnsThisAbility = pokemon.checkIfPlayerHasAbilityOfStarter(ownedAbilityAttrs); + + if (missingDexAttrs || !playerOwnsThisAbility) { + this.ownedIcon.setTint(0x808080); + } + + if (this.boss) { + this.updateBossSegmentDividers(pokemon as EnemyPokemon); + } + } + + /** + * Show or hide the type effectiveness multiplier window + * Passing undefined will hide the window + */ + updateEffectiveness(effectiveness?: string) { + this.currentEffectiveness = effectiveness; + + if (!globalScene.typeHints || effectiveness === undefined || this.flyoutMenu.flyoutVisible) { + this.effectivenessContainer.setVisible(false); + return; + } + + this.effectivenessText.setText(effectiveness); + this.effectivenessWindow.width = 10 + this.effectivenessText.displayWidth; + this.effectivenessContainer.setVisible(true); + } + + /** + * Request the flyoutMenu to toggle if available and hides or shows the effectiveness window where necessary + */ + toggleFlyout(visible: boolean): void { + this.flyoutMenu.toggleFlyout(visible); + + if (visible) { + this.effectivenessContainer.setVisible(false); + } else { + this.updateEffectiveness(this.currentEffectiveness); + } + } + + updateBossSegments(pokemon: EnemyPokemon): void { + const boss = !!pokemon.bossSegments; + + if (boss !== this.boss) { + this.boss = boss; + + [ + this.nameText, + this.genderText, + this.teraIcon, + this.splicedIcon, + this.shinyIcon, + this.ownedIcon, + this.championRibbon, + this.statusIndicator, + this.levelContainer, + this.statValuesContainer, + ].map(e => (e.x += 48 * (boss ? -1 : 1))); + this.hpBar.x += 38 * (boss ? -1 : 1); + this.hpBar.y += 2 * (this.boss ? -1 : 1); + this.hpBar.setTexture(`overlay_hp${boss ? "_boss" : ""}`); + this.box.setTexture(this.getTextureName()); + this.statsBox.setTexture(`${this.getTextureName()}_stats`); + } + + this.bossSegments = boss ? pokemon.bossSegments : 0; + this.updateBossSegmentDividers(pokemon); + } + + updateBossSegmentDividers(pokemon: EnemyPokemon): void { + while (this.hpBarSegmentDividers.length) { + this.hpBarSegmentDividers.pop()?.destroy(); + } + + if (this.boss && this.bossSegments > 1) { + const uiTheme = globalScene.uiTheme; + const maxHp = pokemon.getMaxHp(); + for (let s = 1; s < this.bossSegments; s++) { + const dividerX = (Math.round((maxHp / this.bossSegments) * s) / maxHp) * this.hpBar.width; + const divider = globalScene.add.rectangle( + 0, + 0, + 1, + this.hpBar.height - (uiTheme ? 0 : 1), + pokemon.bossSegmentIndex >= s ? 0xffffff : 0x404040, + ); + divider.setOrigin(0.5, 0).setName("hpBar_divider_" + s.toString()); + this.add(divider); + this.moveBelow(divider as Phaser.GameObjects.GameObject, this.statsContainer); + + divider.setPositionRelative(this.hpBar, dividerX, uiTheme ? 0 : 1); + this.hpBarSegmentDividers.push(divider); + } + } + } + + override updateStatusIcon(pokemon: EnemyPokemon): void { + super.updateStatusIcon(pokemon, (this.ownedIcon.visible ? 8 : 0) + (this.championRibbon.visible ? 8 : 0)); + } + + protected override updatePokemonHp( + pokemon: EnemyPokemon, + resolve: (r: void | PromiseLike) => void, + instant?: boolean, + ): void { + super.updatePokemonHp(pokemon, resolve, instant); + this.lastHp = pokemon.hp; + } +} diff --git a/src/ui/battle-info/player-battle-info.ts b/src/ui/battle-info/player-battle-info.ts new file mode 100644 index 00000000000..634f89b7922 --- /dev/null +++ b/src/ui/battle-info/player-battle-info.ts @@ -0,0 +1,242 @@ +import { getLevelRelExp, getLevelTotalExp } from "#app/data/exp"; +import type { PlayerPokemon } from "#app/field/pokemon"; +import { globalScene } from "#app/global-scene"; +import { ExpGainsSpeed } from "#enums/exp-gains-speed"; +import { Stat } from "#enums/stat"; +import BattleInfo from "./battle-info"; +import type { BattleInfoParamList } from "./battle-info"; + +export class PlayerBattleInfo extends BattleInfo { + protected player: true = true; + protected hpNumbersContainer: Phaser.GameObjects.Container; + + override get statOrder(): Stat[] { + return [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.ACC, Stat.EVA, Stat.SPD]; + } + + override getTextureName(): string { + return this.mini ? "pbinfo_player_mini" : "pbinfo_player"; + } + + override constructTypeIcons(): void { + this.type1Icon = globalScene.add.sprite(-139, -17, "pbinfo_player_type1").setName("icon_type_1").setOrigin(0); + this.type2Icon = globalScene.add.sprite(-139, -1, "pbinfo_player_type2").setName("icon_type_2").setOrigin(0); + this.type3Icon = globalScene.add.sprite(-154, -17, "pbinfo_player_type3").setName("icon_type_3").setOrigin(0); + this.add([this.type1Icon, this.type2Icon, this.type3Icon]); + } + + constructor() { + const posParams: BattleInfoParamList = { + nameTextX: -115, + nameTextY: -15.2, + levelContainerX: -41, + levelContainerY: -10, + hpBarX: -61, + hpBarY: -1, + statBox: { + xOffset: 8, + paddingX: 4, + statOverflow: 1, + }, + }; + super(Math.floor(globalScene.game.canvas.width / 6) - 10, -72, true, posParams); + + this.hpNumbersContainer = globalScene.add.container(-15, 10).setName("container_hp"); + + // hp number container must be beneath the stat container for overlay to display properly + this.addAt(this.hpNumbersContainer, this.getIndex(this.statsContainer)); + + const expBar = globalScene.add.image(-98, 18, "overlay_exp").setName("overlay_exp").setOrigin(0); + this.add(expBar); + + const expMaskRect = globalScene.make + .graphics({}) + .setScale(6) + .fillStyle(0xffffff) + .beginPath() + .fillRect(127, 126, 85, 2); + + const expMask = expMaskRect.createGeometryMask(); + + expBar.setMask(expMask); + + this.expBar = expBar; + this.expMaskRect = expMaskRect; + } + + override initInfo(pokemon: PlayerPokemon): void { + super.initInfo(pokemon); + this.setHpNumbers(pokemon.hp, pokemon.getMaxHp()); + this.expMaskRect.x = (pokemon.levelExp / getLevelTotalExp(pokemon.level, pokemon.species.growthRate)) * 510; + this.lastExp = pokemon.exp; + this.lastLevelExp = pokemon.levelExp; + + this.statValuesContainer.setPosition(8, 7); + } + + override setMini(mini: boolean): void { + if (this.mini === mini) { + return; + } + + this.mini = mini; + + this.box.setTexture(this.getTextureName()); + this.statsBox.setTexture(`${this.getTextureName()}_stats`); + + if (this.player) { + this.y -= 12 * (mini ? 1 : -1); + this.baseY = this.y; + } + + const offsetElements = [ + this.nameText, + this.genderText, + this.teraIcon, + this.splicedIcon, + this.shinyIcon, + this.statusIndicator, + this.levelContainer, + ]; + offsetElements.forEach(el => (el.y += 1.5 * (mini ? -1 : 1))); + + [this.type1Icon, this.type2Icon, this.type3Icon].forEach(el => { + el.x += 4 * (mini ? 1 : -1); + el.y += -8 * (mini ? 1 : -1); + }); + + this.statValuesContainer.x += 2 * (mini ? 1 : -1); + this.statValuesContainer.y += -7 * (mini ? 1 : -1); + + const toggledElements = [this.hpNumbersContainer, this.expBar]; + toggledElements.forEach(el => el.setVisible(!mini)); + } + + /** + * Updates the Hp Number text (that is the "HP/Max HP" text that appears below the player's health bar) + * while the health bar is tweening. + * @param pokemon - The Pokemon the health bar belongs to. + */ + protected override onHpTweenUpdate(pokemon: PlayerPokemon): void { + const tweenHp = Math.ceil(this.hpBar.scaleX * pokemon.getMaxHp()); + this.setHpNumbers(tweenHp, pokemon.getMaxHp()); + this.lastHp = tweenHp; + this.updateHpFrame(); + } + + updatePokemonExp(pokemon: PlayerPokemon, instant?: boolean, levelDurationMultiplier = 1): Promise { + const levelUp = this.lastLevel < pokemon.level; + const relLevelExp = getLevelRelExp(this.lastLevel + 1, pokemon.species.growthRate); + const levelExp = levelUp ? relLevelExp : pokemon.levelExp; + let ratio = relLevelExp ? levelExp / relLevelExp : 0; + if (this.lastLevel >= globalScene.getMaxExpLevel(true)) { + ratio = levelUp ? 1 : 0; + instant = true; + } + const durationMultiplier = Phaser.Tweens.Builders.GetEaseFunction("Sine.easeIn")( + 1 - Math.max(this.lastLevel - 100, 0) / 150, + ); + let duration = + this.visible && !instant + ? ((levelExp - this.lastLevelExp) / relLevelExp) * + BattleInfo.EXP_GAINS_DURATION_BASE * + durationMultiplier * + levelDurationMultiplier + : 0; + const speed = globalScene.expGainsSpeed; + if (speed && speed >= ExpGainsSpeed.DEFAULT) { + duration = speed >= ExpGainsSpeed.SKIP ? ExpGainsSpeed.DEFAULT : duration / Math.pow(2, speed); + } + if (ratio === 1) { + this.lastLevelExp = 0; + this.lastLevel++; + } else { + this.lastExp = pokemon.exp; + this.lastLevelExp = pokemon.levelExp; + } + if (duration) { + globalScene.playSound("se/exp"); + } + return new Promise(resolve => { + globalScene.tweens.add({ + targets: this.expMaskRect, + ease: "Sine.easeIn", + x: ratio * 510, + duration: duration, + onComplete: () => { + if (!globalScene) { + return resolve(); + } + if (duration) { + globalScene.sound.stopByKey("se/exp"); + } + if (ratio === 1) { + globalScene.playSound("se/level_up"); + this.setLevel(this.lastLevel); + globalScene.time.delayedCall(500 * levelDurationMultiplier, () => { + this.expMaskRect.x = 0; + this.updateInfo(pokemon, instant).then(() => resolve()); + }); + return; + } + resolve(); + }, + }); + }); + } + + /** + * Updates the info on the info bar. + * + * In addition to performing all the steps of {@linkcode BattleInfo.updateInfo}, + * it also updates the EXP Bar + */ + override async updateInfo(pokemon: PlayerPokemon, instant?: boolean): Promise { + await super.updateInfo(pokemon, instant); + const isLevelCapped = pokemon.level >= globalScene.getMaxExpLevel(); + const oldLevelCapped = this.lastLevelCapped; + this.lastLevelCapped = isLevelCapped; + + if (this.lastExp !== pokemon.exp || this.lastLevel !== pokemon.level) { + const durationMultipler = Math.max( + Phaser.Tweens.Builders.GetEaseFunction("Cubic.easeIn")(1 - Math.min(pokemon.level - this.lastLevel, 10) / 10), + 0.1, + ); + await this.updatePokemonExp(pokemon, false, durationMultipler); + } else if (isLevelCapped !== oldLevelCapped) { + this.setLevel(pokemon.level); + } + } + + /** + * Set the HP numbers text, that is the "HP/Max HP" text that appears below the player's health bar. + * @param hp - The current HP of the player. + * @param maxHp - The maximum HP of the player. + */ + setHpNumbers(hp: number, maxHp: number): void { + if (!globalScene) { + return; + } + this.hpNumbersContainer.removeAll(true); + const hpStr = hp.toString(); + const maxHpStr = maxHp.toString(); + let offset = 0; + for (let i = maxHpStr.length - 1; i >= 0; i--) { + this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", maxHpStr[i])); + } + this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", "/")); + for (let i = hpStr.length - 1; i >= 0; i--) { + this.hpNumbersContainer.add(globalScene.add.image(offset++ * -8, 0, "numbers", hpStr[i])); + } + } + + /** + * Set the level numbers container to display the provided level + * + * Overrides the default implementation to handle displaying level capped numbers in red. + * @param level - The level to display + */ + override setLevel(level: number): void { + super.setLevel(level, level >= globalScene.getMaxExpLevel() ? "numbers_red" : "numbers"); + } +} diff --git a/src/ui/egg-counter-container.ts b/src/ui/egg-counter-container.ts index 7bec7c97480..7bb32189681 100644 --- a/src/ui/egg-counter-container.ts +++ b/src/ui/egg-counter-container.ts @@ -43,14 +43,13 @@ export default class EggCounterContainer extends Phaser.GameObjects.Container { this.add(this.eggCountWindow); - const eggSprite = globalScene.add.sprite(19, 18, "egg", "egg_0"); - eggSprite.setScale(0.32); + const eggSprite = globalScene.add.sprite(19, 18, "egg", "egg_0").setScale(0.32); - this.eggCountText = addTextObject(28, 13, `${this.eggCount}`, TextStyle.MESSAGE, { fontSize: "66px" }); - this.eggCountText.setName("text-egg-count"); + this.eggCountText = addTextObject(28, 13, `${this.eggCount}`, TextStyle.MESSAGE, { fontSize: "66px" }).setName( + "text-egg-count", + ); - this.add(eggSprite); - this.add(this.eggCountText); + this.add([eggSprite, this.eggCountText]); } /** diff --git a/src/ui/evolution-scene-handler.ts b/src/ui/evolution-scene-handler.ts index cea91ce4e2c..7372fc6f2b5 100644 --- a/src/ui/evolution-scene-handler.ts +++ b/src/ui/evolution-scene-handler.ts @@ -22,18 +22,12 @@ export default class EvolutionSceneHandler extends MessageUiHandler { const ui = this.getUi(); this.evolutionContainer = globalScene.add.container(0, -globalScene.game.canvas.height / 6); - ui.add(this.evolutionContainer); - const messageBg = globalScene.add.sprite(0, 0, "bg", globalScene.windowType); - messageBg.setOrigin(0, 1); - messageBg.setVisible(false); - ui.add(messageBg); + const messageBg = globalScene.add.sprite(0, 0, "bg", globalScene.windowType).setOrigin(0, 1).setVisible(false); this.messageBg = messageBg; - this.messageContainer = globalScene.add.container(12, -39); - this.messageContainer.setVisible(false); - ui.add(this.messageContainer); + this.messageContainer = globalScene.add.container(12, -39).setVisible(false); const message = addTextObject(0, 0, "", TextStyle.MESSAGE, { maxLines: 2, @@ -43,6 +37,8 @@ export default class EvolutionSceneHandler extends MessageUiHandler { }); this.messageContainer.add(message); + ui.add([this.evolutionContainer, this.messageBg, this.messageContainer]); + this.message = message; this.initPromptSprite(this.messageContainer); @@ -52,10 +48,8 @@ export default class EvolutionSceneHandler extends MessageUiHandler { super.show(_args); globalScene.ui.bringToTop(this.evolutionContainer); - globalScene.ui.bringToTop(this.messageBg); - globalScene.ui.bringToTop(this.messageContainer); - this.messageBg.setVisible(true); - this.messageContainer.setVisible(true); + globalScene.ui.bringToTop(this.messageBg.setVisible(true)); + globalScene.ui.bringToTop(this.messageContainer.setVisible(true)); return true; } diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index 5a0978a934d..6dbbcd47300 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -10,7 +10,7 @@ import { getLocalizedSpriteKey, fixedInt, padInt } from "#app/utils/common"; import { MoveCategory } from "#enums/MoveCategory"; import i18next from "i18next"; import { Button } from "#enums/buttons"; -import type { PokemonMove } from "#app/field/pokemon"; +import type { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import type { CommandPhase } from "#app/phases/command-phase"; import MoveInfoOverlay from "./move-info-overlay"; @@ -279,7 +279,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { this.moveInfoOverlay.show(pokemonMove.getMove()); pokemon.getOpponents().forEach(opponent => { - opponent.updateEffectiveness(this.getEffectivenessText(pokemon, opponent, pokemonMove)); + (opponent as EnemyPokemon).updateEffectiveness(this.getEffectivenessText(pokemon, opponent, pokemonMove)); }); } @@ -391,7 +391,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { const opponents = (globalScene.getCurrentPhase() as CommandPhase).getPokemon().getOpponents(); opponents.forEach(opponent => { - opponent.updateEffectiveness(undefined); + (opponent as EnemyPokemon).updateEffectiveness(); }); } diff --git a/src/ui/filter-bar.ts b/src/ui/filter-bar.ts index 2aade130ed1..622488c04cd 100644 --- a/src/ui/filter-bar.ts +++ b/src/ui/filter-bar.ts @@ -5,16 +5,7 @@ import { addTextObject, getTextColor, TextStyle } from "./text"; import type { UiTheme } from "#enums/ui-theme"; import { addWindow, WindowVariant } from "./ui-theme"; import { globalScene } from "#app/global-scene"; - -export enum DropDownColumn { - GEN, - TYPES, - BIOME, - CAUGHT, - UNLOCKS, - MISC, - SORT, -} +import type { DropDownColumn } from "#enums/drop-down-column"; export class FilterBar extends Phaser.GameObjects.Container { private window: Phaser.GameObjects.NineSlice; @@ -49,13 +40,9 @@ export class FilterBar extends Phaser.GameObjects.Container { this.cursorOffset = cursorOffset; this.window = addWindow(0, 0, width, height, false, false, undefined, undefined, WindowVariant.THIN); - this.add(this.window); - this.cursorObj = globalScene.add.image(1, 1, "cursor"); - this.cursorObj.setScale(0.5); - this.cursorObj.setVisible(false); - this.cursorObj.setOrigin(0, 0); - this.add(this.cursorObj); + this.cursorObj = globalScene.add.image(1, 1, "cursor").setScale(0.5).setVisible(false).setOrigin(0); + this.add([this.window, this.cursorObj]); } /** diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/pokedex-ui-handler.ts index 08fe5d7442f..179d5b4664b 100644 --- a/src/ui/pokedex-ui-handler.ts +++ b/src/ui/pokedex-ui-handler.ts @@ -23,7 +23,8 @@ import type { Species } from "#enums/species"; import { Button } from "#enums/buttons"; import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#app/ui/dropdown"; import { PokedexMonContainer } from "#app/ui/pokedex-mon-container"; -import { DropDownColumn, FilterBar } from "#app/ui/filter-bar"; +import { FilterBar } from "#app/ui/filter-bar"; +import { DropDownColumn } from "#enums/drop-down-column"; import { ScrollBar } from "#app/ui/scroll-bar"; import { Abilities } from "#enums/abilities"; import { diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index 18b5d2384ef..d8012a58875 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -8,7 +8,7 @@ import type Pokemon from "../field/pokemon"; import i18next from "i18next"; import type { DexEntry, StarterDataEntry } from "../system/game-data"; import { DexAttr } from "../system/game-data"; -import { fixedInt } from "#app/utils/common"; +import { fixedInt, getShinyDescriptor } from "#app/utils/common"; import ConfirmUiHandler from "./confirm-ui-handler"; import { StatsContainer } from "./stats-container"; import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text"; @@ -343,18 +343,19 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { this.pokemonShinyIcon.setVisible(pokemon.isShiny()); this.pokemonShinyIcon.setTint(getVariantTint(baseVariant)); if (this.pokemonShinyIcon.visible) { - const shinyDescriptor = - doubleShiny || baseVariant - ? `${baseVariant === 2 ? i18next.t("common:epicShiny") : baseVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}${doubleShiny ? `/${pokemon.fusionVariant === 2 ? i18next.t("common:epicShiny") : pokemon.fusionVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}` : ""}` - : ""; - this.pokemonShinyIcon.on("pointerover", () => - globalScene.ui.showTooltip( - "", - `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, - true, - ), - ); - this.pokemonShinyIcon.on("pointerout", () => globalScene.ui.hideTooltip()); + let shinyDescriptor = ""; + if (doubleShiny || baseVariant) { + shinyDescriptor = " (" + getShinyDescriptor(baseVariant); + if (doubleShiny) { + shinyDescriptor += "/" + getShinyDescriptor(pokemon.fusionVariant); + } + shinyDescriptor += ")"; + } + this.pokemonShinyIcon + .on("pointerover", () => + globalScene.ui.showTooltip("", i18next.t("common:shinyOnHover") + shinyDescriptor, true), + ) + .on("pointerout", () => globalScene.ui.hideTooltip()); const newShiny = BigInt(1 << (pokemon.shiny ? 1 : 0)); const newVariant = BigInt(1 << (pokemon.variant + 4)); diff --git a/src/ui/settings/settings-display-ui-handler.ts b/src/ui/settings/settings-display-ui-handler.ts index 86120b2eea2..0c62646ebf4 100644 --- a/src/ui/settings/settings-display-ui-handler.ts +++ b/src/ui/settings/settings-display-ui-handler.ts @@ -39,12 +39,6 @@ export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler label: "Español (LATAM)", }; break; - case "it": - this.settings[languageIndex].options[0] = { - value: "Italiano", - label: "Italiano", - }; - break; case "fr": this.settings[languageIndex].options[0] = { value: "Français", @@ -57,24 +51,18 @@ export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler label: "Deutsch", }; break; + case "it": + this.settings[languageIndex].options[0] = { + value: "Italiano", + label: "Italiano", + }; + break; case "pt-BR": this.settings[languageIndex].options[0] = { value: "Português (BR)", label: "Português (BR)", }; break; - case "zh-CN": - this.settings[languageIndex].options[0] = { - value: "简体中文", - label: "简体中文", - }; - break; - case "zh-TW": - this.settings[languageIndex].options[0] = { - value: "繁體中文", - label: "繁體中文", - }; - break; case "ko": case "ko-KR": this.settings[languageIndex].options[0] = { @@ -88,10 +76,46 @@ export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler label: "日本語", }; break; - case "ca-ES": + case "zh-CN": + this.settings[languageIndex].options[0] = { + value: "简体中文", + label: "简体中文", + }; + break; + case "zh-TW": + this.settings[languageIndex].options[0] = { + value: "繁體中文", + label: "繁體中文", + }; + break; + case "ca": this.settings[languageIndex].options[0] = { value: "Català", - label: "Català", + label: "Català (Needs Help)", + }; + break; + case "tr": + this.settings[languageIndex].options[0] = { + value: "Türkçe", + label: "Türkçe (Needs Help)", + }; + break; + case "ru": + this.settings[languageIndex].options[0] = { + value: "Русский", + label: "Русский (Needs Help)", + }; + break; + case "da": + this.settings[languageIndex].options[0] = { + value: "Dansk", + label: "Dansk (Needs Help)", + }; + break; + case "ro": + this.settings[languageIndex].options[0] = { + value: "Română", + label: "Română (Needs Help)", }; break; case "he": diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 6fa32d19df0..2a9f933bbfa 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -53,7 +53,8 @@ import { Button } from "#enums/buttons"; import { EggSourceType } from "#enums/egg-source-types"; import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#app/ui/dropdown"; import { StarterContainer } from "#app/ui/starter-container"; -import { DropDownColumn, FilterBar } from "#app/ui/filter-bar"; +import { FilterBar } from "#app/ui/filter-bar"; +import { DropDownColumn } from "#enums/drop-down-column"; import { ScrollBar } from "#app/ui/scroll-bar"; import { SelectChallengePhase } from "#app/phases/select-challenge-phase"; import { EncounterPhase } from "#app/phases/encounter-phase"; @@ -161,7 +162,25 @@ const languageSettings: { [key: string]: LanguageSetting } = { starterInfoYOffset: 0.5, starterInfoXPos: 29, }, - "he":{ + da:{ + starterInfoTextSize: "56px", + instructionTextSize: "38px", + }, + tr:{ + starterInfoTextSize: "56px", + instructionTextSize: "38px", + }, + ro:{ + starterInfoTextSize: "56px", + instructionTextSize: "38px", + }, + ru: { + starterInfoTextSize: "46px", + instructionTextSize: "38px", + starterInfoYOffset: 0.5, + starterInfoXPos: 26, + }, + he:{ starterInfoTextSize: "56px", instructionTextSize: "38px", }, diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index f93a1826b3e..24e790f7c61 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -11,6 +11,7 @@ import { isNullOrUndefined, toReadableString, formatStat, + getShinyDescriptor, } from "#app/utils/common"; import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters"; @@ -444,18 +445,19 @@ export default class SummaryUiHandler extends UiHandler { this.shinyIcon.setVisible(this.pokemon.isShiny(false)); this.shinyIcon.setTint(getVariantTint(baseVariant)); if (this.shinyIcon.visible) { - const shinyDescriptor = - doubleShiny || baseVariant - ? `${baseVariant === 2 ? i18next.t("common:epicShiny") : baseVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}${doubleShiny ? `/${this.pokemon.fusionVariant === 2 ? i18next.t("common:epicShiny") : this.pokemon.fusionVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}` : ""}` - : ""; - this.shinyIcon.on("pointerover", () => - globalScene.ui.showTooltip( - "", - `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, - true, - ), - ); - this.shinyIcon.on("pointerout", () => globalScene.ui.hideTooltip()); + let shinyDescriptor = ""; + if (doubleShiny || baseVariant) { + shinyDescriptor = " (" + getShinyDescriptor(baseVariant); + if (doubleShiny) { + shinyDescriptor += "/" + getShinyDescriptor(this.pokemon.fusionVariant); + } + shinyDescriptor += ")"; + } + this.shinyIcon + .on("pointerover", () => + globalScene.ui.showTooltip("", i18next.t("common:shinyOnHover") + shinyDescriptor, true), + ) + .on("pointerout", () => globalScene.ui.hideTooltip()); } this.fusionShinyIcon.setPosition(this.shinyIcon.x, this.shinyIcon.y); diff --git a/src/utils/common.ts b/src/utils/common.ts index bc2488a9070..b967236dc5d 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -2,6 +2,7 @@ import { MoneyFormat } from "#enums/money-format"; import { Moves } from "#enums/moves"; import i18next from "i18next"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; +import type { Variant } from "#app/sprites/variant"; export type nil = null | undefined; @@ -434,15 +435,19 @@ export function hasAllLocalizedSprites(lang?: string): boolean { case "es-ES": case "es-MX": case "fr": + case "da": case "de": case "he": case "it": case "zh-CN": case "zh-TW": case "pt-BR": + case "ro": + case "tr": case "ko": case "ja": - case "ca-ES": + case "ca": + case "ru": return true; default: return false; @@ -577,3 +582,18 @@ 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()); } + +/** Get the localized shiny descriptor for the provided variant + * @param variant - The variant to get the shiny descriptor for + * @returns The localized shiny descriptor + */ +export function getShinyDescriptor(variant: Variant): string { + switch (variant) { + case 2: + return i18next.t("common:epicShiny"); + case 1: + return i18next.t("common:rareShiny"); + case 0: + return i18next.t("common:commonShiny"); + } +} diff --git a/test/abilities/aroma_veil.test.ts b/test/abilities/aroma_veil.test.ts index 38683bcb1e3..aeec33eccf7 100644 --- a/test/abilities/aroma_veil.test.ts +++ b/test/abilities/aroma_veil.test.ts @@ -40,7 +40,7 @@ describe("Moves - Aroma Veil", () => { game.move.select(Moves.GROWL); game.move.select(Moves.GROWL); - await game.forceEnemyMove(Moves.HEAL_BLOCK); + await game.move.selectEnemyMove(Moves.HEAL_BLOCK); await game.toNextTurn(); party.forEach(p => { expect(p.getTag(BattlerTagType.HEAL_BLOCK)).toBeUndefined(); @@ -54,8 +54,8 @@ describe("Moves - Aroma Veil", () => { game.move.select(Moves.GROWL); game.move.select(Moves.GROWL, 1); - await game.forceEnemyMove(Moves.IMPRISON, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.IMPRISON, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.arena.getTag(ArenaTagType.IMPRISON)).toBeDefined(); party.forEach(p => { diff --git a/test/abilities/battery.test.ts b/test/abilities/battery.test.ts index 251ca6ccf16..123889c24af 100644 --- a/test/abilities/battery.test.ts +++ b/test/abilities/battery.test.ts @@ -39,7 +39,7 @@ describe("Abilities - Battery", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); - await game.startBattle([Species.PIKACHU, Species.CHARJABUG]); + await game.classicMode.startBattle([Species.PIKACHU, Species.CHARJABUG]); game.move.select(Moves.DAZZLING_GLEAM); game.move.select(Moves.SPLASH, 1); @@ -54,7 +54,7 @@ describe("Abilities - Battery", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); - await game.startBattle([Species.PIKACHU, Species.CHARJABUG]); + await game.classicMode.startBattle([Species.PIKACHU, Species.CHARJABUG]); game.move.select(Moves.BREAKING_SWIPE); game.move.select(Moves.SPLASH, 1); @@ -69,7 +69,7 @@ describe("Abilities - Battery", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); - await game.startBattle([Species.CHARJABUG, Species.PIKACHU]); + await game.classicMode.startBattle([Species.CHARJABUG, Species.PIKACHU]); game.move.select(Moves.DAZZLING_GLEAM); game.move.select(Moves.SPLASH, 1); diff --git a/test/abilities/commander.test.ts b/test/abilities/commander.test.ts index 0e6cb1b9208..0fddb8e9bf6 100644 --- a/test/abilities/commander.test.ts +++ b/test/abilities/commander.test.ts @@ -59,8 +59,8 @@ describe("Abilities - Commander", () => { expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); // Force both enemies to target the Tatsugiri - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); await game.phaseInterceptor.to("BerryPhase", false); game.scene.getEnemyField().forEach(enemy => expect(enemy.getLastXMoves(1)[0].result).toBe(MoveResult.MISS)); @@ -100,8 +100,8 @@ describe("Abilities - Commander", () => { expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); await game.setTurnOrder([BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER]); @@ -183,8 +183,8 @@ describe("Abilities - Commander", () => { expect(game.scene.currentBattle.turnCommands[0]?.skip).toBeTruthy(); - await game.forceEnemyMove(Moves.WHIRLWIND, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.WHIRLWIND, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); // Test may time out here if Whirlwind forced out a Pokemon await game.phaseInterceptor.to("TurnEndPhase"); diff --git a/test/abilities/costar.test.ts b/test/abilities/costar.test.ts index 7b1e362689d..02d607c2e9f 100644 --- a/test/abilities/costar.test.ts +++ b/test/abilities/costar.test.ts @@ -33,7 +33,7 @@ describe("Abilities - COSTAR", () => { test("ability copies positive stat stages", async () => { game.override.enemyAbility(Abilities.BALL_FETCH); - await game.startBattle([Species.MAGIKARP, Species.MAGIKARP, Species.FLAMIGO]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP, Species.FLAMIGO]); let [leftPokemon, rightPokemon] = game.scene.getPlayerField(); @@ -58,7 +58,7 @@ describe("Abilities - COSTAR", () => { test("ability copies negative stat stages", async () => { game.override.enemyAbility(Abilities.INTIMIDATE); - await game.startBattle([Species.MAGIKARP, Species.MAGIKARP, Species.FLAMIGO]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP, Species.FLAMIGO]); let [leftPokemon, rightPokemon] = game.scene.getPlayerField(); diff --git a/test/abilities/cud_chew.test.ts b/test/abilities/cud_chew.test.ts index 2f65ac5fd97..60205b62b70 100644 --- a/test/abilities/cud_chew.test.ts +++ b/test/abilities/cud_chew.test.ts @@ -76,7 +76,7 @@ describe("Abilities - Cud Chew", () => { farigiraf.hp = farigiraf.getMaxHp() / 2 - 1; game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("TurnEndPhase"); // doesn't trigger since cud chew hasn't eaten berry yet @@ -86,7 +86,7 @@ describe("Abilities - Cud Chew", () => { // get heal pulsed back to full before the cud chew proc game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.HEAL_PULSE); + await game.move.selectEnemyMove(Moves.HEAL_PULSE); await game.phaseInterceptor.to("TurnEndPhase"); // globalScene.queueAbilityDisplay should be called twice: diff --git a/test/abilities/dancer.test.ts b/test/abilities/dancer.test.ts index cdd1e3221e9..b85fc7bdcd4 100644 --- a/test/abilities/dancer.test.ts +++ b/test/abilities/dancer.test.ts @@ -77,8 +77,8 @@ describe("Abilities - Dancer", () => { game.move.select(Moves.REVELATION_DANCE, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2); game.move.select(Moves.FIERY_DANCE, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2); - await game.forceEnemyMove(Moves.INSTRUCT, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.MIRROR_MOVE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.INSTRUCT, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.MIRROR_MOVE, BattlerIndex.PLAYER); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("MovePhase"); // Oricorio rev dance await game.phaseInterceptor.to("MovePhase"); // Feebas fiery dance diff --git a/test/abilities/desolate-land.test.ts b/test/abilities/desolate-land.test.ts index 697bd0a4c48..da2c285e38f 100644 --- a/test/abilities/desolate-land.test.ts +++ b/test/abilities/desolate-land.test.ts @@ -50,8 +50,8 @@ describe("Abilities - Desolate Land", () => { game.move.select(Moves.SPLASH, 0, 2); game.move.select(Moves.SPLASH, 1, 2); - await game.forceEnemyMove(Moves.ROAR, 0); - await game.forceEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.ROAR, 0); + await game.move.selectEnemyMove(Moves.SPLASH, 1); await game.phaseInterceptor.to("TurnEndPhase"); @@ -66,8 +66,8 @@ describe("Abilities - Desolate Land", () => { game.move.select(Moves.SPLASH, 0, 2); game.move.select(Moves.SPLASH, 1, 2); - await game.forceEnemyMove(Moves.ROAR, 1); - await game.forceEnemyMove(Moves.SPLASH, 0); + await game.move.selectEnemyMove(Moves.ROAR, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 0); await game.phaseInterceptor.to("TurnEndPhase"); @@ -103,8 +103,8 @@ describe("Abilities - Desolate Land", () => { game.move.select(Moves.SPLASH, 0, 2); game.move.select(Moves.SPLASH, 1, 2); - await game.forceEnemyMove(Moves.MEMENTO, 0); - await game.forceEnemyMove(Moves.MEMENTO, 1); + await game.move.selectEnemyMove(Moves.MEMENTO, 0); + await game.move.selectEnemyMove(Moves.MEMENTO, 1); await game.phaseInterceptor.to("TurnEndPhase"); diff --git a/test/abilities/flower_gift.test.ts b/test/abilities/flower_gift.test.ts index f2b32dc4c80..df8830bca6d 100644 --- a/test/abilities/flower_gift.test.ts +++ b/test/abilities/flower_gift.test.ts @@ -67,8 +67,8 @@ describe("Abilities - Flower Gift", () => { // turn 1 game.move.select(Moves.SUNNY_DAY, 0); game.move.select(ally_move, 1, ally_target); - await game.forceEnemyMove(enemy_move, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(enemy_move, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); // Ensure sunny day is used last. await game.setTurnOrder([attacker_index, target_index, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(TurnEndPhase); @@ -79,8 +79,8 @@ describe("Abilities - Flower Gift", () => { // turn 2. Make target use recover to reset hp calculation. game.move.select(Moves.SPLASH, 0, target_index); game.move.select(ally_move, 1, ally_target); - await game.forceEnemyMove(enemy_move, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(enemy_move, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, target_index, attacker_index]); await game.phaseInterceptor.to(TurnEndPhase); const damageWithGift = initialHp - target.hp; diff --git a/test/abilities/flower_veil.test.ts b/test/abilities/flower_veil.test.ts index ce45906c4a9..7f51414d8a5 100644 --- a/test/abilities/flower_veil.test.ts +++ b/test/abilities/flower_veil.test.ts @@ -49,7 +49,7 @@ describe("Abilities - Flower Veil", () => { await game.classicMode.startBattle([Species.BULBASAUR]); const user = game.scene.getPlayerPokemon()!; game.move.select(Moves.REST); - await game.forceEnemyMove(Moves.TACKLE); + await game.move.selectEnemyMove(Moves.TACKLE); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); expect(user.status?.effect).toBe(StatusEffect.SLEEP); @@ -57,7 +57,7 @@ describe("Abilities - Flower Veil", () => { // remove sleep status so we can get burn from the orb user.resetStatus(); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(user.status?.effect).toBe(StatusEffect.BURN); }); @@ -71,8 +71,8 @@ describe("Abilities - Flower Veil", () => { vi.spyOn(ally, "getAbility").mockReturnValue(allAbilities[Abilities.BALL_FETCH]); game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.YAWN, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.YAWN, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.YAWN, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.YAWN, BattlerIndex.PLAYER_2); await game.phaseInterceptor.to("BerryPhase"); const user = game.scene.getPlayerPokemon()!; @@ -86,7 +86,7 @@ describe("Abilities - Flower Veil", () => { await game.classicMode.startBattle([Species.BULBASAUR]); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.THUNDER_WAVE); + await game.move.selectEnemyMove(Moves.THUNDER_WAVE); await game.toNextTurn(); expect(game.scene.getPlayerPokemon()!.status).toBeUndefined(); vi.spyOn(allMoves[Moves.THUNDER_WAVE], "accuracy", "get").mockClear(); @@ -101,8 +101,8 @@ describe("Abilities - Flower Veil", () => { vi.spyOn(ally, "getAbility").mockReturnValue(allAbilities[Abilities.BALL_FETCH]); game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.THUNDER_WAVE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.THUNDER_WAVE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.THUNDER_WAVE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.THUNDER_WAVE, BattlerIndex.PLAYER_2); await game.phaseInterceptor.to("BerryPhase"); expect(user.status?.effect).toBe(StatusEffect.PARALYSIS); expect(ally.status?.effect).toBe(StatusEffect.PARALYSIS); diff --git a/test/abilities/forecast.test.ts b/test/abilities/forecast.test.ts index 03b5d993a54..f2aa350ef37 100644 --- a/test/abilities/forecast.test.ts +++ b/test/abilities/forecast.test.ts @@ -30,7 +30,7 @@ describe("Abilities - Forecast", () => { */ const testWeatherFormChange = async (game: GameManager, weather: WeatherType, form: number, initialForm?: number) => { game.override.weather(weather).starterForms({ [Species.CASTFORM]: initialForm }); - await game.startBattle([Species.CASTFORM]); + await game.classicMode.startBattle([Species.CASTFORM]); game.move.select(Moves.SPLASH); @@ -44,7 +44,7 @@ describe("Abilities - Forecast", () => { */ const testRevertFormAgainstAbility = async (game: GameManager, ability: Abilities) => { game.override.starterForms({ [Species.CASTFORM]: SUNNY_FORM }).enemyAbility(ability); - await game.startBattle([Species.CASTFORM]); + await game.classicMode.startBattle([Species.CASTFORM]); game.move.select(Moves.SPLASH); @@ -81,7 +81,7 @@ describe("Abilities - Forecast", () => { [Species.GROUDON]: 1, [Species.RAYQUAZA]: 1, }); - await game.startBattle([ + await game.classicMode.startBattle([ Species.CASTFORM, Species.FEEBAS, Species.KYOGRE, @@ -201,7 +201,7 @@ describe("Abilities - Forecast", () => { it("has no effect on Pokémon other than Castform", async () => { game.override.enemyAbility(Abilities.FORECAST).enemySpecies(Species.SHUCKLE); - await game.startBattle([Species.CASTFORM]); + await game.classicMode.startBattle([Species.CASTFORM]); game.move.select(Moves.RAIN_DANCE); await game.phaseInterceptor.to(TurnEndPhase); @@ -212,7 +212,7 @@ describe("Abilities - Forecast", () => { it("reverts to Normal Form when Forecast is suppressed, changes form to match the weather when it regains it", async () => { game.override.enemyMoveset([Moves.GASTRO_ACID]).weather(WeatherType.RAIN); - await game.startBattle([Species.CASTFORM, Species.PIKACHU]); + await game.classicMode.startBattle([Species.CASTFORM, Species.PIKACHU]); const castform = game.scene.getPlayerPokemon()!; expect(castform.formIndex).toBe(RAINY_FORM); @@ -243,7 +243,7 @@ describe("Abilities - Forecast", () => { it("does not change Castform's form until after Stealth Rock deals damage", async () => { game.override.weather(WeatherType.RAIN).enemyMoveset([Moves.STEALTH_ROCK]); - await game.startBattle([Species.PIKACHU, Species.CASTFORM]); + await game.classicMode.startBattle([Species.PIKACHU, Species.CASTFORM]); // First turn - set up stealth rock game.move.select(Moves.SPLASH); @@ -267,7 +267,7 @@ describe("Abilities - Forecast", () => { it("should be in Normal Form after the user is switched out", async () => { game.override.weather(WeatherType.RAIN); - await game.startBattle([Species.CASTFORM, Species.MAGIKARP]); + await game.classicMode.startBattle([Species.CASTFORM, Species.MAGIKARP]); const castform = game.scene.getPlayerPokemon()!; expect(castform.formIndex).toBe(RAINY_FORM); diff --git a/test/abilities/friend_guard.test.ts b/test/abilities/friend_guard.test.ts index 0afe678b175..350ff737c58 100644 --- a/test/abilities/friend_guard.test.ts +++ b/test/abilities/friend_guard.test.ts @@ -43,8 +43,8 @@ describe("Moves - Friend Guard", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); // Get the last return value from `getAttackDamage` @@ -60,8 +60,8 @@ describe("Moves - Friend Guard", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); // Get the last return value from `getAttackDamage` @@ -83,8 +83,8 @@ describe("Moves - Friend Guard", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const turn1Damage = spy.mock.results[spy.mock.results.length - 1].value.damage; @@ -93,8 +93,8 @@ describe("Moves - Friend Guard", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const turn2Damage = spy.mock.results[spy.mock.results.length - 1].value.damage; @@ -109,8 +109,8 @@ describe("Moves - Friend Guard", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.DRAGON_RAGE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.DRAGON_RAGE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const turn1Damage = spy.mock.results[spy.mock.results.length - 1].value.damage; @@ -120,8 +120,8 @@ describe("Moves - Friend Guard", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.DRAGON_RAGE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.DRAGON_RAGE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const turn2Damage = spy.mock.results[spy.mock.results.length - 1].value.damage; diff --git a/test/abilities/good_as_gold.test.ts b/test/abilities/good_as_gold.test.ts index 09bdaafb11f..adb54810381 100644 --- a/test/abilities/good_as_gold.test.ts +++ b/test/abilities/good_as_gold.test.ts @@ -1,6 +1,6 @@ import { BattlerIndex } from "#app/battle"; -import { allAbilities } from "#app/data/data-lists"; import { ArenaTagSide } from "#app/data/arena-tag"; +import { allAbilities } from "#app/data/data-lists"; import { ArenaTagType } from "#app/enums/arena-tag-type"; import { BattlerTagType } from "#app/enums/battler-tag-type"; import { Stat } from "#app/enums/stat"; @@ -74,8 +74,8 @@ describe("Abilities - Good As Gold", () => { game.move.select(Moves.SWORDS_DANCE, 0); game.move.select(Moves.SAFEGUARD, 1); - await game.forceEnemyMove(Moves.STEALTH_ROCK); - await game.forceEnemyMove(Moves.HAZE); + await game.move.selectEnemyMove(Moves.STEALTH_ROCK); + await game.move.selectEnemyMove(Moves.HAZE); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to("BerryPhase"); expect(good_as_gold.getAbility().id).toBe(Abilities.GOOD_AS_GOLD); @@ -107,35 +107,33 @@ describe("Abilities - Good As Gold", () => { expect(game.scene.getPlayerField()[1].getTag(BattlerTagType.HELPING_HAND)).toBeUndefined(); }); - it("should block the ally's heal bell, but only if the good as gold user is on the field", async () => { - game.override.battleStyle("double"); - game.override.moveset([Moves.HEAL_BELL, Moves.SPLASH]); - game.override.statusEffect(StatusEffect.BURN); - await game.classicMode.startBattle([Species.MAGIKARP, Species.FEEBAS, Species.ABRA]); - const [good_as_gold, ball_fetch] = game.scene.getPlayerField(); - - // Force second pokemon to have ball fetch to isolate to a single mon. - vi.spyOn(ball_fetch, "getAbility").mockReturnValue(allAbilities[Abilities.BALL_FETCH]); + // TODO: re-enable when heal bell is fixed + it.todo("should block the ally's heal bell, but only if the good as gold user is on the field", async () => { + game.override.battleStyle("double").statusEffect(StatusEffect.BURN); + await game.classicMode.startBattle([Species.MILOTIC, Species.FEEBAS, Species.ABRA]); + const [milotic, feebas, abra] = game.scene.getPlayerParty(); + game.field.mockAbility(milotic, Abilities.GOOD_AS_GOLD); + game.field.mockAbility(feebas, Abilities.BALL_FETCH); + game.field.mockAbility(abra, Abilities.BALL_FETCH); // turn 1 - game.move.select(Moves.SPLASH, 0); - game.move.select(Moves.HEAL_BELL, 1); + game.move.use(Moves.SPLASH, 0); + game.move.use(Moves.HEAL_BELL, 1); await game.toNextTurn(); - expect(good_as_gold.status?.effect).toBe(StatusEffect.BURN); + expect(milotic.status?.effect).toBe(StatusEffect.BURN); game.doSwitchPokemon(2); - game.move.select(Moves.HEAL_BELL, 0); + game.move.use(Moves.HEAL_BELL, 1); await game.toNextTurn(); - expect(good_as_gold.status?.effect).toBeUndefined(); + expect(milotic.status?.effect).toBeUndefined(); }); it("should not block field targeted effects like rain dance", async () => { game.override.battleStyle("single"); game.override.enemyMoveset([Moves.RAIN_DANCE]); - game.override.weather(WeatherType.NONE); await game.classicMode.startBattle([Species.MAGIKARP]); - game.move.select(Moves.SPLASH, 0); + game.move.use(Moves.SPLASH, 0); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.RAIN); diff --git a/test/abilities/gorilla_tactics.test.ts b/test/abilities/gorilla_tactics.test.ts index edaf1669809..06f0c1d0e3d 100644 --- a/test/abilities/gorilla_tactics.test.ts +++ b/test/abilities/gorilla_tactics.test.ts @@ -39,7 +39,7 @@ describe("Abilities - Gorilla Tactics", () => { const initialAtkStat = darmanitan.getStat(Stat.ATK); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("TurnEndPhase"); @@ -57,13 +57,13 @@ describe("Abilities - Gorilla Tactics", () => { // First turn, lock move to Growl game.move.select(Moves.GROWL); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); // Second turn, Growl is interrupted by Disable await game.toNextTurn(); game.move.select(Moves.GROWL); - await game.forceEnemyMove(Moves.DISABLE); + await game.move.selectEnemyMove(Moves.DISABLE); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnEndPhase"); diff --git a/test/abilities/gulp_missile.test.ts b/test/abilities/gulp_missile.test.ts index 4db2ae4190d..64cd106cc5e 100644 --- a/test/abilities/gulp_missile.test.ts +++ b/test/abilities/gulp_missile.test.ts @@ -241,13 +241,13 @@ describe("Abilities - Gulp Missile", () => { await game.classicMode.startBattle([Species.CRAMORANT]); game.move.select(Moves.SURF); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.getPlayerPokemon()!.formIndex).toBe(GULPING_FORM); game.move.select(Moves.SUBSTITUTE); - await game.forceEnemyMove(Moves.POWER_TRIP); + await game.move.selectEnemyMove(Moves.POWER_TRIP); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toNextTurn(); diff --git a/test/abilities/harvest.test.ts b/test/abilities/harvest.test.ts index 23c0ed9088c..36b1b879598 100644 --- a/test/abilities/harvest.test.ts +++ b/test/abilities/harvest.test.ts @@ -61,7 +61,7 @@ describe("Abilities - Harvest", () => { await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.NUZZLE); + await game.move.selectEnemyMove(Moves.NUZZLE); await game.phaseInterceptor.to("BerryPhase"); expect(getPlayerBerries()).toHaveLength(0); expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toHaveLength(1); @@ -87,7 +87,7 @@ describe("Abilities - Harvest", () => { // Chug a few berries without harvest (should get tracked) game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.NUZZLE); + await game.move.selectEnemyMove(Moves.NUZZLE); await game.toNextTurn(); expect(milotic.battleData.berriesEaten).toEqual(expect.arrayContaining([BerryType.ENIGMA, BerryType.LUM])); @@ -98,7 +98,7 @@ describe("Abilities - Harvest", () => { 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.move.selectEnemyMove(Moves.NUZZLE); await game.toNextTurn(); @@ -109,7 +109,7 @@ describe("Abilities - Harvest", () => { // proc a high roll and we _should_ get a berry back! game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(milotic.battleData.berriesEaten).toHaveLength(3); @@ -126,7 +126,7 @@ describe("Abilities - Harvest", () => { regieleki.hp = 1; game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.doKillOpponents(); await game.phaseInterceptor.to("TurnEndPhase"); @@ -154,7 +154,7 @@ describe("Abilities - Harvest", () => { regieleki.hp = regieleki.getMaxHp() / 4 + 1; game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SUPER_FANG); + await game.move.selectEnemyMove(Moves.SUPER_FANG); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); @@ -165,7 +165,7 @@ describe("Abilities - Harvest", () => { // heal up so harvest doesn't proc and kill enemy game.move.select(Moves.EARTHQUAKE); - await game.forceEnemyMove(Moves.HEAL_PULSE); + await game.move.selectEnemyMove(Moves.HEAL_PULSE); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextWave(); @@ -191,7 +191,7 @@ describe("Abilities - Harvest", () => { feebas.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF]; game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("BerryPhase"); // Force RNG roll to hit the first berry we find that matches. @@ -219,7 +219,7 @@ describe("Abilities - Harvest", () => { player.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF]; game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("TurnEndPhase"); expectBerriesContaining(...initBerries); @@ -231,7 +231,7 @@ describe("Abilities - Harvest", () => { await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.INCINERATE); + await game.move.selectEnemyMove(Moves.INCINERATE); await game.phaseInterceptor.to("TurnEndPhase"); expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); @@ -242,7 +242,7 @@ describe("Abilities - Harvest", () => { await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.KNOCK_OFF); + await game.move.selectEnemyMove(Moves.KNOCK_OFF); await game.phaseInterceptor.to("TurnEndPhase"); expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); @@ -308,7 +308,7 @@ describe("Abilities - Harvest", () => { // steal a sitrus and immediately consume it game.move.select(Moves.FALSE_SWIPE); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("BerryPhase"); expect(player.battleData.berriesEaten).toEqual([BerryType.SITRUS]); diff --git a/test/abilities/heatproof.test.ts b/test/abilities/heatproof.test.ts index 016237bb02f..0bec7e4a3db 100644 --- a/test/abilities/heatproof.test.ts +++ b/test/abilities/heatproof.test.ts @@ -38,7 +38,7 @@ describe("Abilities - Heatproof", () => { }); it("reduces Fire type damage by half", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const enemy = game.scene.getEnemyPokemon()!; const initialHP = 1000; @@ -61,7 +61,7 @@ describe("Abilities - Heatproof", () => { it("reduces Burn damage by half", async () => { game.override.enemyStatusEffect(StatusEffect.BURN).enemySpecies(Species.ABRA); - await game.startBattle(); + await game.classicMode.startBattle(); const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/abilities/hyper_cutter.test.ts b/test/abilities/hyper_cutter.test.ts index 99a9db28025..76b66c2990e 100644 --- a/test/abilities/hyper_cutter.test.ts +++ b/test/abilities/hyper_cutter.test.ts @@ -34,7 +34,7 @@ describe("Abilities - Hyper Cutter", () => { // Reference Link: https://bulbapedia.bulbagarden.net/wiki/Hyper_Cutter_(Ability) it("only prevents ATK drops", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/abilities/libero.test.ts b/test/abilities/libero.test.ts index a6942b18aad..ea4e288bdb0 100644 --- a/test/abilities/libero.test.ts +++ b/test/abilities/libero.test.ts @@ -39,7 +39,7 @@ describe("Abilities - Libero", () => { test("ability applies and changes a pokemon's type", async () => { game.override.moveset([Moves.SPLASH]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -54,7 +54,7 @@ describe("Abilities - Libero", () => { test.skip("ability applies only once per switch in", async () => { game.override.moveset([Moves.SPLASH, Moves.AGILITY]); - await game.startBattle([Species.MAGIKARP, Species.BULBASAUR]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.BULBASAUR]); let leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -90,7 +90,7 @@ describe("Abilities - Libero", () => { test("ability applies correctly even if the pokemon's move has a variable type", async () => { game.override.moveset([Moves.WEATHER_BALL]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -110,7 +110,7 @@ describe("Abilities - Libero", () => { game.override.moveset([Moves.TACKLE]); game.override.passiveAbility(Abilities.REFRIGERATE); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -128,7 +128,7 @@ describe("Abilities - Libero", () => { test("ability applies correctly even if the pokemon's move calls another move", async () => { game.override.moveset([Moves.NATURE_POWER]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -143,7 +143,7 @@ describe("Abilities - Libero", () => { test("ability applies correctly even if the pokemon's move is delayed / charging", async () => { game.override.moveset([Moves.DIG]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -158,7 +158,7 @@ describe("Abilities - Libero", () => { game.override.moveset([Moves.TACKLE]); game.override.enemyMoveset(Moves.SPLASH); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -176,7 +176,7 @@ describe("Abilities - Libero", () => { game.override.moveset([Moves.TACKLE]); game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -191,7 +191,7 @@ describe("Abilities - Libero", () => { game.override.moveset([Moves.TACKLE]); game.override.enemySpecies(Species.GASTLY); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -205,7 +205,7 @@ describe("Abilities - Libero", () => { test("ability is not applied if pokemon's type is the same as the move's type", async () => { game.override.moveset([Moves.SPLASH]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -220,7 +220,7 @@ describe("Abilities - Libero", () => { test("ability is not applied if pokemon is terastallized", async () => { game.override.moveset([Moves.SPLASH]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -236,7 +236,7 @@ describe("Abilities - Libero", () => { test("ability is not applied if pokemon uses struggle", async () => { game.override.moveset([Moves.STRUGGLE]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -250,7 +250,7 @@ describe("Abilities - Libero", () => { test("ability is not applied if the pokemon's move fails", async () => { game.override.moveset([Moves.BURN_UP]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -265,7 +265,7 @@ describe("Abilities - Libero", () => { game.override.moveset([Moves.TRICK_OR_TREAT]); game.override.enemySpecies(Species.GASTLY); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -279,7 +279,7 @@ describe("Abilities - Libero", () => { test("ability applies correctly and the pokemon curses itself", async () => { game.override.moveset([Moves.CURSE]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); diff --git a/test/abilities/magic_bounce.test.ts b/test/abilities/magic_bounce.test.ts index 78e4114724c..be1ad2b413a 100644 --- a/test/abilities/magic_bounce.test.ts +++ b/test/abilities/magic_bounce.test.ts @@ -52,7 +52,7 @@ describe("Abilities - Magic Bounce", () => { game.override.enemyMoveset([Moves.FLY]); game.move.select(Moves.GROWL); - await game.forceEnemyMove(Moves.FLY); + await game.move.selectEnemyMove(Moves.FLY); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("BerryPhase"); @@ -183,7 +183,7 @@ describe("Abilities - Magic Bounce", () => { // turn 1 game.move.select(Moves.ENCORE); - await game.forceEnemyMove(Moves.TACKLE); + await game.move.selectEnemyMove(Moves.TACKLE); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); expect(enemyPokemon.getTag(BattlerTagType.ENCORE)!["moveId"]).toBe(Moves.TACKLE); @@ -209,7 +209,7 @@ describe("Abilities - Magic Bounce", () => { // turn 1 game.move.select(Moves.GROWL); - await game.forceEnemyMove(Moves.TACKLE); + await game.move.selectEnemyMove(Moves.TACKLE); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); @@ -218,7 +218,7 @@ describe("Abilities - Magic Bounce", () => { // turn 2 game.move.select(Moves.ENCORE); - await game.forceEnemyMove(Moves.TACKLE); + await game.move.selectEnemyMove(Moves.TACKLE); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("BerryPhase"); expect(enemyPokemon.getTag(BattlerTagType.ENCORE)!["moveId"]).toBe(Moves.TACKLE); @@ -254,7 +254,7 @@ describe("Abilities - Magic Bounce", () => { vi.spyOn(stomping_tantrum, "calculateBattlePower"); game.move.select(Moves.SPORE); - await game.forceEnemyMove(Moves.CHARM); + await game.move.selectEnemyMove(Moves.CHARM); await game.phaseInterceptor.to("TurnEndPhase"); expect(enemy.getLastXMoves(1)[0].result).toBe("success"); @@ -346,7 +346,7 @@ describe("Abilities - Magic Bounce", () => { game.override.moveset([Moves.TOXIC, Moves.CHARM]); await game.classicMode.startBattle([Species.BULBASAUR]); game.move.select(Moves.TOXIC); - await game.forceEnemyMove(Moves.FLY); + await game.move.selectEnemyMove(Moves.FLY); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.TOXIC); diff --git a/test/abilities/magic_guard.test.ts b/test/abilities/magic_guard.test.ts index 96a9f4dab74..61d06a74c58 100644 --- a/test/abilities/magic_guard.test.ts +++ b/test/abilities/magic_guard.test.ts @@ -46,7 +46,7 @@ describe("Abilities - Magic Guard", () => { it("ability should prevent damage caused by weather", async () => { game.override.weather(WeatherType.SANDSTORM); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -70,7 +70,7 @@ describe("Abilities - Magic Guard", () => { //Toxic keeps track of the turn counters -> important that Magic Guard keeps track of post-Toxic turns game.override.statusEffect(StatusEffect.POISON); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -91,7 +91,7 @@ describe("Abilities - Magic Guard", () => { game.override.enemyMoveset([Moves.WORRY_SEED, Moves.WORRY_SEED, Moves.WORRY_SEED, Moves.WORRY_SEED]); game.override.statusEffect(StatusEffect.POISON); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -110,7 +110,7 @@ describe("Abilities - Magic Guard", () => { game.override.enemyStatusEffect(StatusEffect.BURN); game.override.enemyAbility(Abilities.MAGIC_GUARD); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); game.move.select(Moves.SPLASH); @@ -132,7 +132,7 @@ describe("Abilities - Magic Guard", () => { game.override.enemyStatusEffect(StatusEffect.TOXIC); game.override.enemyAbility(Abilities.MAGIC_GUARD); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); game.move.select(Moves.SPLASH); @@ -159,7 +159,7 @@ describe("Abilities - Magic Guard", () => { const newTag = getArenaTag(ArenaTagType.SPIKES, 5, Moves.SPIKES, 0, 0, ArenaTagSide.BOTH)!; game.scene.arena.tags.push(newTag); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; game.move.select(Moves.SPLASH); @@ -184,7 +184,7 @@ describe("Abilities - Magic Guard", () => { game.scene.arena.tags.push(playerTag); game.scene.arena.tags.push(enemyTag); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; game.move.select(Moves.SPLASH); @@ -206,7 +206,7 @@ describe("Abilities - Magic Guard", () => { }); it("Magic Guard prevents against damage from volatile status effects", async () => { - await game.startBattle([Species.DUSKULL]); + await game.classicMode.startBattle([Species.DUSKULL]); game.override.moveset([Moves.CURSE]); game.override.enemyAbility(Abilities.MAGIC_GUARD); @@ -231,7 +231,7 @@ describe("Abilities - Magic Guard", () => { it("Magic Guard prevents crash damage", async () => { game.override.moveset([Moves.HIGH_JUMP_KICK]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -249,7 +249,7 @@ describe("Abilities - Magic Guard", () => { it("Magic Guard prevents damage from recoil", async () => { game.override.moveset([Moves.TAKE_DOWN]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -266,7 +266,7 @@ describe("Abilities - Magic Guard", () => { it("Magic Guard does not prevent damage from Struggle's recoil", async () => { game.override.moveset([Moves.STRUGGLE]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -284,7 +284,7 @@ describe("Abilities - Magic Guard", () => { //This tests different move attributes than the recoil tests above it("Magic Guard prevents self-damage from attacking moves", async () => { game.override.moveset([Moves.STEEL_BEAM]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -301,7 +301,7 @@ describe("Abilities - Magic Guard", () => { /* it("Magic Guard does not prevent self-damage from confusion", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); game.move.select(Moves.CHARM); @@ -311,7 +311,7 @@ describe("Abilities - Magic Guard", () => { it("Magic Guard does not prevent self-damage from non-attacking moves", async () => { game.override.moveset([Moves.BELLY_DRUM]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -333,7 +333,7 @@ describe("Abilities - Magic Guard", () => { game.override.enemyMoveset([Moves.SPORE, Moves.SPORE, Moves.SPORE, Moves.SPORE]); game.override.enemyAbility(Abilities.BAD_DREAMS); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -355,7 +355,7 @@ describe("Abilities - Magic Guard", () => { game.override.moveset([Moves.TACKLE]); game.override.enemyAbility(Abilities.AFTERMATH); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -379,7 +379,7 @@ describe("Abilities - Magic Guard", () => { game.override.moveset([Moves.TACKLE]); game.override.enemyAbility(Abilities.IRON_BARBS); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -402,7 +402,7 @@ describe("Abilities - Magic Guard", () => { game.override.moveset([Moves.ABSORB]); game.override.enemyAbility(Abilities.LIQUID_OOZE); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -425,7 +425,7 @@ describe("Abilities - Magic Guard", () => { game.override.passiveAbility(Abilities.SOLAR_POWER); game.override.weather(WeatherType.SUNNY); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/test/abilities/mimicry.test.ts b/test/abilities/mimicry.test.ts index 598f5790aa8..de196ffc939 100644 --- a/test/abilities/mimicry.test.ts +++ b/test/abilities/mimicry.test.ts @@ -55,7 +55,7 @@ describe("Abilities - Mimicry", () => { const playerPokemon = game.scene.getPlayerPokemon(); game.move.select(Moves.TRANSFORM); - await game.forceEnemyMove(Moves.PSYCHIC_TERRAIN); + await game.move.selectEnemyMove(Moves.PSYCHIC_TERRAIN); await game.toNextTurn(); expect(playerPokemon?.getTypes().includes(PokemonType.PSYCHIC)).toBe(true); @@ -64,7 +64,7 @@ describe("Abilities - Mimicry", () => { } game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(playerPokemon?.getTypes().includes(PokemonType.ELECTRIC)).toBe(true); }); @@ -75,13 +75,13 @@ describe("Abilities - Mimicry", () => { const playerPokemon = game.scene.getPlayerPokemon(); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.FORESTS_CURSE); + await game.move.selectEnemyMove(Moves.FORESTS_CURSE); await game.toNextTurn(); expect(playerPokemon?.summonData.addedType).toBe(PokemonType.GRASS); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.GRASSY_TERRAIN); + await game.move.selectEnemyMove(Moves.GRASSY_TERRAIN); await game.phaseInterceptor.to("TurnEndPhase"); expect(playerPokemon?.summonData.addedType).toBeNull(); diff --git a/test/abilities/mirror_armor.test.ts b/test/abilities/mirror_armor.test.ts index bd61f39ba75..5f9c63531d4 100644 --- a/test/abilities/mirror_armor.test.ts +++ b/test/abilities/mirror_armor.test.ts @@ -46,7 +46,7 @@ describe("Ability - Mirror Armor", () => { // Enemy has intimidate, enemy should lose -1 atk game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); await game.toNextTurn(); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(-1); @@ -63,7 +63,7 @@ describe("Ability - Mirror Armor", () => { // Enemy has intimidate, enemy should lose -1 atk game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); await game.toNextTurn(); expect(userPokemon.getStatStage(Stat.ATK)).toBe(-1); @@ -82,8 +82,8 @@ describe("Ability - Mirror Armor", () => { // Enemy has intimidate, enemy should lose -2 atk each game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER_2); await game.toNextTurn(); expect(enemy1.getStatStage(Stat.ATK)).toBe(-2); @@ -104,8 +104,8 @@ describe("Ability - Mirror Armor", () => { // Enemy has intimidate, enemy should lose -1 atk game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER_2); await game.toNextTurn(); expect(enemy1.getStatStage(Stat.ATK)).toBe(0); @@ -124,7 +124,7 @@ describe("Ability - Mirror Armor", () => { // Enemy has intimidate and uses tickle, enemy receives -2 atk and -1 defense game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.TICKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TICKLE, BattlerIndex.PLAYER); await game.toNextTurn(); expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(-1); @@ -144,8 +144,8 @@ describe("Ability - Mirror Armor", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.TICKLE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.TICKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.TICKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TICKLE, BattlerIndex.PLAYER_2); await game.toNextTurn(); expect(player1.getStatStage(Stat.ATK)).toBe(0); @@ -168,7 +168,7 @@ describe("Ability - Mirror Armor", () => { // Enemy has intimidate and uses tickle, enemy receives -2 atk and -1 defense game.move.select(Moves.TICKLE); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); await game.toNextTurn(); expect(userPokemon.getStatStage(Stat.DEF)).toBe(-1); @@ -187,7 +187,7 @@ describe("Ability - Mirror Armor", () => { // Enemy has intimidate and uses tickle, enemy has white smoke, no one loses stats game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.TICKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TICKLE, BattlerIndex.PLAYER); await game.toNextTurn(); expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(0); @@ -206,7 +206,7 @@ describe("Ability - Mirror Armor", () => { // Enemy has intimidate and uses tickle, enemy has white smoke, no one loses stats game.move.select(Moves.TICKLE); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); await game.toNextTurn(); expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(0); @@ -224,7 +224,7 @@ describe("Ability - Mirror Armor", () => { // Enemy uses octolock, player loses stats at end of turn game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.OCTOLOCK, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.OCTOLOCK, BattlerIndex.PLAYER); await game.toNextTurn(); expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(0); @@ -242,7 +242,7 @@ describe("Ability - Mirror Armor", () => { // Player uses octolock, enemy loses stats at end of turn game.move.select(Moves.OCTOLOCK); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); await game.toNextTurn(); expect(userPokemon.getStatStage(Stat.DEF)).toBe(0); @@ -261,7 +261,7 @@ describe("Ability - Mirror Armor", () => { const userPokemon = game.scene.getPlayerPokemon()!; game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); await game.toNextTurn(); expect(userPokemon.getStatStage(Stat.ATK)).toBe(-1); @@ -276,11 +276,11 @@ describe("Ability - Mirror Armor", () => { const userPokemon = game.scene.getPlayerPokemon()!; game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.STICKY_WEB, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.STICKY_WEB, BattlerIndex.PLAYER); await game.toNextTurn(); game.doSwitchPokemon(1); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); await game.toNextTurn(); expect(userPokemon.getStatStage(Stat.SPD)).toBe(0); @@ -297,14 +297,14 @@ describe("Ability - Mirror Armor", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.STICKY_WEB, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.STICKY_WEB, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER_2); await game.toNextTurn(); game.doSwitchPokemon(2); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER_2); await game.toNextTurn(); expect(enemy1.getStatStage(Stat.SPD)).toBe(-1); diff --git a/test/abilities/moxie.test.ts b/test/abilities/moxie.test.ts index bccdeda2b93..d4e1927e077 100644 --- a/test/abilities/moxie.test.ts +++ b/test/abilities/moxie.test.ts @@ -38,7 +38,7 @@ describe("Abilities - Moxie", () => { it("should raise ATK stat stage by 1 when winning a battle", async () => { const moveToUse = Moves.AERIAL_ACE; - await game.startBattle([Species.MIGHTYENA, Species.MIGHTYENA]); + await game.classicMode.startBattle([Species.MIGHTYENA, Species.MIGHTYENA]); const playerPokemon = game.scene.getPlayerPokemon()!; @@ -56,7 +56,7 @@ describe("Abilities - Moxie", () => { async () => { game.override.battleStyle("double"); const moveToUse = Moves.AERIAL_ACE; - await game.startBattle([Species.MIGHTYENA, Species.MIGHTYENA]); + await game.classicMode.startBattle([Species.MIGHTYENA, Species.MIGHTYENA]); const [firstPokemon, secondPokemon] = game.scene.getPlayerField(); diff --git a/test/abilities/mycelium_might.test.ts b/test/abilities/mycelium_might.test.ts index 4a5700045fa..18465f9b64e 100644 --- a/test/abilities/mycelium_might.test.ts +++ b/test/abilities/mycelium_might.test.ts @@ -41,7 +41,7 @@ describe("Abilities - Mycelium Might", () => { **/ it("will move last in its priority bracket and ignore protective abilities", async () => { - await game.startBattle([Species.REGIELEKI]); + await game.classicMode.startBattle([Species.REGIELEKI]); const enemyPokemon = game.scene.getEnemyPokemon(); const playerIndex = game.scene.getPlayerPokemon()?.getBattlerIndex(); @@ -65,7 +65,7 @@ describe("Abilities - Mycelium Might", () => { it("will still go first if a status move that is in a higher priority bracket than the opponent's move is used", async () => { game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); - await game.startBattle([Species.REGIELEKI]); + await game.classicMode.startBattle([Species.REGIELEKI]); const enemyPokemon = game.scene.getEnemyPokemon(); const playerIndex = game.scene.getPlayerPokemon()?.getBattlerIndex(); @@ -87,7 +87,7 @@ describe("Abilities - Mycelium Might", () => { }, 20000); it("will not affect non-status moves", async () => { - await game.startBattle([Species.REGIELEKI]); + await game.classicMode.startBattle([Species.REGIELEKI]); const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); diff --git a/test/abilities/neutralizing_gas.test.ts b/test/abilities/neutralizing_gas.test.ts index 979583b7d97..cf19f36c9d0 100644 --- a/test/abilities/neutralizing_gas.test.ts +++ b/test/abilities/neutralizing_gas.test.ts @@ -110,16 +110,16 @@ describe("Abilities - Neutralizing Gas", () => { await game.classicMode.startBattle([Species.ACCELGOR, Species.ACCELGOR]); game.move.select(Moves.SPLASH, 0); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.ENTRAINMENT, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.ENTRAINMENT, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined(); // Now one neut gas user is left game.move.select(Moves.SPLASH, 0); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.ENTRAINMENT, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.ENTRAINMENT, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined(); // No neut gas users are left diff --git a/test/abilities/pastel_veil.test.ts b/test/abilities/pastel_veil.test.ts index 4ae9763c4a6..21da1d1353d 100644 --- a/test/abilities/pastel_veil.test.ts +++ b/test/abilities/pastel_veil.test.ts @@ -34,7 +34,7 @@ describe("Abilities - Pastel Veil", () => { }); it("prevents the user and its allies from being afflicted by poison", async () => { - await game.startBattle([Species.MAGIKARP, Species.GALAR_PONYTA]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.GALAR_PONYTA]); const ponyta = game.scene.getPlayerField()[1]; const magikarp = game.scene.getPlayerField()[0]; ponyta.abilityIndex = 1; @@ -50,7 +50,7 @@ describe("Abilities - Pastel Veil", () => { }); it("it heals the poisoned status condition of allies if user is sent out into battle", async () => { - await game.startBattle([Species.MAGIKARP, Species.FEEBAS, Species.GALAR_PONYTA]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.FEEBAS, Species.GALAR_PONYTA]); const ponyta = game.scene.getPlayerParty()[2]; const magikarp = game.scene.getPlayerField()[0]; ponyta.abilityIndex = 1; diff --git a/test/abilities/perish_body.test.ts b/test/abilities/perish_body.test.ts index 27e76cb52ad..140e087843c 100644 --- a/test/abilities/perish_body.test.ts +++ b/test/abilities/perish_body.test.ts @@ -64,14 +64,14 @@ describe("Abilities - Perish Song", () => { const magikarp = game.scene.getEnemyPokemon(); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.PERISH_SONG); + await game.move.selectEnemyMove(Moves.PERISH_SONG); await game.toNextTurn(); expect(feebas?.summonData.tags[0].turnCount).toBe(3); expect(magikarp?.summonData.tags[0].turnCount).toBe(3); game.doSwitchPokemon(1); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const cursola = game.scene.getPlayerPokemon(); @@ -79,7 +79,7 @@ describe("Abilities - Perish Song", () => { expect(magikarp?.summonData.tags[0].turnCount).toBe(2); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.AQUA_JET); + await game.move.selectEnemyMove(Moves.AQUA_JET); await game.toNextTurn(); expect(cursola?.summonData.tags.length).toBe(0); @@ -94,7 +94,7 @@ describe("Abilities - Perish Song", () => { const cursola = game.scene.getPlayerPokemon(); game.move.select(Moves.WHIRLWIND); - await game.forceEnemyMove(Moves.PERISH_SONG); + await game.move.selectEnemyMove(Moves.PERISH_SONG); await game.toNextTurn(); const magikarp = game.scene.getEnemyPokemon(); @@ -102,7 +102,7 @@ describe("Abilities - Perish Song", () => { expect(magikarp?.summonData.tags.length).toBe(0); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.AQUA_JET); + await game.move.selectEnemyMove(Moves.AQUA_JET); await game.toNextTurn(); expect(cursola?.summonData.tags[0].turnCount).toBe(2); diff --git a/test/abilities/power_spot.test.ts b/test/abilities/power_spot.test.ts index c3accdb04f8..0a062537202 100644 --- a/test/abilities/power_spot.test.ts +++ b/test/abilities/power_spot.test.ts @@ -39,7 +39,7 @@ describe("Abilities - Power Spot", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); - await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]); + await game.classicMode.startBattle([Species.REGIELEKI, Species.STONJOURNER]); game.move.select(Moves.DAZZLING_GLEAM); game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase); @@ -53,7 +53,7 @@ describe("Abilities - Power Spot", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); - await game.startBattle([Species.REGIELEKI, Species.STONJOURNER]); + await game.classicMode.startBattle([Species.REGIELEKI, Species.STONJOURNER]); game.move.select(Moves.BREAKING_SWIPE); game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(MoveEffectPhase); @@ -67,7 +67,7 @@ describe("Abilities - Power Spot", () => { vi.spyOn(moveToCheck, "calculateBattlePower"); - await game.startBattle([Species.STONJOURNER, Species.REGIELEKI]); + await game.classicMode.startBattle([Species.STONJOURNER, Species.REGIELEKI]); game.move.select(Moves.BREAKING_SWIPE); game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/test/abilities/protean.test.ts b/test/abilities/protean.test.ts index 8e6b69dabd6..bfe6dd32282 100644 --- a/test/abilities/protean.test.ts +++ b/test/abilities/protean.test.ts @@ -39,7 +39,7 @@ describe("Abilities - Protean", () => { test("ability applies and changes a pokemon's type", async () => { game.override.moveset([Moves.SPLASH]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -54,7 +54,7 @@ describe("Abilities - Protean", () => { test.skip("ability applies only once per switch in", async () => { game.override.moveset([Moves.SPLASH, Moves.AGILITY]); - await game.startBattle([Species.MAGIKARP, Species.BULBASAUR]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.BULBASAUR]); let leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -90,7 +90,7 @@ describe("Abilities - Protean", () => { test("ability applies correctly even if the pokemon's move has a variable type", async () => { game.override.moveset([Moves.WEATHER_BALL]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -110,7 +110,7 @@ describe("Abilities - Protean", () => { game.override.moveset([Moves.TACKLE]); game.override.passiveAbility(Abilities.REFRIGERATE); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -128,7 +128,7 @@ describe("Abilities - Protean", () => { test("ability applies correctly even if the pokemon's move calls another move", async () => { game.override.moveset([Moves.NATURE_POWER]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -143,7 +143,7 @@ describe("Abilities - Protean", () => { test("ability applies correctly even if the pokemon's move is delayed / charging", async () => { game.override.moveset([Moves.DIG]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -158,7 +158,7 @@ describe("Abilities - Protean", () => { game.override.moveset([Moves.TACKLE]); game.override.enemyMoveset(Moves.SPLASH); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -176,7 +176,7 @@ describe("Abilities - Protean", () => { game.override.moveset([Moves.TACKLE]); game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -191,7 +191,7 @@ describe("Abilities - Protean", () => { game.override.moveset([Moves.TACKLE]); game.override.enemySpecies(Species.GASTLY); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -205,7 +205,7 @@ describe("Abilities - Protean", () => { test("ability is not applied if pokemon's type is the same as the move's type", async () => { game.override.moveset([Moves.SPLASH]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -220,7 +220,7 @@ describe("Abilities - Protean", () => { test("ability is not applied if pokemon is terastallized", async () => { game.override.moveset([Moves.SPLASH]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -236,7 +236,7 @@ describe("Abilities - Protean", () => { test("ability is not applied if pokemon uses struggle", async () => { game.override.moveset([Moves.STRUGGLE]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -250,7 +250,7 @@ describe("Abilities - Protean", () => { test("ability is not applied if the pokemon's move fails", async () => { game.override.moveset([Moves.BURN_UP]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -265,7 +265,7 @@ describe("Abilities - Protean", () => { game.override.moveset([Moves.TRICK_OR_TREAT]); game.override.enemySpecies(Species.GASTLY); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); @@ -279,7 +279,7 @@ describe("Abilities - Protean", () => { test("ability applies correctly and the pokemon curses itself", async () => { game.override.moveset([Moves.CURSE]); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); diff --git a/test/abilities/quick_draw.test.ts b/test/abilities/quick_draw.test.ts index 79a29b0ce77..e761d236a93 100644 --- a/test/abilities/quick_draw.test.ts +++ b/test/abilities/quick_draw.test.ts @@ -41,7 +41,7 @@ describe("Abilities - Quick Draw", () => { }); test("makes pokemon going first in its priority bracket", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const pokemon = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; @@ -63,7 +63,7 @@ describe("Abilities - Quick Draw", () => { retry: 5, }, async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const pokemon = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; @@ -83,7 +83,7 @@ describe("Abilities - Quick Draw", () => { test("does not increase priority", async () => { game.override.enemyMoveset([Moves.EXTREME_SPEED]); - await game.startBattle(); + await game.classicMode.startBattle(); const pokemon = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/abilities/sand_veil.test.ts b/test/abilities/sand_veil.test.ts index b82c79c681b..116850e1e5a 100644 --- a/test/abilities/sand_veil.test.ts +++ b/test/abilities/sand_veil.test.ts @@ -38,7 +38,7 @@ describe("Abilities - Sand Veil", () => { }); test("ability should increase the evasiveness of the source", async () => { - await game.startBattle([Species.SNORLAX, Species.BLISSEY]); + await game.classicMode.startBattle([Species.SNORLAX, Species.BLISSEY]); const leadPokemon = game.scene.getPlayerField(); diff --git a/test/abilities/schooling.test.ts b/test/abilities/schooling.test.ts index 803b4d2062a..ac4e3c837c5 100644 --- a/test/abilities/schooling.test.ts +++ b/test/abilities/schooling.test.ts @@ -39,7 +39,7 @@ describe("Abilities - SCHOOLING", () => { [Species.WISHIWASHI]: schoolForm, }); - await game.startBattle([Species.MAGIKARP, Species.WISHIWASHI]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.WISHIWASHI]); const wishiwashi = game.scene.getPlayerParty().find(p => p.species.speciesId === Species.WISHIWASHI)!; expect(wishiwashi).not.toBe(undefined); diff --git a/test/abilities/screen_cleaner.test.ts b/test/abilities/screen_cleaner.test.ts index 840291f6420..ea99ba00f87 100644 --- a/test/abilities/screen_cleaner.test.ts +++ b/test/abilities/screen_cleaner.test.ts @@ -33,7 +33,7 @@ describe("Abilities - Screen Cleaner", () => { game.override.moveset([Moves.HAIL]); game.override.enemyMoveset([Moves.AURORA_VEIL, Moves.AURORA_VEIL, Moves.AURORA_VEIL, Moves.AURORA_VEIL]); - await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); game.move.select(Moves.HAIL); await game.phaseInterceptor.to(TurnEndPhase); @@ -50,7 +50,7 @@ describe("Abilities - Screen Cleaner", () => { it("removes Light Screen", async () => { game.override.enemyMoveset([Moves.LIGHT_SCREEN, Moves.LIGHT_SCREEN, Moves.LIGHT_SCREEN, Moves.LIGHT_SCREEN]); - await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); @@ -67,7 +67,7 @@ describe("Abilities - Screen Cleaner", () => { it("removes Reflect", async () => { game.override.enemyMoveset([Moves.REFLECT, Moves.REFLECT, Moves.REFLECT, Moves.REFLECT]); - await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); game.move.select(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/test/abilities/shields_down.test.ts b/test/abilities/shields_down.test.ts index 2f9d2fb1f97..444b1fabf73 100644 --- a/test/abilities/shields_down.test.ts +++ b/test/abilities/shields_down.test.ts @@ -76,7 +76,7 @@ describe("Abilities - SHIELDS DOWN", () => { await game.classicMode.startBattle([Species.MINIOR]); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPORE); + await game.move.selectEnemyMove(Moves.SPORE); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.getPlayerPokemon()!.status).toBe(undefined); @@ -115,12 +115,12 @@ describe("Abilities - SHIELDS DOWN", () => { // turn 1 game.move.select(Moves.GRAVITY); - await game.forceEnemyMove(Moves.TOXIC_SPIKES); + await game.move.selectEnemyMove(Moves.TOXIC_SPIKES); await game.toNextTurn(); // turn 2 game.doSwitchPokemon(1); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.MINIOR); @@ -134,7 +134,7 @@ describe("Abilities - SHIELDS DOWN", () => { await game.classicMode.startBattle([Species.MAGIKARP, Species.MINIOR]); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.YAWN); + await game.move.selectEnemyMove(Moves.YAWN); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.getPlayerPokemon()!.findTag(tag => tag.tagType === BattlerTagType.DROWSY)).toBe(undefined); @@ -146,7 +146,7 @@ describe("Abilities - SHIELDS DOWN", () => { await game.classicMode.startBattle([Species.MINIOR]); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.CONFUSE_RAY); + await game.move.selectEnemyMove(Moves.CONFUSE_RAY); await game.phaseInterceptor.to(TurnEndPhase); @@ -162,7 +162,7 @@ describe("Abilities - SHIELDS DOWN", () => { await game.classicMode.startBattle([Species.MINIOR]); game.move.select(Moves.SPORE); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.SLEEP); diff --git a/test/abilities/simple.test.ts b/test/abilities/simple.test.ts index 1f084b1bf4c..cf3a692a7b0 100644 --- a/test/abilities/simple.test.ts +++ b/test/abilities/simple.test.ts @@ -31,7 +31,7 @@ describe("Abilities - Simple", () => { }); it("should double stat changes when applied", async () => { - await game.startBattle([Species.SLOWBRO]); + await game.classicMode.startBattle([Species.SLOWBRO]); const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/test/abilities/stakeout.test.ts b/test/abilities/stakeout.test.ts index 8a2231bba0b..d986046a7e1 100644 --- a/test/abilities/stakeout.test.ts +++ b/test/abilities/stakeout.test.ts @@ -42,7 +42,7 @@ describe("Abilities - Stakeout", () => { const [enemy1] = game.scene.getEnemyParty(); game.move.select(Moves.SURF); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const damage1 = enemy1.getInverseHp(); enemy1.hp = enemy1.getMaxHp(); @@ -65,17 +65,17 @@ describe("Abilities - Stakeout", () => { const [enemy1] = game.scene.getEnemyParty(); game.move.select(Moves.SURF); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const damage1 = enemy1.getInverseHp(); enemy1.hp = enemy1.getMaxHp(); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.FLIP_TURN); + await game.move.selectEnemyMove(Moves.FLIP_TURN); await game.toNextTurn(); game.move.select(Moves.SURF); - await game.forceEnemyMove(Moves.FLIP_TURN); + await game.move.selectEnemyMove(Moves.FLIP_TURN); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); diff --git a/test/abilities/stall.test.ts b/test/abilities/stall.test.ts index 68b3fdedcd8..5c17f71c48d 100644 --- a/test/abilities/stall.test.ts +++ b/test/abilities/stall.test.ts @@ -37,7 +37,7 @@ describe("Abilities - Stall", () => { **/ it("Pokemon with Stall should move last in its priority bracket regardless of speed", async () => { - await game.startBattle([Species.SHUCKLE]); + await game.classicMode.startBattle([Species.SHUCKLE]); const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); @@ -55,7 +55,7 @@ describe("Abilities - Stall", () => { }, 20000); it("Pokemon with Stall will go first if a move that is in a higher priority bracket than the opponent's move is used", async () => { - await game.startBattle([Species.SHUCKLE]); + await game.classicMode.startBattle([Species.SHUCKLE]); const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); @@ -74,7 +74,7 @@ describe("Abilities - Stall", () => { it("If both Pokemon have stall and use the same move, speed is used to determine who goes first.", async () => { game.override.ability(Abilities.STALL); - await game.startBattle([Species.SHUCKLE]); + await game.classicMode.startBattle([Species.SHUCKLE]); const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); diff --git a/test/abilities/sturdy.test.ts b/test/abilities/sturdy.test.ts index bda8c6d1e35..dbdd1b4570e 100644 --- a/test/abilities/sturdy.test.ts +++ b/test/abilities/sturdy.test.ts @@ -36,14 +36,14 @@ describe("Abilities - Sturdy", () => { }); test("Sturdy activates when user is at full HP", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); game.move.select(Moves.CLOSE_COMBAT); await game.phaseInterceptor.to(MoveEndPhase); expect(game.scene.getEnemyParty()[0].hp).toBe(1); }); test("Sturdy doesn't activate when user is not at full HP", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const enemyPokemon: EnemyPokemon = game.scene.getEnemyParty()[0]; enemyPokemon.hp = enemyPokemon.getMaxHp() - 1; @@ -56,7 +56,7 @@ describe("Abilities - Sturdy", () => { }); test("Sturdy pokemon should be immune to OHKO moves", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); game.move.select(Moves.FISSURE); await game.phaseInterceptor.to(MoveEndPhase); @@ -67,7 +67,7 @@ describe("Abilities - Sturdy", () => { test("Sturdy is ignored by pokemon with `Abilities.MOLD_BREAKER`", async () => { game.override.ability(Abilities.MOLD_BREAKER); - await game.startBattle(); + await game.classicMode.startBattle(); game.move.select(Moves.CLOSE_COMBAT); await game.phaseInterceptor.to(DamageAnimPhase); diff --git a/test/abilities/supreme_overlord.test.ts b/test/abilities/supreme_overlord.test.ts index 6cc52de64bf..4c0be80daea 100644 --- a/test/abilities/supreme_overlord.test.ts +++ b/test/abilities/supreme_overlord.test.ts @@ -44,7 +44,7 @@ describe("Abilities - Supreme Overlord", () => { }); it("should increase Power by 20% if 2 Pokemon are fainted in the party", async () => { - await game.startBattle([Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE]); + await game.classicMode.startBattle([Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE]); game.move.select(Moves.EXPLOSION); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); diff --git a/test/abilities/sweet_veil.test.ts b/test/abilities/sweet_veil.test.ts index e609aa6e7d2..80d7165619f 100644 --- a/test/abilities/sweet_veil.test.ts +++ b/test/abilities/sweet_veil.test.ts @@ -33,7 +33,7 @@ describe("Abilities - Sweet Veil", () => { }); it("prevents the user and its allies from falling asleep", async () => { - await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]); + await game.classicMode.startBattle([Species.SWIRLIX, Species.MAGIKARP]); game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); @@ -45,7 +45,7 @@ describe("Abilities - Sweet Veil", () => { it("causes Rest to fail when used by the user or its allies", async () => { game.override.enemyMoveset(Moves.SPLASH); - await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]); + await game.classicMode.startBattle([Species.SWIRLIX, Species.MAGIKARP]); game.move.select(Moves.SPLASH); game.move.select(Moves.REST, 1); @@ -57,7 +57,7 @@ describe("Abilities - Sweet Veil", () => { it("causes Yawn to fail if used on the user or its allies", async () => { game.override.enemyMoveset([Moves.YAWN, Moves.YAWN, Moves.YAWN, Moves.YAWN]); - await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]); + await game.classicMode.startBattle([Species.SWIRLIX, Species.MAGIKARP]); game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); @@ -73,7 +73,7 @@ describe("Abilities - Sweet Veil", () => { game.override.startingLevel(5); game.override.enemyMoveset(Moves.SPLASH); - await game.startBattle([Species.SHUCKLE, Species.SHUCKLE, Species.SWIRLIX]); + await game.classicMode.startBattle([Species.SHUCKLE, Species.SHUCKLE, Species.SWIRLIX]); game.move.select(Moves.SPLASH); game.move.select(Moves.YAWN, 1, BattlerIndex.PLAYER); diff --git a/test/abilities/unburden.test.ts b/test/abilities/unburden.test.ts index ff28c3b6a09..ea4f84545aa 100644 --- a/test/abilities/unburden.test.ts +++ b/test/abilities/unburden.test.ts @@ -244,8 +244,8 @@ describe("Abilities - Unburden", () => { // Turn 1: Treecko gets hit by False Swipe and eats Sitrus Berry, activating Unburden game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.FALSE_SWIPE, 0); - await game.forceEnemyMove(Moves.FALSE_SWIPE, 0); + await game.move.selectEnemyMove(Moves.FALSE_SWIPE, 0); + await game.move.selectEnemyMove(Moves.FALSE_SWIPE, 0); await game.phaseInterceptor.to("TurnEndPhase"); expect(getHeldItemCount(treecko)).toBeLessThan(playerHeldItems); @@ -302,7 +302,7 @@ describe("Abilities - Unburden", () => { // Turn 1: Get hit by False Swipe and eat Sitrus Berry, activating Unburden game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.FALSE_SWIPE); + await game.move.selectEnemyMove(Moves.FALSE_SWIPE); await game.toNextTurn(); expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItems); @@ -310,7 +310,7 @@ describe("Abilities - Unburden", () => { // Turn 2: Get hit by Worry Seed, deactivating Unburden game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.WORRY_SEED); + await game.move.selectEnemyMove(Moves.WORRY_SEED); await game.toNextTurn(); expect(getHeldItemCount(playerPokemon)).toBeLessThan(playerHeldItems); @@ -343,13 +343,13 @@ describe("Abilities - Unburden", () => { const initialSpeed = treecko.getStat(Stat.SPD); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.THIEF); + await game.move.selectEnemyMove(Moves.THIEF); game.doSelectPartyPokemon(1); await game.toNextTurn(); game.doRevivePokemon(1); game.doSwitchPokemon(1); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(game.scene.getPlayerPokemon()!).toBe(treecko); @@ -372,8 +372,8 @@ describe("Abilities - Unburden", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.REVIVAL_BLESSING, 1); - await game.forceEnemyMove(Moves.THIEF, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.THIEF, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]); game.doSelectPartyPokemon(0, "RevivalBlessingPhase"); await game.toNextTurn(); diff --git a/test/abilities/wimp_out.test.ts b/test/abilities/wimp_out.test.ts index 67885a82163..32a627f20f9 100644 --- a/test/abilities/wimp_out.test.ts +++ b/test/abilities/wimp_out.test.ts @@ -544,8 +544,8 @@ describe("Abilities - Wimp Out", () => { // turn 1 game.move.select(Moves.DRAGON_ENERGY, 0); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.ENDURE); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.ENDURE); await game.phaseInterceptor.to("SelectModifierPhase"); expect(game.scene.currentBattle.waveIndex).toBe(wave + 1); diff --git a/test/abilities/wind_power.test.ts b/test/abilities/wind_power.test.ts index 66c72d454ab..11585520c73 100644 --- a/test/abilities/wind_power.test.ts +++ b/test/abilities/wind_power.test.ts @@ -31,7 +31,7 @@ describe("Abilities - Wind Power", () => { }); it("it becomes charged when hit by wind moves", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const shiftry = game.scene.getEnemyPokemon()!; expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); @@ -46,7 +46,7 @@ describe("Abilities - Wind Power", () => { game.override.ability(Abilities.WIND_POWER); game.override.enemySpecies(Species.MAGIKARP); - await game.startBattle([Species.SHIFTRY]); + await game.classicMode.startBattle([Species.SHIFTRY]); const shiftry = game.scene.getPlayerPokemon()!; expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); @@ -61,7 +61,7 @@ describe("Abilities - Wind Power", () => { game.override.enemySpecies(Species.MAGIKARP); game.override.ability(Abilities.WIND_POWER); - await game.startBattle([Species.SHIFTRY]); + await game.classicMode.startBattle([Species.SHIFTRY]); const magikarp = game.scene.getEnemyPokemon()!; const shiftry = game.scene.getPlayerPokemon()!; @@ -79,7 +79,7 @@ describe("Abilities - Wind Power", () => { it("does not interact with Sandstorm", async () => { game.override.enemySpecies(Species.MAGIKARP); - await game.startBattle([Species.SHIFTRY]); + await game.classicMode.startBattle([Species.SHIFTRY]); const shiftry = game.scene.getPlayerPokemon()!; expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); diff --git a/test/abilities/wonder_skin.test.ts b/test/abilities/wonder_skin.test.ts index fd4cc77bd1c..cb5dd4e117f 100644 --- a/test/abilities/wonder_skin.test.ts +++ b/test/abilities/wonder_skin.test.ts @@ -36,7 +36,7 @@ describe("Abilities - Wonder Skin", () => { vi.spyOn(moveToCheck, "calculateBattleAccuracy"); - await game.startBattle([Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU]); game.move.select(Moves.CHARM); await game.phaseInterceptor.to(MoveEffectPhase); @@ -48,7 +48,7 @@ describe("Abilities - Wonder Skin", () => { vi.spyOn(moveToCheck, "calculateBattleAccuracy"); - await game.startBattle([Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU]); game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MoveEffectPhase); diff --git a/test/abilities/zero_to_hero.test.ts b/test/abilities/zero_to_hero.test.ts index 2cdc516dc6b..c159d007765 100644 --- a/test/abilities/zero_to_hero.test.ts +++ b/test/abilities/zero_to_hero.test.ts @@ -39,7 +39,7 @@ describe("Abilities - ZERO TO HERO", () => { [Species.PALAFIN]: heroForm, }); - await game.startBattle([Species.FEEBAS, Species.PALAFIN, Species.PALAFIN]); + await game.classicMode.startBattle([Species.FEEBAS, Species.PALAFIN, Species.PALAFIN]); const palafin1 = game.scene.getPlayerParty()[1]; const palafin2 = game.scene.getPlayerParty()[2]; @@ -61,7 +61,7 @@ describe("Abilities - ZERO TO HERO", () => { }); it("should swap to Hero form when switching out during a battle", async () => { - await game.startBattle([Species.PALAFIN, Species.FEEBAS]); + await game.classicMode.startBattle([Species.PALAFIN, Species.FEEBAS]); const palafin = game.scene.getPlayerPokemon()!; expect(palafin.formIndex).toBe(baseForm); @@ -72,7 +72,7 @@ describe("Abilities - ZERO TO HERO", () => { }); it("should not swap to Hero form if switching due to faint", async () => { - await game.startBattle([Species.PALAFIN, Species.FEEBAS]); + await game.classicMode.startBattle([Species.PALAFIN, Species.FEEBAS]); const palafin = game.scene.getPlayerPokemon()!; expect(palafin.formIndex).toBe(baseForm); @@ -89,7 +89,7 @@ describe("Abilities - ZERO TO HERO", () => { [Species.PALAFIN]: heroForm, }); - await game.startBattle([Species.PALAFIN, Species.FEEBAS]); + await game.classicMode.startBattle([Species.PALAFIN, Species.FEEBAS]); const palafin = game.scene.getPlayerPokemon()!; expect(palafin.formIndex).toBe(heroForm); diff --git a/test/arena/weather_fog.test.ts b/test/arena/weather_fog.test.ts index ae41c9d14e8..69f167b8cf1 100644 --- a/test/arena/weather_fog.test.ts +++ b/test/arena/weather_fog.test.ts @@ -37,7 +37,7 @@ describe("Weather - Fog", () => { vi.spyOn(moveToCheck, "calculateBattleAccuracy"); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); game.move.select(Moves.TACKLE); await game.phaseInterceptor.to(MoveEffectPhase); diff --git a/test/battle/battle-order.test.ts b/test/battle/battle-order.test.ts index 43fa1e59c14..876730169f9 100644 --- a/test/battle/battle-order.test.ts +++ b/test/battle/battle-order.test.ts @@ -32,7 +32,7 @@ describe("Battle order", () => { }); it("opponent faster than player 50 vs 150", async () => { - await game.startBattle([Species.BULBASAUR]); + await game.classicMode.startBattle([Species.BULBASAUR]); const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -51,7 +51,7 @@ describe("Battle order", () => { }, 20000); it("Player faster than opponent 150 vs 50", async () => { - await game.startBattle([Species.BULBASAUR]); + await game.classicMode.startBattle([Species.BULBASAUR]); const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -71,7 +71,7 @@ describe("Battle order", () => { it("double - both opponents faster than player 50/50 vs 150/150", async () => { game.override.battleStyle("double"); - await game.startBattle([Species.BULBASAUR, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BULBASAUR, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); @@ -95,7 +95,7 @@ describe("Battle order", () => { it("double - speed tie except 1 - 100/100 vs 100/150", async () => { game.override.battleStyle("double"); - await game.startBattle([Species.BULBASAUR, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BULBASAUR, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); @@ -119,7 +119,7 @@ describe("Battle order", () => { it("double - speed tie 100/150 vs 100/150", async () => { game.override.battleStyle("double"); - await game.startBattle([Species.BULBASAUR, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BULBASAUR, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); diff --git a/test/battle/battle.test.ts b/test/battle/battle.test.ts index e980984580e..8c4315dcabc 100644 --- a/test/battle/battle.test.ts +++ b/test/battle/battle.test.ts @@ -85,7 +85,7 @@ describe("Test Battle Phase", () => { }, 20000); it("newGame one-liner", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); @@ -98,7 +98,7 @@ describe("Test Battle Phase", () => { game.override.moveset([Moves.TACKLE]); game.override.enemyAbility(Abilities.HYDRATION); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); - await game.startBattle(); + await game.classicMode.startBattle(); game.move.select(Moves.TACKLE); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(SelectModifierPhase, false); }, 20000); @@ -112,7 +112,7 @@ describe("Test Battle Phase", () => { game.override.enemyAbility(Abilities.HYDRATION); game.override.enemyMoveset([Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP]); game.override.battleStyle("single"); - await game.startBattle(); + await game.classicMode.startBattle(); game.move.select(Moves.TACKLE); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnInitPhase, false); }, 20000); @@ -127,7 +127,7 @@ describe("Test Battle Phase", () => { }, 20000); it("start battle with selected team", async () => { - await game.startBattle([Species.CHARIZARD, Species.CHANSEY, Species.MEW]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.CHANSEY, Species.MEW]); expect(game.scene.getPlayerParty()[0].species.speciesId).toBe(Species.CHARIZARD); expect(game.scene.getPlayerParty()[1].species.speciesId).toBe(Species.CHANSEY); expect(game.scene.getPlayerParty()[2].species.speciesId).toBe(Species.MEW); @@ -207,7 +207,7 @@ describe("Test Battle Phase", () => { game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); game.override.ability(Abilities.HYDRATION); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); @@ -217,7 +217,7 @@ describe("Test Battle Phase", () => { game.override.enemySpecies(Species.MIGHTYENA); game.override.enemyAbility(Abilities.HYDRATION); game.override.ability(Abilities.HYDRATION); - await game.startBattle([Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BLASTOISE]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); @@ -228,7 +228,7 @@ describe("Test Battle Phase", () => { game.override.enemyAbility(Abilities.HYDRATION); game.override.ability(Abilities.HYDRATION); game.override.startingWave(3); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); @@ -239,7 +239,7 @@ describe("Test Battle Phase", () => { game.override.enemyAbility(Abilities.HYDRATION); game.override.ability(Abilities.HYDRATION); game.override.startingWave(3); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD, Species.DARKRAI, Species.GABITE]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD, Species.DARKRAI, Species.GABITE]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); @@ -255,7 +255,7 @@ describe("Test Battle Phase", () => { game.override.startingWave(3); game.override.moveset([moveToUse]); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); - await game.startBattle([Species.DARMANITAN, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.DARMANITAN, Species.CHARIZARD]); game.move.select(moveToUse); await game.phaseInterceptor.to(DamageAnimPhase, false); @@ -275,7 +275,7 @@ describe("Test Battle Phase", () => { game.override.startingWave(3); game.override.moveset([moveToUse]); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); - await game.startBattle(); + await game.classicMode.startBattle(); const turn = game.scene.currentBattle.turn; game.move.select(moveToUse); await game.toNextTurn(); @@ -318,7 +318,7 @@ describe("Test Battle Phase", () => { .enemyMoveset(Moves.SPLASH) .startingHeldItems([{ name: "TEMP_STAT_STAGE_BOOSTER", type: Stat.ACC }]); - await game.startBattle(); + await game.classicMode.startBattle(); game.scene.getPlayerPokemon()!.hp = 1; game.move.select(moveToUse); diff --git a/test/battle/double_battle.test.ts b/test/battle/double_battle.test.ts index a30d55aac3d..99c52ea5add 100644 --- a/test/battle/double_battle.test.ts +++ b/test/battle/double_battle.test.ts @@ -34,7 +34,7 @@ describe("Double Battles", () => { // (There were bugs that either only summon one when can summon two, player stuck in switchPhase etc) it("3v2 edge case: player summons 2 pokemon on the next battle after being fainted and revived", async () => { game.override.battleStyle("double").enemyMoveset(Moves.SPLASH).moveset(Moves.SPLASH); - await game.startBattle([Species.BULBASAUR, Species.CHARIZARD, Species.SQUIRTLE]); + await game.classicMode.startBattle([Species.BULBASAUR, Species.CHARIZARD, Species.SQUIRTLE]); game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH, 1); diff --git a/test/battle/special_battle.test.ts b/test/battle/special_battle.test.ts index 163f23e488d..6f4034cd8cd 100644 --- a/test/battle/special_battle.test.ts +++ b/test/battle/special_battle.test.ts @@ -33,63 +33,63 @@ describe("Test Battle Phase", () => { it("startBattle 2vs1 boss", async () => { game.override.battleStyle("single").startingWave(10); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 boss", async () => { game.override.battleStyle("double").startingWave(10); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 trainer", async () => { game.override.battleStyle("double").startingWave(5); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs1 trainer", async () => { game.override.battleStyle("single").startingWave(5); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs1 rival", async () => { game.override.battleStyle("single").startingWave(8); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 rival", async () => { game.override.battleStyle("double").startingWave(8); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 1vs1 trainer", async () => { game.override.battleStyle("single").startingWave(5); - await game.startBattle([Species.BLASTOISE]); + await game.classicMode.startBattle([Species.BLASTOISE]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 trainer", async () => { game.override.battleStyle("double").startingWave(5); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 4vs2 trainer", async () => { game.override.battleStyle("double").startingWave(5); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD, Species.DARKRAI, Species.GABITE]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD, Species.DARKRAI, Species.GABITE]); expect(game.scene.ui?.getMode()).toBe(UiMode.COMMAND); expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); diff --git a/test/daily_mode.test.ts b/test/daily_mode.test.ts index a7f5784087a..a5901da4821 100644 --- a/test/daily_mode.test.ts +++ b/test/daily_mode.test.ts @@ -30,7 +30,7 @@ describe("Daily Mode", () => { }); it("should initialize properly", async () => { - await game.dailyMode.runToSummon(); + await game.dailyMode.startBattle(); const party = game.scene.getPlayerParty(); expect(party).toHaveLength(3); diff --git a/test/evolution.test.ts b/test/evolution.test.ts index 4f91cd99382..a453d744da8 100644 --- a/test/evolution.test.ts +++ b/test/evolution.test.ts @@ -110,7 +110,7 @@ describe("Evolution", () => { .startingLevel(16) .enemyLevel(50); - await game.startBattle([Species.TOTODILE]); + await game.classicMode.startBattle([Species.TOTODILE]); const totodile = game.scene.getPlayerPokemon()!; const hpBefore = totodile.hp; @@ -138,7 +138,7 @@ describe("Evolution", () => { .startingLevel(13) .enemyLevel(30); - await game.startBattle([Species.CYNDAQUIL]); + await game.classicMode.startBattle([Species.CYNDAQUIL]); const cyndaquil = game.scene.getPlayerPokemon()!; cyndaquil.hp = Math.floor(cyndaquil.getMaxHp() / 2); @@ -171,7 +171,7 @@ describe("Evolution", () => { * If the value is 0, it's a 3 family maushold, whereas if the value is * 1, 2 or 3, it's a 4 family maushold */ - await game.startBattle([Species.TANDEMAUS]); // starts us off with a tandemaus + await game.classicMode.startBattle([Species.TANDEMAUS]); // starts us off with a tandemaus const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.level = 25; // tandemaus evolves at level 25 vi.spyOn(Utils, "randSeedInt").mockReturnValue(0); // setting the random generator to be 0 to force a three family maushold diff --git a/test/items/dire_hit.test.ts b/test/items/dire_hit.test.ts index 6e20bc723e5..e848bceb514 100644 --- a/test/items/dire_hit.test.ts +++ b/test/items/dire_hit.test.ts @@ -40,7 +40,7 @@ describe("Items - Dire Hit", () => { }, 20000); it("should raise CRIT stage by 1", async () => { - await game.startBattle([Species.GASTLY]); + await game.classicMode.startBattle([Species.GASTLY]); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -56,7 +56,7 @@ describe("Items - Dire Hit", () => { it("should renew how many battles are left of existing DIRE_HIT when picking up new DIRE_HIT", async () => { game.override.itemRewards([{ name: "DIRE_HIT" }]); - await game.startBattle([Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU]); game.move.select(Moves.SPLASH); diff --git a/test/items/exp_booster.test.ts b/test/items/exp_booster.test.ts index ec7528c3b23..106574b6849 100644 --- a/test/items/exp_booster.test.ts +++ b/test/items/exp_booster.test.ts @@ -29,7 +29,7 @@ describe("EXP Modifier Items", () => { it("EXP booster items stack multiplicatively", async () => { game.override.startingHeldItems([{ name: "LUCKY_EGG", count: 3 }, { name: "GOLDEN_EGG" }]); - await game.startBattle(); + await game.classicMode.startBattle(); const partyMember = game.scene.getPlayerPokemon()!; partyMember.exp = 100; diff --git a/test/items/leek.test.ts b/test/items/leek.test.ts index 9bde2c86339..7a6975f6dae 100644 --- a/test/items/leek.test.ts +++ b/test/items/leek.test.ts @@ -32,7 +32,7 @@ describe("Items - Leek", () => { }); it("should raise CRIT stage by 2 when held by FARFETCHD", async () => { - await game.startBattle([Species.FARFETCHD]); + await game.classicMode.startBattle([Species.FARFETCHD]); const enemyMember = game.scene.getEnemyPokemon()!; @@ -46,7 +46,7 @@ describe("Items - Leek", () => { }, 20000); it("should raise CRIT stage by 2 when held by GALAR_FARFETCHD", async () => { - await game.startBattle([Species.GALAR_FARFETCHD]); + await game.classicMode.startBattle([Species.GALAR_FARFETCHD]); const enemyMember = game.scene.getEnemyPokemon()!; @@ -60,7 +60,7 @@ describe("Items - Leek", () => { }, 20000); it("should raise CRIT stage by 2 when held by SIRFETCHD", async () => { - await game.startBattle([Species.SIRFETCHD]); + await game.classicMode.startBattle([Species.SIRFETCHD]); const enemyMember = game.scene.getEnemyPokemon()!; @@ -77,7 +77,7 @@ describe("Items - Leek", () => { // Randomly choose from the Farfetch'd line const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD]; - await game.startBattle([species[randInt(species.length)], Species.PIKACHU]); + await game.classicMode.startBattle([species[randInt(species.length)], Species.PIKACHU]); const [partyMember, ally] = game.scene.getPlayerParty(); @@ -105,7 +105,7 @@ describe("Items - Leek", () => { // Randomly choose from the Farfetch'd line const species = [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD]; - await game.startBattle([Species.PIKACHU, species[randInt(species.length)]]); + await game.classicMode.startBattle([Species.PIKACHU, species[randInt(species.length)]]); const [partyMember, ally] = game.scene.getPlayerParty(); @@ -130,7 +130,7 @@ describe("Items - Leek", () => { }, 20000); it("should not raise CRIT stage when held by a Pokemon outside of FARFETCHD line", async () => { - await game.startBattle([Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU]); const enemyMember = game.scene.getEnemyPokemon()!; diff --git a/test/items/leftovers.test.ts b/test/items/leftovers.test.ts index 19739703f19..f4825c2b721 100644 --- a/test/items/leftovers.test.ts +++ b/test/items/leftovers.test.ts @@ -34,7 +34,7 @@ describe("Items - Leftovers", () => { }); it("leftovers works", async () => { - await game.startBattle([Species.ARCANINE]); + await game.classicMode.startBattle([Species.ARCANINE]); // Make sure leftovers are there expect(game.scene.modifiers[0].type.id).toBe("LEFTOVERS"); diff --git a/test/items/light_ball.test.ts b/test/items/light_ball.test.ts index cdcffe810fa..214f6f624e6 100644 --- a/test/items/light_ball.test.ts +++ b/test/items/light_ball.test.ts @@ -150,7 +150,7 @@ describe("Items - Light Ball", () => { }, 20000); it("LIGHT_BALL held by fused PIKACHU (part)", async () => { - await game.startBattle([Species.MAROWAK, Species.PIKACHU]); + await game.classicMode.startBattle([Species.MAROWAK, Species.PIKACHU]); const partyMember = game.scene.getPlayerParty()[0]; const ally = game.scene.getPlayerParty()[1]; @@ -189,7 +189,7 @@ describe("Items - Light Ball", () => { }, 20000); it("LIGHT_BALL not held by PIKACHU", async () => { - await game.startBattle([Species.MAROWAK]); + await game.classicMode.startBattle([Species.MAROWAK]); const partyMember = game.scene.getPlayerParty()[0]; diff --git a/test/items/metal_powder.test.ts b/test/items/metal_powder.test.ts index e924d75fce9..a9a81072622 100644 --- a/test/items/metal_powder.test.ts +++ b/test/items/metal_powder.test.ts @@ -82,7 +82,7 @@ describe("Items - Metal Powder", () => { }); it("METAL_POWDER held by DITTO", async () => { - await game.startBattle([Species.DITTO]); + await game.classicMode.startBattle([Species.DITTO]); const partyMember = game.scene.getPlayerParty()[0]; @@ -105,7 +105,7 @@ describe("Items - Metal Powder", () => { }, 20000); it("METAL_POWDER held by fused DITTO (base)", async () => { - await game.startBattle([Species.DITTO, Species.MAROWAK]); + await game.classicMode.startBattle([Species.DITTO, Species.MAROWAK]); const partyMember = game.scene.getPlayerParty()[0]; const ally = game.scene.getPlayerParty()[1]; @@ -138,7 +138,7 @@ describe("Items - Metal Powder", () => { }, 20000); it("METAL_POWDER held by fused DITTO (part)", async () => { - await game.startBattle([Species.MAROWAK, Species.DITTO]); + await game.classicMode.startBattle([Species.MAROWAK, Species.DITTO]); const partyMember = game.scene.getPlayerParty()[0]; const ally = game.scene.getPlayerParty()[1]; @@ -171,7 +171,7 @@ describe("Items - Metal Powder", () => { }, 20000); it("METAL_POWDER not held by DITTO", async () => { - await game.startBattle([Species.MAROWAK]); + await game.classicMode.startBattle([Species.MAROWAK]); const partyMember = game.scene.getPlayerParty()[0]; diff --git a/test/items/scope_lens.test.ts b/test/items/scope_lens.test.ts index f67966ea3c9..c8061ea3696 100644 --- a/test/items/scope_lens.test.ts +++ b/test/items/scope_lens.test.ts @@ -31,7 +31,7 @@ describe("Items - Scope Lens", () => { }, 20000); it("should raise CRIT stage by 1", async () => { - await game.startBattle([Species.GASTLY]); + await game.classicMode.startBattle([Species.GASTLY]); const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/test/moves/alluring_voice.test.ts b/test/moves/alluring_voice.test.ts index 240e008f311..9265c5f970d 100644 --- a/test/moves/alluring_voice.test.ts +++ b/test/moves/alluring_voice.test.ts @@ -29,20 +29,18 @@ describe("Moves - Alluring Voice", () => { .disableCrits() .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.ICE_SCALES) - .enemyMoveset([Moves.HOWL]) + .enemyMoveset(Moves.HOWL) .startingLevel(10) .enemyLevel(10) - .starterSpecies(Species.FEEBAS) - .ability(Abilities.BALL_FETCH) - .moveset([Moves.ALLURING_VOICE]); + .ability(Abilities.BALL_FETCH); }); it("should confuse the opponent if their stat stages were raised", async () => { - await game.classicMode.startBattle(); + await game.classicMode.startBattle([Species.FEEBAS]); const enemy = game.scene.getEnemyPokemon()!; - game.move.select(Moves.ALLURING_VOICE); + game.move.use(Moves.ALLURING_VOICE); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(BerryPhase); diff --git a/test/moves/astonish.test.ts b/test/moves/astonish.test.ts index accddcd545d..daa9b0bb878 100644 --- a/test/moves/astonish.test.ts +++ b/test/moves/astonish.test.ts @@ -39,7 +39,7 @@ describe("Moves - Astonish", () => { }); test("move effect should cancel the target's move on the turn it applies", async () => { - await game.startBattle([Species.MEOWSCARADA]); + await game.classicMode.startBattle([Species.MEOWSCARADA]); const leadPokemon = game.scene.getPlayerPokemon()!; diff --git a/test/moves/beat_up.test.ts b/test/moves/beat_up.test.ts index ad6cad40d32..09166dafb9d 100644 --- a/test/moves/beat_up.test.ts +++ b/test/moves/beat_up.test.ts @@ -35,7 +35,7 @@ describe("Moves - Beat Up", () => { }); it("should hit once for each healthy player Pokemon", async () => { - await game.startBattle([ + await game.classicMode.startBattle([ Species.MAGIKARP, Species.BULBASAUR, Species.CHARMANDER, @@ -63,7 +63,7 @@ describe("Moves - Beat Up", () => { }); it("should not count player Pokemon with status effects towards hit count", async () => { - await game.startBattle([ + await game.classicMode.startBattle([ Species.MAGIKARP, Species.BULBASAUR, Species.CHARMANDER, diff --git a/test/moves/belly_drum.test.ts b/test/moves/belly_drum.test.ts index 8ee1026bf20..9deff207446 100644 --- a/test/moves/belly_drum.test.ts +++ b/test/moves/belly_drum.test.ts @@ -42,7 +42,7 @@ describe("Moves - BELLY DRUM", () => { // Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/Belly_Drum_(move) test("raises the user's ATK stat stage to its max, at the cost of 1/2 of its maximum HP", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); @@ -55,7 +55,7 @@ describe("Moves - BELLY DRUM", () => { }); test("will still take effect if an uninvolved stat stage is at max", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); @@ -73,7 +73,7 @@ describe("Moves - BELLY DRUM", () => { }); test("fails if the pokemon's ATK stat stage is at its maximum", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -87,7 +87,7 @@ describe("Moves - BELLY DRUM", () => { }); test("fails if the user's health is less than 1/2", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); diff --git a/test/moves/chilly_reception.test.ts b/test/moves/chilly_reception.test.ts index 56da5dd400c..1c6c5ce127e 100644 --- a/test/moves/chilly_reception.test.ts +++ b/test/moves/chilly_reception.test.ts @@ -77,7 +77,7 @@ describe("Moves - Chilly Reception", () => { await game.classicMode.startBattle([Species.SLOWKING, Species.MEOWTH]); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.TACKLE); + await game.move.selectEnemyMove(Moves.TACKLE); await game.phaseInterceptor.to("BerryPhase", false); expect(game.scene.arena.weather?.weatherType).toBe(undefined); diff --git a/test/moves/chloroblast.test.ts b/test/moves/chloroblast.test.ts index 175227bbd5e..b2130da83eb 100644 --- a/test/moves/chloroblast.test.ts +++ b/test/moves/chloroblast.test.ts @@ -1,3 +1,4 @@ +import { MoveResult } from "#app/field/pokemon"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -22,21 +23,23 @@ describe("Moves - Chloroblast", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .moveset([Moves.CHLOROBLAST]) .ability(Abilities.BALL_FETCH) .battleStyle("single") .disableCrits() .enemySpecies(Species.MAGIKARP) - .enemyAbility(Abilities.BALL_FETCH) - .enemyMoveset(Moves.PROTECT); + .enemyAbility(Abilities.BALL_FETCH); }); it("should not deal recoil damage if the opponent uses protect", async () => { await game.classicMode.startBattle([Species.FEEBAS]); - game.move.select(Moves.CHLOROBLAST); - await game.phaseInterceptor.to("BerryPhase"); + game.move.use(Moves.CHLOROBLAST); + await game.move.forceEnemyMove(Moves.PROTECT); + await game.toEndOfTurn(); - expect(game.scene.getPlayerPokemon()!.isFullHp()).toBe(true); + const player = game.field.getPlayerPokemon(); + + expect(player.isFullHp()).toBe(true); + expect(player.getLastXMoves()[0]).toMatchObject({ result: MoveResult.MISS, move: Moves.CHLOROBLAST }); }); }); diff --git a/test/moves/clangorous_soul.test.ts b/test/moves/clangorous_soul.test.ts index 56f19a0e088..c7165a0a881 100644 --- a/test/moves/clangorous_soul.test.ts +++ b/test/moves/clangorous_soul.test.ts @@ -38,7 +38,7 @@ describe("Moves - Clangorous Soul", () => { //Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/Clangorous_Soul_(move) it("raises the user's ATK, DEF, SPATK, SPDEF, and SPD stat stages by 1 each at the cost of 1/3 of its maximum HP", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); @@ -55,7 +55,7 @@ describe("Moves - Clangorous Soul", () => { }); it("will still take effect if one or more of the involved stat stages are not at max", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); @@ -78,7 +78,7 @@ describe("Moves - Clangorous Soul", () => { }); it("fails if all stat stages involved are at max", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -100,7 +100,7 @@ describe("Moves - Clangorous Soul", () => { }); it("fails if the user's health is less than 1/3", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); diff --git a/test/moves/crafty_shield.test.ts b/test/moves/crafty_shield.test.ts index c61e6d3848a..ec4c87fa060 100644 --- a/test/moves/crafty_shield.test.ts +++ b/test/moves/crafty_shield.test.ts @@ -39,7 +39,7 @@ describe("Moves - Crafty Shield", () => { }); test("should protect the user and allies from status moves", async () => { - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); @@ -57,7 +57,7 @@ describe("Moves - Crafty Shield", () => { test("should not protect the user and allies from attack moves", async () => { game.override.enemyMoveset([Moves.TACKLE]); - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); @@ -76,7 +76,7 @@ describe("Moves - Crafty Shield", () => { game.override.enemySpecies(Species.DUSCLOPS); game.override.enemyMoveset([Moves.CURSE]); - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); @@ -92,7 +92,7 @@ describe("Moves - Crafty Shield", () => { }); test("should not block allies' self-targeted moves", async () => { - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); diff --git a/test/moves/defog.test.ts b/test/moves/defog.test.ts index 58631150b6f..87c3845d55c 100644 --- a/test/moves/defog.test.ts +++ b/test/moves/defog.test.ts @@ -39,7 +39,7 @@ describe("Moves - Defog", () => { const enemyPokemon = game.scene.getEnemyField(); game.move.select(Moves.SAFEGUARD); - await game.forceEnemyMove(Moves.DEFOG); + await game.move.selectEnemyMove(Moves.DEFOG); await game.phaseInterceptor.to("BerryPhase"); expect(playerPokemon[0].isSafeguarded(enemyPokemon[0])).toBe(false); @@ -53,12 +53,12 @@ describe("Moves - Defog", () => { const playerPokemon = game.scene.getPlayerField(); game.move.select(Moves.MIST); - await game.forceEnemyMove(Moves.DEFOG); + await game.move.selectEnemyMove(Moves.DEFOG); await game.toNextTurn(); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.GROWL); + await game.move.selectEnemyMove(Moves.GROWL); await game.phaseInterceptor.to("BerryPhase"); diff --git a/test/moves/disable.test.ts b/test/moves/disable.test.ts index d21716145a4..5b2b687bd5d 100644 --- a/test/moves/disable.test.ts +++ b/test/moves/disable.test.ts @@ -139,12 +139,12 @@ describe("Moves - Disable", () => { const enemyMon = game.scene.getEnemyPokemon()!; game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH, BattlerIndex.PLAYER); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); game.move.select(Moves.DISABLE); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); diff --git a/test/moves/double_team.test.ts b/test/moves/double_team.test.ts index 8eac6be11f4..b97fb1a338e 100644 --- a/test/moves/double_team.test.ts +++ b/test/moves/double_team.test.ts @@ -33,7 +33,7 @@ describe("Moves - Double Team", () => { }); it("raises the user's EVA stat stage by 1", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const ally = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/moves/dragon_tail.test.ts b/test/moves/dragon_tail.test.ts index 0e7cd04d078..409ce7e28f8 100644 --- a/test/moves/dragon_tail.test.ts +++ b/test/moves/dragon_tail.test.ts @@ -206,7 +206,7 @@ describe("Moves - Dragon Tail", () => { return min; }); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.DRAGON_TAIL); + await game.move.selectEnemyMove(Moves.DRAGON_TAIL); await game.toNextTurn(); expect(bulbasaur.isOnField()).toBe(false); @@ -260,7 +260,7 @@ describe("Moves - Dragon Tail", () => { eevee.status = new Status(StatusEffect.FAINT); expect(eevee.isFainted()).toBe(true); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); // Turn 2: Mock an RNG call that would normally call for switching to Eevee, but it is fainted @@ -268,7 +268,7 @@ describe("Moves - Dragon Tail", () => { return min; }); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.DRAGON_TAIL); + await game.move.selectEnemyMove(Moves.DRAGON_TAIL); await game.toNextTurn(); expect(lapras.isOnField()).toBe(false); @@ -289,7 +289,7 @@ describe("Moves - Dragon Tail", () => { eevee.status = new Status(StatusEffect.FAINT); expect(eevee.isFainted()).toBe(true); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); // Turn 2: Mock an RNG call that would normally call for switching to Eevee, but it is fainted @@ -297,7 +297,7 @@ describe("Moves - Dragon Tail", () => { return min; }); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.DRAGON_TAIL); + await game.move.selectEnemyMove(Moves.DRAGON_TAIL); await game.toNextTurn(); expect(lapras.isOnField()).toBe(true); diff --git a/test/moves/dynamax_cannon.test.ts b/test/moves/dynamax_cannon.test.ts index 6c4f1a321e3..62004e62778 100644 --- a/test/moves/dynamax_cannon.test.ts +++ b/test/moves/dynamax_cannon.test.ts @@ -45,7 +45,7 @@ describe("Moves - Dynamax Cannon", () => { it("should return 100 power against an enemy below level cap", async () => { game.override.enemyLevel(1); - await game.startBattle([Species.ETERNATUS]); + await game.classicMode.startBattle([Species.ETERNATUS]); game.move.select(dynamaxCannon.id); @@ -57,7 +57,7 @@ describe("Moves - Dynamax Cannon", () => { it("should return 100 power against an enemy at level cap", async () => { game.override.enemyLevel(10); - await game.startBattle([Species.ETERNATUS]); + await game.classicMode.startBattle([Species.ETERNATUS]); game.move.select(dynamaxCannon.id); @@ -69,7 +69,7 @@ describe("Moves - Dynamax Cannon", () => { it("should return 120 power against an enemy 1% above level cap", async () => { game.override.enemyLevel(101); - await game.startBattle([Species.ETERNATUS]); + await game.classicMode.startBattle([Species.ETERNATUS]); game.move.select(dynamaxCannon.id); @@ -84,7 +84,7 @@ describe("Moves - Dynamax Cannon", () => { it("should return 140 power against an enemy 2% above level capp", async () => { game.override.enemyLevel(102); - await game.startBattle([Species.ETERNATUS]); + await game.classicMode.startBattle([Species.ETERNATUS]); game.move.select(dynamaxCannon.id); @@ -99,7 +99,7 @@ describe("Moves - Dynamax Cannon", () => { it("should return 160 power against an enemy 3% above level cap", async () => { game.override.enemyLevel(103); - await game.startBattle([Species.ETERNATUS]); + await game.classicMode.startBattle([Species.ETERNATUS]); game.move.select(dynamaxCannon.id); @@ -114,7 +114,7 @@ describe("Moves - Dynamax Cannon", () => { it("should return 180 power against an enemy 4% above level cap", async () => { game.override.enemyLevel(104); - await game.startBattle([Species.ETERNATUS]); + await game.classicMode.startBattle([Species.ETERNATUS]); game.move.select(dynamaxCannon.id); @@ -129,7 +129,7 @@ describe("Moves - Dynamax Cannon", () => { it("should return 200 power against an enemy 5% above level cap", async () => { game.override.enemyLevel(105); - await game.startBattle([Species.ETERNATUS]); + await game.classicMode.startBattle([Species.ETERNATUS]); game.move.select(dynamaxCannon.id); @@ -144,7 +144,7 @@ describe("Moves - Dynamax Cannon", () => { it("should return 200 power against an enemy way above level cap", async () => { game.override.enemyLevel(999); - await game.startBattle([Species.ETERNATUS]); + await game.classicMode.startBattle([Species.ETERNATUS]); game.move.select(dynamaxCannon.id); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); diff --git a/test/moves/encore.test.ts b/test/moves/encore.test.ts index 519e7860c04..f941328fc90 100644 --- a/test/moves/encore.test.ts +++ b/test/moves/encore.test.ts @@ -42,7 +42,7 @@ describe("Moves - Encore", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; game.move.select(Moves.ENCORE); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(enemyPokemon.getTag(BattlerTagType.ENCORE)).toBeDefined(); diff --git a/test/moves/fairy_lock.test.ts b/test/moves/fairy_lock.test.ts index e967221bcae..faffdee2304 100644 --- a/test/moves/fairy_lock.test.ts +++ b/test/moves/fairy_lock.test.ts @@ -40,8 +40,8 @@ describe("Moves - Fairy Lock", () => { game.move.select(Moves.FAIRY_LOCK); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, ArenaTagSide.PLAYER)).toBeDefined(); expect(game.scene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, ArenaTagSide.ENEMY)).toBeDefined(); @@ -50,8 +50,8 @@ describe("Moves - Fairy Lock", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); await game.phaseInterceptor.to("BerryPhase"); expect(playerPokemon[0].isTrapped()).toEqual(true); expect(playerPokemon[1].isTrapped()).toEqual(true); @@ -70,8 +70,8 @@ describe("Moves - Fairy Lock", () => { game.move.select(Moves.FAIRY_LOCK); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, ArenaTagSide.PLAYER)).toBeDefined(); @@ -84,8 +84,8 @@ describe("Moves - Fairy Lock", () => { game.move.select(Moves.SPLASH); game.doSwitchPokemon(2); - await game.forceEnemyMove(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); await game.phaseInterceptor.to("BerryPhase"); await game.toNextTurn(); @@ -98,8 +98,8 @@ describe("Moves - Fairy Lock", () => { game.move.select(Moves.FAIRY_LOCK); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, ArenaTagSide.PLAYER)).toBeDefined(); @@ -108,9 +108,9 @@ describe("Moves - Fairy Lock", () => { await game.toNextTurn(); game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.WHIRLWIND, 0); + await game.move.selectEnemyMove(Moves.WHIRLWIND, 0); game.doSelectPartyPokemon(2); - await game.forceEnemyMove(Moves.WHIRLWIND, 1); + await game.move.selectEnemyMove(Moves.WHIRLWIND, 1); game.doSelectPartyPokemon(2); await game.phaseInterceptor.to("BerryPhase"); await game.toNextTurn(); @@ -126,8 +126,8 @@ describe("Moves - Fairy Lock", () => { game.move.select(Moves.FAIRY_LOCK); game.move.select(Moves.MEMENTO, 1); game.doSelectPartyPokemon(2); - await game.forceEnemyMove(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, ArenaTagSide.PLAYER)).toBeDefined(); expect(game.scene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, ArenaTagSide.ENEMY)).toBeDefined(); @@ -135,8 +135,8 @@ describe("Moves - Fairy Lock", () => { await game.toNextTurn(); game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); + await game.move.selectEnemyMove(Moves.SPLASH, 1); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.getPlayerField()[0].isTrapped()).toEqual(true); expect(game.scene.getPlayerField()[1].isTrapped()).toEqual(true); diff --git a/test/moves/fillet_away.test.ts b/test/moves/fillet_away.test.ts index 477cdf76fc7..9de237b28a1 100644 --- a/test/moves/fillet_away.test.ts +++ b/test/moves/fillet_away.test.ts @@ -39,7 +39,7 @@ describe("Moves - FILLET AWAY", () => { //Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/fillet_away_(move) test("raises the user's ATK, SPATK, and SPD stat stages by 2 each, at the cost of 1/2 of its maximum HP", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); @@ -54,7 +54,7 @@ describe("Moves - FILLET AWAY", () => { }); test("still takes effect if one or more of the involved stat stages are not at max", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); @@ -73,7 +73,7 @@ describe("Moves - FILLET AWAY", () => { }); test("fails if all stat stages involved are at max", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; @@ -91,7 +91,7 @@ describe("Moves - FILLET AWAY", () => { }); test("fails if the user's health is less than 1/2", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = toDmgValue(leadPokemon.getMaxHp() / RATIO); diff --git a/test/moves/flame_burst.test.ts b/test/moves/flame_burst.test.ts index fb92537a238..963b0f04a9a 100644 --- a/test/moves/flame_burst.test.ts +++ b/test/moves/flame_burst.test.ts @@ -46,7 +46,7 @@ describe("Moves - Flame Burst", () => { }); it("inflicts damage to the target's ally equal to 1/16 of its max HP", async () => { - await game.startBattle([Species.PIKACHU, Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU, Species.PIKACHU]); const [leftEnemy, rightEnemy] = game.scene.getEnemyField(); game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex()); @@ -60,7 +60,7 @@ describe("Moves - Flame Burst", () => { it("does not inflict damage to the target's ally if the target was not affected by Flame Burst", async () => { game.override.enemyAbility(Abilities.FLASH_FIRE); - await game.startBattle([Species.PIKACHU, Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU, Species.PIKACHU]); const [leftEnemy, rightEnemy] = game.scene.getEnemyField(); game.move.select(Moves.FLAME_BURST, 0, leftEnemy.getBattlerIndex()); @@ -72,7 +72,7 @@ describe("Moves - Flame Burst", () => { }); it("does not interact with the target ally's abilities", async () => { - await game.startBattle([Species.PIKACHU, Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU, Species.PIKACHU]); const [leftEnemy, rightEnemy] = game.scene.getEnemyField(); vi.spyOn(rightEnemy, "getAbility").mockReturnValue(allAbilities[Abilities.FLASH_FIRE]); @@ -86,7 +86,7 @@ describe("Moves - Flame Burst", () => { }); it("effect damage is prevented by Magic Guard", async () => { - await game.startBattle([Species.PIKACHU, Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU, Species.PIKACHU]); const [leftEnemy, rightEnemy] = game.scene.getEnemyField(); vi.spyOn(rightEnemy, "getAbility").mockReturnValue(allAbilities[Abilities.MAGIC_GUARD]); diff --git a/test/moves/flower_shield.test.ts b/test/moves/flower_shield.test.ts index 4840c6f018f..d95ef6299b7 100644 --- a/test/moves/flower_shield.test.ts +++ b/test/moves/flower_shield.test.ts @@ -36,7 +36,7 @@ describe("Moves - Flower Shield", () => { it("raises DEF stat stage by 1 for all Grass-type Pokemon on the field by one stage - single battle", async () => { game.override.enemySpecies(Species.CHERRIM); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const cherrim = game.scene.getEnemyPokemon()!; const magikarp = game.scene.getPlayerPokemon()!; @@ -53,7 +53,7 @@ describe("Moves - Flower Shield", () => { it("raises DEF stat stage by 1 for all Grass-type Pokemon on the field by one stage - double battle", async () => { game.override.enemySpecies(Species.MAGIKARP).startingBiome(Biome.GRASS).battleStyle("double"); - await game.startBattle([Species.CHERRIM, Species.MAGIKARP]); + await game.classicMode.startBattle([Species.CHERRIM, Species.MAGIKARP]); const field = game.scene.getField(true); const grassPokemons = field.filter(p => p.getTypes().includes(PokemonType.GRASS)); @@ -78,7 +78,7 @@ describe("Moves - Flower Shield", () => { game.override.enemyMoveset([Moves.DIG, Moves.DIG, Moves.DIG, Moves.DIG]); game.override.enemyLevel(50); - await game.startBattle([Species.CHERRIM]); + await game.classicMode.startBattle([Species.CHERRIM]); const paras = game.scene.getEnemyPokemon()!; const cherrim = game.scene.getPlayerPokemon()!; @@ -97,7 +97,7 @@ describe("Moves - Flower Shield", () => { it("does nothing if there are no Grass-type Pokemon on the field", async () => { game.override.enemySpecies(Species.MAGIKARP); - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const enemy = game.scene.getEnemyPokemon()!; const ally = game.scene.getPlayerPokemon()!; diff --git a/test/moves/fly.test.ts b/test/moves/fly.test.ts index 74f8bc4a770..81d04f53ff8 100644 --- a/test/moves/fly.test.ts +++ b/test/moves/fly.test.ts @@ -104,10 +104,10 @@ describe("Moves - Fly", () => { game.move.select(Moves.FLY); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); - await game.forceEnemyMove(Moves.GRAVITY); + await game.move.selectEnemyMove(Moves.GRAVITY); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnEndPhase"); diff --git a/test/moves/follow_me.test.ts b/test/moves/follow_me.test.ts index 68c4f111bb1..228a835b17d 100644 --- a/test/moves/follow_me.test.ts +++ b/test/moves/follow_me.test.ts @@ -43,8 +43,8 @@ describe("Moves - Follow Me", () => { game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY); // Force both enemies to target the player Pokemon that did not use Follow Me - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); await game.phaseInterceptor.to(TurnEndPhase, false); @@ -61,8 +61,8 @@ describe("Moves - Follow Me", () => { game.move.select(Moves.FOLLOW_ME, 1); // Each player is targeted by an enemy - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); await game.phaseInterceptor.to(TurnEndPhase, false); @@ -84,8 +84,8 @@ describe("Moves - Follow Me", () => { game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY_2); // Target doesn't need to be specified if the move is self-targeted - await game.forceEnemyMove(Moves.FOLLOW_ME); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.FOLLOW_ME); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase, false); @@ -104,8 +104,8 @@ describe("Moves - Follow Me", () => { game.move.select(Moves.SNIPE_SHOT, 0, BattlerIndex.ENEMY); game.move.select(Moves.SNIPE_SHOT, 1, BattlerIndex.ENEMY_2); - await game.forceEnemyMove(Moves.FOLLOW_ME); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.FOLLOW_ME); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase, false); diff --git a/test/moves/foresight.test.ts b/test/moves/foresight.test.ts index d33a00bf136..82a39eceae5 100644 --- a/test/moves/foresight.test.ts +++ b/test/moves/foresight.test.ts @@ -31,7 +31,7 @@ describe("Moves - Foresight", () => { }); it("should allow Normal and Fighting moves to hit Ghost types", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const enemy = game.scene.getEnemyPokemon()!; @@ -55,7 +55,7 @@ describe("Moves - Foresight", () => { it("should ignore target's evasiveness boosts", async () => { game.override.enemyMoveset([Moves.MINIMIZE]); - await game.startBattle(); + await game.classicMode.startBattle(); const pokemon = game.scene.getPlayerPokemon()!; vi.spyOn(pokemon, "getAccuracyMultiplier"); diff --git a/test/moves/fusion_bolt.test.ts b/test/moves/fusion_bolt.test.ts index 33498a857a9..5e515a3bc47 100644 --- a/test/moves/fusion_bolt.test.ts +++ b/test/moves/fusion_bolt.test.ts @@ -36,7 +36,7 @@ describe("Moves - Fusion Bolt", () => { }); it("should not make contact", async () => { - await game.startBattle([Species.ZEKROM]); + await game.classicMode.startBattle([Species.ZEKROM]); const partyMember = game.scene.getPlayerPokemon()!; const initialHp = partyMember.hp; diff --git a/test/moves/fusion_flare.test.ts b/test/moves/fusion_flare.test.ts index 61bb126a75a..b947b9e7f7e 100644 --- a/test/moves/fusion_flare.test.ts +++ b/test/moves/fusion_flare.test.ts @@ -36,7 +36,7 @@ describe("Moves - Fusion Flare", () => { }); it("should thaw freeze status condition", async () => { - await game.startBattle([Species.RESHIRAM]); + await game.classicMode.startBattle([Species.RESHIRAM]); const partyMember = game.scene.getPlayerPokemon()!; diff --git a/test/moves/fusion_flare_bolt.test.ts b/test/moves/fusion_flare_bolt.test.ts index da2d48a7cdb..1d248e09510 100644 --- a/test/moves/fusion_flare_bolt.test.ts +++ b/test/moves/fusion_flare_bolt.test.ts @@ -138,7 +138,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { }, 20000); it("FUSION_FLARE should double power of subsequent FUSION_BOLT if moves are aimed at allies", async () => { - await game.startBattle([Species.ZEKROM, Species.RESHIRAM]); + await game.classicMode.startBattle([Species.ZEKROM, Species.RESHIRAM]); game.move.select(fusionBolt.id, 0, BattlerIndex.PLAYER_2); game.move.select(fusionFlare.id, 1, BattlerIndex.PLAYER); diff --git a/test/moves/growth.test.ts b/test/moves/growth.test.ts index 37cd84638ba..2e3ebfcde52 100644 --- a/test/moves/growth.test.ts +++ b/test/moves/growth.test.ts @@ -32,7 +32,7 @@ describe("Moves - Growth", () => { }); it("should raise SPATK stat stage by 1", async () => { - await game.startBattle([Species.MIGHTYENA]); + await game.classicMode.startBattle([Species.MIGHTYENA]); const playerPokemon = game.scene.getPlayerPokemon()!; diff --git a/test/moves/grudge.test.ts b/test/moves/grudge.test.ts index ecde5351d6d..48bb79c5f02 100644 --- a/test/moves/grudge.test.ts +++ b/test/moves/grudge.test.ts @@ -37,7 +37,7 @@ describe("Moves - Grudge", () => { const playerPokemon = game.scene.getPlayerPokemon(); game.move.select(Moves.EMBER); - await game.forceEnemyMove(Moves.GRUDGE); + await game.move.selectEnemyMove(Moves.GRUDGE); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("BerryPhase"); @@ -51,12 +51,12 @@ describe("Moves - Grudge", () => { const playerPokemon = game.scene.getPlayerPokemon(); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.GRUDGE); + await game.move.selectEnemyMove(Moves.GRUDGE); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toNextTurn(); game.move.select(Moves.EMBER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("BerryPhase"); @@ -78,7 +78,7 @@ describe("Moves - Grudge", () => { const playerPokemon = game.scene.getPlayerPokemon(); game.move.select(Moves.FALSE_SWIPE); - await game.forceEnemyMove(Moves.GRUDGE); + await game.move.selectEnemyMove(Moves.GRUDGE); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("BerryPhase"); diff --git a/test/moves/guard_split.test.ts b/test/moves/guard_split.test.ts index d182e94b203..0f5c69c7d85 100644 --- a/test/moves/guard_split.test.ts +++ b/test/moves/guard_split.test.ts @@ -34,7 +34,7 @@ describe("Moves - Guard Split", () => { it("should average the user's DEF and SPDEF stats with those of the target", async () => { game.override.enemyMoveset(Moves.SPLASH); - await game.startBattle([Species.INDEEDEE]); + await game.classicMode.startBattle([Species.INDEEDEE]); const player = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; @@ -54,7 +54,7 @@ describe("Moves - Guard Split", () => { it("should be idempotent", async () => { game.override.enemyMoveset([Moves.GUARD_SPLIT]); - await game.startBattle([Species.INDEEDEE]); + await game.classicMode.startBattle([Species.INDEEDEE]); const player = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/moves/hard_press.test.ts b/test/moves/hard_press.test.ts index e1a01c0109d..12cf049a022 100644 --- a/test/moves/hard_press.test.ts +++ b/test/moves/hard_press.test.ts @@ -37,7 +37,7 @@ describe("Moves - Hard Press", () => { }); it("should return 100 power if target HP ratio is at 100%", async () => { - await game.startBattle([Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU]); game.move.select(Moves.HARD_PRESS); await game.phaseInterceptor.to(MoveEffectPhase); @@ -46,7 +46,7 @@ describe("Moves - Hard Press", () => { }); it("should return 50 power if target HP ratio is at 50%", async () => { - await game.startBattle([Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU]); const targetHpRatio = 0.5; const enemy = game.scene.getEnemyPokemon()!; @@ -59,7 +59,7 @@ describe("Moves - Hard Press", () => { }); it("should return 1 power if target HP ratio is at 1%", async () => { - await game.startBattle([Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU]); const targetHpRatio = 0.01; const enemy = game.scene.getEnemyPokemon()!; @@ -72,7 +72,7 @@ describe("Moves - Hard Press", () => { }); it("should return 1 power if target HP ratio is less than 1%", async () => { - await game.startBattle([Species.PIKACHU]); + await game.classicMode.startBattle([Species.PIKACHU]); const targetHpRatio = 0.005; const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/moves/haze.test.ts b/test/moves/haze.test.ts index 4ddb6d1c7c5..33d4fe2dfda 100644 --- a/test/moves/haze.test.ts +++ b/test/moves/haze.test.ts @@ -36,7 +36,7 @@ describe("Moves - Haze", () => { }); it("should reset all stat changes of all Pokemon on field", async () => { - await game.startBattle([Species.RATTATA]); + await game.classicMode.startBattle([Species.RATTATA]); const user = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/moves/hyper_beam.test.ts b/test/moves/hyper_beam.test.ts index e6b3955ef0d..a4cbf7d9245 100644 --- a/test/moves/hyper_beam.test.ts +++ b/test/moves/hyper_beam.test.ts @@ -38,7 +38,7 @@ describe("Moves - Hyper Beam", () => { }); it("should force the user to recharge on the next turn (and only that turn)", async () => { - await game.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.MAGIKARP]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/test/moves/imprison.test.ts b/test/moves/imprison.test.ts index cefbaa52cad..dfa3b3ad757 100644 --- a/test/moves/imprison.test.ts +++ b/test/moves/imprison.test.ts @@ -36,7 +36,7 @@ describe("Moves - Imprison", () => { const playerPokemon = game.scene.getPlayerPokemon()!; game.move.select(Moves.TRANSFORM); - await game.forceEnemyMove(Moves.IMPRISON); + await game.move.selectEnemyMove(Moves.IMPRISON); await game.toNextTurn(); const playerMoveset = playerPokemon.getMoveset().map(x => x?.moveId); const enemyMoveset = game.scene @@ -51,7 +51,7 @@ describe("Moves - Imprison", () => { // Second turn, Imprison forces Struggle to occur game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const move1 = playerPokemon.getLastXMoves(1)[0]!; expect(move1.move).toBe(Moves.STRUGGLE); @@ -63,7 +63,7 @@ describe("Moves - Imprison", () => { const playerPokemon1 = game.scene.getPlayerPokemon()!; game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.IMPRISON); + await game.move.selectEnemyMove(Moves.IMPRISON); await game.toNextTurn(); const imprisonArenaTag = game.scene.arena.getTag(ArenaTagType.IMPRISON); const imprisonBattlerTag1 = playerPokemon1.getTag(BattlerTagType.IMPRISON); @@ -72,7 +72,7 @@ describe("Moves - Imprison", () => { // Second turn, Imprison forces Struggle to occur game.doSwitchPokemon(1); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const playerPokemon2 = game.scene.getPlayerPokemon()!; const imprisonBattlerTag2 = playerPokemon2.getTag(BattlerTagType.IMPRISON); @@ -87,12 +87,12 @@ describe("Moves - Imprison", () => { const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; game.move.select(Moves.IMPRISON); - await game.forceEnemyMove(Moves.GROWL); + await game.move.selectEnemyMove(Moves.GROWL); await game.toNextTurn(); expect(game.scene.arena.getTag(ArenaTagType.IMPRISON)).toBeDefined(); expect(enemyPokemon.getTag(BattlerTagType.IMPRISON)).toBeDefined(); game.doSwitchPokemon(1); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(playerPokemon.isActive(true)).toBeFalsy(); expect(game.scene.arena.getTag(ArenaTagType.IMPRISON)).toBeUndefined(); diff --git a/test/moves/instruct.test.ts b/test/moves/instruct.test.ts index dd25db4ec90..719349760dc 100644 --- a/test/moves/instruct.test.ts +++ b/test/moves/instruct.test.ts @@ -48,7 +48,7 @@ describe("Moves - Instruct", () => { game.move.changeMoveset(enemy, Moves.SONIC_BOOM); game.move.select(Moves.INSTRUCT); - await game.forceEnemyMove(Moves.SONIC_BOOM); + await game.move.selectEnemyMove(Moves.SONIC_BOOM); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("MovePhase"); // enemy attacks us @@ -75,12 +75,12 @@ describe("Moves - Instruct", () => { game.move.changeMoveset(enemy, [Moves.SONIC_BOOM, Moves.SUBSTITUTE]); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SUBSTITUTE); + await game.move.selectEnemyMove(Moves.SUBSTITUTE); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toNextTurn(); game.move.select(Moves.INSTRUCT); - await game.forceEnemyMove(Moves.SONIC_BOOM); + await game.move.selectEnemyMove(Moves.SONIC_BOOM); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnEndPhase", false); @@ -169,7 +169,7 @@ describe("Moves - Instruct", () => { moveUsed.ppUsed = moveUsed.getMovePp() - 1; game.move.select(Moves.INSTRUCT); - await game.forceEnemyMove(Moves.HIDDEN_POWER); + await game.move.selectEnemyMove(Moves.HIDDEN_POWER); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnEndPhase", false); @@ -210,8 +210,8 @@ describe("Moves - Instruct", () => { game.move.select(Moves.SPLASH, BattlerIndex.PLAYER); game.move.select(Moves.FIERY_DANCE, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY); - await game.forceEnemyMove(Moves.INSTRUCT, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.INSTRUCT, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to("BerryPhase"); @@ -248,7 +248,7 @@ describe("Moves - Instruct", () => { await game.classicMode.startBattle([Species.AMOONGUSS]); game.move.select(Moves.INSTRUCT); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("TurnEndPhase", false); @@ -265,7 +265,7 @@ describe("Moves - Instruct", () => { game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.ENEMY); game.move.select(Moves.DISABLE, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY); - await game.forceEnemyMove(Moves.SONIC_BOOM, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SONIC_BOOM, BattlerIndex.PLAYER); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to("TurnEndPhase", false); @@ -311,7 +311,7 @@ describe("Moves - Instruct", () => { ]; game.move.select(Moves.INSTRUCT); - await game.forceEnemyMove(Moves.HYPER_BEAM); + await game.move.selectEnemyMove(Moves.HYPER_BEAM); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); @@ -326,23 +326,21 @@ describe("Moves - Instruct", () => { }); it("should not repeat move since forgotten by target", async () => { - game.override.enemyLevel(5).xpMultiplier(0).enemySpecies(Species.WURMPLE).enemyMoveset(Moves.INSTRUCT); + game.override.enemyMoveset(Moves.INSTRUCT); await game.classicMode.startBattle([Species.REGIELEKI]); const regieleki = game.scene.getPlayerPokemon()!; - // fill out moveset with random moves - game.move.changeMoveset(regieleki, [Moves.ELECTRO_DRIFT, Moves.SPLASH, Moves.ICE_BEAM, Moves.ANCIENT_POWER]); - - game.move.select(Moves.ELECTRO_DRIFT); - await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); - await game.phaseInterceptor.to("FaintPhase"); - await game.move.learnMove(Moves.ELECTROWEB); - await game.toNextWave(); + regieleki.pushMoveHistory({ + move: Moves.ELECTRO_DRIFT, + targets: [BattlerIndex.PLAYER], + result: MoveResult.SUCCESS, + virtual: false, + }); game.move.select(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); - await game.phaseInterceptor.to("TurnEndPhase", false); - expect(game.scene.getEnemyField()[0].getLastXMoves()[0].result).toBe(MoveResult.FAIL); + await game.toEndOfTurn(); + expect(game.field.getEnemyPokemon().getLastXMoves()[0].result).toBe(MoveResult.FAIL); }); it("should disregard priority of instructed move on use", async () => { @@ -360,7 +358,7 @@ describe("Moves - Instruct", () => { ]; game.move.select(Moves.INSTRUCT); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("TurnEndPhase", false); // lucario instructed enemy whirlwind at 0 priority to switch itself out @@ -379,8 +377,8 @@ describe("Moves - Instruct", () => { game.move.select(Moves.QUICK_ATTACK, BattlerIndex.PLAYER, BattlerIndex.ENEMY); // succeeds due to terrain no game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.PSYCHIC_TERRAIN); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.PSYCHIC_TERRAIN); await game.toNextTurn(); game.move.select(Moves.SPLASH, BattlerIndex.PLAYER); @@ -404,8 +402,8 @@ describe("Moves - Instruct", () => { game.move.select(Moves.VINE_WHIP, BattlerIndex.PLAYER, BattlerIndex.ENEMY); game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.PSYCHIC_TERRAIN); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.PSYCHIC_TERRAIN); await game.toNextTurn(); game.move.select(Moves.SPLASH, BattlerIndex.PLAYER); @@ -515,14 +513,14 @@ describe("Moves - Instruct", () => { game.move.select(Moves.SPLASH, BattlerIndex.PLAYER); game.move.select(Moves.SPLASH, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.BULLET_SEED, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.BULLET_SEED, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.ENEMY); game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY); - await game.forceEnemyMove(Moves.BULLET_SEED, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.BULLET_SEED, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to("BerryPhase"); @@ -531,8 +529,8 @@ describe("Moves - Instruct", () => { await game.toNextTurn(); game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER, BattlerIndex.ENEMY); game.move.select(Moves.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY); - await game.forceEnemyMove(Moves.BULLET_SEED, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.BULLET_SEED, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2]); await game.phaseInterceptor.to("BerryPhase"); diff --git a/test/moves/jaw_lock.test.ts b/test/moves/jaw_lock.test.ts index 71896dc3b62..85750b6efda 100644 --- a/test/moves/jaw_lock.test.ts +++ b/test/moves/jaw_lock.test.ts @@ -40,7 +40,7 @@ describe("Moves - Jaw Lock", () => { }); it("should trap the move's user and target", async () => { - await game.startBattle([Species.BULBASAUR]); + await game.classicMode.startBattle([Species.BULBASAUR]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -61,7 +61,7 @@ describe("Moves - Jaw Lock", () => { it("should not trap either pokemon if the target faints", async () => { game.override.enemyLevel(1); - await game.startBattle([Species.BULBASAUR]); + await game.classicMode.startBattle([Species.BULBASAUR]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -86,7 +86,7 @@ describe("Moves - Jaw Lock", () => { }); it("should only trap the user until the target faints", async () => { - await game.startBattle([Species.BULBASAUR]); + await game.classicMode.startBattle([Species.BULBASAUR]); const leadPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -109,7 +109,7 @@ describe("Moves - Jaw Lock", () => { it("should not trap other targets after the first target is trapped", async () => { game.override.battleStyle("double"); - await game.startBattle([Species.CHARMANDER, Species.BULBASAUR]); + await game.classicMode.startBattle([Species.CHARMANDER, Species.BULBASAUR]); const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); @@ -138,7 +138,7 @@ describe("Moves - Jaw Lock", () => { it("should not trap either pokemon if the target is protected", async () => { game.override.enemyMoveset([Moves.PROTECT]); - await game.startBattle([Species.BULBASAUR]); + await game.classicMode.startBattle([Species.BULBASAUR]); const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/test/moves/last-resort.test.ts b/test/moves/last-resort.test.ts index a7b462f3ca4..65b50bc4e89 100644 --- a/test/moves/last-resort.test.ts +++ b/test/moves/last-resort.test.ts @@ -86,11 +86,11 @@ describe("Moves - Last Resort", () => { // use mirror move normally to trigger absorb virtually game.move.select(Moves.MIRROR_MOVE); - await game.forceEnemyMove(Moves.ABSORB); + await game.move.selectEnemyMove(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.move.selectEnemyMove(Moves.SWORDS_DANCE); // goes first to proc dancer ahead of time await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnEndPhase"); expectLastResortFail(); @@ -154,10 +154,10 @@ describe("Moves - Last Resort", () => { // ensure enemy last resort succeeds game.move.select(Moves.MIRROR_MOVE); - await game.forceEnemyMove(Moves.ABSORB); + await game.move.selectEnemyMove(Moves.ABSORB); await game.phaseInterceptor.to("TurnEndPhase"); game.move.select(Moves.MIRROR_MOVE); - await game.forceEnemyMove(Moves.LAST_RESORT); + await game.move.selectEnemyMove(Moves.LAST_RESORT); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnEndPhase"); diff --git a/test/moves/lucky_chant.test.ts b/test/moves/lucky_chant.test.ts index e2a28a7bbe3..9fa6ff43eab 100644 --- a/test/moves/lucky_chant.test.ts +++ b/test/moves/lucky_chant.test.ts @@ -35,7 +35,7 @@ describe("Moves - Lucky Chant", () => { }); it("should prevent critical hits from moves", async () => { - await game.startBattle([Species.CHARIZARD]); + await game.classicMode.startBattle([Species.CHARIZARD]); const playerPokemon = game.scene.getPlayerPokemon()!; @@ -56,7 +56,7 @@ describe("Moves - Lucky Chant", () => { it("should prevent critical hits against the user's ally", async () => { game.override.battleStyle("double"); - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerField(); @@ -79,7 +79,7 @@ describe("Moves - Lucky Chant", () => { it("should prevent critical hits from field effects", async () => { game.override.enemyMoveset([Moves.TACKLE]); - await game.startBattle([Species.CHARIZARD]); + await game.classicMode.startBattle([Species.CHARIZARD]); const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/test/moves/lunar_blessing.test.ts b/test/moves/lunar_blessing.test.ts index ee35107fccd..5021a47ff7f 100644 --- a/test/moves/lunar_blessing.test.ts +++ b/test/moves/lunar_blessing.test.ts @@ -33,7 +33,7 @@ describe("Moves - Lunar Blessing", () => { }); it("should restore 25% HP of the user and its ally", async () => { - await game.startBattle([Species.RATTATA, Species.RATTATA]); + await game.classicMode.startBattle([Species.RATTATA, Species.RATTATA]); const [leftPlayer, rightPlayer] = game.scene.getPlayerField(); vi.spyOn(leftPlayer, "getMaxHp").mockReturnValue(100); @@ -61,7 +61,7 @@ describe("Moves - Lunar Blessing", () => { it("should cure status effect of the user and its ally", async () => { game.override.statusEffect(StatusEffect.BURN); - await game.startBattle([Species.RATTATA, Species.RATTATA]); + await game.classicMode.startBattle([Species.RATTATA, Species.RATTATA]); const [leftPlayer, rightPlayer] = game.scene.getPlayerField(); vi.spyOn(leftPlayer, "resetStatus"); diff --git a/test/moves/magic_coat.test.ts b/test/moves/magic_coat.test.ts index 4e0bd7f0a98..ad0bd47d7cf 100644 --- a/test/moves/magic_coat.test.ts +++ b/test/moves/magic_coat.test.ts @@ -62,12 +62,12 @@ describe("Moves - Magic Coat", () => { // turn 1 game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.MAGIC_COAT); + await game.move.selectEnemyMove(Moves.MAGIC_COAT); await game.toNextTurn(); // turn 2 game.move.select(Moves.GROWL); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.ATK)).toBe(-1); }); @@ -102,8 +102,8 @@ describe("Moves - Magic Coat", () => { game.move.select(Moves.GROWL, 0); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.MAGIC_COAT); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.MAGIC_COAT); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.getPlayerField().every(p => p.getStatStage(Stat.ATK) === -1)).toBeTruthy(); @@ -129,8 +129,8 @@ describe("Moves - Magic Coat", () => { game.move.select(Moves.MAGIC_COAT, 0); game.move.select(Moves.GROWL, 1); - await game.forceEnemyMove(Moves.MAGIC_COAT); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.MAGIC_COAT); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.getEnemyField()[0].getStatStage(Stat.ATK)).toBe(0); @@ -192,12 +192,12 @@ describe("Moves - Magic Coat", () => { // turn 1 game.move.select(Moves.GROWL); - await game.forceEnemyMove(Moves.MAGIC_COAT); + await game.move.selectEnemyMove(Moves.MAGIC_COAT); await game.toNextTurn(); // turn 2 game.move.select(Moves.ENCORE); - await game.forceEnemyMove(Moves.TACKLE); + await game.move.selectEnemyMove(Moves.TACKLE); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to("BerryPhase"); expect(enemyPokemon.getTag(BattlerTagType.ENCORE)!["moveId"]).toBe(Moves.TACKLE); @@ -233,7 +233,7 @@ describe("Moves - Magic Coat", () => { vi.spyOn(stomping_tantrum, "calculateBattlePower"); game.move.select(Moves.SPORE); - await game.forceEnemyMove(Moves.CHARM); + await game.move.selectEnemyMove(Moves.CHARM); await game.phaseInterceptor.to("TurnEndPhase"); expect(enemy.getLastXMoves(1)[0].result).toBe("success"); diff --git a/test/moves/magnet_rise.test.ts b/test/moves/magnet_rise.test.ts index 62ad0c88091..3f15a109f11 100644 --- a/test/moves/magnet_rise.test.ts +++ b/test/moves/magnet_rise.test.ts @@ -33,7 +33,7 @@ describe("Moves - Magnet Rise", () => { }); it("MAGNET RISE", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const startingHp = game.scene.getPlayerParty()[0].hp; game.move.select(moveToUse); @@ -44,7 +44,7 @@ describe("Moves - Magnet Rise", () => { }, 20000); it("MAGNET RISE - Gravity", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const startingHp = game.scene.getPlayerParty()[0].hp; game.move.select(moveToUse); diff --git a/test/moves/make_it_rain.test.ts b/test/moves/make_it_rain.test.ts index 4d94537bcec..b897304662d 100644 --- a/test/moves/make_it_rain.test.ts +++ b/test/moves/make_it_rain.test.ts @@ -34,7 +34,7 @@ describe("Moves - Make It Rain", () => { }); it("should only lower SPATK stat stage by 1 once in a double battle", async () => { - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerPokemon()!; @@ -50,7 +50,7 @@ describe("Moves - Make It Rain", () => { game.override.enemyLevel(1); // ensures the enemy will faint game.override.battleStyle("single"); - await game.startBattle([Species.CHARIZARD]); + await game.classicMode.startBattle([Species.CHARIZARD]); const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -66,7 +66,7 @@ describe("Moves - Make It Rain", () => { it("should reduce Sp. Atk. once after KOing two enemies", async () => { game.override.enemyLevel(1); // ensures the enemy will faint - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyField(); @@ -81,7 +81,7 @@ describe("Moves - Make It Rain", () => { }); it("should lower SPATK stat stage by 1 if it only hits the second target", async () => { - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const playerPokemon = game.scene.getPlayerPokemon()!; diff --git a/test/moves/mat_block.test.ts b/test/moves/mat_block.test.ts index 9ed0f497af9..3e7958d665b 100644 --- a/test/moves/mat_block.test.ts +++ b/test/moves/mat_block.test.ts @@ -39,7 +39,7 @@ describe("Moves - Mat Block", () => { }); test("should protect the user and allies from attack moves", async () => { - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); @@ -57,7 +57,7 @@ describe("Moves - Mat Block", () => { test("should not protect the user and allies from status moves", async () => { game.override.enemyMoveset([Moves.GROWL]); - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); @@ -73,7 +73,7 @@ describe("Moves - Mat Block", () => { }); test("should fail when used after the first turn", async () => { - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); const leadPokemon = game.scene.getPlayerField(); diff --git a/test/moves/metal_burst.test.ts b/test/moves/metal_burst.test.ts index 7fa5434dc58..cadcbe07a0d 100644 --- a/test/moves/metal_burst.test.ts +++ b/test/moves/metal_burst.test.ts @@ -42,8 +42,8 @@ describe("Moves - Metal Burst", () => { game.move.select(Moves.METAL_BURST); game.move.select(Moves.FISSURE, 1, BattlerIndex.ENEMY); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2]); @@ -63,8 +63,8 @@ describe("Moves - Metal Burst", () => { game.move.select(Moves.METAL_BURST); game.move.select(Moves.PRECIPICE_BLADES, 1); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2]); diff --git a/test/moves/mirror_move.test.ts b/test/moves/mirror_move.test.ts index 438c594d839..6a73e3a1f05 100644 --- a/test/moves/mirror_move.test.ts +++ b/test/moves/mirror_move.test.ts @@ -40,8 +40,8 @@ describe("Moves - Mirror Move", () => { game.move.select(Moves.MIRROR_MOVE, 0, BattlerIndex.ENEMY); // target's last move is Tackle, enemy should receive damage from Mirror Move copying Tackle game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.GROWL, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.GROWL, BattlerIndex.PLAYER_2); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER]); await game.toNextTurn(); diff --git a/test/moves/multi_target.test.ts b/test/moves/multi_target.test.ts index ad47d540a14..af98c9a89f4 100644 --- a/test/moves/multi_target.test.ts +++ b/test/moves/multi_target.test.ts @@ -36,7 +36,7 @@ describe("Multi-target damage reduction", () => { }); it("should reduce d.gleam damage when multiple enemies but not tackle", async () => { - await game.startBattle([Species.MAGIKARP, Species.FEEBAS]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.FEEBAS]); const [enemy1, enemy2] = game.scene.getEnemyField(); @@ -76,7 +76,7 @@ describe("Multi-target damage reduction", () => { }); it("should reduce earthquake when more than one pokemon other than user is not fainted", async () => { - await game.startBattle([Species.MAGIKARP, Species.FEEBAS]); + await game.classicMode.startBattle([Species.MAGIKARP, Species.FEEBAS]); const player2 = game.scene.getPlayerParty()[1]; const [enemy1, enemy2] = game.scene.getEnemyField(); diff --git a/test/moves/parting_shot.test.ts b/test/moves/parting_shot.test.ts index a65c1a5b3a5..26f8790d3b9 100644 --- a/test/moves/parting_shot.test.ts +++ b/test/moves/parting_shot.test.ts @@ -35,7 +35,7 @@ describe("Moves - Parting Shot", () => { test("Parting Shot when buffed by prankster should fail against dark types", async () => { game.override.enemySpecies(Species.POOCHYENA).ability(Abilities.PRANKSTER); - await game.startBattle([Species.MURKROW, Species.MEOWTH]); + await game.classicMode.startBattle([Species.MURKROW, Species.MEOWTH]); const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); @@ -50,7 +50,7 @@ describe("Moves - Parting Shot", () => { test("Parting shot should fail against good as gold ability", async () => { game.override.enemySpecies(Species.GHOLDENGO).enemyAbility(Abilities.GOOD_AS_GOLD); - await game.startBattle([Species.MURKROW, Species.MEOWTH]); + await game.classicMode.startBattle([Species.MURKROW, Species.MEOWTH]); const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); @@ -68,7 +68,13 @@ describe("Moves - Parting Shot", () => { "Parting shot should fail if target is -6/-6 de-buffed", async () => { game.override.moveset([Moves.PARTING_SHOT, Moves.MEMENTO, Moves.SPLASH]); - await game.startBattle([Species.MEOWTH, Species.MEOWTH, Species.MEOWTH, Species.MURKROW, Species.ABRA]); + await game.classicMode.startBattle([ + Species.MEOWTH, + Species.MEOWTH, + Species.MEOWTH, + Species.MURKROW, + Species.ABRA, + ]); // use Memento 3 times to debuff enemy game.move.select(Moves.MEMENTO); @@ -111,7 +117,7 @@ describe("Moves - Parting Shot", () => { "Parting shot shouldn't allow switch out when mist is active", async () => { game.override.enemySpecies(Species.ALTARIA).enemyAbility(Abilities.NONE).enemyMoveset([Moves.MIST]); - await game.startBattle([Species.SNORLAX, Species.MEOWTH]); + await game.classicMode.startBattle([Species.SNORLAX, Species.MEOWTH]); const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); @@ -130,7 +136,7 @@ describe("Moves - Parting Shot", () => { "Parting shot shouldn't allow switch out against clear body ability", async () => { game.override.enemySpecies(Species.TENTACOOL).enemyAbility(Abilities.CLEAR_BODY); - await game.startBattle([Species.SNORLAX, Species.MEOWTH]); + await game.classicMode.startBattle([Species.SNORLAX, Species.MEOWTH]); const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); @@ -148,7 +154,7 @@ describe("Moves - Parting Shot", () => { // TODO: fix this bug to pass the test! "Parting shot should de-buff and not fail if no party available to switch - party size 1", async () => { - await game.startBattle([Species.MURKROW]); + await game.classicMode.startBattle([Species.MURKROW]); const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).toBeDefined(); @@ -166,7 +172,7 @@ describe("Moves - Parting Shot", () => { // TODO: fix this bug to pass the test! "Parting shot regularly not fail if no party available to switch - party fainted", async () => { - await game.startBattle([Species.MURKROW, Species.MEOWTH]); + await game.classicMode.startBattle([Species.MURKROW, Species.MEOWTH]); game.move.select(Moves.SPLASH); // intentionally kill party pokemon, switch to second slot (now 1 party mon is fainted) diff --git a/test/moves/plasma_fists.test.ts b/test/moves/plasma_fists.test.ts index b6a5ceaed68..0c3412d8e60 100644 --- a/test/moves/plasma_fists.test.ts +++ b/test/moves/plasma_fists.test.ts @@ -42,8 +42,8 @@ describe("Moves - Plasma Fists", () => { game.move.select(Moves.PLASMA_FISTS, 0, BattlerIndex.ENEMY); game.move.select(Moves.TACKLE, 1, BattlerIndex.ENEMY_2); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); diff --git a/test/moves/pledge_moves.test.ts b/test/moves/pledge_moves.test.ts index 9dbf2b4cb02..6c66c4bbe2d 100644 --- a/test/moves/pledge_moves.test.ts +++ b/test/moves/pledge_moves.test.ts @@ -256,8 +256,8 @@ describe("Moves - Pledge Moves", () => { game.move.select(Moves.FIRE_PLEDGE, 0, BattlerIndex.ENEMY); game.move.select(Moves.GRASS_PLEDGE, 1, BattlerIndex.ENEMY_2); - await game.forceEnemyMove(Moves.SPORE, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPORE, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2]); @@ -290,8 +290,8 @@ describe("Moves - Pledge Moves", () => { game.move.select(Moves.WATER_PLEDGE, 0, BattlerIndex.ENEMY); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.FOLLOW_ME); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.FOLLOW_ME); await game.phaseInterceptor.to("BerryPhase", false); diff --git a/test/moves/powder.test.ts b/test/moves/powder.test.ts index 457beb60f91..b65525109ad 100644 --- a/test/moves/powder.test.ts +++ b/test/moves/powder.test.ts @@ -1,15 +1,15 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import Phaser from "phaser"; -import GameManager from "#test/testUtils/gameManager"; +import { BattlerIndex } from "#app/battle"; +import { MoveResult, PokemonMove } from "#app/field/pokemon"; +import { BerryPhase } from "#app/phases/berry-phase"; +import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; -import { Species } from "#enums/species"; -import { BerryPhase } from "#app/phases/berry-phase"; -import { MoveResult, PokemonMove } from "#app/field/pokemon"; import { PokemonType } from "#enums/pokemon-type"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase"; +import { Species } from "#enums/species"; import { StatusEffect } from "#enums/status-effect"; -import { BattlerIndex } from "#app/battle"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; describe("Moves - Powder", () => { let phaserGame: Phaser.Game; @@ -161,7 +161,6 @@ describe("Moves - Powder", () => { game.move.select(Moves.ROAR, 0, BattlerIndex.ENEMY_2); game.move.select(Moves.SPLASH, 1); await game.toNextTurn(); - await game.toNextTurn(); // Requires game.toNextTurn() twice due to double battle // Turn 2: Enemy should activate Powder twice: From using Ember, and from copying Fiery Dance via Dancer playerPokemon.hp = playerPokemon.getMaxHp(); @@ -234,8 +233,8 @@ describe("Moves - Powder", () => { game.move.select(Moves.POWDER, 0, BattlerIndex.ENEMY); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.GRASS_PLEDGE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.FIRE_PLEDGE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.GRASS_PLEDGE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.FIRE_PLEDGE, BattlerIndex.PLAYER); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(BerryPhase, false); @@ -251,8 +250,8 @@ describe("Moves - Powder", () => { game.move.select(Moves.POWDER, 0, BattlerIndex.ENEMY); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.FIRE_PLEDGE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.WATER_PLEDGE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.FIRE_PLEDGE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.WATER_PLEDGE, BattlerIndex.PLAYER); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to(BerryPhase, false); @@ -268,8 +267,8 @@ describe("Moves - Powder", () => { game.move.select(Moves.POWDER, 0, BattlerIndex.ENEMY); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.FIRE_PLEDGE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.WATER_PLEDGE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.FIRE_PLEDGE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.WATER_PLEDGE, BattlerIndex.PLAYER); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(BerryPhase, false); diff --git a/test/moves/power_split.test.ts b/test/moves/power_split.test.ts index f15275fce9e..ca712f0a64e 100644 --- a/test/moves/power_split.test.ts +++ b/test/moves/power_split.test.ts @@ -34,7 +34,7 @@ describe("Moves - Power Split", () => { it("should average the user's ATK and SPATK stats with those of the target", async () => { game.override.enemyMoveset(Moves.SPLASH); - await game.startBattle([Species.INDEEDEE]); + await game.classicMode.startBattle([Species.INDEEDEE]); const player = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; @@ -54,7 +54,7 @@ describe("Moves - Power Split", () => { it("should be idempotent", async () => { game.override.enemyMoveset([Moves.POWER_SPLIT]); - await game.startBattle([Species.INDEEDEE]); + await game.classicMode.startBattle([Species.INDEEDEE]); const player = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/moves/purify.test.ts b/test/moves/purify.test.ts index 191539d8cec..0439ba39108 100644 --- a/test/moves/purify.test.ts +++ b/test/moves/purify.test.ts @@ -37,7 +37,7 @@ describe("Moves - Purify", () => { }); test("Purify heals opponent status effect and restores user hp", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const enemyPokemon: EnemyPokemon = game.scene.getEnemyPokemon()!; const playerPokemon: PlayerPokemon = game.scene.getPlayerPokemon()!; @@ -54,7 +54,7 @@ describe("Moves - Purify", () => { }); test("Purify does not heal if opponent doesnt have any status effect", async () => { - await game.startBattle(); + await game.classicMode.startBattle(); const playerPokemon: PlayerPokemon = game.scene.getPlayerPokemon()!; diff --git a/test/moves/quash.test.ts b/test/moves/quash.test.ts index 5bf8271320b..f242dafe365 100644 --- a/test/moves/quash.test.ts +++ b/test/moves/quash.test.ts @@ -39,8 +39,8 @@ describe("Moves - Quash", () => { game.move.select(Moves.QUASH, 0, BattlerIndex.PLAYER_2); game.move.select(Moves.SUNNY_DAY, 1); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.RAIN_DANCE); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.RAIN_DANCE); await game.phaseInterceptor.to("TurnEndPhase", false); // will be sunny if player_2 moved last because of quash, rainy otherwise @@ -67,8 +67,8 @@ describe("Moves - Quash", () => { game.move.select(Moves.RAIN_DANCE, 0); game.move.select(Moves.SUNNY_DAY, 1); - await game.forceEnemyMove(Moves.QUASH, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.QUASH, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.QUASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.QUASH, BattlerIndex.PLAYER_2); await game.phaseInterceptor.to("TurnEndPhase", false); expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SUNNY); @@ -81,15 +81,15 @@ describe("Moves - Quash", () => { game.move.select(Moves.SPLASH, 0); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.TRICK_ROOM); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.TRICK_ROOM); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("TurnInitPhase"); // both users are quashed - accelgor should move last w/ TR so rain should be up at end of turn game.move.select(Moves.RAIN_DANCE, 0); game.move.select(Moves.SUNNY_DAY, 1); - await game.forceEnemyMove(Moves.QUASH, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.QUASH, BattlerIndex.PLAYER_2); + await game.move.selectEnemyMove(Moves.QUASH, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.QUASH, BattlerIndex.PLAYER_2); await game.phaseInterceptor.to("TurnEndPhase", false); expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.RAIN); diff --git a/test/moves/rage_fist.test.ts b/test/moves/rage_fist.test.ts index 0aabb717f1b..9e5810039a8 100644 --- a/test/moves/rage_fist.test.ts +++ b/test/moves/rage_fist.test.ts @@ -75,7 +75,7 @@ describe("Moves - Rage Fist", () => { await game.classicMode.startBattle([Species.REGIROCK]); game.move.select(Moves.SUBSTITUTE); - await game.forceEnemyMove(Moves.DOUBLE_KICK); + await game.move.selectEnemyMove(Moves.DOUBLE_KICK); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toNextTurn(); @@ -84,12 +84,12 @@ describe("Moves - Rage Fist", () => { // remove substitute and get confused game.move.select(Moves.TIDY_UP); - await game.forceEnemyMove(Moves.CONFUSE_RAY); + await game.move.selectEnemyMove(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.move.selectEnemyMove(Moves.CONFUSE_RAY); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.move.forceConfusionActivation(true); await game.toNextTurn(); @@ -123,7 +123,7 @@ describe("Moves - Rage Fist", () => { // beat up a magikarp game.move.select(Moves.RAGE_FIST); - await game.forceEnemyMove(Moves.DOUBLE_KICK); + await game.move.selectEnemyMove(Moves.DOUBLE_KICK); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnEndPhase"); diff --git a/test/moves/rage_powder.test.ts b/test/moves/rage_powder.test.ts index 284b558f842..206fd590896 100644 --- a/test/moves/rage_powder.test.ts +++ b/test/moves/rage_powder.test.ts @@ -38,8 +38,8 @@ describe("Moves - Rage Powder", () => { game.move.select(Moves.QUICK_ATTACK, 0, BattlerIndex.ENEMY); game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY_2); - await game.forceEnemyMove(Moves.RAGE_POWDER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.RAGE_POWDER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("BerryPhase", false); @@ -61,8 +61,8 @@ describe("Moves - Rage Powder", () => { game.move.select(Moves.QUICK_ATTACK, 0, BattlerIndex.ENEMY); game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY_2); - await game.forceEnemyMove(Moves.RAGE_POWDER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.RAGE_POWDER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("BerryPhase", false); diff --git a/test/moves/reflect_type.test.ts b/test/moves/reflect_type.test.ts index efd58bfeadf..63772aa746f 100644 --- a/test/moves/reflect_type.test.ts +++ b/test/moves/reflect_type.test.ts @@ -37,17 +37,17 @@ describe("Moves - Reflect Type", () => { const enemyPokemon = game.scene.getEnemyPokemon(); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.BURN_UP); + await game.move.selectEnemyMove(Moves.BURN_UP); await game.toNextTurn(); game.move.select(Moves.FORESTS_CURSE); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); expect(enemyPokemon?.getTypes().includes(PokemonType.UNKNOWN)).toBe(true); expect(enemyPokemon?.getTypes().includes(PokemonType.GRASS)).toBe(true); game.move.select(Moves.REFLECT_TYPE); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("TurnEndPhase"); expect(playerPokemon?.getTypes()[0]).toBe(PokemonType.NORMAL); expect(playerPokemon?.getTypes().includes(PokemonType.GRASS)).toBe(true); diff --git a/test/moves/retaliate.test.ts b/test/moves/retaliate.test.ts index 81ea353a120..40f31635d9b 100644 --- a/test/moves/retaliate.test.ts +++ b/test/moves/retaliate.test.ts @@ -37,7 +37,7 @@ describe("Moves - Retaliate", () => { it("increases power if ally died previous turn", async () => { vi.spyOn(retaliate, "calculateBattlePower"); - await game.startBattle([Species.ABRA, Species.COBALION]); + await game.classicMode.startBattle([Species.ABRA, Species.COBALION]); game.move.select(Moves.RETALIATE); await game.phaseInterceptor.to("TurnEndPhase"); expect(retaliate.calculateBattlePower).toHaveLastReturnedWith(70); diff --git a/test/moves/revival_blessing.test.ts b/test/moves/revival_blessing.test.ts index b36cd43eb83..ded18e3ffb8 100644 --- a/test/moves/revival_blessing.test.ts +++ b/test/moves/revival_blessing.test.ts @@ -98,8 +98,8 @@ describe("Moves - Revival Blessing", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.REVIVAL_BLESSING, 1); - await game.forceEnemyMove(Moves.FISSURE, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.FISSURE, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]); await game.phaseInterceptor.to("MoveEndPhase"); diff --git a/test/moves/rollout.test.ts b/test/moves/rollout.test.ts index dab9ef67596..dafa72dd5fa 100644 --- a/test/moves/rollout.test.ts +++ b/test/moves/rollout.test.ts @@ -42,7 +42,7 @@ describe("Moves - Rollout", () => { const turns = 6; const dmgHistory: number[] = []; - await game.startBattle(); + await game.classicMode.startBattle(); const playerPkm = game.scene.getPlayerParty()[0]; vi.spyOn(playerPkm, "stats", "get").mockReturnValue([500000, 1, 1, 1, 1, 1]); // HP, ATK, DEF, SPATK, SPDEF, SPD diff --git a/test/moves/round.test.ts b/test/moves/round.test.ts index 43e505705ae..ccdf4cbf089 100644 --- a/test/moves/round.test.ts +++ b/test/moves/round.test.ts @@ -45,8 +45,8 @@ describe("Moves - Round", () => { game.move.select(Moves.ROUND, 0, BattlerIndex.ENEMY); game.move.select(Moves.ROUND, 1, BattlerIndex.ENEMY_2); - await game.forceEnemyMove(Moves.ROUND, BattlerIndex.PLAYER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.ROUND, BattlerIndex.PLAYER); + await game.move.selectEnemyMove(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]); diff --git a/test/moves/secret_power.test.ts b/test/moves/secret_power.test.ts index f6870c5ed1d..99945002b8d 100644 --- a/test/moves/secret_power.test.ts +++ b/test/moves/secret_power.test.ts @@ -49,13 +49,13 @@ describe("Moves - Secret Power", () => { // No Terrain + Biome.VOLCANO --> Burn game.move.select(Moves.SECRET_POWER); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("TurnEndPhase"); expect(enemyPokemon.status?.effect).toBe(StatusEffect.BURN); // Misty Terrain --> SpAtk -1 game.move.select(Moves.SECRET_POWER); - await game.forceEnemyMove(Moves.MISTY_TERRAIN); + await game.move.selectEnemyMove(Moves.MISTY_TERRAIN); await game.phaseInterceptor.to("TurnEndPhase"); expect(enemyPokemon.getStatStage(Stat.SPATK)).toBe(-1); }); diff --git a/test/moves/shell_trap.test.ts b/test/moves/shell_trap.test.ts index 313d02b4d73..2aa4712152d 100644 --- a/test/moves/shell_trap.test.ts +++ b/test/moves/shell_trap.test.ts @@ -38,7 +38,7 @@ describe("Moves - Shell Trap", () => { }); it("should activate after the user is hit by a physical attack", async () => { - await game.startBattle([Species.CHARIZARD, Species.TURTONATOR]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.TURTONATOR]); const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); @@ -61,7 +61,7 @@ describe("Moves - Shell Trap", () => { it("should fail if the user is only hit by special attacks", async () => { game.override.enemyMoveset([Moves.SWIFT]); - await game.startBattle([Species.CHARIZARD, Species.TURTONATOR]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.TURTONATOR]); const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); @@ -84,7 +84,7 @@ describe("Moves - Shell Trap", () => { it("should fail if the user isn't hit with any attack", async () => { game.override.enemyMoveset(Moves.SPLASH); - await game.startBattle([Species.CHARIZARD, Species.TURTONATOR]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.TURTONATOR]); const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); @@ -107,7 +107,7 @@ describe("Moves - Shell Trap", () => { it("should not activate from an ally's attack", async () => { game.override.enemyMoveset(Moves.SPLASH); - await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]); + await game.classicMode.startBattle([Species.BLASTOISE, Species.CHARIZARD]); const playerPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); @@ -131,7 +131,7 @@ describe("Moves - Shell Trap", () => { game.override.battleStyle("single"); vi.spyOn(allMoves[Moves.RAZOR_LEAF], "priority", "get").mockReturnValue(-4); - await game.startBattle([Species.CHARIZARD]); + await game.classicMode.startBattle([Species.CHARIZARD]); const playerPokemon = game.scene.getPlayerPokemon()!; const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/test/moves/speed_swap.test.ts b/test/moves/speed_swap.test.ts index 2b010885e34..f2be761b64e 100644 --- a/test/moves/speed_swap.test.ts +++ b/test/moves/speed_swap.test.ts @@ -34,7 +34,7 @@ describe("Moves - Speed Swap", () => { }); it("should swap the user's SPD and the target's SPD stats", async () => { - await game.startBattle([Species.INDEEDEE]); + await game.classicMode.startBattle([Species.INDEEDEE]); const player = game.scene.getPlayerPokemon()!; const enemy = game.scene.getEnemyPokemon()!; diff --git a/test/moves/spikes.test.ts b/test/moves/spikes.test.ts index 3dfa398d7d6..f37b54a2904 100644 --- a/test/moves/spikes.test.ts +++ b/test/moves/spikes.test.ts @@ -32,7 +32,7 @@ describe("Moves - Spikes", () => { }); it("should not damage the team that set them", async () => { - await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + await game.classicMode.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); game.move.select(Moves.SPIKES); await game.toNextTurn(); @@ -52,7 +52,7 @@ describe("Moves - Spikes", () => { it("should damage opposing pokemon that are forced to switch in", async () => { game.override.startingWave(5); - await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + await game.classicMode.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); game.move.select(Moves.SPIKES); await game.toNextTurn(); @@ -66,7 +66,7 @@ describe("Moves - Spikes", () => { it("should damage opposing pokemon that choose to switch in", async () => { game.override.startingWave(5); - await game.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); + await game.classicMode.startBattle([Species.MIGHTYENA, Species.POOCHYENA]); game.move.select(Moves.SPIKES); await game.toNextTurn(); diff --git a/test/moves/spit_up.test.ts b/test/moves/spit_up.test.ts index 7197d9b75c3..b11d74da64a 100644 --- a/test/moves/spit_up.test.ts +++ b/test/moves/spit_up.test.ts @@ -50,7 +50,7 @@ describe("Moves - Spit Up", () => { const stacksToSetup = 1; const expectedPower = 100; - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); @@ -72,7 +72,7 @@ describe("Moves - Spit Up", () => { const stacksToSetup = 2; const expectedPower = 200; - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); @@ -95,7 +95,7 @@ describe("Moves - Spit Up", () => { const stacksToSetup = 3; const expectedPower = 300; - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); @@ -117,7 +117,7 @@ describe("Moves - Spit Up", () => { }); it("fails without stacks", async () => { - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; @@ -138,7 +138,7 @@ describe("Moves - Spit Up", () => { describe("restores stat boosts granted by stacks", () => { it("decreases stats based on stored values (both boosts equal)", async () => { - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); @@ -169,7 +169,7 @@ describe("Moves - Spit Up", () => { }); it("decreases stats based on stored values (different boosts)", async () => { - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); diff --git a/test/moves/spotlight.test.ts b/test/moves/spotlight.test.ts index 2c4f652e408..e617682bdd5 100644 --- a/test/moves/spotlight.test.ts +++ b/test/moves/spotlight.test.ts @@ -39,8 +39,8 @@ describe("Moves - Spotlight", () => { game.move.select(Moves.SPOTLIGHT, 0, BattlerIndex.ENEMY); game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY_2); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase, false); @@ -56,8 +56,8 @@ describe("Moves - Spotlight", () => { game.move.select(Moves.SPOTLIGHT, 0, BattlerIndex.ENEMY); game.move.select(Moves.QUICK_ATTACK, 1, BattlerIndex.ENEMY_2); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.FOLLOW_ME); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.FOLLOW_ME); await game.phaseInterceptor.to("BerryPhase", false); diff --git a/test/moves/stockpile.test.ts b/test/moves/stockpile.test.ts index 4b8f51c32b2..196a1d8ca9a 100644 --- a/test/moves/stockpile.test.ts +++ b/test/moves/stockpile.test.ts @@ -39,7 +39,7 @@ describe("Moves - Stockpile", () => { }); it("gains a stockpile stack and raises user's DEF and SPDEF stat stages by 1 on each use, fails at max stacks (3)", async () => { - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const user = game.scene.getPlayerPokemon()!; @@ -83,7 +83,7 @@ describe("Moves - Stockpile", () => { }); it("gains a stockpile stack even if user's DEF and SPDEF stat stages are at +6", async () => { - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const user = game.scene.getPlayerPokemon()!; diff --git a/test/moves/swallow.test.ts b/test/moves/swallow.test.ts index d548522068b..cff9daaf97a 100644 --- a/test/moves/swallow.test.ts +++ b/test/moves/swallow.test.ts @@ -43,7 +43,7 @@ describe("Moves - Swallow", () => { const stacksToSetup = 1; const expectedHeal = 25; - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; vi.spyOn(pokemon, "getMaxHp").mockReturnValue(100); @@ -70,7 +70,7 @@ describe("Moves - Swallow", () => { const stacksToSetup = 2; const expectedHeal = 50; - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; vi.spyOn(pokemon, "getMaxHp").mockReturnValue(100); @@ -98,7 +98,7 @@ describe("Moves - Swallow", () => { const stacksToSetup = 3; const expectedHeal = 100; - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; vi.spyOn(pokemon, "getMaxHp").mockReturnValue(100); @@ -125,7 +125,7 @@ describe("Moves - Swallow", () => { }); it("fails without stacks", async () => { - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; @@ -144,7 +144,7 @@ describe("Moves - Swallow", () => { describe("restores stat stage boosts granted by stacks", () => { it("decreases stats based on stored values (both boosts equal)", async () => { - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); @@ -173,7 +173,7 @@ describe("Moves - Swallow", () => { }); it("lower stat stages based on stored values (different boosts)", async () => { - await game.startBattle([Species.ABOMASNOW]); + await game.classicMode.startBattle([Species.ABOMASNOW]); const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); diff --git a/test/moves/tackle.test.ts b/test/moves/tackle.test.ts index 162836cd181..5fd8ba589fc 100644 --- a/test/moves/tackle.test.ts +++ b/test/moves/tackle.test.ts @@ -36,7 +36,7 @@ describe("Moves - Tackle", () => { it("TACKLE against ghost", async () => { const moveToUse = Moves.TACKLE; game.override.enemySpecies(Species.GENGAR); - await game.startBattle([Species.MIGHTYENA]); + await game.classicMode.startBattle([Species.MIGHTYENA]); const hpOpponent = game.scene.currentBattle.enemyParty[0].hp; game.move.select(moveToUse); await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnEndPhase); @@ -46,7 +46,7 @@ describe("Moves - Tackle", () => { it("TACKLE against not resistant", async () => { const moveToUse = Moves.TACKLE; - await game.startBattle([Species.MIGHTYENA]); + await game.classicMode.startBattle([Species.MIGHTYENA]); game.scene.currentBattle.enemyParty[0].stats[Stat.DEF] = 50; game.scene.getPlayerParty()[0].stats[Stat.ATK] = 50; diff --git a/test/moves/tail_whip.test.ts b/test/moves/tail_whip.test.ts index 2d3ade2691d..d15864dd671 100644 --- a/test/moves/tail_whip.test.ts +++ b/test/moves/tail_whip.test.ts @@ -36,7 +36,7 @@ describe("Moves - Tail whip", () => { it("should lower DEF stat stage by 1", async () => { const moveToUse = Moves.TAIL_WHIP; - await game.startBattle([Species.MIGHTYENA, Species.MIGHTYENA]); + await game.classicMode.startBattle([Species.MIGHTYENA, Species.MIGHTYENA]); const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(0); diff --git a/test/moves/taunt.test.ts b/test/moves/taunt.test.ts index e0bb13c61fb..bcb4789f888 100644 --- a/test/moves/taunt.test.ts +++ b/test/moves/taunt.test.ts @@ -37,7 +37,7 @@ describe("Moves - Taunt", () => { // First turn, Player Pokemon succeeds using Growl without Taunt game.move.select(Moves.GROWL); - await game.forceEnemyMove(Moves.TAUNT); + await game.move.selectEnemyMove(Moves.TAUNT); await game.toNextTurn(); const move1 = playerPokemon.getLastXMoves(1)[0]!; expect(move1.move).toBe(Moves.GROWL); @@ -46,7 +46,7 @@ describe("Moves - Taunt", () => { // Second turn, Taunt forces Struggle to occur game.move.select(Moves.GROWL); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const move2 = playerPokemon.getLastXMoves(1)[0]!; expect(move2.move).toBe(Moves.STRUGGLE); diff --git a/test/moves/telekinesis.test.ts b/test/moves/telekinesis.test.ts index e889926b5c8..e5a21e915fa 100644 --- a/test/moves/telekinesis.test.ts +++ b/test/moves/telekinesis.test.ts @@ -106,7 +106,7 @@ describe("Moves - Telekinesis", () => { const enemyOpponent = game.scene.getEnemyPokemon()!; game.move.select(Moves.TELEKINESIS); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to("TurnEndPhase"); expect(enemyOpponent.getTag(BattlerTagType.TELEKINESIS)).toBeDefined(); expect(enemyOpponent.getTag(BattlerTagType.FLOATING)).toBeDefined(); @@ -114,7 +114,7 @@ describe("Moves - Telekinesis", () => { await game.toNextTurn(); vi.spyOn(allMoves[Moves.MUD_SHOT], "accuracy", "get").mockReturnValue(0); game.move.select(Moves.MUD_SHOT); - await game.forceEnemyMove(Moves.INGRAIN); + await game.move.selectEnemyMove(Moves.INGRAIN); await game.phaseInterceptor.to("TurnEndPhase"); expect(enemyOpponent.getTag(BattlerTagType.TELEKINESIS)).toBeDefined(); expect(enemyOpponent.getTag(BattlerTagType.INGRAIN)).toBeDefined(); diff --git a/test/moves/thousand_arrows.test.ts b/test/moves/thousand_arrows.test.ts index 7259fda8560..39bc8617767 100644 --- a/test/moves/thousand_arrows.test.ts +++ b/test/moves/thousand_arrows.test.ts @@ -33,7 +33,7 @@ describe("Moves - Thousand Arrows", () => { }); it("move should hit and ground Flying-type targets", async () => { - await game.startBattle([Species.ILLUMISE]); + await game.classicMode.startBattle([Species.ILLUMISE]); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -53,7 +53,7 @@ describe("Moves - Thousand Arrows", () => { game.override.enemySpecies(Species.SNORLAX); game.override.enemyAbility(Abilities.LEVITATE); - await game.startBattle([Species.ILLUMISE]); + await game.classicMode.startBattle([Species.ILLUMISE]); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -72,7 +72,7 @@ describe("Moves - Thousand Arrows", () => { it("move should hit and ground targets under the effects of Magnet Rise", async () => { game.override.enemySpecies(Species.SNORLAX); - await game.startBattle([Species.ILLUMISE]); + await game.classicMode.startBattle([Species.ILLUMISE]); const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/test/moves/thunder_wave.test.ts b/test/moves/thunder_wave.test.ts index abfb5828d3b..326d7ecbdc0 100644 --- a/test/moves/thunder_wave.test.ts +++ b/test/moves/thunder_wave.test.ts @@ -34,7 +34,7 @@ describe("Moves - Thunder Wave", () => { it("paralyzes non-statused Pokemon that are not Ground types", async () => { game.override.enemySpecies(Species.MAGIKARP); - await game.startBattle(); + await game.classicMode.startBattle(); const enemyPokemon: EnemyPokemon = game.scene.getEnemyPokemon()!; @@ -47,7 +47,7 @@ describe("Moves - Thunder Wave", () => { it("does not paralyze if the Pokemon is a Ground-type", async () => { game.override.enemySpecies(Species.DIGLETT); - await game.startBattle(); + await game.classicMode.startBattle(); const enemyPokemon: EnemyPokemon = game.scene.getEnemyPokemon()!; @@ -60,7 +60,7 @@ describe("Moves - Thunder Wave", () => { it("does not paralyze if the Pokemon already has a status effect", async () => { game.override.enemySpecies(Species.MAGIKARP).enemyStatusEffect(StatusEffect.BURN); - await game.startBattle(); + await game.classicMode.startBattle(); const enemyPokemon: EnemyPokemon = game.scene.getEnemyPokemon()!; @@ -73,7 +73,7 @@ describe("Moves - Thunder Wave", () => { it("affects Ground types if the user has Normalize", async () => { game.override.ability(Abilities.NORMALIZE).enemySpecies(Species.DIGLETT); - await game.startBattle(); + await game.classicMode.startBattle(); const enemyPokemon: EnemyPokemon = game.scene.getEnemyPokemon()!; @@ -86,7 +86,7 @@ describe("Moves - Thunder Wave", () => { it("does not affect Ghost types if the user has Normalize", async () => { game.override.ability(Abilities.NORMALIZE).enemySpecies(Species.HAUNTER); - await game.startBattle(); + await game.classicMode.startBattle(); const enemyPokemon: EnemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/test/moves/torment.test.ts b/test/moves/torment.test.ts index d06837d2806..d11de46bf10 100644 --- a/test/moves/torment.test.ts +++ b/test/moves/torment.test.ts @@ -40,7 +40,7 @@ describe("Moves - Torment", () => { // First turn, Player Pokemon uses Tackle successfully game.move.select(Moves.TACKLE); - await game.forceEnemyMove(Moves.TORMENT); + await game.move.selectEnemyMove(Moves.TORMENT); await game.toNextTurn(); const move1 = playerPokemon.getLastXMoves(1)[0]!; expect(move1.move).toBe(Moves.TACKLE); @@ -49,14 +49,14 @@ describe("Moves - Torment", () => { // Second turn, Torment forces Struggle to occur game.move.select(Moves.TACKLE); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); const move2 = playerPokemon.getLastXMoves(1)[0]!; expect(move2.move).toBe(Moves.STRUGGLE); // Third turn, Tackle can be used. game.move.select(Moves.TACKLE); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.phaseInterceptor.to(TurnEndPhase); const move3 = playerPokemon.getLastXMoves(1)[0]!; expect(move3.move).toBe(Moves.TACKLE); diff --git a/test/moves/whirlwind.test.ts b/test/moves/whirlwind.test.ts index 67ffb77612c..3558f968c66 100644 --- a/test/moves/whirlwind.test.ts +++ b/test/moves/whirlwind.test.ts @@ -51,7 +51,7 @@ describe("Moves - Whirlwind", () => { const staraptor = game.scene.getPlayerPokemon()!; game.move.select(move); - await game.forceEnemyMove(Moves.WHIRLWIND); + await game.move.selectEnemyMove(Moves.WHIRLWIND); await game.phaseInterceptor.to("BerryPhase", false); @@ -69,7 +69,7 @@ describe("Moves - Whirlwind", () => { return min; }); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.WHIRLWIND); + await game.move.selectEnemyMove(Moves.WHIRLWIND); await game.toNextTurn(); expect(bulbasaur.isOnField()).toBe(false); @@ -81,7 +81,7 @@ describe("Moves - Whirlwind", () => { return min + 1; }); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.WHIRLWIND); + await game.move.selectEnemyMove(Moves.WHIRLWIND); await game.toNextTurn(); expect(bulbasaur.isOnField()).toBe(false); @@ -101,7 +101,7 @@ describe("Moves - Whirlwind", () => { return min; }); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.WHIRLWIND); + await game.move.selectEnemyMove(Moves.WHIRLWIND); await game.toNextTurn(); expect(lapras.isOnField()).toBe(false); @@ -120,7 +120,7 @@ describe("Moves - Whirlwind", () => { eevee.status = new Status(StatusEffect.FAINT); expect(eevee.isFainted()).toBe(true); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); // Turn 2: Mock an RNG call that would normally call for switching to Eevee, but it is fainted @@ -128,7 +128,7 @@ describe("Moves - Whirlwind", () => { return min; }); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.WHIRLWIND); + await game.move.selectEnemyMove(Moves.WHIRLWIND); await game.toNextTurn(); expect(lapras.isOnField()).toBe(false); @@ -147,7 +147,7 @@ describe("Moves - Whirlwind", () => { eevee.status = new Status(StatusEffect.FAINT); expect(eevee.isFainted()).toBe(true); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); // Turn 2: Mock an RNG call that would normally call for switching to Eevee, but it is fainted @@ -155,7 +155,7 @@ describe("Moves - Whirlwind", () => { return min; }); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.WHIRLWIND); + await game.move.selectEnemyMove(Moves.WHIRLWIND); await game.toNextTurn(); expect(lapras.isOnField()).toBe(true); @@ -184,7 +184,7 @@ describe("Moves - Whirlwind", () => { // Player uses Whirlwind; opponent uses Splash game.move.select(Moves.WHIRLWIND); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); // Verify that the failure message is displayed for Whirlwind @@ -214,8 +214,8 @@ describe("Moves - Whirlwind", () => { game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH); - await game.forceEnemyMove(Moves.MEMENTO); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.MEMENTO); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); // Get the enemy pokemon id so we can check if is the same after switch. @@ -225,8 +225,8 @@ describe("Moves - Whirlwind", () => { game.move.select(Moves.WHIRLWIND, 0, BattlerIndex.ENEMY); game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.SPLASH); await game.toNextTurn(); diff --git a/test/moves/wide_guard.test.ts b/test/moves/wide_guard.test.ts index 85ebad806d7..08357476e5e 100644 --- a/test/moves/wide_guard.test.ts +++ b/test/moves/wide_guard.test.ts @@ -38,7 +38,7 @@ describe("Moves - Wide Guard", () => { }); test("should protect the user and allies from multi-target attack moves", async () => { - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); @@ -56,7 +56,7 @@ describe("Moves - Wide Guard", () => { test("should protect the user and allies from multi-target status moves", async () => { game.override.enemyMoveset([Moves.GROWL]); - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); @@ -74,7 +74,7 @@ describe("Moves - Wide Guard", () => { test("should not protect the user and allies from single-target moves", async () => { game.override.enemyMoveset([Moves.TACKLE]); - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); @@ -92,7 +92,7 @@ describe("Moves - Wide Guard", () => { test("should protect the user from its ally's multi-target move", async () => { game.override.enemyMoveset([Moves.SPLASH]); - await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); const leadPokemon = game.scene.getPlayerField(); const enemyPokemon = game.scene.getEnemyField(); diff --git a/test/phases/learn-move-phase.test.ts b/test/phases/learn-move-phase.test.ts index 019b833d386..b8b718a9669 100644 --- a/test/phases/learn-move-phase.test.ts +++ b/test/phases/learn-move-phase.test.ts @@ -56,9 +56,7 @@ describe("Learn Move Phase", () => { game.scene.ui.processInput(Button.ACTION); }); game.onNextPrompt("LearnMovePhase", UiMode.SUMMARY, () => { - for (let x = 0; x < moveSlotNum; x++) { - game.scene.ui.processInput(Button.DOWN); - } + game.scene.ui.setCursor(moveSlotNum); game.scene.ui.processInput(Button.ACTION); }); await game.phaseInterceptor.to(LearnMovePhase); @@ -88,9 +86,7 @@ describe("Learn Move Phase", () => { game.scene.ui.processInput(Button.ACTION); }); game.onNextPrompt("LearnMovePhase", UiMode.SUMMARY, () => { - for (let x = 0; x < 4; x++) { - game.scene.ui.processInput(Button.DOWN); // moves down 4 times to the 5th move slot - } + game.scene.ui.setCursor(4); game.scene.ui.processInput(Button.ACTION); }); game.onNextPrompt("LearnMovePhase", UiMode.CONFIRM, () => { @@ -102,64 +98,4 @@ describe("Learn Move Phase", () => { expect(bulbasaur.level).toBeGreaterThanOrEqual(levelReq); expect(bulbasaur.getMoveset().map(m => m?.moveId)).toEqual(prevMoveset); }); - - it("macro should add moves in free slots normally", async () => { - await game.classicMode.startBattle([Species.BULBASAUR]); - const bulbasaur = game.scene.getPlayerPokemon()!; - - game.move.changeMoveset(bulbasaur, [Moves.SPLASH, Moves.ABSORB, Moves.ACID]); - game.move.select(Moves.SPLASH); - await game.move.learnMove(Moves.SACRED_FIRE, 0, 1); - expect(bulbasaur.getMoveset().map(m => m?.moveId)).toEqual([ - Moves.SPLASH, - Moves.ABSORB, - Moves.ACID, - Moves.SACRED_FIRE, - ]); - }); - - it("macro should replace moves", async () => { - await game.classicMode.startBattle([Species.BULBASAUR]); - const bulbasaur = game.scene.getPlayerPokemon()!; - - game.move.changeMoveset(bulbasaur, [Moves.SPLASH, Moves.ABSORB, Moves.ACID, Moves.VINE_WHIP]); - game.move.select(Moves.SPLASH); - await game.move.learnMove(Moves.SACRED_FIRE, 0, 1); - expect(bulbasaur.getMoveset().map(m => m?.moveId)).toEqual([ - Moves.SPLASH, - Moves.SACRED_FIRE, - Moves.ACID, - Moves.VINE_WHIP, - ]); - }); - - it("macro should allow for cancelling move learning", async () => { - await game.classicMode.startBattle([Species.BULBASAUR]); - const bulbasaur = game.scene.getPlayerPokemon()!; - - game.move.changeMoveset(bulbasaur, [Moves.SPLASH, Moves.ABSORB, Moves.ACID, Moves.VINE_WHIP]); - game.move.select(Moves.SPLASH); - await game.move.learnMove(Moves.SACRED_FIRE, 0, 4); - expect(bulbasaur.getMoveset().map(m => m?.moveId)).toEqual([ - Moves.SPLASH, - Moves.ABSORB, - Moves.ACID, - Moves.VINE_WHIP, - ]); - }); - - it("macro works on off-field party members", async () => { - await game.classicMode.startBattle([Species.BULBASAUR, Species.SQUIRTLE]); - const squirtle = game.scene.getPlayerParty()[1]!; - - game.move.changeMoveset(squirtle, [Moves.SPLASH, Moves.WATER_GUN, Moves.FREEZE_DRY, Moves.GROWL]); - game.move.select(Moves.TACKLE); - await game.move.learnMove(Moves.SHELL_SMASH, 1, 0); - expect(squirtle.getMoveset().map(m => m?.moveId)).toEqual([ - Moves.SHELL_SMASH, - Moves.WATER_GUN, - Moves.FREEZE_DRY, - Moves.GROWL, - ]); - }); }); diff --git a/test/testUtils/gameManager.ts b/test/testUtils/gameManager.ts index 8dd90decf1a..39b6000e308 100644 --- a/test/testUtils/gameManager.ts +++ b/test/testUtils/gameManager.ts @@ -1,16 +1,15 @@ import { updateUserInfo } from "#app/account"; import { BattlerIndex } from "#app/battle"; import BattleScene from "#app/battle-scene"; -import { getMoveTargets } from "#app/data/moves/move"; import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import Trainer from "#app/field/trainer"; import { GameModes, getGameMode } from "#app/game-mode"; +import { globalScene } from "#app/global-scene"; import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type"; import overrides from "#app/overrides"; import { CheckSwitchPhase } from "#app/phases/check-switch-phase"; import { CommandPhase } from "#app/phases/command-phase"; import { EncounterPhase } from "#app/phases/encounter-phase"; -import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; import { FaintPhase } from "#app/phases/faint-phase"; import { LoginPhase } from "#app/phases/login-phase"; import { MovePhase } from "#app/phases/move-phase"; @@ -22,42 +21,40 @@ import { TitlePhase } from "#app/phases/title-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { TurnStartPhase } from "#app/phases/turn-start-phase"; -import ErrorInterceptor from "#test/testUtils/errorInterceptor"; -import type InputsHandler from "#test/testUtils/inputsHandler"; import type BallUiHandler from "#app/ui/ball-ui-handler"; import type BattleMessageUiHandler from "#app/ui/battle-message-ui-handler"; import type CommandUiHandler from "#app/ui/command-ui-handler"; import type ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; import type PartyUiHandler from "#app/ui/party-ui-handler"; +import type StarterSelectUiHandler from "#app/ui/starter-select-ui-handler"; import type TargetSelectUiHandler from "#app/ui/target-select-ui-handler"; -import { UiMode } from "#enums/ui-mode"; import { isNullOrUndefined } from "#app/utils/common"; -import { BattleStyle } from "#enums/battle-style"; import { Button } from "#enums/buttons"; import { ExpGainsSpeed } from "#enums/exp-gains-speed"; import { ExpNotification } from "#enums/exp-notification"; -import type { Moves } from "#enums/moves"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { PlayerGender } from "#enums/player-gender"; import type { Species } from "#enums/species"; +import { UiMode } from "#enums/ui-mode"; +import ErrorInterceptor from "#test/testUtils/errorInterceptor"; import { generateStarter, waitUntil } from "#test/testUtils/gameManagerUtils"; import GameWrapper from "#test/testUtils/gameWrapper"; import { ChallengeModeHelper } from "#test/testUtils/helpers/challengeModeHelper"; import { ClassicModeHelper } from "#test/testUtils/helpers/classicModeHelper"; import { DailyModeHelper } from "#test/testUtils/helpers/dailyModeHelper"; +import { FieldHelper } from "#test/testUtils/helpers/field-helper"; import { ModifierHelper } from "#test/testUtils/helpers/modifiersHelper"; import { MoveHelper } from "#test/testUtils/helpers/moveHelper"; import { OverridesHelper } from "#test/testUtils/helpers/overridesHelper"; import { ReloadHelper } from "#test/testUtils/helpers/reloadHelper"; import { SettingsHelper } from "#test/testUtils/helpers/settingsHelper"; +import type InputsHandler from "#test/testUtils/inputsHandler"; +import { MockFetch } from "#test/testUtils/mocks/mockFetch"; import PhaseInterceptor from "#test/testUtils/phaseInterceptor"; import TextInterceptor from "#test/testUtils/TextInterceptor"; import { AES, enc } from "crypto-js"; import fs from "node:fs"; import { expect, vi } from "vitest"; -import { globalScene } from "#app/global-scene"; -import type StarterSelectUiHandler from "#app/ui/starter-select-ui-handler"; -import { MockFetch } from "#test/testUtils/mocks/mockFetch"; /** * Class to manage the game state and transitions between phases. @@ -76,6 +73,7 @@ export default class GameManager { public readonly settings: SettingsHelper; public readonly reload: ReloadHelper; public readonly modifiers: ModifierHelper; + public readonly field: FieldHelper; /** * Creates an instance of GameManager. @@ -123,6 +121,7 @@ export default class GameManager { this.settings = new SettingsHelper(this); this.reload = new ReloadHelper(this); this.modifiers = new ModifierHelper(this); + this.field = new FieldHelper(this); this.override.sanitizeOverrides(); // Disables Mystery Encounters on all tests (can be overridden at test level) @@ -271,42 +270,6 @@ export default class GameManager { } } - /** - * @deprecated Use `game.classicMode.startBattle()` or `game.dailyMode.startBattle()` instead - * - * Transitions to the start of a battle. - * @param species - Optional array of species to start the battle with. - * @returns A promise that resolves when the battle is started. - */ - async startBattle(species?: Species[]) { - await this.classicMode.runToSummon(species); - - if (this.scene.battleStyle === BattleStyle.SWITCH) { - this.onNextPrompt( - "CheckSwitchPhase", - UiMode.CONFIRM, - () => { - this.setMode(UiMode.MESSAGE); - this.endPhase(); - }, - () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase), - ); - - this.onNextPrompt( - "CheckSwitchPhase", - UiMode.CONFIRM, - () => { - this.setMode(UiMode.MESSAGE); - this.endPhase(); - }, - () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase), - ); - } - - await this.phaseInterceptor.to(CommandPhase); - console.log("==================[New Turn]=================="); - } - /** * Emulate a player's target selection after a move is chosen, usually called automatically by {@linkcode MoveHelper.select}. * Will trigger during the next {@linkcode SelectTargetPhase} @@ -377,35 +340,6 @@ export default class GameManager { ); } - /** - * Forces the next enemy selecting a move to use the given move in its moveset against the - * given target (if applicable). - * @param moveId - The {@linkcode Moves | move} the enemy will use - * @param target - The {@linkcode BattlerIndex} of the target against which the enemy will use the given move; - * will use normal target selection priorities if omitted. - */ - async forceEnemyMove(moveId: Moves, target?: BattlerIndex) { - // Wait for the next EnemyCommandPhase to start - await this.phaseInterceptor.to(EnemyCommandPhase, false); - const enemy = this.scene.getEnemyField()[(this.scene.getCurrentPhase() as EnemyCommandPhase).getFieldIndex()]; - const legalTargets = getMoveTargets(enemy, moveId); - - vi.spyOn(enemy, "getNextMove").mockReturnValueOnce({ - move: moveId, - targets: - target !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target) - ? [target] - : enemy.getNextTargets(moveId), - }); - - /** - * Run the EnemyCommandPhase to completion. - * This allows this function to be called consecutively to - * force a move for each enemy in a double battle. - */ - await this.phaseInterceptor.to(EnemyCommandPhase); - } - forceEnemyToSwitch() { const originalMatchupScore = Trainer.prototype.getPartyMemberMatchupScores; Trainer.prototype.getPartyMemberMatchupScores = () => { @@ -417,9 +351,15 @@ export default class GameManager { }; } - /** Transition to the next upcoming {@linkcode CommandPhase} */ + /** Transition to the first {@linkcode CommandPhase} of the next turn. */ async toNextTurn() { - await this.phaseInterceptor.to(CommandPhase); + await this.phaseInterceptor.to("TurnInitPhase"); + await this.phaseInterceptor.to("CommandPhase"); + } + + /** Transition to the {@linkcode TurnEndPhase | end of the current turn}. */ + async toEndOfTurn() { + await this.phaseInterceptor.to("TurnEndPhase"); } /** @@ -541,8 +481,8 @@ export default class GameManager { } /** - * Select a pokemon from the party menu during the given phase. - * Only really handles the basic case of "navigate to party slot and press Action twice" - + * Select a pokemon from the party menu during the given phase. + * Only really handles the basic case of "navigate to party slot and press Action twice" - * any menus that come up afterwards are ignored and must be handled separately by the caller. * @param slot - The 0-indexed position of the pokemon in your party to switch to * @param inPhase - Which phase to expect the selection to occur in. Defaults to `SwitchPhase` diff --git a/test/testUtils/helpers/field-helper.ts b/test/testUtils/helpers/field-helper.ts new file mode 100644 index 00000000000..6d762853cad --- /dev/null +++ b/test/testUtils/helpers/field-helper.ts @@ -0,0 +1,87 @@ +// -- start tsdoc imports -- +// biome-ignore lint/correctness/noUnusedImports: TSDoc import +import type { globalScene } from "#app/global-scene"; +// -- end tsdoc imports -- + +import type { BattlerIndex } from "#app/battle"; +import type { Ability } from "#app/data/abilities/ability-class"; +import { allAbilities } from "#app/data/data-lists"; +import type Pokemon from "#app/field/pokemon"; +import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; +import type { Abilities } from "#enums/abilities"; +import type { PokemonType } from "#enums/pokemon-type"; +import { Stat } from "#enums/stat"; +import { GameManagerHelper } from "#test/testUtils/helpers/gameManagerHelper"; +import { expect, type MockInstance, vi } from "vitest"; + +/** Helper to manage pokemon */ +export class FieldHelper extends GameManagerHelper { + /** + * Passthrough for {@linkcode globalScene.getPlayerPokemon} that adds an `undefined` check for + * the Pokemon so that the return type for the function doesn't have `undefined`. + * This removes the need to add a `!` like when calling `game.scene.getPlayerPokemon()!`. + * @param includeSwitching Whether a pokemon that is currently switching out is valid, default `true` + * @returns The first {@linkcode PlayerPokemon} that is {@linkcode globalScene.getPlayerField on the field} + * and {@linkcode PlayerPokemon.isActive is active} + * (aka {@linkcode PlayerPokemon.isAllowedInBattle is allowed in battle}). + */ + public getPlayerPokemon(includeSwitching = true): PlayerPokemon { + const pokemon = this.game.scene.getPlayerPokemon(includeSwitching); + expect(pokemon).toBeDefined(); + return pokemon!; + } + + /** + * Passthrough for {@linkcode globalScene.getEnemyPokemon} that adds an `undefined` check for + * the Pokemon so that the return type for the function doesn't have `undefined`. + * This removes the need to add a `!` like when calling `game.scene.getEnemyPokemon()!`. + * @param includeSwitching Whether a pokemon that is currently switching out is valid, default `true` + * @returns The first {@linkcode EnemyPokemon} that is {@linkcode globalScene.getEnemyField on the field} + * and {@linkcode EnemyPokemon.isActive is active} + * (aka {@linkcode EnemyPokemon.isAllowedInBattle is allowed in battle}). + */ + public getEnemyPokemon(includeSwitching = true): EnemyPokemon { + const pokemon = this.game.scene.getEnemyPokemon(includeSwitching); + expect(pokemon).toBeDefined(); + return pokemon!; + } + + /** + * @returns The {@linkcode BattlerIndex | indexes} of Pokemon on the field in order of decreasing Speed. + * Speed ties are returned in increasing order of index. + * + * Note: Trick Room does not modify the speed of Pokemon on the field. + */ + public getSpeedOrder(): BattlerIndex[] { + return this.game.scene + .getField(true) + .sort((pA, pB) => pB.getEffectiveStat(Stat.SPD) - pA.getEffectiveStat(Stat.SPD)) + .map(p => p.getBattlerIndex()); + } + + /** + * Mocks a pokemon's ability, overriding its existing ability (takes precedence over global overrides) + * @param pokemon - The pokemon to mock the ability of + * @param ability - The ability to be mocked + * @returns A {@linkcode MockInstance} object + * @see {@linkcode vi.spyOn} + * @see https://vitest.dev/api/mock#mockreturnvalue + */ + public mockAbility(pokemon: Pokemon, ability: Abilities): MockInstance<(baseOnly?: boolean) => Ability> { + return vi.spyOn(pokemon, "getAbility").mockReturnValue(allAbilities[ability]); + } + + /** + * Forces a pokemon to be terastallized. Defaults to the pokemon's primary type if not specified. + * + * This function only mocks the Pokemon's tera-related variables; it does NOT activate any tera-related abilities. + * + * @param pokemon - The pokemon to terastallize. + * @param teraType - (optional) The {@linkcode PokemonType} to terastallize it as. + */ + public forceTera(pokemon: Pokemon, teraType?: PokemonType): void { + vi.spyOn(pokemon, "isTerastallized", "get").mockReturnValue(true); + teraType ??= pokemon.getSpeciesForm(true).type1; + vi.spyOn(pokemon, "teraType", "get").mockReturnValue(teraType); + } +} diff --git a/test/testUtils/helpers/moveHelper.ts b/test/testUtils/helpers/moveHelper.ts index 269cf65ea56..b3cdffeb636 100644 --- a/test/testUtils/helpers/moveHelper.ts +++ b/test/testUtils/helpers/moveHelper.ts @@ -1,14 +1,14 @@ import type { BattlerIndex } from "#app/battle"; -import { Button } from "#app/enums/buttons"; +import { getMoveTargets } from "#app/data/moves/move"; import type Pokemon from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon"; import Overrides from "#app/overrides"; import type { CommandPhase } from "#app/phases/command-phase"; -import { LearnMovePhase } from "#app/phases/learn-move-phase"; +import type { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Command } from "#app/ui/command-ui-handler"; -import { UiMode } from "#enums/ui-mode"; import { Moves } from "#enums/moves"; +import { UiMode } from "#enums/ui-mode"; import { getMovePosition } from "#test/testUtils/gameManagerUtils"; import { GameManagerHelper } from "#test/testUtils/helpers/gameManagerHelper"; import { vi } from "vitest"; @@ -92,6 +92,35 @@ export class MoveHelper extends GameManagerHelper { } } + /** + * Modifies a player pokemon's moveset to contain only the selected move and then + * selects it to be used during the next {@linkcode CommandPhase}. + * + * Warning: Will disable the player moveset override if it is enabled! + * + * Note: If you need to check for changes in the player's moveset as part of the test, it may be + * best to use {@linkcode changeMoveset} and {@linkcode select} instead. + * @param moveId - the move to use + * @param pkmIndex - the pokemon index. Relevant for double-battles only (defaults to 0) + * @param targetIndex - (optional) The {@linkcode BattlerIndex} of the Pokemon to target for single-target moves, or `null` if a manual call to `selectTarget()` is required + * @param useTera - If `true`, the Pokemon also chooses to Terastallize. This does not require a Tera Orb. Default: `false`. + */ + public use(moveId: Moves, pkmIndex: 0 | 1 = 0, targetIndex?: BattlerIndex | null, useTera = false): void { + if ([Overrides.MOVESET_OVERRIDE].flat().length > 0) { + vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([]); + console.warn("Warning: `use` overwrites the Pokemon's moveset and disables the player moveset override!"); + } + + const pokemon = this.game.scene.getPlayerField()[pkmIndex]; + pokemon.moveset = [new PokemonMove(moveId)]; + + if (useTera) { + this.selectWithTera(moveId, pkmIndex, targetIndex); + return; + } + this.select(moveId, pkmIndex, targetIndex); + } + /** * Forces the Paralysis or Freeze status to activate on the next move by temporarily mocking {@linkcode Overrides.STATUS_ACTIVATION_OVERRIDE}, * advancing to the next `MovePhase`, and then resetting the override to `null` @@ -133,37 +162,73 @@ export class MoveHelper extends GameManagerHelper { } /** - * Simulates learning a move for a player pokemon. - * @param move The {@linkcode Moves} being learnt - * @param partyIndex The party position of the {@linkcode PlayerPokemon} learning the move (defaults to 0) - * @param moveSlotIndex The INDEX (0-4) of the move slot to replace if existent move slots are full; - * defaults to 0 (first slot) and 4 aborts the procedure - * @returns a promise that resolves once the move has been successfully learnt + * Forces the next enemy selecting a move to use the given move in its moveset + * against the given target (if applicable). + * @param moveId The {@linkcode MoveId | move} the enemy will use + * @param target (Optional) the {@linkcode BattlerIndex | target} which the enemy will use the given move against */ - public async learnMove(move: Moves | number, partyIndex = 0, moveSlotIndex = 0) { - return new Promise(async (resolve, reject) => { - this.game.scene.pushPhase(new LearnMovePhase(partyIndex, move)); + public async selectEnemyMove(moveId: Moves, target?: BattlerIndex) { + // Wait for the next EnemyCommandPhase to start + await this.game.phaseInterceptor.to("EnemyCommandPhase", false); + const enemy = + this.game.scene.getEnemyField()[(this.game.scene.getCurrentPhase() as EnemyCommandPhase).getFieldIndex()]; + const legalTargets = getMoveTargets(enemy, moveId); - // if slots are full, queue up inputs to replace existing moves - if (this.game.scene.getPlayerParty()[partyIndex].moveset.filter(m => m).length === 4) { - this.game.onNextPrompt("LearnMovePhase", UiMode.CONFIRM, () => { - this.game.scene.ui.processInput(Button.ACTION); // "Should a move be forgotten and replaced with XXX?" - }); - this.game.onNextPrompt("LearnMovePhase", UiMode.SUMMARY, () => { - for (let x = 0; x < (moveSlotIndex ?? 0); x++) { - this.game.scene.ui.processInput(Button.DOWN); // Scrolling in summary pane to move position - } - this.game.scene.ui.processInput(Button.ACTION); - if (moveSlotIndex === 4) { - this.game.onNextPrompt("LearnMovePhase", UiMode.CONFIRM, () => { - this.game.scene.ui.processInput(Button.ACTION); // "Give up on learning XXX?" - }); - } - }); - } - - await this.game.phaseInterceptor.to(LearnMovePhase).catch(e => reject(e)); - resolve(); + vi.spyOn(enemy, "getNextMove").mockReturnValueOnce({ + move: moveId, + targets: + target !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target) + ? [target] + : enemy.getNextTargets(moveId), }); + + /** + * Run the EnemyCommandPhase to completion. + * This allows this function to be called consecutively to + * force a move for each enemy in a double battle. + */ + await this.game.phaseInterceptor.to("EnemyCommandPhase"); + } + + /** + * Forces the next enemy selecting a move to use the given move against the given target (if applicable). + * + * Warning: Overwrites the pokemon's moveset and disables the moveset override! + * + * Note: If you need to check for changes in the enemy's moveset as part of the test, it may be + * best to use {@linkcode changeMoveset} and {@linkcode selectEnemyMove} instead. + * @param moveId The {@linkcode MoveId | move} the enemy will use + * @param target (Optional) the {@linkcode BattlerIndex | target} which the enemy will use the given move against + */ + public async forceEnemyMove(moveId: Moves, target?: BattlerIndex) { + // Wait for the next EnemyCommandPhase to start + await this.game.phaseInterceptor.to("EnemyCommandPhase", false); + + const enemy = + this.game.scene.getEnemyField()[(this.game.scene.getCurrentPhase() as EnemyCommandPhase).getFieldIndex()]; + + if ([Overrides.OPP_MOVESET_OVERRIDE].flat().length > 0) { + vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([]); + console.warn( + "Warning: `forceEnemyMove` overwrites the Pokemon's moveset and disables the enemy moveset override!", + ); + } + enemy.moveset = [new PokemonMove(moveId)]; + const legalTargets = getMoveTargets(enemy, moveId); + + vi.spyOn(enemy, "getNextMove").mockReturnValueOnce({ + move: moveId, + targets: + target !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target) + ? [target] + : enemy.getNextTargets(moveId), + }); + + /** + * Run the EnemyCommandPhase to completion. + * This allows this function to be called consecutively to + * force a move for each enemy in a double battle. + */ + await this.game.phaseInterceptor.to("EnemyCommandPhase"); } } diff --git a/test/testUtils/mocks/mockGameObject.ts b/test/testUtils/mocks/mockGameObject.ts index 4c243ec9ca1..1e156b99d21 100644 --- a/test/testUtils/mocks/mockGameObject.ts +++ b/test/testUtils/mocks/mockGameObject.ts @@ -1,3 +1,7 @@ export interface MockGameObject { name: string; + active: boolean; + destroy?(): void; + setActive(active: boolean): this; + setName(name: string): this; } diff --git a/test/testUtils/mocks/mockVideoGameObject.ts b/test/testUtils/mocks/mockVideoGameObject.ts index 65a5c37b244..1789229b1c7 100644 --- a/test/testUtils/mocks/mockVideoGameObject.ts +++ b/test/testUtils/mocks/mockVideoGameObject.ts @@ -3,11 +3,20 @@ import type { MockGameObject } from "./mockGameObject"; /** Mocks video-related stuff */ export class MockVideoGameObject implements MockGameObject { public name: string; + public active = true; public play = () => null; public stop = () => this; - public setOrigin = () => null; - public setScale = () => null; - public setVisible = () => null; - public setLoop = () => null; + public setOrigin = () => this; + public setScale = () => this; + public setVisible = () => this; + public setLoop = () => this; + public setName = (name: string) => { + this.name = name; + return this; + }; + public setActive = (active: boolean) => { + this.active = active; + return this; + }; } diff --git a/test/testUtils/mocks/mocksContainer/mockContainer.ts b/test/testUtils/mocks/mocksContainer/mockContainer.ts index 5e739fbe3cc..f1371643ce3 100644 --- a/test/testUtils/mocks/mocksContainer/mockContainer.ts +++ b/test/testUtils/mocks/mocksContainer/mockContainer.ts @@ -2,199 +2,257 @@ import type MockTextureManager from "#test/testUtils/mocks/mockTextureManager"; import type { MockGameObject } from "../mockGameObject"; export default class MockContainer implements MockGameObject { - protected x; - protected y; + protected x: number; + protected y: number; protected scene; - protected width; - protected height; - protected visible; - private alpha; + protected width: number; + protected height: number; + protected visible: boolean; + private alpha: number; private style; public frame; protected textureManager; public list: MockGameObject[] = []; public name: string; + public active = true; - constructor(textureManager: MockTextureManager, x, y) { + constructor(textureManager: MockTextureManager, x: number, y: number) { this.x = x; this.y = y; this.frame = {}; this.textureManager = textureManager; } - setVisible(visible) { + setVisible(visible: boolean): this { this.visible = visible; + return this; } - once(_event, _callback, _source) {} + once(_event, _callback, _source): this { + return this; + } - off(_event, _callback, _source) {} + off(_event, _callback, _source): this { + return this; + } - removeFromDisplayList() { + removeFromDisplayList(): this { // same as remove or destroy + return this; } - removeBetween(_startIndex, _endIndex, _destroyChild) { + removeBetween(_startIndex, _endIndex, _destroyChild): this { // Removes multiple children across an index range + return this; } addedToScene() { // This callback is invoked when this Game Object is added to a Scene. } - setSize(_width, _height) { + setSize(_width: number, _height: number): this { // Sets the size of this Game Object. + return this; } - setMask() { + setMask(): this { /// Sets the mask that this Game Object will use to render with. + return this; } - setPositionRelative(_source, _x, _y) { + setPositionRelative(_source, _x, _y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. + return this; } - setInteractive = () => null; + setInteractive(): this { + return this; + } - setOrigin(x, y) { + setOrigin(x = 0.5, y = x): this { this.x = x; this.y = y; + return this; } - setAlpha(alpha) { + setAlpha(alpha = 1): this { this.alpha = alpha; + return this; } - setFrame(_frame, _updateSize?: boolean, _updateOrigin?: boolean) { + setFrame(_frame, _updateSize?: boolean, _updateOrigin?: boolean): this { // Sets the frame this Game Object will use to render with. + return this; } - setScale(_scale) { + setScale(_x = 1, _y = _x): this { // Sets the scale of this Game Object. + return this; } - setPosition(x, y) { + setPosition(x = 0, y = x, _z = 0, _w = 0): this { this.x = x; this.y = y; + return this; } - setX(x) { + setX(x = 0): this { this.x = x; + return this; } - setY(y) { + setY(y = 0): this { this.y = y; + return this; } destroy() { this.list = []; } - setShadow(_shadowXpos, _shadowYpos, _shadowColor) { + setShadow(_shadowXpos, _shadowYpos, _shadowColor): this { // Sets the shadow settings for this Game Object. + return this; } - setLineSpacing(_lineSpacing) { + setLineSpacing(_lineSpacing): this { // Sets the line spacing value of this Game Object. + return this; } - setText(_text) { + setText(_text): this { // Sets the text this Game Object will display. + return this; } - setAngle(_angle) { + setAngle(_angle): this { // Sets the angle of this Game Object. + return this; } - setShadowOffset(_offsetX, _offsetY) { + setShadowOffset(_offsetX, _offsetY): this { // Sets the shadow offset values. + return this; } setWordWrapWidth(_width) { // Sets the width (in pixels) to use for wrapping lines. } - setFontSize(_fontSize) { + setFontSize(_fontSize): this { // Sets the font size of this Game Object. + return this; } getBounds() { return { width: this.width, height: this.height }; } - setColor(_color) { + setColor(_color): this { // Sets the tint of this Game Object. + return this; } - setShadowColor(_color) { + setShadowColor(_color): this { // Sets the shadow color. + return this; } - setTint(_color) { + setTint(_color: this) { // Sets the tint of this Game Object. + return this; } - setStrokeStyle(_thickness, _color) { + setStrokeStyle(_thickness, _color): this { // Sets the stroke style for the graphics. return this; } - setDepth(_depth) { - // Sets the depth of this Game Object. + setDepth(_depth): this { + // Sets the depth of this Game Object.\ + return this; } - setTexture(_texture) { - // Sets the texture this Game Object will use to render with. + setTexture(_texture): this { + // Sets the texture this Game Object will use to render with.\ + return this; } - clearTint() { - // Clears any previously set tint. + clearTint(): this { + // Clears any previously set tint.\ + return this; } - sendToBack() { - // Sends this Game Object to the back of its parent's display list. + sendToBack(): this { + // Sends this Game Object to the back of its parent's display list.\ + return this; } - moveTo(_obj) { - // Moves this Game Object to the given index in the list. + moveTo(_obj): this { + // Moves this Game Object to the given index in the list.\ + return this; } - moveAbove(_obj) { + moveAbove(_obj): this { // Moves this Game Object to be above the given Game Object in the display list. + return this; } - moveBelow(_obj) { + moveBelow(_obj): this { // Moves this Game Object to be below the given Game Object in the display list. + return this; } - setName(name: string) { + setName(name: string): this { this.name = name; + return this; } - bringToTop(_obj) { + bringToTop(_obj): this { // Brings this Game Object to the top of its parents display list. + return this; } - on(_event, _callback, _source) {} - - add(obj) { - // Adds a child to this Game Object. - this.list.push(obj); + on(_event, _callback, _source): this { + return this; } - removeAll() { + add(obj: MockGameObject | MockGameObject[]): this { + if (Array.isArray(obj)) { + this.list.push(...obj); + } else { + this.list.push(obj); + } + return this; + } + + removeAll(): this { // Removes all Game Objects from this Container. this.list = []; + return this; } - addAt(obj, index) { + addAt(obj: MockGameObject | MockGameObject[], index = 0): this { // Adds a Game Object to this Container at the given index. - this.list.splice(index, 0, obj); + if (!Array.isArray(obj)) { + obj = [obj]; + } + this.list.splice(index, 0, ...obj); + return this; } - remove(obj) { - const index = this.list.indexOf(obj); - if (index !== -1) { - this.list.splice(index, 1); + remove(obj: MockGameObject | MockGameObject[], destroyChild = false): this { + if (!Array.isArray(obj)) { + obj = [obj]; } + for (const item of obj) { + const index = this.list.indexOf(item); + if (index !== -1) { + this.list.splice(index, 1); + } + if (destroyChild) { + item.destroy?.(); + } + } + return this; } getIndex(obj) { @@ -210,15 +268,48 @@ export default class MockContainer implements MockGameObject { return this.list; } - getByName(key: string) { + getByName(key: string): MockGameObject | null { return this.list.find(v => v.name === key) ?? new MockContainer(this.textureManager, 0, 0); } - disableInteractive = () => null; + disableInteractive(): this { + return this; + } - each(method) { - for (const item of this.list) { - method(item); + // biome-ignore lint/complexity/noBannedTypes: This matches the signature of the method it mocks + each(callback: Function, context?: object, ...args: any[]): this { + if (context !== undefined) { + callback = callback.bind(context); } + for (const item of this.list.slice()) { + callback(item, ...args); + } + return this; + } + + // biome-ignore lint/complexity/noBannedTypes: This matches the signature of the method it mocks + iterate(callback: Function, context?: object, ...args: any[]): this { + if (context !== undefined) { + callback = callback.bind(context); + } + for (const item of this.list) { + callback(item, ...args); + } + return this; + } + + copyPosition(source: { x?: number; y?: number }): this { + if (source.x !== undefined) { + this.x = source.x; + } + if (source.y !== undefined) { + this.y = source.y; + } + return this; + } + + setActive(active: boolean): this { + this.active = active; + return this; } } diff --git a/test/testUtils/mocks/mocksContainer/mockGraphics.ts b/test/testUtils/mocks/mocksContainer/mockGraphics.ts index ebf84e935e3..cd43bb3a877 100644 --- a/test/testUtils/mocks/mocksContainer/mockGraphics.ts +++ b/test/testUtils/mocks/mocksContainer/mockGraphics.ts @@ -4,61 +4,81 @@ export default class MockGraphics implements MockGameObject { private scene; public list: MockGameObject[] = []; public name: string; + public active = true; constructor(textureManager, _config) { this.scene = textureManager.scene; } - fillStyle(_color) { + fillStyle(_color): this { // Sets the fill style to be used by the fill methods. + return this; } - beginPath() { + beginPath(): this { // Starts a new path by emptying the list of sub-paths. Call this method when you want to create a new path. + return this; } - fillRect(_x, _y, _width, _height) { + fillRect(_x, _y, _width, _height): this { // Adds a rectangle shape to the path which is filled when you call fill(). + return this; } - createGeometryMask() { + createGeometryMask(): this { // Creates a geometry mask. + return this; } - setOrigin(_x, _y) {} + setOrigin(_x, _y): this { + return this; + } - setAlpha(_alpha) {} + setAlpha(_alpha): this { + return this; + } - setVisible(_visible) {} + setVisible(_visible): this { + return this; + } - setName(_name) {} + setName(_name) { + return this; + } - once(_event, _callback, _source) {} + once(_event, _callback, _source) { + return this; + } - removeFromDisplayList() { + removeFromDisplayList(): this { // same as remove or destroy + return this; } addedToScene() { // This callback is invoked when this Game Object is added to a Scene. } - setPositionRelative(_source, _x, _y) { + setPositionRelative(_source, _x, _y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. + return this; } destroy() { this.list = []; } - setScale(_scale) { - // Sets the scale of this Game Object. + setScale(_scale): this { + return this; } - off(_event, _callback, _source) {} + off(_event, _callback, _source): this { + return this; + } - add(obj) { + add(obj): this { // Adds a child to this Game Object. this.list.push(obj); + return this; } removeAll() { @@ -90,4 +110,13 @@ export default class MockGraphics implements MockGameObject { getAll() { return this.list; } + + copyPosition(_source): this { + return this; + } + + setActive(active: boolean): this { + this.active = active; + return this; + } } diff --git a/test/testUtils/mocks/mocksContainer/mockRectangle.ts b/test/testUtils/mocks/mocksContainer/mockRectangle.ts index 7bdf343759d..7f54a0e255f 100644 --- a/test/testUtils/mocks/mocksContainer/mockRectangle.ts +++ b/test/testUtils/mocks/mocksContainer/mockRectangle.ts @@ -5,39 +5,57 @@ export default class MockRectangle implements MockGameObject { private scene; public list: MockGameObject[] = []; public name: string; + public active = true; constructor(textureManager, _x, _y, _width, _height, fillColor) { this.fillColor = fillColor; this.scene = textureManager.scene; } - setOrigin(_x, _y) {} + setOrigin(_x, _y): this { + return this; + } - setAlpha(_alpha) {} - setVisible(_visible) {} + setAlpha(_alpha): this { + return this; + } + setVisible(_visible): this { + return this; + } - setName(_name) {} + setName(_name): this { + return this; + } - once(_event, _callback, _source) {} + once(_event, _callback, _source): this { + return this; + } - removeFromDisplayList() { + removeFromDisplayList(): this { // same as remove or destroy + return this; } addedToScene() { // This callback is invoked when this Game Object is added to a Scene. } - setPositionRelative(_source, _x, _y) { + setPositionRelative(_source, _x, _y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. + return this; } destroy() { this.list = []; } - add(obj) { + add(obj: MockGameObject | MockGameObject[]): this { // Adds a child to this Game Object. - this.list.push(obj); + if (Array.isArray(obj)) { + this.list.push(...obj); + } else { + this.list.push(obj); + } + return this; } removeAll() { @@ -45,16 +63,18 @@ export default class MockRectangle implements MockGameObject { this.list = []; } - addAt(obj, index) { + addAt(obj, index): this { // Adds a Game Object to this Container at the given index. this.list.splice(index, 0, obj); + return this; } - remove(obj) { + remove(obj): this { const index = this.list.indexOf(obj); if (index !== -1) { this.list.splice(index, 1); } + return this; } getIndex(obj) { @@ -69,9 +89,17 @@ export default class MockRectangle implements MockGameObject { getAll() { return this.list; } - setScale(_scale) { + setScale(_scale): this { // return this.phaserText.setScale(scale); + return this; } - off() {} + off(): this { + return this; + } + + setActive(active: boolean): this { + this.active = active; + return this; + } } diff --git a/test/testUtils/mocks/mocksContainer/mockSprite.ts b/test/testUtils/mocks/mocksContainer/mockSprite.ts index dcc3588f127..df36b3a29fd 100644 --- a/test/testUtils/mocks/mocksContainer/mockSprite.ts +++ b/test/testUtils/mocks/mocksContainer/mockSprite.ts @@ -1,6 +1,5 @@ import Phaser from "phaser"; import type { MockGameObject } from "../mockGameObject"; -import Sprite = Phaser.GameObjects.Sprite; import Frame = Phaser.Textures.Frame; export default class MockSprite implements MockGameObject { @@ -14,6 +13,7 @@ export default class MockSprite implements MockGameObject { public anims; public list: MockGameObject[] = []; public name: string; + public active = true; constructor(textureManager, x, y, texture) { this.textureManager = textureManager; this.scene = textureManager.scene; @@ -21,7 +21,9 @@ export default class MockSprite implements MockGameObject { Phaser.GameObjects.Sprite.prototype.setInteractive = this.setInteractive; // @ts-ignore Phaser.GameObjects.Sprite.prototype.setTexture = this.setTexture; + // @ts-ignore Phaser.GameObjects.Sprite.prototype.setSizeToFrame = this.setSizeToFrame; + // @ts-ignore Phaser.GameObjects.Sprite.prototype.setFrame = this.setFrame; // Phaser.GameObjects.Sprite.prototype.disable = this.disable; @@ -37,46 +39,55 @@ export default class MockSprite implements MockGameObject { }; } - setTexture(_key: string, _frame?: string | number) { + setTexture(_key: string, _frame?: string | number): this { return this; } - setSizeToFrame(_frame?: boolean | Frame): Sprite { - return {} as Sprite; + setSizeToFrame(_frame?: boolean | Frame): this { + return this; } - setPipeline(obj) { + setPipeline(obj): this { // Sets the pipeline of this Game Object. - return this.phaserSprite.setPipeline(obj); + this.phaserSprite.setPipeline(obj); + return this; } - off(_event, _callback, _source) {} + off(_event, _callback, _source): this { + return this; + } - setTintFill(color) { + setTintFill(color): this { // Sets the tint fill color. - return this.phaserSprite.setTintFill(color); + this.phaserSprite.setTintFill(color); + return this; } - setScale(scale) { - return this.phaserSprite.setScale(scale); + setScale(scale = 1): this { + this.phaserSprite.setScale(scale); + return this; } - setOrigin(x, y) { - return this.phaserSprite.setOrigin(x, y); + setOrigin(x = 0.5, y = x): this { + this.phaserSprite.setOrigin(x, y); + return this; } - setSize(width, height) { + setSize(width, height): this { // Sets the size of this Game Object. - return this.phaserSprite.setSize(width, height); + this.phaserSprite.setSize(width, height); + return this; } - once(event, callback, source) { - return this.phaserSprite.once(event, callback, source); + once(event, callback, source): this { + this.phaserSprite.once(event, callback, source); + return this; } - removeFromDisplayList() { + removeFromDisplayList(): this { // same as remove or destroy - return this.phaserSprite.removeFromDisplayList(); + this.phaserSprite.removeFromDisplayList(); + return this; } addedToScene() { @@ -84,97 +95,121 @@ export default class MockSprite implements MockGameObject { return this.phaserSprite.addedToScene(); } - setVisible(visible) { - return this.phaserSprite.setVisible(visible); + setVisible(visible): this { + this.phaserSprite.setVisible(visible); + return this; } - setPosition(x, y) { - return this.phaserSprite.setPosition(x, y); + setPosition(x, y): this { + this.phaserSprite.setPosition(x, y); + return this; } - setRotation(radians) { - return this.phaserSprite.setRotation(radians); + setRotation(radians): this { + this.phaserSprite.setRotation(radians); + return this; } - stop() { - return this.phaserSprite.stop(); + stop(): this { + this.phaserSprite.stop(); + return this; } - setInteractive = () => null; - - on(event, callback, source) { - return this.phaserSprite.on(event, callback, source); + setInteractive(): this { + return this; } - setAlpha(alpha) { - return this.phaserSprite.setAlpha(alpha); + on(event, callback, source): this { + this.phaserSprite.on(event, callback, source); + return this; } - setTint(color) { + setAlpha(alpha): this { + this.phaserSprite.setAlpha(alpha); + return this; + } + + setTint(color): this { // Sets the tint of this Game Object. - return this.phaserSprite.setTint(color); + this.phaserSprite.setTint(color); + return this; } - setFrame(frame, _updateSize?: boolean, _updateOrigin?: boolean) { + setFrame(frame, _updateSize?: boolean, _updateOrigin?: boolean): this { // Sets the frame this Game Object will use to render with. this.frame = frame; - return frame; + return this; } - setPositionRelative(source, x, y) { + setPositionRelative(source, x, y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. - return this.phaserSprite.setPositionRelative(source, x, y); + this.phaserSprite.setPositionRelative(source, x, y); + return this; } - setY(y) { - return this.phaserSprite.setY(y); + setY(y: number): this { + this.phaserSprite.setY(y); + return this; } - setCrop(x, y, width, height) { + setCrop(x: number, y: number, width: number, height: number): this { // Sets the crop size of this Game Object. - return this.phaserSprite.setCrop(x, y, width, height); + this.phaserSprite.setCrop(x, y, width, height); + return this; } - clearTint() { + clearTint(): this { // Clears any previously set tint. - return this.phaserSprite.clearTint(); + this.phaserSprite.clearTint(); + return this; } - disableInteractive() { + disableInteractive(): this { // Disables Interactive features of this Game Object. - return null; + return this; } apply() { - return this.phaserSprite.apply(); + this.phaserSprite.apply(); + return this; } - play() { + play(): this { // return this.phaserSprite.play(); return this; } - setPipelineData(key, value) { + setPipelineData(key: string, value: any): this { this.pipelineData[key] = value; + return this; } destroy() { return this.phaserSprite.destroy(); } - setName(name) { - return this.phaserSprite.setName(name); + setName(name: string): this { + this.phaserSprite.setName(name); + return this; } - setAngle(angle) { - return this.phaserSprite.setAngle(angle); + setAngle(angle): this { + this.phaserSprite.setAngle(angle); + return this; } - setMask() {} + setMask(): this { + return this; + } - add(obj) { + add(obj: MockGameObject | MockGameObject[]): this { // Adds a child to this Game Object. - this.list.push(obj); + if (Array.isArray(obj)) { + this.list.push(...obj); + } else { + this.list.push(obj); + } + return this; } removeAll() { @@ -182,16 +217,18 @@ export default class MockSprite implements MockGameObject { this.list = []; } - addAt(obj, index) { + addAt(obj, index): this { // Adds a Game Object to this Container at the given index. this.list.splice(index, 0, obj); + return this; } - remove(obj) { + remove(obj): this { const index = this.list.indexOf(obj); if (index !== -1) { this.list.splice(index, 1); } + return this; } getIndex(obj) { @@ -206,4 +243,14 @@ export default class MockSprite implements MockGameObject { getAll() { return this.list; } + + copyPosition(obj): this { + this.phaserSprite.copyPosition(obj); + return this; + } + + setActive(active: boolean): this { + this.phaserSprite.setActive(active); + return this; + } } diff --git a/test/testUtils/mocks/mocksContainer/mockText.ts b/test/testUtils/mocks/mocksContainer/mockText.ts index 1f3f0ad792f..2345ff70c0d 100644 --- a/test/testUtils/mocks/mocksContainer/mockText.ts +++ b/test/testUtils/mocks/mocksContainer/mockText.ts @@ -12,6 +12,7 @@ export default class MockText implements MockGameObject { public text = ""; public name: string; public color?: string; + public active = true; constructor(textureManager, _x, _y, _content, _styleOptions) { this.scene = textureManager.scene; @@ -107,42 +108,51 @@ export default class MockText implements MockGameObject { } } - setScale(_scale) { + setScale(_scale): this { // return this.phaserText.setScale(scale); + return this; } - setShadow(_shadowXpos, _shadowYpos, _shadowColor) { + setShadow(_shadowXpos, _shadowYpos, _shadowColor): this { // Sets the shadow settings for this Game Object. // return this.phaserText.setShadow(shadowXpos, shadowYpos, shadowColor); + return this; } - setLineSpacing(_lineSpacing) { + setLineSpacing(_lineSpacing): this { // Sets the line spacing value of this Game Object. // return this.phaserText.setLineSpacing(lineSpacing); + return this; } - setOrigin(_x, _y) { + setOrigin(_x, _y): this { // return this.phaserText.setOrigin(x, y); + return this; } - once(_event, _callback, _source) { + once(_event, _callback, _source): this { // return this.phaserText.once(event, callback, source); + return this; } off(_event, _callback, _obj) {} removedFromScene() {} - addToDisplayList() {} - - setStroke(_color, _thickness) { - // Sets the stroke color and thickness. - // return this.phaserText.setStroke(color, thickness); + addToDisplayList(): this { + return this; } - removeFromDisplayList() { + setStroke(_color, _thickness): this { + // Sets the stroke color and thickness. + // return this.phaserText.setStroke(color, thickness); + return this; + } + + removeFromDisplayList(): this { // same as remove or destroy // return this.phaserText.removeFromDisplayList(); + return this; } addedToScene() { @@ -150,16 +160,18 @@ export default class MockText implements MockGameObject { // return this.phaserText.addedToScene(); } - setVisible(_visible) { - // return this.phaserText.setVisible(visible); + setVisible(_visible): this { + return this; } - setY(_y) { + setY(_y): this { // return this.phaserText.setY(y); + return this; } - setX(_x) { + setX(_x): this { // return this.phaserText.setX(x); + return this; } /** @@ -169,37 +181,45 @@ export default class MockText implements MockGameObject { * @param z The z position of this Game Object. Default 0. * @param w The w position of this Game Object. Default 0. */ - setPosition(_x?: number, _y?: number, _z?: number, _w?: number) {} + setPosition(_x?: number, _y?: number, _z?: number, _w?: number): this { + return this; + } - setText(text) { + setText(text): this { // Sets the text this Game Object will display. // return this.phaserText.setText\(text); this.text = text; + return this; } - setAngle(_angle) { + setAngle(_angle): this { // Sets the angle of this Game Object. // return this.phaserText.setAngle(angle); + return this; } - setPositionRelative(_source, _x, _y) { + setPositionRelative(_source, _x, _y): this { /// Sets the position of this Game Object to be a relative position from the source Game Object. // return this.phaserText.setPositionRelative(source, x, y); + return this; } - setShadowOffset(_offsetX, _offsetY) { + setShadowOffset(_offsetX, _offsetY): this { // Sets the shadow offset values. // return this.phaserText.setShadowOffset(offsetX, offsetY); + return this; } - setWordWrapWidth(width) { + setWordWrapWidth(width): this { // Sets the width (in pixels) to use for wrapping lines. this.wordWrapWidth = width; + return this; } - setFontSize(_fontSize) { + setFontSize(_fontSize): this { // Sets the font size of this Game Object. // return this.phaserText.setFontSize(fontSize); + return this; } getBounds() { @@ -209,25 +229,31 @@ export default class MockText implements MockGameObject { }; } - setColor(color: string) { + setColor(color: string): this { this.color = color; + return this; } - setInteractive = () => null; + setInteractive(): this { + return this; + } - setShadowColor(_color) { + setShadowColor(_color): this { // Sets the shadow color. // return this.phaserText.setShadowColor(color); + return this; } - setTint(_color) { + setTint(_color): this { // Sets the tint of this Game Object. // return this.phaserText.setTint(color); + return this; } - setStrokeStyle(_thickness, _color) { + setStrokeStyle(_thickness, _color): this { // Sets the stroke style for the graphics. // return this.phaserText.setStrokeStyle(thickness, color); + return this; } destroy() { @@ -235,20 +261,24 @@ export default class MockText implements MockGameObject { this.list = []; } - setAlpha(_alpha) { + setAlpha(_alpha): this { // return this.phaserText.setAlpha(alpha); + return this; } - setName(name: string) { + setName(name: string): this { this.name = name; + return this; } - setAlign(_align) { + setAlign(_align): this { // return this.phaserText.setAlign(align); + return this; } - setMask() { + setMask(): this { /// Sets the mask that this Game Object will use to render with. + return this; } getBottomLeft() { @@ -265,37 +295,43 @@ export default class MockText implements MockGameObject { }; } - disableInteractive() { + disableInteractive(): this { // Disables interaction with this Game Object. + return this; } - clearTint() { + clearTint(): this { // Clears tint on this Game Object. + return this; } - add(obj) { + add(obj): this { // Adds a child to this Game Object. this.list.push(obj); + return this; } - removeAll() { + removeAll(): this { // Removes all Game Objects from this Container. this.list = []; + return this; } - addAt(obj, index) { + addAt(obj, index): this { // Adds a Game Object to this Container at the given index. this.list.splice(index, 0, obj); + return this; } - remove(obj) { + remove(obj): this { const index = this.list.indexOf(obj); if (index !== -1) { this.list.splice(index, 1); } + return this; } - getIndex(obj) { + getIndex(obj): number { const index = this.list.indexOf(obj); return index || -1; } @@ -317,5 +353,10 @@ export default class MockText implements MockGameObject { return this.runWordWrap(this.text).split("\n"); } + // biome-ignore lint/complexity/noBannedTypes: This matches the signature of the class this mocks on(_event: string | symbol, _fn: Function, _context?: any) {} + + setActive(_active: boolean): this { + return this; + } } diff --git a/test/testUtils/mocks/mocksContainer/mockTexture.ts b/test/testUtils/mocks/mocksContainer/mockTexture.ts index eb8b70902fa..3b01f9ab4ea 100644 --- a/test/testUtils/mocks/mocksContainer/mockTexture.ts +++ b/test/testUtils/mocks/mocksContainer/mockTexture.ts @@ -12,6 +12,7 @@ export default class MockTexture implements MockGameObject { public frames: object; public firstFrame: string; public name: string; + public active: boolean; constructor(manager, key: string, source) { this.manager = manager; @@ -39,4 +40,14 @@ export default class MockTexture implements MockGameObject { getSourceImage() { return null; } + + setActive(active: boolean): this { + this.active = active; + return this; + } + + setName(name: string): this { + this.name = name; + return this; + } } diff --git a/test/testUtils/testFileInitialization.ts b/test/testUtils/testFileInitialization.ts index 15635289e6f..ba90cba7d5b 100644 --- a/test/testUtils/testFileInitialization.ts +++ b/test/testUtils/testFileInitialization.ts @@ -70,10 +70,10 @@ export function initTestFile() { * @param x The relative x position * @param y The relative y position */ - const setPositionRelative = function (guideObject: any, x: number, y: number) { + const setPositionRelative = function (guideObject: any, x: number, y: number): any { const offsetX = guideObject.width * (-0.5 + (0.5 - guideObject.originX)); const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY)); - this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y); + return this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y); }; Phaser.GameObjects.Container.prototype.setPositionRelative = setPositionRelative; diff --git a/test/ui/pokedex.test.ts b/test/ui/pokedex.test.ts index ff5ca116ba8..007fc43c3b9 100644 --- a/test/ui/pokedex.test.ts +++ b/test/ui/pokedex.test.ts @@ -8,7 +8,7 @@ import { Abilities } from "#enums/abilities"; import { Species } from "#enums/species"; import { allSpecies, getPokemonSpecies, type PokemonForm } from "#app/data/pokemon-species"; import { Button } from "#enums/buttons"; -import { DropDownColumn } from "#app/ui/filter-bar"; +import { DropDownColumn } from "#enums/drop-down-column"; import type PokemonSpecies from "#app/data/pokemon-species"; import { PokemonType } from "#enums/pokemon-type"; import { UiMode } from "#enums/ui-mode"; diff --git a/test/ui/type-hints.test.ts b/test/ui/type-hints.test.ts index 2051af76754..b32f5ed9b88 100644 --- a/test/ui/type-hints.test.ts +++ b/test/ui/type-hints.test.ts @@ -99,8 +99,8 @@ describe("UI - Type Hints", () => { // Use soak to change type of remaining abra to water game.move.select(Moves.SOAK, 1); - await game.forceEnemyMove(Moves.SPLASH); - await game.forceEnemyMove(Moves.TELEPORT); + await game.move.selectEnemyMove(Moves.SPLASH); + await game.move.selectEnemyMove(Moves.TELEPORT); await game.toNextTurn(); game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => {