Merge branch 'beta' of https://github.com/pagefaultgames/pokerogue into evcndrf2
14
.github/test-filters.yml
vendored
@ -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*"
|
9
.github/workflows/test-shard-template.yml
vendored
@ -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
|
||||
|
7
.github/workflows/tests.yml
vendored
@ -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'}}
|
||||
|
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pokemon-rogue-battle",
|
||||
"version": "1.9.4",
|
||||
"version": "1.9.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pokemon-rogue-battle",
|
||||
"version": "1.9.4",
|
||||
"version": "1.9.5",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@material/material-color-utilities": "^0.2.7",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "pokemon-rogue-battle",
|
||||
"private": true,
|
||||
"version": "1.9.4",
|
||||
"version": "1.9.5",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "statuses_ca_ES.png",
|
||||
"image": "statuses_ca.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 22,
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
188
public/images/statuses_da.json
Normal file
@ -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$"
|
||||
}
|
||||
}
|
BIN
public/images/statuses_da.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
188
public/images/statuses_ro.json
Normal file
@ -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$"
|
||||
}
|
||||
}
|
BIN
public/images/statuses_ro.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
188
public/images/statuses_ru.json
Normal file
@ -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$"
|
||||
}
|
||||
}
|
BIN
public/images/statuses_ru.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
188
public/images/statuses_tr.json
Normal file
@ -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$"
|
||||
}
|
||||
}
|
BIN
public/images/statuses_tr.png
Normal file
After Width: | Height: | Size: 441 B |
@ -1,7 +1,7 @@
|
||||
{
|
||||
"textures": [
|
||||
{
|
||||
"image": "types_ca-ES.png",
|
||||
"image": "types_ca.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {
|
||||
"w": 32,
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
440
public/images/types_da.json
Normal file
@ -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$"
|
||||
}
|
||||
}
|
BIN
public/images/types_da.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
440
public/images/types_ro.json
Normal file
@ -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$"
|
||||
}
|
||||
}
|
BIN
public/images/types_ro.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
440
public/images/types_ru.json
Normal file
@ -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$"
|
||||
}
|
||||
}
|
BIN
public/images/types_ru.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
440
public/images/types_tr.json
Normal file
@ -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$"
|
||||
}
|
||||
}
|
BIN
public/images/types_tr.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
@ -1 +1 @@
|
||||
Subproject commit 42cd5cf577f475c22bc82d55e7ca358eb4f3184f
|
||||
Subproject commit 4dab23d6a78b6cf32db43c9953e3c2000f448007
|
149
scripts/decrypt-save.js
Normal file
@ -0,0 +1,149 @@
|
||||
import pkg from "crypto-js";
|
||||
const { AES, enc } = pkg;
|
||||
// biome-ignore lint: This is how you import fs from node
|
||||
import * as fs from "node:fs";
|
||||
|
||||
const SAVE_KEY = "x0i2O7WRiANTqPmZ";
|
||||
|
||||
/**
|
||||
* A map of condensed keynames to their associated full names
|
||||
* NOTE: Update this if `src/system/game-data#systemShortKeys` ever changes!
|
||||
*/
|
||||
const systemShortKeys = {
|
||||
seenAttr: "$sa",
|
||||
caughtAttr: "$ca",
|
||||
natureAttr: "$na",
|
||||
seenCount: "$s",
|
||||
caughtCount: "$c",
|
||||
hatchedCount: "$hc",
|
||||
ivs: "$i",
|
||||
moveset: "$m",
|
||||
eggMoves: "$em",
|
||||
candyCount: "$x",
|
||||
friendship: "$f",
|
||||
abilityAttr: "$a",
|
||||
passiveAttr: "$pa",
|
||||
valueReduction: "$vr",
|
||||
classicWinCount: "$wc",
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace the shortened key names with their full names
|
||||
* @param {string} dataStr - The string to convert
|
||||
* @returns {string} The string with shortened keynames replaced with full names
|
||||
*/
|
||||
function convertSystemDataStr(dataStr) {
|
||||
const fromKeys = Object.values(systemShortKeys);
|
||||
const toKeys = Object.keys(systemShortKeys);
|
||||
for (const k in fromKeys) {
|
||||
dataStr = dataStr.replace(new RegExp(`${fromKeys[k].replace("$", "\\$")}`, "g"), toKeys[k]);
|
||||
}
|
||||
|
||||
return dataStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a save
|
||||
* @param {string} path - The path to the encrypted save file
|
||||
* @returns {string} The decrypted save data
|
||||
*/
|
||||
function decryptSave(path) {
|
||||
// Check if the file exists
|
||||
if (!fs.existsSync(path)) {
|
||||
console.error(`File not found: ${path}`);
|
||||
process.exit(1);
|
||||
}
|
||||
let fileData;
|
||||
try {
|
||||
fileData = fs.readFileSync(path, "utf8");
|
||||
} catch (e) {
|
||||
switch (e.code) {
|
||||
case "ENOENT":
|
||||
console.error(`File not found: ${path}`);
|
||||
break;
|
||||
case "EACCES":
|
||||
console.error(`Could not open ${path}: Permission denied`);
|
||||
break;
|
||||
case "EISDIR":
|
||||
console.error(`Unable to read ${path} as it is a directory`);
|
||||
break;
|
||||
default:
|
||||
console.error(`Error reading file: ${e.message}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
return convertSystemDataStr(AES.decrypt(fileData, SAVE_KEY).toString(enc.Utf8));
|
||||
}
|
||||
|
||||
/* Print the usage message and exits */
|
||||
function printUsage() {
|
||||
console.log(`
|
||||
Usage: node decrypt-save.js <encrypted-file> [save-file]
|
||||
|
||||
Arguments:
|
||||
file-path Path to the encrypted save file to decrypt.
|
||||
save-file Path to where the decrypted data should be written. If not provided, the decrypted data will be printed to the console.
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message and exit.
|
||||
|
||||
Description:
|
||||
This script decrypts an encrypted pokerogue save file
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `data` to `filePath`, gracefully communicating errors that arise
|
||||
* @param {string} filePath
|
||||
* @param {string} data
|
||||
*/
|
||||
function writeToFile(filePath, data) {
|
||||
try {
|
||||
fs.writeFileSync(filePath, data);
|
||||
} catch (e) {
|
||||
switch (e.code) {
|
||||
case "EACCES":
|
||||
console.error(`Could not open ${filePath}: Permission denied`);
|
||||
break;
|
||||
case "EISDIR":
|
||||
console.error(`Unable to write to ${filePath} as it is a directory`);
|
||||
break;
|
||||
default:
|
||||
console.error(`Error writing file: ${e.message}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
let args = process.argv.slice(2);
|
||||
// Get options
|
||||
const options = args.filter(arg => arg.startsWith("-"));
|
||||
// get args
|
||||
args = args.filter(arg => !arg.startsWith("-"));
|
||||
|
||||
if (args.length === 0 || options.includes("-h") || options.includes("--help") || args.length > 2) {
|
||||
printUsage();
|
||||
process.exit(0);
|
||||
}
|
||||
// If the user provided a second argument, check if the file exists already and refuse to write to it.
|
||||
if (args.length === 2) {
|
||||
const destPath = args[1];
|
||||
if (fs.existsSync(destPath)) {
|
||||
console.error(`Refusing to overwrite ${destPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, commence decryption.
|
||||
const decrypt = decryptSave(args[0]);
|
||||
|
||||
if (args.length === 1) {
|
||||
process.stdout.write(decrypt);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
writeToFile(destPath, decrypt);
|
||||
}
|
||||
|
||||
main();
|
@ -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)
|
||||
|
@ -7528,7 +7528,7 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr {
|
||||
|
||||
/** Causes the effect to fail when the target's ability is unsupressable or already suppressed. */
|
||||
getCondition(): MoveConditionFunc {
|
||||
return (user, target, move) => target.getAbility().isSuppressable && !target.summonData.abilitySuppressed;
|
||||
return (_user, target, _move) => !target.summonData.abilitySuppressed && (target.getAbility().isSuppressable || (target.hasPassive() && target.getPassiveAbility().isSuppressable));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -581,7 +581,7 @@ function calculateEggRewardsForPokemon(pokemon: PlayerPokemon): [number, number]
|
||||
}
|
||||
|
||||
function getEggOptions(commonEggs: number, rareEggs: number) {
|
||||
const eggDescription = i18next.t(`${namespace}:title`) + ":\n" + i18next.t(trainerNameKey);
|
||||
const eggDescription = i18next.t(`${namespace}:title`);
|
||||
const eggOptions: IEggOptions[] = [];
|
||||
|
||||
if (commonEggs > 0) {
|
||||
|
@ -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),
|
||||
|
9
src/enums/drop-down-column.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export enum DropDownColumn {
|
||||
GEN,
|
||||
TYPES,
|
||||
BIOME,
|
||||
CAUGHT,
|
||||
UNLOCKS,
|
||||
MISC,
|
||||
SORT
|
||||
}
|
@ -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,
|
||||
@ -3337,22 +3339,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
|
||||
@ -5508,6 +5498,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
}
|
||||
|
||||
export class PlayerPokemon extends Pokemon {
|
||||
protected battleInfo: PlayerBattleInfo;
|
||||
public compatibleTms: Moves[];
|
||||
|
||||
constructor(
|
||||
@ -6026,6 +6017,7 @@ export class PlayerPokemon extends Pokemon {
|
||||
}
|
||||
|
||||
export class EnemyPokemon extends Pokemon {
|
||||
protected battleInfo: EnemyBattleInfo;
|
||||
public trainerSlot: TrainerSlot;
|
||||
public aiType: AiType;
|
||||
public bossSegments: number;
|
||||
@ -6694,6 +6686,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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) =>
|
||||
|
@ -65,14 +65,14 @@ const fonts: Array<LoadingFontFaceProperty> = [
|
||||
unicodeRange: rangesByLanguage.chinese,
|
||||
}),
|
||||
extraOptions: { sizeAdjust: "70%", format: "woff2" },
|
||||
only: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca"],
|
||||
only: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca", "da", "tr", "ro", "ru"],
|
||||
},
|
||||
{
|
||||
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"],
|
||||
only: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca", "da", "tr", "ro", "ru"],
|
||||
},
|
||||
// japanese
|
||||
{
|
||||
@ -174,7 +174,7 @@ export async function initI18n(): Promise<void> {
|
||||
"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"],
|
||||
supportedLngs: ["en", "es-ES", "es-MX", "fr", "it", "de", "zh-CN", "zh-TW", "pt-BR", "ko", "ja", "ca", "da", "tr", "ro", "ru"],
|
||||
backend: {
|
||||
loadPath(lng: string, [ns]: string[]) {
|
||||
let fileName: string;
|
||||
|
@ -193,35 +193,35 @@ export const Setting: Array<Setting> = [
|
||||
options: [
|
||||
{
|
||||
value: "1",
|
||||
label: "1x",
|
||||
label: i18next.t("settings:gameSpeed1x"),
|
||||
},
|
||||
{
|
||||
value: "1.25",
|
||||
label: "1.25x",
|
||||
label: i18next.t("settings:gameSpeed1_25x"),
|
||||
},
|
||||
{
|
||||
value: "1.5",
|
||||
label: "1.5x",
|
||||
label: i18next.t("settings:gameSpeed1_5x"),
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "2x",
|
||||
label: i18next.t("settings:gameSpeed2x"),
|
||||
},
|
||||
{
|
||||
value: "2.5",
|
||||
label: "2.5x",
|
||||
label: i18next.t("settings:gameSpeed2_5x"),
|
||||
},
|
||||
{
|
||||
value: "3",
|
||||
label: "3x",
|
||||
label: i18next.t("settings:gameSpeed3x"),
|
||||
},
|
||||
{
|
||||
value: "4",
|
||||
label: "4x",
|
||||
label: i18next.t("settings:gameSpeed4x"),
|
||||
},
|
||||
{
|
||||
value: "5",
|
||||
label: "5x",
|
||||
label: i18next.t("settings:gameSpeed5x"),
|
||||
},
|
||||
],
|
||||
default: 3,
|
||||
@ -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: i18next.t("settings:back"),
|
||||
|
12
src/typings/phaser/index.d.ts
vendored
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)}`;
|
||||
|
@ -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<Phaser.GameObjects.GameObject>(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<void> {
|
||||
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<void> {
|
||||
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
|
||||
}
|
692
src/ui/battle-info/battle-info.ts
Normal file
@ -0,0 +1,692 @@
|
||||
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(pokemon: Pokemon): boolean {
|
||||
const name = pokemon.getNameToRender();
|
||||
if (this.lastName === name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.updateNameText(pokemon);
|
||||
this.genderText.setPositionRelative(this.nameText, this.nameText.displayWidth, 0);
|
||||
|
||||
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>) => 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<void> {
|
||||
let resolve: (r: void | PromiseLike<void>) => void = () => {};
|
||||
const promise = new Promise<void>(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);
|
||||
|
||||
const teraTypeUpdated = this.updateTeraType(pokemon.isTerastallized ? pokemon.getTeraType() : PokemonType.UNKNOWN);
|
||||
|
||||
const isFusion = pokemon.isFusion(true);
|
||||
|
||||
if (nameUpdated || teraTypeUpdated) {
|
||||
this.updateIconDisplay(isFusion);
|
||||
}
|
||||
|
||||
this.updateStatusIcon(pokemon);
|
||||
|
||||
this.setTypes(pokemon.getTypes(true, false, undefined, true));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
235
src/ui/battle-info/enemy-battle-info.ts
Normal file
@ -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<Phaser.GameObjects.GameObject>(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>) => void,
|
||||
instant?: boolean,
|
||||
): void {
|
||||
super.updatePokemonHp(pokemon, resolve, instant);
|
||||
this.lastHp = pokemon.hp;
|
||||
}
|
||||
}
|
242
src/ui/battle-info/player-battle-info.ts
Normal file
@ -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<void> {
|
||||
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<void> {
|
||||
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");
|
||||
}
|
||||
}
|
@ -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]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
||||
@ -292,7 +292,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
|
||||
this.accuracyText.setVisible(hasMove);
|
||||
this.moveCategoryIcon.setVisible(hasMove);
|
||||
|
||||
this.cursorObj.setPosition(13 + (cursor % 2 === 1 ? 100 : 0), -31 + (cursor >= 2 ? 15 : 0));
|
||||
this.cursorObj.setPosition(13 + (cursor % 2 === 1 ? 114 : 0), -31 + (cursor >= 2 ? 15 : 0));
|
||||
|
||||
return changed;
|
||||
}
|
||||
@ -322,7 +322,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
|
||||
const moveset = pokemon.getMoveset();
|
||||
|
||||
for (let moveIndex = 0; moveIndex < 4; moveIndex++) {
|
||||
const moveText = addTextObject(moveIndex % 2 === 0 ? 0 : 100, moveIndex < 2 ? 0 : 16, "-", TextStyle.WINDOW);
|
||||
const moveText = addTextObject(moveIndex % 2 === 0 ? 0 : 114, moveIndex < 2 ? 0 : 16, "-", TextStyle.WINDOW);
|
||||
moveText.setName("text-empty-move");
|
||||
|
||||
if (moveIndex < moveset.length) {
|
||||
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,7 @@ enum MenuOptions {
|
||||
}
|
||||
|
||||
let wikiUrl = "https://wiki.pokerogue.net/start";
|
||||
const discordUrl = "https://discord.gg/uWpTfdKG49";
|
||||
const discordUrl = "https://discord.gg/pokerogue";
|
||||
const githubUrl = "https://github.com/pagefaultgames/pokerogue";
|
||||
const redditUrl = "https://www.reddit.com/r/pokerogue";
|
||||
const donateUrl = "https://github.com/sponsors/pagefaultgames";
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
default:
|
||||
|
@ -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";
|
||||
@ -108,17 +109,21 @@ const languageSettings: { [key: string]: LanguageSetting } = {
|
||||
instructionTextSize: "38px",
|
||||
},
|
||||
de: {
|
||||
starterInfoTextSize: "48px",
|
||||
starterInfoTextSize: "54px",
|
||||
instructionTextSize: "35px",
|
||||
starterInfoXPos: 33,
|
||||
starterInfoXPos: 35,
|
||||
},
|
||||
"es-ES": {
|
||||
starterInfoTextSize: "52px",
|
||||
instructionTextSize: "35px",
|
||||
starterInfoTextSize: "50px",
|
||||
instructionTextSize: "38px",
|
||||
starterInfoYOffset: 0.5,
|
||||
starterInfoXPos: 38,
|
||||
},
|
||||
"es-MX": {
|
||||
starterInfoTextSize: "52px",
|
||||
instructionTextSize: "35px",
|
||||
starterInfoTextSize: "50px",
|
||||
instructionTextSize: "38px",
|
||||
starterInfoYOffset: 0.5,
|
||||
starterInfoXPos: 38,
|
||||
},
|
||||
fr: {
|
||||
starterInfoTextSize: "54px",
|
||||
@ -128,21 +133,16 @@ const languageSettings: { [key: string]: LanguageSetting } = {
|
||||
starterInfoTextSize: "56px",
|
||||
instructionTextSize: "38px",
|
||||
},
|
||||
pt_BR: {
|
||||
starterInfoTextSize: "47px",
|
||||
instructionTextSize: "38px",
|
||||
"pt-BR": {
|
||||
starterInfoTextSize: "48px",
|
||||
instructionTextSize: "42px",
|
||||
starterInfoYOffset: 0.5,
|
||||
starterInfoXPos: 33,
|
||||
},
|
||||
zh: {
|
||||
starterInfoTextSize: "47px",
|
||||
instructionTextSize: "38px",
|
||||
starterInfoYOffset: 1,
|
||||
starterInfoXPos: 24,
|
||||
},
|
||||
pt: {
|
||||
starterInfoTextSize: "48px",
|
||||
instructionTextSize: "42px",
|
||||
starterInfoXPos: 33,
|
||||
starterInfoTextSize: "56px",
|
||||
instructionTextSize: "36px",
|
||||
starterInfoXPos: 26,
|
||||
},
|
||||
ko: {
|
||||
starterInfoTextSize: "60px",
|
||||
@ -156,9 +156,29 @@ const languageSettings: { [key: string]: LanguageSetting } = {
|
||||
starterInfoYOffset: 0.5,
|
||||
starterInfoXPos: 33,
|
||||
},
|
||||
"ca-ES": {
|
||||
starterInfoTextSize: "52px",
|
||||
ca: {
|
||||
starterInfoTextSize: "48px",
|
||||
instructionTextSize: "38px",
|
||||
starterInfoYOffset: 0.5,
|
||||
starterInfoXPos: 29,
|
||||
},
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
@ -1237,7 +1239,7 @@ export default class SummaryUiHandler extends UiHandler {
|
||||
this.moveSelect = true;
|
||||
this.extraMoveRowContainer.setVisible(true);
|
||||
this.selectedMoveIndex = -1;
|
||||
this.setCursor(0);
|
||||
this.setCursor(this.summaryUiMode === SummaryUiMode.LEARN_MOVE ? 4 : 0);
|
||||
this.showMoveEffect();
|
||||
}
|
||||
|
||||
|
@ -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,14 +435,18 @@ export function hasAllLocalizedSprites(lang?: string): boolean {
|
||||
case "es-ES":
|
||||
case "es-MX":
|
||||
case "fr":
|
||||
case "da":
|
||||
case "de":
|
||||
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;
|
||||
@ -576,3 +581,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");
|
||||
}
|
||||
}
|
||||
|
@ -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 => {
|
||||
|
@ -24,11 +24,12 @@ describe("Abilities - Aura Break", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override.battleStyle("single");
|
||||
game.override.moveset([Moves.MOONBLAST, Moves.DARK_PULSE, Moves.MOONBLAST, Moves.DARK_PULSE]);
|
||||
game.override.enemyMoveset(Moves.SPLASH);
|
||||
game.override.enemyAbility(Abilities.AURA_BREAK);
|
||||
game.override.enemySpecies(Species.SHUCKLE);
|
||||
game.override
|
||||
.battleStyle("single")
|
||||
.moveset([Moves.MOONBLAST, Moves.DARK_PULSE])
|
||||
.enemyMoveset(Moves.SPLASH)
|
||||
.enemyAbility(Abilities.AURA_BREAK)
|
||||
.enemySpecies(Species.SHUCKLE);
|
||||
});
|
||||
|
||||
it("reverses the effect of Fairy Aura", async () => {
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -54,10 +54,7 @@ describe("Abilities - Contrary", () => {
|
||||
});
|
||||
|
||||
it("should block negative effects", async () => {
|
||||
game.override
|
||||
.enemyPassiveAbility(Abilities.CLEAR_BODY)
|
||||
.enemyMoveset([Moves.HOWL, Moves.HOWL, Moves.HOWL, Moves.HOWL])
|
||||
.moveset([Moves.SPLASH]);
|
||||
game.override.enemyPassiveAbility(Abilities.CLEAR_BODY).enemyMoveset(Moves.HOWL).moveset([Moves.SPLASH]);
|
||||
await game.classicMode.startBattle([Species.SLOWBRO]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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]);
|
||||
|
||||
|
@ -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()!;
|
||||
|
||||
|
@ -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()!;
|
||||
|
||||
|
@ -106,8 +106,7 @@ describe("Abilities - Ice Face", () => {
|
||||
});
|
||||
|
||||
it("transforms to Ice Face when Hail or Snow starts", async () => {
|
||||
game.override.moveset([Moves.QUICK_ATTACK]);
|
||||
game.override.enemyMoveset([Moves.HAIL, Moves.HAIL, Moves.HAIL, Moves.HAIL]);
|
||||
game.override.moveset([Moves.QUICK_ATTACK]).enemyMoveset(Moves.HAIL);
|
||||
|
||||
await game.classicMode.startBattle([Species.MAGIKARP]);
|
||||
|
||||
@ -128,8 +127,7 @@ describe("Abilities - Ice Face", () => {
|
||||
});
|
||||
|
||||
it("transforms to Ice Face when summoned on arena with active Snow or Hail", async () => {
|
||||
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
game.override.moveset([Moves.SNOWSCAPE]);
|
||||
game.override.enemyMoveset(Moves.TACKLE).moveset([Moves.SNOWSCAPE]);
|
||||
|
||||
await game.classicMode.startBattle([Species.EISCUE, Species.NINJASK]);
|
||||
|
||||
@ -155,8 +153,7 @@ describe("Abilities - Ice Face", () => {
|
||||
});
|
||||
|
||||
it("will not revert to its Ice Face if there is already Hail when it changes into Noice", async () => {
|
||||
game.override.enemySpecies(Species.SHUCKLE);
|
||||
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
game.override.enemySpecies(Species.SHUCKLE).enemyMoveset(Moves.TACKLE);
|
||||
|
||||
await game.classicMode.startBattle([Species.EISCUE]);
|
||||
|
||||
@ -175,7 +172,7 @@ describe("Abilities - Ice Face", () => {
|
||||
});
|
||||
|
||||
it("persists form change when switched out", async () => {
|
||||
game.override.enemyMoveset([Moves.QUICK_ATTACK, Moves.QUICK_ATTACK, Moves.QUICK_ATTACK, Moves.QUICK_ATTACK]);
|
||||
game.override.enemyMoveset(Moves.QUICK_ATTACK);
|
||||
|
||||
await game.classicMode.startBattle([Species.EISCUE, Species.MAGIKARP]);
|
||||
|
||||
|
@ -29,17 +29,18 @@ describe("Abilities - Libero", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override.battleStyle("single");
|
||||
game.override.ability(Abilities.LIBERO);
|
||||
game.override.startingLevel(100);
|
||||
game.override.enemySpecies(Species.RATTATA);
|
||||
game.override.enemyMoveset([Moves.ENDURE, Moves.ENDURE, Moves.ENDURE, Moves.ENDURE]);
|
||||
game.override
|
||||
.battleStyle("single")
|
||||
.ability(Abilities.LIBERO)
|
||||
.startingLevel(100)
|
||||
.enemySpecies(Species.RATTATA)
|
||||
.enemyMoveset(Moves.ENDURE);
|
||||
});
|
||||
|
||||
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 +55,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 +91,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 +111,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 +129,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 +144,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 +159,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);
|
||||
@ -173,10 +174,9 @@ describe("Abilities - Libero", () => {
|
||||
});
|
||||
|
||||
test("ability applies correctly even if the pokemon's move is protected against", async () => {
|
||||
game.override.moveset([Moves.TACKLE]);
|
||||
game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]);
|
||||
game.override.moveset([Moves.TACKLE]).enemyMoveset(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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -24,13 +24,15 @@ describe("Abilities - Mycelium Might", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override.battleStyle("single");
|
||||
game.override.disableCrits();
|
||||
game.override.enemySpecies(Species.SHUCKLE);
|
||||
game.override.enemyAbility(Abilities.CLEAR_BODY);
|
||||
game.override.enemyMoveset([Moves.QUICK_ATTACK, Moves.QUICK_ATTACK, Moves.QUICK_ATTACK, Moves.QUICK_ATTACK]);
|
||||
game.override.ability(Abilities.MYCELIUM_MIGHT);
|
||||
game.override.moveset([Moves.QUICK_ATTACK, Moves.BABY_DOLL_EYES]);
|
||||
game.override
|
||||
.battleStyle("single")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.SHUCKLE)
|
||||
.enemyAbility(Abilities.CLEAR_BODY)
|
||||
|
||||
.enemyMoveset(Moves.QUICK_ATTACK)
|
||||
.ability(Abilities.MYCELIUM_MIGHT)
|
||||
.moveset([Moves.QUICK_ATTACK, Moves.BABY_DOLL_EYES]);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -41,7 +43,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();
|
||||
@ -64,8 +66,8 @@ describe("Abilities - Mycelium Might", () => {
|
||||
}, 20000);
|
||||
|
||||
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]);
|
||||
game.override.enemyMoveset(Moves.TACKLE);
|
||||
await game.classicMode.startBattle([Species.REGIELEKI]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
const playerIndex = game.scene.getPlayerPokemon()?.getBattlerIndex();
|
||||
@ -87,7 +89,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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -25,10 +25,11 @@ describe("Abilities - POWER CONSTRUCT", () => {
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.SPLASH;
|
||||
game.override.battleStyle("single");
|
||||
game.override.ability(Abilities.POWER_CONSTRUCT);
|
||||
game.override.moveset([moveToUse]);
|
||||
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
game.override
|
||||
.battleStyle("single")
|
||||
.ability(Abilities.POWER_CONSTRUCT)
|
||||
.moveset([moveToUse])
|
||||
.enemyMoveset(Moves.TACKLE);
|
||||
});
|
||||
|
||||
test("check if fainted 50% Power Construct Pokemon switches to base form on arena reset", async () => {
|
||||
|
@ -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);
|
||||
|
@ -29,17 +29,18 @@ describe("Abilities - Protean", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override.battleStyle("single");
|
||||
game.override.ability(Abilities.PROTEAN);
|
||||
game.override.startingLevel(100);
|
||||
game.override.enemySpecies(Species.RATTATA);
|
||||
game.override.enemyMoveset([Moves.ENDURE, Moves.ENDURE, Moves.ENDURE, Moves.ENDURE]);
|
||||
game.override
|
||||
.battleStyle("single")
|
||||
.ability(Abilities.PROTEAN)
|
||||
.startingLevel(100)
|
||||
.enemySpecies(Species.RATTATA)
|
||||
.enemyMoveset(Moves.ENDURE);
|
||||
});
|
||||
|
||||
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 +55,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 +91,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 +111,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 +129,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 +144,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 +159,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);
|
||||
@ -173,10 +174,9 @@ describe("Abilities - Protean", () => {
|
||||
});
|
||||
|
||||
test("ability applies correctly even if the pokemon's move is protected against", async () => {
|
||||
game.override.moveset([Moves.TACKLE]);
|
||||
game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]);
|
||||
game.override.moveset([Moves.TACKLE]).enemyMoveset(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);
|
||||
|
@ -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()!;
|
||||
|