Merge branch 'pagefaultgames:main' into candy-upgrade

This commit is contained in:
José Ricardo Fleury Oliveira 2024-05-21 20:20:55 -03:00 committed by GitHub
commit f0f5a85ce2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
70 changed files with 3434 additions and 457 deletions

View File

@ -74,7 +74,7 @@ Check out our [Trello Board](https://trello.com/b/z10B703R/pokerogue-board) to s
### 🎨 Trainer Portraits
- pkmn_realidea (Paid Commissions)
### 🎨 Pokemon Sprites
### 🎨 Pokemon Sprites and Animation
- GAMEFREAK (Pokémon Black/White 2)
- Smogon Sprite Project (Various Artists)
- Skyflyer
@ -100,6 +100,7 @@ Check out our [Trello Board](https://trello.com/b/z10B703R/pokerogue-board) to s
- bizcoeindoloro
- mangalos810
- Involuntary-Twitch
- selstar
### 🎨 Move Animations
- Pokémon Reborn

View File

@ -1,15 +1,15 @@
{
"0": {
"7b4a9c": "323f81",
"63197b": "142557",
"a55ace": "6265b4",
"7b4a9c": "d684ce",
"63197b": "9c528c",
"a55ace": "ffb5f7",
"101010": "101010",
"b57bce": "99a3ee",
"08426b": "277eb2",
"ce0021": "ce0021",
"ffd600": "ffc3f4",
"d69400": "ff61e2",
"216b94": "4aa6ce",
"b57bce": "ffd6ef",
"08426b": "638400",
"ce0021": "940821",
"ffd600": "ffd600",
"d69400": "d69400",
"216b94": "8ca508",
"ffffff": "ffffff",
"a5a5a5": "a5a5a5",
"6b6b6b": "6b6b6b"

View File

@ -14,26 +14,26 @@
"943a7b": "175990"
},
"1": {
"3a3a7b": "1d0f4e",
"5aadef": "3d4381",
"6384ce": "2f2a5f",
"631052": "892d03",
"ce6bb5": "f1a139",
"adceff": "666fb4",
"3a3a7b": "084a00",
"5aadef": "6b9c29",
"6384ce": "317300",
"631052": "c52931",
"ce6bb5": "ffada5",
"adceff": "84d64a",
"000000": "000000",
"ad52ad": "d5711b",
"ad52ad": "e6737b",
"636363": "636363",
"ffffff": "ffffff",
"d6d6d6": "d6d6d6",
"943a7b": "af4e0c"
"943a7b": "d6525a"
},
"2": {
"3a3a7b": "584055",
"5aadef": "c1aec0",
"6384ce": "866881",
"3a3a7b": "3d2349",
"5aadef": "cbabca",
"6384ce": "916c8b",
"631052": "54070c",
"ce6bb5": "bc3b1d",
"adceff": "dfcddd",
"adceff": "e8d2e6",
"000000": "000000",
"ad52ad": "94241c",
"636363": "636363",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -909,6 +909,11 @@
2,
2
],
"472": [
0,
0,
0
],
"475-mega": [
0,
2,
@ -2050,6 +2055,16 @@
2,
1
],
"41": [
0,
1,
1
],
"42": [
0,
1,
1
],
"308": [
0,
1,
@ -2869,7 +2884,7 @@
],
"383": [
0,
2,
1,
1
],
"384-mega": [
@ -4143,6 +4158,16 @@
1,
1
],
"41": [
0,
1,
1
],
"42": [
0,
1,
1
],
"308": [
0,
1,
@ -4538,7 +4563,7 @@
],
"747": [
0,
1,
2,
1
],
"748": [
@ -4591,6 +4616,11 @@
1,
1
],
"770": [
0,
0,
0
],
"771": [
0,
2,

View File

@ -1,4 +1,21 @@
{
"1": {
"000000": "000000",
"7b2129": "032a10",
"9c2929": "10371a",
"ff736b": "419e49",
"ff2129": "2b5b32",
"bd3131": "0f461c",
"3a3a3a": "383540",
"736363": "625769",
"ffffff": "fff6de",
"bdbdd6": "e5d4b6",
"9c6b31": "d51b3e",
"ffce31": "ff435d",
"94848c": "72798b",
"ffbdbd": "49c74f",
"ad9ca5": "ad9ca5"
},
"2": {
"000000": "000000",
"7b2129": "123953",

View File

@ -1,19 +1,19 @@
{
"0": {
"298c8c": "1c3820",
"5aada5": "3e5d43",
"84cece": "758076",
"004a52": "102c16",
"106b63": "0d1e10",
"298c8c": "427373",
"5aada5": "6b9c94",
"84cece": "94bdbd",
"004a52": "192121",
"106b63": "21524a",
"191921": "191921",
"106b7b": "102c16",
"29848c": "224427",
"6b4200": "54190e",
"c59c52": "a65c3f",
"9c7329": "763826",
"dece94": "e46424",
"ffefa5": "ff9942",
"bdad73": "cb3000"
"106b7b": "293a42",
"29848c": "424a5a",
"6b4200": "523a10",
"c59c52": "b59463",
"9c7329": "846b3a",
"dece94": "b5de21",
"ffefa5": "d6ff42",
"bdad73": "94bd00"
},
"1": {
"298c8c": "793907",

View File

@ -0,0 +1,24 @@
{
"1": {
"101010": "101010",
"8cb5ef": "4e538f",
"4a427b": "14093b",
"637bb5": "37326f",
"73215a": "aa4c18",
"b5529c": "cc7b32",
"bdceff": "868ecc",
"ffffff": "ffffff",
"636363": "636363"
},
"2": {
"101010": "101010",
"8cb5ef": "cbabca",
"4a427b": "4d3259",
"637bb5": "916c8b",
"73215a": "670f10",
"b5529c": "94241c",
"bdceff": "e8d2e6",
"ffffff": "ffffff",
"636363": "636363"
}
}

View File

@ -0,0 +1,24 @@
{
"1": {
"3a3a7b": "1d0f4e",
"6384ce": "2f2a5f",
"adceff": "666fb4",
"5aadef": "3d4381",
"631052": "892d03",
"000000": "000000",
"ce6bb5": "f1a139",
"ad52ad": "d5711b",
"943a7b": "af4e0c"
},
"2": {
"3a3a7b": "3d2349",
"6384ce": "916c8b",
"adceff": "e8d2e6",
"5aadef": "cbabca",
"631052": "54070c",
"000000": "000000",
"ce6bb5": "bc3b1d",
"ad52ad": "94241c",
"943a7b": "6c1314"
}
}

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "747_2.png",
"format": "RGBA8888",
"size": {
"w": 110,
"h": 110
},
"scale": 1,
"frames": [
{
"filename": "0003.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
},
"frame": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
}
},
{
"filename": "0004.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
},
"frame": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
}
},
{
"filename": "0007.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
},
"frame": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
}
},
{
"filename": "0008.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
},
"frame": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
}
},
{
"filename": "0001.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 46
},
"frame": {
"x": 55,
"y": 0,
"w": 55,
"h": 46
}
},
{
"filename": "0002.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 46
},
"frame": {
"x": 55,
"y": 0,
"w": 55,
"h": 46
}
},
{
"filename": "0005.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 55,
"h": 46
},
"frame": {
"x": 55,
"y": 46,
"w": 55,
"h": 46
}
},
{
"filename": "0006.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 55,
"h": 46
},
"frame": {
"x": 55,
"y": 46,
"w": 55,
"h": 46
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:e4c4f790c4f0286f608dcdb15a609059:464f7ae7db1c0d034c2a1a65612b0da8:b26f7254994561969f00f765318acf1c$"
}
}

View File

@ -0,0 +1,755 @@
{
"textures": [
{
"image": "890-eternamax_2.png",
"format": "RGBA8888",
"size": {
"w": 579,
"h": 579
},
"scale": 1,
"frames": [
{
"filename": "0035.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 9,
"w": 100,
"h": 98
},
"frame": {
"x": 0,
"y": 0,
"w": 100,
"h": 98
}
},
{
"filename": "0031.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 8,
"w": 95,
"h": 100
},
"frame": {
"x": 100,
"y": 0,
"w": 95,
"h": 100
}
},
{
"filename": "0029.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 8,
"w": 91,
"h": 100
},
"frame": {
"x": 0,
"y": 98,
"w": 91,
"h": 100
}
},
{
"filename": "0001.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 9,
"w": 96,
"h": 98
},
"frame": {
"x": 91,
"y": 100,
"w": 96,
"h": 98
}
},
{
"filename": "0032.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 9,
"w": 95,
"h": 99
},
"frame": {
"x": 187,
"y": 100,
"w": 95,
"h": 99
}
},
{
"filename": "0030.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 9,
"y": 10,
"w": 91,
"h": 98
},
"frame": {
"x": 0,
"y": 198,
"w": 91,
"h": 98
}
},
{
"filename": "0007.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 10,
"w": 88,
"h": 98
},
"frame": {
"x": 91,
"y": 198,
"w": 88,
"h": 98
}
},
{
"filename": "0002.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 10,
"w": 95,
"h": 97
},
"frame": {
"x": 195,
"y": 0,
"w": 95,
"h": 97
}
},
{
"filename": "0003.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 11,
"w": 95,
"h": 97
},
"frame": {
"x": 179,
"y": 199,
"w": 95,
"h": 97
}
},
{
"filename": "0004.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 11,
"w": 95,
"h": 97
},
"frame": {
"x": 274,
"y": 199,
"w": 95,
"h": 97
}
},
{
"filename": "0033.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 11,
"w": 95,
"h": 97
},
"frame": {
"x": 290,
"y": 0,
"w": 95,
"h": 97
}
},
{
"filename": "0034.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 11,
"w": 94,
"h": 96
},
"frame": {
"x": 282,
"y": 97,
"w": 94,
"h": 96
}
},
{
"filename": "0028.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 11,
"w": 90,
"h": 97
},
"frame": {
"x": 369,
"y": 193,
"w": 90,
"h": 97
}
},
{
"filename": "0005.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 13,
"w": 93,
"h": 95
},
"frame": {
"x": 385,
"y": 0,
"w": 93,
"h": 95
}
},
{
"filename": "0017.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 13,
"y": 9,
"w": 91,
"h": 96
},
"frame": {
"x": 385,
"y": 95,
"w": 91,
"h": 96
}
},
{
"filename": "0008.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 87,
"h": 97
},
"frame": {
"x": 369,
"y": 290,
"w": 87,
"h": 97
}
},
{
"filename": "0009.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 12,
"w": 90,
"h": 96
},
"frame": {
"x": 456,
"y": 290,
"w": 90,
"h": 96
}
},
{
"filename": "0015.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 8,
"w": 90,
"h": 96
},
"frame": {
"x": 459,
"y": 191,
"w": 90,
"h": 96
}
},
{
"filename": "0016.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 13,
"y": 8,
"w": 90,
"h": 95
},
"frame": {
"x": 476,
"y": 95,
"w": 90,
"h": 95
}
},
{
"filename": "0014.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 89,
"h": 95
},
"frame": {
"x": 478,
"y": 0,
"w": 89,
"h": 95
}
},
{
"filename": "0027.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 12,
"w": 89,
"h": 96
},
"frame": {
"x": 456,
"y": 386,
"w": 89,
"h": 96
}
},
{
"filename": "0025.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 11,
"w": 89,
"h": 95
},
"frame": {
"x": 0,
"y": 296,
"w": 89,
"h": 95
}
},
{
"filename": "0006.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 9,
"y": 14,
"w": 89,
"h": 94
},
"frame": {
"x": 89,
"y": 296,
"w": 89,
"h": 94
}
},
{
"filename": "0011.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 88,
"h": 95
},
"frame": {
"x": 178,
"y": 296,
"w": 88,
"h": 95
}
},
{
"filename": "0023.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 87,
"h": 95
},
"frame": {
"x": 89,
"y": 390,
"w": 87,
"h": 95
}
},
{
"filename": "0013.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 12,
"w": 89,
"h": 94
},
"frame": {
"x": 0,
"y": 391,
"w": 89,
"h": 94
}
},
{
"filename": "0012.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 14,
"w": 89,
"h": 93
},
"frame": {
"x": 266,
"y": 387,
"w": 89,
"h": 93
}
},
{
"filename": "0019.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 16,
"y": 13,
"w": 85,
"h": 91
},
"frame": {
"x": 266,
"y": 296,
"w": 85,
"h": 91
}
},
{
"filename": "0024.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 13,
"w": 88,
"h": 94
},
"frame": {
"x": 176,
"y": 391,
"w": 88,
"h": 94
}
},
{
"filename": "0010.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 13,
"w": 87,
"h": 94
},
"frame": {
"x": 355,
"y": 387,
"w": 87,
"h": 94
}
},
{
"filename": "0018.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 16,
"y": 11,
"w": 87,
"h": 94
},
"frame": {
"x": 264,
"y": 480,
"w": 87,
"h": 94
}
},
{
"filename": "0026.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 14,
"w": 89,
"h": 93
},
"frame": {
"x": 351,
"y": 481,
"w": 89,
"h": 93
}
},
{
"filename": "0022.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 87,
"h": 93
},
"frame": {
"x": 440,
"y": 482,
"w": 87,
"h": 93
}
},
{
"filename": "0021.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 13,
"y": 10,
"w": 86,
"h": 94
},
"frame": {
"x": 0,
"y": 485,
"w": 86,
"h": 94
}
},
{
"filename": "0020.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 13,
"y": 14,
"w": 85,
"h": 91
},
"frame": {
"x": 86,
"y": 485,
"w": 85,
"h": 91
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:8fd9e1830200ec8e4aac8571cc2d27a6:c966e3efce03c7bae43d7bca6d6dfa62:cedd2711a12bbacba5623505fe88bd92$"
}
}

View File

@ -0,0 +1,755 @@
{
"textures": [
{
"image": "890-eternamax_3.png",
"format": "RGBA8888",
"size": {
"w": 579,
"h": 579
},
"scale": 1,
"frames": [
{
"filename": "0035.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 9,
"w": 100,
"h": 98
},
"frame": {
"x": 0,
"y": 0,
"w": 100,
"h": 98
}
},
{
"filename": "0031.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 8,
"w": 95,
"h": 100
},
"frame": {
"x": 100,
"y": 0,
"w": 95,
"h": 100
}
},
{
"filename": "0029.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 8,
"w": 91,
"h": 100
},
"frame": {
"x": 0,
"y": 98,
"w": 91,
"h": 100
}
},
{
"filename": "0001.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 9,
"w": 96,
"h": 98
},
"frame": {
"x": 91,
"y": 100,
"w": 96,
"h": 98
}
},
{
"filename": "0032.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 9,
"w": 95,
"h": 99
},
"frame": {
"x": 187,
"y": 100,
"w": 95,
"h": 99
}
},
{
"filename": "0030.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 9,
"y": 10,
"w": 91,
"h": 98
},
"frame": {
"x": 0,
"y": 198,
"w": 91,
"h": 98
}
},
{
"filename": "0007.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 10,
"w": 88,
"h": 98
},
"frame": {
"x": 91,
"y": 198,
"w": 88,
"h": 98
}
},
{
"filename": "0002.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 10,
"w": 95,
"h": 97
},
"frame": {
"x": 195,
"y": 0,
"w": 95,
"h": 97
}
},
{
"filename": "0003.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 11,
"w": 95,
"h": 97
},
"frame": {
"x": 179,
"y": 199,
"w": 95,
"h": 97
}
},
{
"filename": "0004.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 11,
"w": 95,
"h": 97
},
"frame": {
"x": 274,
"y": 199,
"w": 95,
"h": 97
}
},
{
"filename": "0033.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 11,
"w": 95,
"h": 97
},
"frame": {
"x": 290,
"y": 0,
"w": 95,
"h": 97
}
},
{
"filename": "0034.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 11,
"w": 94,
"h": 96
},
"frame": {
"x": 282,
"y": 97,
"w": 94,
"h": 96
}
},
{
"filename": "0028.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 11,
"w": 90,
"h": 97
},
"frame": {
"x": 369,
"y": 193,
"w": 90,
"h": 97
}
},
{
"filename": "0005.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 8,
"y": 13,
"w": 93,
"h": 95
},
"frame": {
"x": 385,
"y": 0,
"w": 93,
"h": 95
}
},
{
"filename": "0017.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 13,
"y": 9,
"w": 91,
"h": 96
},
"frame": {
"x": 385,
"y": 95,
"w": 91,
"h": 96
}
},
{
"filename": "0008.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 87,
"h": 97
},
"frame": {
"x": 369,
"y": 290,
"w": 87,
"h": 97
}
},
{
"filename": "0009.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 12,
"w": 90,
"h": 96
},
"frame": {
"x": 456,
"y": 290,
"w": 90,
"h": 96
}
},
{
"filename": "0015.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 8,
"w": 90,
"h": 96
},
"frame": {
"x": 459,
"y": 191,
"w": 90,
"h": 96
}
},
{
"filename": "0016.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 13,
"y": 8,
"w": 90,
"h": 95
},
"frame": {
"x": 476,
"y": 95,
"w": 90,
"h": 95
}
},
{
"filename": "0014.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 89,
"h": 95
},
"frame": {
"x": 478,
"y": 0,
"w": 89,
"h": 95
}
},
{
"filename": "0027.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 12,
"w": 89,
"h": 96
},
"frame": {
"x": 456,
"y": 386,
"w": 89,
"h": 96
}
},
{
"filename": "0025.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 11,
"w": 89,
"h": 95
},
"frame": {
"x": 0,
"y": 296,
"w": 89,
"h": 95
}
},
{
"filename": "0006.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 9,
"y": 14,
"w": 89,
"h": 94
},
"frame": {
"x": 89,
"y": 296,
"w": 89,
"h": 94
}
},
{
"filename": "0011.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 88,
"h": 95
},
"frame": {
"x": 178,
"y": 296,
"w": 88,
"h": 95
}
},
{
"filename": "0023.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 87,
"h": 95
},
"frame": {
"x": 89,
"y": 390,
"w": 87,
"h": 95
}
},
{
"filename": "0013.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 12,
"w": 89,
"h": 94
},
"frame": {
"x": 0,
"y": 391,
"w": 89,
"h": 94
}
},
{
"filename": "0012.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 14,
"w": 89,
"h": 93
},
"frame": {
"x": 266,
"y": 387,
"w": 89,
"h": 93
}
},
{
"filename": "0019.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 16,
"y": 13,
"w": 85,
"h": 91
},
"frame": {
"x": 266,
"y": 296,
"w": 85,
"h": 91
}
},
{
"filename": "0024.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 13,
"w": 88,
"h": 94
},
"frame": {
"x": 176,
"y": 391,
"w": 88,
"h": 94
}
},
{
"filename": "0010.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 13,
"w": 87,
"h": 94
},
"frame": {
"x": 355,
"y": 387,
"w": 87,
"h": 94
}
},
{
"filename": "0018.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 16,
"y": 11,
"w": 87,
"h": 94
},
"frame": {
"x": 264,
"y": 480,
"w": 87,
"h": 94
}
},
{
"filename": "0026.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 11,
"y": 14,
"w": 89,
"h": 93
},
"frame": {
"x": 351,
"y": 481,
"w": 89,
"h": 93
}
},
{
"filename": "0022.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 12,
"y": 11,
"w": 87,
"h": 93
},
"frame": {
"x": 440,
"y": 482,
"w": 87,
"h": 93
}
},
{
"filename": "0021.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 13,
"y": 10,
"w": 86,
"h": 94
},
"frame": {
"x": 0,
"y": 485,
"w": 86,
"h": 94
}
},
{
"filename": "0020.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 112,
"h": 112
},
"spriteSourceSize": {
"x": 13,
"y": 14,
"w": 85,
"h": 91
},
"frame": {
"x": 86,
"y": 485,
"w": 85,
"h": 91
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:8fd9e1830200ec8e4aac8571cc2d27a6:c966e3efce03c7bae43d7bca6d6dfa62:cedd2711a12bbacba5623505fe88bd92$"
}
}

View File

@ -0,0 +1,26 @@
{
"1": {
"101010": "101010",
"637bb5": "37326f",
"4a427b": "14093b",
"bdceff": "868ecc",
"8cb5ef": "4e538f",
"b5529c": "cc7b32",
"73215a": "aa4c18",
"d673bd": "f0ad57",
"ffffff": "ffffff",
"636363": "636363"
},
"2": {
"101010": "101010",
"637bb5": "916c8b",
"4a427b": "4d3259",
"bdceff": "e8d2e6",
"8cb5ef": "cbabca",
"b5529c": "94241c",
"73215a": "670f10",
"d673bd": "bc3b1d",
"ffffff": "ffffff",
"636363": "636363"
}
}

View File

@ -0,0 +1,30 @@
{
"1": {
"3a3a7b": "1d0f4e",
"5aadef": "3d4381",
"6384ce": "2f2a5f",
"631052": "892d03",
"ce6bb5": "f1a139",
"adceff": "666fb4",
"000000": "000000",
"ad52ad": "d5711b",
"636363": "636363",
"ffffff": "ffffff",
"d6d6d6": "d6d6d6",
"943a7b": "af4e0c"
},
"2": {
"3a3a7b": "3d2349",
"5aadef": "cbabca",
"6384ce": "916c8b",
"631052": "54070c",
"ce6bb5": "bc3b1d",
"adceff": "e8d2e6",
"000000": "000000",
"ad52ad": "94241c",
"636363": "636363",
"ffffff": "ffffff",
"d6d6d6": "d6d6d6",
"943a7b": "6c1314"
}
}

View File

@ -11,6 +11,7 @@ import { BattleSpec } from "./enums/battle-spec";
import { PlayerGender } from "./system/game-data";
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
import { MoneyAchv } from "./system/achv";
import { PokeballType } from "./data/pokeball";
export enum BattleType {
WILD,
@ -61,6 +62,7 @@ export default class Battle {
public battleSeed: string;
private battleSeedState: string;
public moneyScattered: number;
public lastUsedPokeball: PokeballType;
private rngCounter: integer = 0;
@ -86,6 +88,7 @@ export default class Battle {
this.battleSeed = Utils.randomString(16, true);
this.battleSeedState = null;
this.moneyScattered = 0;
this.lastUsedPokeball = null;
}
private initBattleSpec(): void {

View File

@ -9,7 +9,7 @@ import { BattlerTag } from "./battler-tags";
import { BattlerTagType } from "./enums/battler-tag-type";
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
import { Gender } from "./gender";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove, VariablePowerAttr, applyMoveAttrs } from "./move";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type";
import { Stat } from "./pokemon-stat";
@ -22,6 +22,7 @@ import i18next, { Localizable } from "#app/plugins/i18n.js";
import { Command } from "../ui/command-ui-handler";
import Battle from "#app/battle.js";
import { ability } from "#app/locales/en/ability.js";
import { PokeballType, getPokeballName } from "./pokeball";
export class Ability implements Localizable {
public id: Abilities;
@ -490,8 +491,13 @@ export class PostDefendFormChangeAbAttr extends PostDefendAbAttr {
export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const attackPriority = new Utils.IntegerHolder(move.getMove().priority);
applyMoveAttrs(IncrementMovePriorityAttr,attacker,null,move.getMove(),attackPriority);
applyAbAttrs(IncrementMovePriorityAbAttr, attacker, null, move.getMove(), attackPriority);
if(move.getMove().moveTarget===MoveTarget.USER) {
return false;
}
if(attackPriority.value > 0 && !move.getMove().isMultiTarget()) {
cancelled.value = true;
return true;
@ -1822,6 +1828,36 @@ export class MultCritAbAttr extends AbAttr {
}
}
/**
* Guarantees a critical hit according to the given condition, except if target prevents critical hits. ie. Merciless
* @extends AbAttr
* @see {@linkcode apply}
*/
export class ConditionalCritAbAttr extends AbAttr {
private condition: PokemonAttackCondition;
constructor(condition: PokemonAttackCondition, checkUser?: Boolean) {
super();
this.condition = condition;
}
/**
* @param pokemon {@linkcode Pokemon} user.
* @param args [0] {@linkcode Utils.BooleanHolder} If true critical hit is guaranteed.
* [1] {@linkcode Pokemon} Target.
* [2] {@linkcode Move} used by ability user.
*/
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const target = (args[1] as Pokemon);
const move = (args[2] as Move);
if(!this.condition(pokemon,target,move))
return false;
(args[0] as Utils.BooleanHolder).value = true;
return true;
}
}
export class BlockNonDirectDamageAbAttr extends AbAttr {
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
@ -2246,6 +2282,61 @@ export class PostTurnFormChangeAbAttr extends PostTurnAbAttr {
}
}
/**
* Attribute used for abilities (Bad Dreams) that damages the opponents for being asleep
*/
export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr {
/**
* Deals damage to all sleeping opponents equal to 1/8 of their max hp (min 1)
* @param {Pokemon} pokemon Pokemon that has this ability
* @param {boolean} passive N/A
* @param {any[]} args N/A
* @returns {boolean} true if any opponents are sleeping
*/
applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
let hadEffect: boolean = false;
for(let opp of pokemon.getOpponents()) {
if(opp.status !== undefined && opp.status.effect === StatusEffect.SLEEP) {
opp.damageAndUpdate(Math.floor(Math.max(1, opp.getMaxHp() / 8)), HitResult.OTHER);
pokemon.scene.queueMessage(i18next.t('abilityTriggers:badDreams', {pokemonName: `${getPokemonPrefix(opp)}${opp.name}`}));
hadEffect = true;
}
}
return hadEffect;
}
}
/**
* Grabs the last failed Pokeball used
* @extends PostTurnAbAttr
* @see {@linkcode applyPostTurn} */
export class FetchBallAbAttr extends PostTurnAbAttr {
constructor() {
super();
}
/**
* Adds the last used Pokeball back into the player's inventory
* @param pokemon {@linkcode Pokemon} with this ability
* @param passive N/A
* @param args N/A
* @returns true if player has used a pokeball and this pokemon is owned by the player
*/
applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
let lastUsed = pokemon.scene.currentBattle.lastUsedPokeball;
if(lastUsed != null && pokemon.isPlayer) {
pokemon.scene.pokeballCounts[lastUsed]++;
pokemon.scene.currentBattle.lastUsedPokeball = null;
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` found a\n${getPokeballName(lastUsed)}!`));
return true;
}
return false;
}
}
export class PostBiomeChangeAbAttr extends AbAttr { }
export class PostBiomeChangeWeatherChangeAbAttr extends PostBiomeChangeAbAttr {
@ -2338,18 +2429,42 @@ export class RunSuccessAbAttr extends AbAttr {
}
}
/**
* Base class for checking if a Pokemon is trapped by arena trap
* @extends AbAttr
* @see {@linkcode applyCheckTrapped}
*/
export class CheckTrappedAbAttr extends AbAttr {
constructor() {
super(false);
}
applyCheckTrapped(pokemon: Pokemon, passive: boolean, trapped: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
applyCheckTrapped(pokemon: Pokemon, passive: boolean, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, args: any[]): boolean | Promise<boolean> {
return false;
}
}
/**
* Determines whether a Pokemon is blocked from switching/running away
* because of a trapping ability or move.
* @extends CheckTrappedAbAttr
* @see {@linkcode applyCheckTrapped}
*/
export class ArenaTrapAbAttr extends CheckTrappedAbAttr {
applyCheckTrapped(pokemon: Pokemon, passive: boolean, trapped: Utils.BooleanHolder, args: any[]): boolean {
/**
* Checks if enemy Pokemon is trapped by an Arena Trap-esque ability
* @param pokemon The {@link Pokemon} with this {@link AbAttr}
* @param passive N/A
* @param trapped {@link Utils.BooleanHolder} indicating whether the other Pokemon is trapped or not
* @param otherPokemon The {@link Pokemon} that is affected by an Arena Trap ability
* @param args N/A
* @returns if enemy Pokemon is trapped or not
*/
applyCheckTrapped(pokemon: Pokemon, passive: boolean, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, args: any[]): boolean {
if (otherPokemon.getTypes().includes(Type.GHOST)){
trapped.value = false;
return false;
}
trapped.value = true;
return true;
}
@ -2614,7 +2729,6 @@ export class SuppressFieldAbilitiesAbAttr extends AbAttr {
}
}
export class AlwaysHitAbAttr extends AbAttr { }
export class UncopiableAbilityAbAttr extends AbAttr {
@ -2859,8 +2973,8 @@ export function applyPostTerrainChangeAbAttrs(attrType: { new(...args: any[]): P
}
export function applyCheckTrappedAbAttrs(attrType: { new(...args: any[]): CheckTrappedAbAttr },
pokemon: Pokemon, trapped: Utils.BooleanHolder, ...args: any[]): Promise<void> {
return applyAbAttrsInternal<CheckTrappedAbAttr>(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, trapped, args), args, true);
pokemon: Pokemon, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, ...args: any[]): Promise<void> {
return applyAbAttrsInternal<CheckTrappedAbAttr>(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, trapped, otherPokemon, args), args, true);
}
export function applyPostBattleAbAttrs(attrType: { new(...args: any[]): PostBattleAbAttr },
@ -3241,7 +3355,7 @@ export function initAbilities() {
.ignorable()
.partial(),
new Ability(Abilities.BAD_DREAMS, 4)
.unimplemented(),
.attr(PostTurnHurtIfSleepingAbAttr),
new Ability(Abilities.PICKPOCKET, 5)
.attr(PostDefendStealHeldItemAbAttr, (target, user, move) => move.hasFlag(MoveFlags.MAKES_CONTACT)),
new Ability(Abilities.SHEER_FORCE, 5)
@ -3442,7 +3556,7 @@ export function initAbilities() {
new Ability(Abilities.WATER_COMPACTION, 7)
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.WATER && move.category !== MoveCategory.STATUS, BattleStat.DEF, 2),
new Ability(Abilities.MERCILESS, 7)
.unimplemented(),
.attr(ConditionalCritAbAttr, (user, target, move) => target.status?.effect === StatusEffect.TOXIC || target.status?.effect === StatusEffect.POISON),
new Ability(Abilities.SHIELDS_DOWN, 7)
.attr(PostBattleInitFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0))
.attr(PostSummonFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0))
@ -3597,7 +3711,8 @@ export function initAbilities() {
new Ability(Abilities.LIBERO, 8)
.unimplemented(),
new Ability(Abilities.BALL_FETCH, 8)
.unimplemented(),
.attr(FetchBallAbAttr)
.condition(getOncePerBattleCondition(Abilities.BALL_FETCH)),
new Ability(Abilities.COTTON_DOWN, 8)
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, BattleStat.SPD, -1, false, true)
.bypassFaint(),

View File

@ -130,9 +130,11 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
return (pokemon: Pokemon) => {
if (pokemon.battleData)
pokemon.battleData.berriesEaten.push(berryType);
const ppRestoreMove = pokemon.getMoveset().find(m => !m.getPpRatio());
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` restored PP to its move ${ppRestoreMove.getName()}\nusing its ${getBerryName(berryType)}!`));
const ppRestoreMove = pokemon.getMoveset().find(m => !m.getPpRatio()) ? pokemon.getMoveset().find(m => !m.getPpRatio()) : pokemon.getMoveset().find(m => m.getPpRatio() < 1);
if(ppRestoreMove !== undefined){
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` restored PP to its move ${ppRestoreMove.getName()}\nusing its ${getBerryName(berryType)}!`));
}
};
}
}

View File

@ -15,14 +15,14 @@ export const speciesEggMoves = {
[Species.SPEAROW]: [ Moves.FLOATY_FALL, Moves.EXTREME_SPEED, Moves.TIDY_UP, Moves.TRIPLE_ARROWS ],
[Species.EKANS]: [ Moves.SHED_TAIL, Moves.DRAGON_DANCE, Moves.SLACK_OFF, Moves.NOXIOUS_TORQUE ],
[Species.SANDSHREW]: [ Moves.DIRE_CLAW, Moves.CEASELESS_EDGE, Moves.SHORE_UP, Moves.PRECIPICE_BLADES ],
[Species.NIDORAN_F]: [ Moves.DIRE_CLAW, Moves.SHORE_UP, Moves.THOUSAND_WAVES, Moves.SALT_CURE ],
[Species.NIDORAN_F]: [ Moves.SANDSEAR_STORM, Moves.BANEFUL_BUNKER, Moves.NO_RETREAT, Moves.MALIGNANT_CHAIN ],
[Species.NIDORAN_M]: [ Moves.NOXIOUS_TORQUE, Moves.KINGS_SHIELD, Moves.NO_RETREAT, Moves.PRECIPICE_BLADES ],
[Species.VULPIX]: [ Moves.MOONBLAST, Moves.PSYCHIC, Moves.MORNING_SUN, Moves.TAIL_GLOW ],
[Species.ZUBAT]: [ Moves.FLOATY_FALL, Moves.DIRE_CLAW, Moves.SWORDS_DANCE, Moves.BRAVE_BIRD ],
[Species.VULPIX]: [ Moves.MOONBLAST, Moves.ICE_BEAM, Moves.MORNING_SUN, Moves.TAIL_GLOW ],
[Species.ZUBAT]: [ Moves.FLOATY_FALL, Moves.DIRE_CLAW, Moves.PARTING_SHOT, Moves.WICKED_BLOW ],
[Species.ODDISH]: [ Moves.SLUDGE_BOMB, Moves.FIERY_DANCE, Moves.STRENGTH_SAP, Moves.SPORE ],
[Species.PARAS]: [ Moves.FIRST_IMPRESSION, Moves.SAPPY_SEED, Moves.CRABHAMMER, Moves.DIRE_CLAW ],
[Species.VENONAT]: [ Moves.SLUDGE_BOMB, Moves.MOONLIGHT, Moves.EARTH_POWER, Moves.MYSTICAL_POWER ],
[Species.DIGLETT]: [ Moves.STRENGTH_SAP, Moves.SWORDS_DANCE, Moves.ICE_SPINNER, Moves.HEADLONG_RUSH ],
[Species.DIGLETT]: [ Moves.REVERSAL, Moves.SWORDS_DANCE, Moves.ICE_SPINNER, Moves.HEADLONG_RUSH ],
[Species.MEOWTH]: [ Moves.COVET, Moves.HAPPY_HOUR, Moves.PARTING_SHOT, Moves.MAKE_IT_RAIN ],
[Species.PSYDUCK]: [ Moves.MYSTICAL_POWER, Moves.AQUA_STEP, Moves.AURA_SPHERE, Moves.MIND_BLOWN ],
[Species.MANKEY]: [ Moves.DRAIN_PUNCH, Moves.RAGING_FURY, Moves.METEOR_MASH, Moves.NO_RETREAT ],
@ -34,18 +34,18 @@ export const speciesEggMoves = {
[Species.TENTACOOL]: [ Moves.BANEFUL_BUNKER, Moves.STRENGTH_SAP, Moves.HAZE, Moves.MALIGNANT_CHAIN ],
[Species.GEODUDE]: [ Moves.BODY_PRESS, Moves.BULK_UP, Moves.SHORE_UP, Moves.HEAD_SMASH ],
[Species.PONYTA]: [ Moves.HIGH_HORSEPOWER, Moves.FIRE_LASH, Moves.SWORDS_DANCE, Moves.VOLT_TACKLE ],
[Species.SLOWPOKE]: [ Moves.BOUNCY_BUBBLE, Moves.PARTING_SHOT, Moves.COSMIC_POWER, Moves.LUMINA_CRASH ],
[Species.SLOWPOKE]: [ Moves.BOUNCY_BUBBLE, Moves.FLAMETHROWER, Moves.MYSTICAL_POWER, Moves.SHED_TAIL ],
[Species.MAGNEMITE]: [ Moves.PARABOLIC_CHARGE, Moves.BODY_PRESS, Moves.ICE_BEAM, Moves.THUNDERCLAP ],
[Species.FARFETCHD]: [ Moves.BATON_PASS, Moves.SACRED_SWORD, Moves.ROOST, Moves.VICTORY_DANCE ],
[Species.DODUO]: [ Moves.TRIPLE_AXEL, Moves.MULTI_ATTACK, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ],
[Species.SEEL]: [ Moves.FREEZE_DRY, Moves.CHILLY_RECEPTION, Moves.SLACK_OFF, Moves.BOUNCY_BUBBLE ],
[Species.GRIMER]: [ Moves.SHADOW_SNEAK, Moves.CURSE, Moves.STRENGTH_SAP, Moves.NOXIOUS_TORQUE ],
[Species.SHELLDER]: [ Moves.ROCK_BLAST, Moves.WATER_SHURIKEN, Moves.BANEFUL_BUNKER, Moves.BONE_RUSH ],
[Species.GASTLY]: [ Moves.FROST_BREATH, Moves.AURA_SPHERE, Moves.NASTY_PLOT, Moves.MALIGNANT_CHAIN ],
[Species.GASTLY]: [ Moves.ICE_BEAM, Moves.AURA_SPHERE, Moves.NASTY_PLOT, Moves.MALIGNANT_CHAIN ],
[Species.ONIX]: [ Moves.SHORE_UP, Moves.BODY_PRESS, Moves.HEAD_SMASH, Moves.SPIN_OUT ],
[Species.DROWZEE]: [ Moves.DREAM_EATER, Moves.RECOVER, Moves.NIGHTMARE, Moves.SPORE ],
[Species.KRABBY]: [ Moves.ICICLE_CRASH, Moves.LIQUIDATION, Moves.IVY_CUDGEL, Moves.SHELL_SMASH ],
[Species.VOLTORB]: [ Moves.BUZZY_BUZZ, Moves.OVERHEAT, Moves.FROST_BREATH, Moves.TAIL_GLOW ],
[Species.VOLTORB]: [ Moves.BUZZY_BUZZ, Moves.OVERHEAT, Moves.ICE_BEAM, Moves.TAIL_GLOW ],
[Species.EXEGGCUTE]: [ Moves.MYSTICAL_POWER, Moves.APPLE_ACID, Moves.TRICK_ROOM, Moves.FICKLE_BEAM ],
[Species.CUBONE]: [ Moves.HEAD_SMASH, Moves.WOOD_HAMMER, Moves.PAIN_SPLIT, Moves.VOLT_TACKLE ],
[Species.LICKITUNG]: [ Moves.BODY_SLAM, Moves.FIRE_LASH, Moves.GRAV_APPLE, Moves.MILK_DRINK ],
@ -57,7 +57,7 @@ export const speciesEggMoves = {
[Species.GOLDEEN]: [ Moves.DRILL_RUN, Moves.FLIP_TURN, Moves.DRAGON_DANCE, Moves.FISHIOUS_REND ],
[Species.STARYU]: [ Moves.CALM_MIND, Moves.BOUNCY_BUBBLE, Moves.MOONBLAST, Moves.MYSTICAL_POWER ],
[Species.SCYTHER]: [ Moves.GEAR_GRIND, Moves.BUG_BITE, Moves.STORM_THROW, Moves.MIGHTY_CLEAVE ],
[Species.PINSIR]: [ Moves.CRUSH_GRIP, Moves.U_TURN, Moves.CLOSE_COMBAT, Moves.EXTREME_SPEED ],
[Species.PINSIR]: [ Moves.EARTHQUAKE, Moves.LEECH_LIFE, Moves.CLOSE_COMBAT, Moves.EXTREME_SPEED ],
[Species.TAUROS]: [ Moves.HIGH_HORSEPOWER, Moves.FLARE_BLITZ, Moves.WAVE_CRASH, Moves.HEAD_CHARGE ],
[Species.MAGIKARP]: [ Moves.FLIP_TURN, Moves.ICE_SPINNER, Moves.LIQUIDATION, Moves.DRAGON_ASCENT ],
[Species.LAPRAS]: [ Moves.RECOVER, Moves.FREEZE_DRY, Moves.CHILLY_RECEPTION, Moves.BOOMBURST ],
@ -79,7 +79,7 @@ export const speciesEggMoves = {
[Species.SENTRET]: [ Moves.TIDY_UP, Moves.THIEF, Moves.NUZZLE, Moves.EXTREME_SPEED ],
[Species.HOOTHOOT]: [ Moves.CALM_MIND, Moves.ESPER_WING, Moves.BOOMBURST, Moves.OBLIVION_WING ],
[Species.LEDYBA]: [ Moves.POLLEN_PUFF, Moves.THIEF, Moves.PARTING_SHOT, Moves.SPORE ],
[Species.SPINARAK]: [ Moves.PARTING_SHOT, Moves.MEGAHORN, Moves.SILK_TRAP, Moves.STRENGTH_SAP ],
[Species.SPINARAK]: [ Moves.GASTRO_ACID, Moves.ATTACK_ORDER, Moves.SUPER_FANG, Moves.STRENGTH_SAP ],
[Species.CHINCHOU]: [ Moves.THUNDERCLAP, Moves.BOUNCY_BUBBLE, Moves.VOLT_SWITCH, Moves.TAIL_GLOW ],
[Species.PICHU]: [ Moves.THUNDERCLAP, Moves.SPLISHY_SPLASH, Moves.FLOATY_FALL, Moves.THUNDER_CAGE ],
[Species.CLEFFA]: [ Moves.TAKE_HEART, Moves.POWER_GEM, Moves.WISH, Moves.LIGHT_OF_RUIN ],
@ -100,16 +100,16 @@ export const speciesEggMoves = {
[Species.DUNSPARCE]: [ Moves.BODY_SLAM, Moves.WICKED_TORQUE, Moves.BLAZING_TORQUE, Moves.EXTREME_SPEED ],
[Species.GLIGAR]: [ Moves.STONE_AXE, Moves.EARTHQUAKE, Moves.ROOST, Moves.FLOATY_FALL ],
[Species.SNUBBULL]: [ Moves.PARTING_SHOT, Moves.EARTHQUAKE, Moves.STUFF_CHEEKS, Moves.MAGICAL_TORQUE ],
[Species.QWILFISH]: [ Moves.BARB_BARRAGE, Moves.BANEFUL_BUNKER, Moves.NUZZLE, Moves.FISHIOUS_REND ],
[Species.QWILFISH]: [ Moves.BARB_BARRAGE, Moves.BANEFUL_BUNKER, Moves.KNOCK_OFF, Moves.FISHIOUS_REND ],
[Species.SHUCKLE]: [ Moves.COSMIC_POWER, Moves.SHORE_UP, Moves.BODY_PRESS, Moves.SALT_CURE ],
[Species.HERACROSS]: [ Moves.ROCK_BLAST, Moves.LUNGE, Moves.ICICLE_SPEAR, Moves.TIDY_UP ],
[Species.SNEASEL]: [ Moves.DIRE_CLAW, Moves.KOWTOW_CLEAVE, Moves.TRIPLE_AXEL, Moves.GLACIAL_LANCE ],
[Species.HERACROSS]: [ Moves.ROCK_BLAST, Moves.FIRST_IMPRESSION, Moves.ICICLE_SPEAR, Moves.TIDY_UP ],
[Species.SNEASEL]: [ Moves.DIRE_CLAW, Moves.SUCKER_PUNCH, Moves.TRIPLE_AXEL, Moves.WICKED_BLOW ],
[Species.TEDDIURSA]: [ Moves.DIRE_CLAW, Moves.FACADE, Moves.BULK_UP, Moves.SLACK_OFF ],
[Species.SLUGMA]: [ Moves.BURNING_BULWARK, Moves.POWER_GEM, Moves.MAGMA_STORM, Moves.HYDRO_STEAM ],
[Species.SWINUB]: [ Moves.ICE_SPINNER, Moves.HEADLONG_RUSH, Moves.MIGHTY_CLEAVE, Moves.GLACIAL_LANCE ],
[Species.CORSOLA]: [ Moves.SCALD, Moves.FREEZE_DRY, Moves.STRENGTH_SAP, Moves.SALT_CURE ],
[Species.REMORAID]: [ Moves.TWIN_BEAM, Moves.SNIPE_SHOT, Moves.SEARING_SHOT, Moves.ELECTRO_SHOT ],
[Species.DELIBIRD]: [ Moves.GLACIATE, Moves.FREEZE_DRY, Moves.CHILLY_RECEPTION, Moves.BLEAKWIND_STORM ],
[Species.REMORAID]: [ Moves.WATER_SHURIKEN, Moves.SNIPE_SHOT, Moves.SEARING_SHOT, Moves.ELECTRO_SHOT ],
[Species.DELIBIRD]: [ Moves.DRILL_RUN, Moves.FLOATY_FALL, Moves.NO_RETREAT, Moves.GLACIAL_LANCE ],
[Species.SKARMORY]: [ Moves.ROOST, Moves.BODY_PRESS, Moves.SPIKY_SHIELD, Moves.BEAK_BLAST ],
[Species.HOUNDOUR]: [ Moves.SEARING_SHOT, Moves.FIERY_WRATH, Moves.PARTING_SHOT, Moves.HYDRO_STEAM ],
[Species.PHANPY]: [ Moves.SHORE_UP, Moves.HEAD_SMASH, Moves.MOUNTAIN_GALE, Moves.VOLT_TACKLE ],
@ -122,10 +122,10 @@ export const speciesEggMoves = {
[Species.MILTANK]: [ Moves.BODY_PRESS, Moves.BULK_UP, Moves.YAWN, Moves.SIZZLY_SLIDE ],
[Species.RAIKOU]: [ Moves.THUNDERCLAP, Moves.NASTY_PLOT, Moves.ICE_BEAM, Moves.PARABOLIC_CHARGE ],
[Species.ENTEI]: [ Moves.BURNING_BULWARK, Moves.DRAGON_DANCE, Moves.EARTHQUAKE, Moves.MIGHTY_CLEAVE ],
[Species.SUICUNE]: [ Moves.HYDRO_STEAM, Moves.CALM_MIND, Moves.FREEZE_DRY, Moves.BOUNCY_BUBBLE ],
[Species.LARVITAR]: [ Moves.DRAGON_DANCE, Moves.MOUNTAIN_GALE, Moves.MIGHTY_CLEAVE, Moves.SHORE_UP ],
[Species.SUICUNE]: [ Moves.RECOVER, Moves.NASTY_PLOT, Moves.FREEZE_DRY, Moves.STEAM_ERUPTION ],
[Species.LARVITAR]: [ Moves.DRAGON_DANCE, Moves.MOUNTAIN_GALE, Moves.SHORE_UP, Moves.DIAMOND_STORM ],
[Species.LUGIA]: [ Moves.TAKE_HEART, Moves.STORED_POWER, Moves.SCALD, Moves.OBLIVION_WING ],
[Species.HO_OH]: [ Moves.BURNING_BULWARK, Moves.U_TURN, Moves.BRAVE_BIRD, Moves.REVIVAL_BLESSING ],
[Species.HO_OH]: [ Moves.SWORDS_DANCE, Moves.EARTHQUAKE, Moves.BRAVE_BIRD, Moves.REVIVAL_BLESSING ],
[Species.CELEBI]: [ Moves.MYSTICAL_POWER, Moves.STORED_POWER, Moves.COSMIC_POWER, Moves.SEED_FLARE ],
[Species.TREECKO]: [ Moves.DRAGON_PULSE, Moves.DRAGON_ENERGY, Moves.SECRET_SWORD, Moves.SEED_FLARE ],
[Species.TORCHIC]: [ Moves.HIGH_JUMP_KICK, Moves.SUPERCELL_SLAM, Moves.KNOCK_OFF, Moves.V_CREATE ],
@ -138,7 +138,7 @@ export const speciesEggMoves = {
[Species.TAILLOW]: [ Moves.SWORDS_DANCE, Moves.FACADE, Moves.DRILL_RUN, Moves.EXTREME_SPEED ],
[Species.WINGULL]: [ Moves.THUNDER, Moves.FLIP_TURN, Moves.DEFOG, Moves.STEAM_ERUPTION ],
[Species.RALTS]: [ Moves.BOOMBURST, Moves.BITTER_BLADE, Moves.QUIVER_DANCE, Moves.VICTORY_DANCE ],
[Species.SURSKIT]: [ Moves.ROOST, Moves.FIERY_DANCE, Moves.STICKY_WEB, Moves.BLEAKWIND_STORM ],
[Species.SURSKIT]: [ Moves.POLLEN_PUFF, Moves.FIERY_DANCE, Moves.BOUNCY_BUBBLE, Moves.AEROBLAST ],
[Species.SHROOMISH]: [ Moves.ACCELEROCK, Moves.TRAILBLAZE, Moves.STORM_THROW, Moves.SAPPY_SEED ],
[Species.SLAKOTH]: [ Moves.FACADE, Moves.JUMP_KICK, Moves.KNOCK_OFF, Moves.SKILL_SWAP ],
[Species.NINCADA]: [ Moves.ATTACK_ORDER, Moves.STICKY_WEB, Moves.SPIRIT_SHACKLE, Moves.SHELL_SMASH ],
@ -146,7 +146,7 @@ export const speciesEggMoves = {
[Species.MAKUHITA]: [ Moves.STORM_THROW, Moves.SLACK_OFF, Moves.HEAT_CRASH, Moves.DOUBLE_IRON_BASH ],
[Species.AZURILL]: [ Moves.JET_PUNCH, Moves.SPIRIT_BREAK, Moves.SWORDS_DANCE, Moves.SURGING_STRIKES ],
[Species.NOSEPASS]: [ Moves.SHORE_UP, Moves.BODY_PRESS, Moves.CALM_MIND, Moves.TACHYON_CUTTER ],
[Species.SKITTY]: [ Moves.THUNDEROUS_KICK, Moves.SKETCH, Moves.TIDY_UP, Moves.V_CREATE ],
[Species.SKITTY]: [ Moves.THUNDEROUS_KICK, Moves.ENTRAINMENT, Moves.TIDY_UP, Moves.V_CREATE ],
[Species.SABLEYE]: [ Moves.RECOVER, Moves.TOPSY_TURVY, Moves.PARTING_SHOT, Moves.SALT_CURE ],
[Species.MAWILE]: [ Moves.BULLET_PUNCH, Moves.MAGICAL_TORQUE, Moves.EARTHQUAKE, Moves.DOUBLE_IRON_BASH ],
[Species.ARON]: [ Moves.HEAD_SMASH, Moves.BODY_PRESS, Moves.SHORE_UP, Moves.SALT_CURE ],
@ -159,8 +159,8 @@ export const speciesEggMoves = {
[Species.GULPIN]: [ Moves.STRENGTH_SAP, Moves.EARTH_POWER, Moves.GROWTH, Moves.MALIGNANT_CHAIN ],
[Species.CARVANHA]: [ Moves.DRILL_RUN, Moves.ICE_SPINNER, Moves.WAVE_CRASH, Moves.SWORDS_DANCE ],
[Species.WAILMER]: [ Moves.CURSE, Moves.LIQUIDATION, Moves.FLOATY_FALL, Moves.RECOVER ],
[Species.NUMEL]: [ Moves.SANDSEAR_STORM, Moves.SPIKES, Moves.SHORE_UP, Moves.SEARING_SHOT ],
[Species.TORKOAL]: [ Moves.SLACK_OFF, Moves.SPIKES, Moves.BODY_PRESS, Moves.BURNING_BULWARK ],
[Species.NUMEL]: [ Moves.TRICK_ROOM, Moves.ENERGY_BALL, Moves.MORNING_SUN, Moves.BLUE_FLARE ],
[Species.TORKOAL]: [ Moves.MORNING_SUN, Moves.BURNING_BULWARK, Moves.BODY_PRESS, Moves.HYDRO_STEAM ],
[Species.SPOINK]: [ Moves.AURA_SPHERE, Moves.MILK_DRINK, Moves.COSMIC_POWER, Moves.EXPANDING_FORCE ],
[Species.SPINDA]: [ Moves.SUPERPOWER, Moves.SLACK_OFF, Moves.FLEUR_CANNON, Moves.V_CREATE ],
[Species.TRAPINCH]: [ Moves.FIRE_LASH, Moves.DRAGON_DARTS, Moves.THOUSAND_ARROWS, Moves.DRAGON_ENERGY ],
@ -176,20 +176,20 @@ export const speciesEggMoves = {
[Species.LILEEP]: [ Moves.POWER_GEM, Moves.SCALD, Moves.STONE_AXE, Moves.SAPPY_SEED ],
[Species.ANORITH]: [ Moves.LIQUIDATION, Moves.LEECH_LIFE, Moves.DRAGON_DANCE, Moves.MIGHTY_CLEAVE ],
[Species.FEEBAS]: [ Moves.CALM_MIND, Moves.FREEZE_DRY, Moves.MOONBLAST, Moves.STEAM_ERUPTION ],
[Species.CASTFORM]: [ Moves.BOOMBURST, Moves.HYDRO_STEAM, Moves.CLEAR_SMOG, Moves.QUIVER_DANCE ],
[Species.CASTFORM]: [ Moves.BOOMBURST, Moves.HYDRO_STEAM, Moves.ERUPTION, Moves.QUIVER_DANCE ],
[Species.KECLEON]: [ Moves.DRAIN_PUNCH, Moves.DRAGON_DANCE, Moves.EXTREME_SPEED, Moves.MULTI_ATTACK ],
[Species.SHUPPET]: [ Moves.DRAIN_PUNCH, Moves.TOPSY_TURVY, Moves.PARTING_SHOT, Moves.SPECTRAL_THIEF ],
[Species.SHUPPET]: [ Moves.STORM_THROW, Moves.TIDY_UP, Moves.PARTING_SHOT, Moves.SPECTRAL_THIEF ],
[Species.DUSKULL]: [ Moves.BULK_UP, Moves.DRAIN_PUNCH, Moves.STRENGTH_SAP, Moves.RAGE_FIST ],
[Species.TROPIUS]: [ Moves.STUFF_CHEEKS, Moves.EARTH_POWER, Moves.APPLE_ACID, Moves.SAPPY_SEED ],
[Species.ABSOL]: [ Moves.KOWTOW_CLEAVE, Moves.SACRED_SWORD, Moves.DIRE_CLAW, Moves.BITTER_BLADE ],
[Species.WYNAUT]: [ Moves.RECOVER, Moves.PERISH_SONG, Moves.TAUNT, Moves.SHED_TAIL ],
[Species.WYNAUT]: [ Moves.RECOVER, Moves.SHED_TAIL, Moves.TAUNT, Moves.COMEUPPANCE ],
[Species.SNORUNT]: [ Moves.AURORA_VEIL, Moves.HYPER_VOICE, Moves.EARTH_POWER, Moves.NO_RETREAT ],
[Species.SPHEAL]: [ Moves.FLIP_TURN, Moves.FREEZE_DRY, Moves.SLACK_OFF, Moves.STEAM_ERUPTION ],
[Species.CLAMPERL]: [ Moves.ICE_SPINNER, Moves.LIQUIDATION, Moves.EARTH_POWER, Moves.ORIGIN_PULSE ],
[Species.CLAMPERL]: [ Moves.ICE_SPINNER, Moves.LIQUIDATION, Moves.EARTH_POWER, Moves.STEAM_ERUPTION ],
[Species.RELICANTH]: [ Moves.BODY_PRESS, Moves.SHORE_UP, Moves.WAVE_CRASH, Moves.FISHIOUS_REND ],
[Species.LUVDISC]: [ Moves.BATON_PASS, Moves.THIEF, Moves.BOUNCY_BUBBLE, Moves.TAKE_HEART ],
[Species.BAGON]: [ Moves.FLOATY_FALL, Moves.FIRE_LASH, Moves.DRAGON_DANCE, Moves.GLAIVE_RUSH ],
[Species.BELDUM]: [ Moves.PSYCHIC_FANGS, Moves.RECOVER, Moves.MOUNTAIN_GALE, Moves.SHIFT_GEAR ],
[Species.BELDUM]: [ Moves.PSYCHIC_FANGS, Moves.RECOVER, Moves.TRIPLE_AXEL, Moves.SHIFT_GEAR ],
[Species.REGIROCK]: [ Moves.STONE_AXE, Moves.BODY_PRESS, Moves.RECOVER, Moves.SALT_CURE ],
[Species.REGICE]: [ Moves.EARTH_POWER, Moves.COSMIC_POWER, Moves.RECOVER, Moves.FREEZE_DRY ],
[Species.REGISTEEL]: [ Moves.BODY_PRESS, Moves.HEAT_CRASH, Moves.RECOVER, Moves.GIGATON_HAMMER ],
@ -208,9 +208,9 @@ export const speciesEggMoves = {
[Species.KRICKETOT]: [ Moves.BONEMERANG, Moves.ROOST, Moves.ROCK_BLAST, Moves.VICTORY_DANCE ],
[Species.SHINX]: [ Moves.FIRE_LASH, Moves.TRIPLE_AXEL, Moves.FACADE, Moves.BOLT_STRIKE ],
[Species.BUDEW]: [ Moves.FIERY_DANCE, Moves.SLUDGE_WAVE, Moves.SPORE, Moves.QUIVER_DANCE ],
[Species.CRANIDOS]: [ Moves.STONE_AXE, Moves.ACCELEROCK, Moves.HEADLONG_RUSH, Moves.DRAGON_DANCE ],
[Species.CRANIDOS]: [ Moves.DRAGON_DANCE, Moves.ACCELEROCK, Moves.HEADLONG_RUSH, Moves.VOLT_TACKLE ],
[Species.SHIELDON]: [ Moves.PAIN_SPLIT, Moves.BODY_PRESS, Moves.KINGS_SHIELD, Moves.DIAMOND_STORM ],
[Species.BURMY]: [ Moves.BODY_PRESS, Moves.TOXIC, Moves.HEAL_ORDER, Moves.DEFEND_ORDER ],
[Species.BURMY]: [ Moves.BODY_PRESS, Moves.DEFEND_ORDER, Moves.HEAL_ORDER, Moves.SAPPY_SEED ],
[Species.COMBEE]: [ Moves.SPORE, Moves.HEAT_WAVE, Moves.KINGS_SHIELD, Moves.QUIVER_DANCE ],
[Species.PACHIRISU]: [ Moves.BADDY_BAD, Moves.SIZZLY_SLIDE, Moves.U_TURN, Moves.ZIPPY_ZAP ],
[Species.BUIZEL]: [ Moves.JET_PUNCH, Moves.TRIPLE_AXEL, Moves.SUPERCELL_SLAM, Moves.SURGING_STRIKES ],
@ -235,16 +235,16 @@ export const speciesEggMoves = {
[Species.CROAGUNK]: [ Moves.DIRE_CLAW, Moves.ICE_PUNCH, Moves.THUNDEROUS_KICK, Moves.VICTORY_DANCE ],
[Species.CARNIVINE]: [ Moves.STRENGTH_SAP, Moves.FIRE_LASH, Moves.MIGHTY_CLEAVE, Moves.FLOWER_TRICK ],
[Species.FINNEON]: [ Moves.QUIVER_DANCE, Moves.BOUNCY_BUBBLE, Moves.FREEZE_DRY, Moves.ORIGIN_PULSE ],
[Species.MANTYKE]: [ Moves.BOUNCY_BUBBLE, Moves.SPIKES, Moves.ROOST, Moves.STEAM_ERUPTION ],
[Species.MANTYKE]: [ Moves.BOUNCY_BUBBLE, Moves.STEALTH_ROCK, Moves.NASTY_PLOT, Moves.STEAM_ERUPTION ],
[Species.SNOVER]: [ Moves.HIGH_HORSEPOWER, Moves.STRENGTH_SAP, Moves.AURORA_VEIL, Moves.IVY_CUDGEL ],
[Species.ROTOM]: [ Moves.STRENGTH_SAP, Moves.FIERY_DANCE, Moves.SPLISHY_SPLASH, Moves.RISING_VOLTAGE ],
[Species.UXIE]: [ Moves.COSMIC_POWER, Moves.BODY_PRESS, Moves.RECOVER, Moves.LUMINA_CRASH ],
[Species.MESPRIT]: [ Moves.QUIVER_DANCE, Moves.AURA_SPHERE, Moves.RECOVER, Moves.LUMINA_CRASH ],
[Species.AZELF]: [ Moves.PHOTON_GEYSER, Moves.ICE_BEAM, Moves.MOONBLAST, Moves.LUMINA_CRASH ],
[Species.ROTOM]: [ Moves.STRENGTH_SAP, Moves.FIERY_DANCE, Moves.SPLISHY_SPLASH, Moves.ELECTRO_DRIFT ],
[Species.UXIE]: [ Moves.COSMIC_POWER, Moves.BODY_PRESS, Moves.RECOVER, Moves.SPARKLY_SWIRL ],
[Species.MESPRIT]: [ Moves.TAIL_GLOW, Moves.AURA_SPHERE, Moves.RECOVER, Moves.LUMINA_CRASH ],
[Species.AZELF]: [ Moves.PSYSTRIKE, Moves.ICE_BEAM, Moves.MOONBLAST, Moves.TAIL_GLOW ],
[Species.DIALGA]: [ Moves.CORE_ENFORCER, Moves.TAKE_HEART, Moves.RECOVER, Moves.MAKE_IT_RAIN ],
[Species.PALKIA]: [ Moves.RECOVER, Moves.TAKE_HEART, Moves.WATER_SPOUT, Moves.DRAGON_ENERGY ],
[Species.HEATRAN]: [ Moves.TORCH_SONG, Moves.RECOVER, Moves.FLASH_CANNON, Moves.MATCHA_GOTCHA ],
[Species.REGIGIGAS]: [ Moves.SKILL_SWAP, Moves.SHORE_UP, Moves.EXTREME_SPEED, Moves.GIGATON_HAMMER ],
[Species.REGIGIGAS]: [ Moves.SKILL_SWAP, Moves.RECOVER, Moves.EXTREME_SPEED, Moves.GIGATON_HAMMER ],
[Species.GIRATINA]: [ Moves.DRAGON_DANCE, Moves.GLAIVE_RUSH, Moves.RECOVER, Moves.SPECTRAL_THIEF ],
[Species.CRESSELIA]: [ Moves.COSMIC_POWER, Moves.SECRET_SWORD, Moves.SIZZLY_SLIDE, Moves.LUMINA_CRASH ],
[Species.PHIONE]: [ Moves.BOUNCY_BUBBLE, Moves.FREEZE_DRY, Moves.SPLISHY_SPLASH, Moves.QUIVER_DANCE ],
@ -260,37 +260,37 @@ export const speciesEggMoves = {
[Species.LILLIPUP]: [ Moves.CLOSE_COMBAT, Moves.THIEF, Moves.HIGH_HORSEPOWER, Moves.LAST_RESPECTS ],
[Species.PURRLOIN]: [ Moves.ENCORE, Moves.ASSIST, Moves.PARTING_SHOT, Moves.WICKED_BLOW ],
[Species.PANSAGE]: [ Moves.SWORDS_DANCE, Moves.TEMPER_FLARE, Moves.EARTHQUAKE, Moves.IVY_CUDGEL ],
[Species.PANSEAR]: [ Moves.NASTY_PLOT, Moves.SCALD, Moves.SCORCHING_SANDS, Moves.SEARING_SHOT ],
[Species.PANPOUR]: [ Moves.NASTY_PLOT, Moves.ENERGY_BALL, Moves.AURA_SPHERE, Moves.STEAM_ERUPTION ],
[Species.MUNNA]: [ Moves.COSMIC_POWER, Moves.AURA_SPHERE, Moves.EARTH_POWER, Moves.LUMINA_CRASH ],
[Species.PANSEAR]: [ Moves.NASTY_PLOT, Moves.SCALD, Moves.SCORCHING_SANDS, Moves.TORCH_SONG ],
[Species.PANPOUR]: [ Moves.NASTY_PLOT, Moves.ENERGY_BALL, Moves.EARTH_POWER, Moves.STEAM_ERUPTION ],
[Species.MUNNA]: [ Moves.COSMIC_POWER, Moves.AURA_SPHERE, Moves.EARTH_POWER, Moves.MYSTICAL_POWER ],
[Species.PIDOVE]: [ Moves.GUNK_SHOT, Moves.TIDY_UP, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ],
[Species.BLITZLE]: [ Moves.HIGH_HORSEPOWER, Moves.THUNDEROUS_KICK, Moves.FLARE_BLITZ, Moves.VOLT_TACKLE ],
[Species.ROGGENROLA]: [ Moves.BODY_PRESS, Moves.CURSE, Moves.SHORE_UP, Moves.DIAMOND_STORM ],
[Species.WOOBAT]: [ Moves.TAKE_HEART, Moves.STORED_POWER, Moves.MYSTICAL_FIRE, Moves.OBLIVION_WING ],
[Species.DRILBUR]: [ Moves.IRON_HEAD, Moves.ICE_SPINNER, Moves.SHIFT_GEAR, Moves.HEADLONG_RUSH ],
[Species.WOOBAT]: [ Moves.ESPER_WING, Moves.STORED_POWER, Moves.MYSTICAL_FIRE, Moves.OBLIVION_WING ],
[Species.DRILBUR]: [ Moves.IRON_HEAD, Moves.ICE_SPINNER, Moves.SHIFT_GEAR, Moves.THOUSAND_ARROWS ],
[Species.AUDINO]: [ Moves.FOLLOW_ME, Moves.MOONBLAST, Moves.WISH, Moves.LUNAR_BLESSING ],
[Species.TIMBURR]: [ Moves.MACH_PUNCH, Moves.DRAIN_PUNCH, Moves.ICE_HAMMER, Moves.DOUBLE_IRON_BASH ],
[Species.TYMPOLE]: [ Moves.LIQUIDATION, Moves.HIGH_HORSEPOWER, Moves.TOXIC, Moves.SHORE_UP ],
[Species.TYMPOLE]: [ Moves.JET_PUNCH, Moves.HIGH_HORSEPOWER, Moves.BULK_UP, Moves.SURGING_STRIKES ],
[Species.THROH]: [ Moves.DRAIN_PUNCH, Moves.SLACK_OFF, Moves.METEOR_MASH, Moves.NO_RETREAT ],
[Species.SAWK]: [ Moves.DRAIN_PUNCH, Moves.MACH_PUNCH, Moves.ENDEAVOR, Moves.VICTORY_DANCE ],
[Species.SEWADDLE]: [ Moves.STONE_AXE, Moves.PSYCHO_CUT, Moves.TIDY_UP, Moves.BITTER_BLADE ],
[Species.VENIPEDE]: [ Moves.SWORDS_DANCE, Moves.BATON_PASS, Moves.NOXIOUS_TORQUE, Moves.BLAZING_TORQUE ],
[Species.COTTONEE]: [ Moves.POLLEN_PUFF, Moves.PARTING_SHOT, Moves.SLEEP_POWDER, Moves.SEED_FLARE ],
[Species.PETILIL]: [ Moves.THUNDEROUS_KICK, Moves.BATON_PASS, Moves.AQUA_STEP, Moves.FIERY_DANCE ],
[Species.PETILIL]: [ Moves.THUNDEROUS_KICK, Moves.SPARKLING_ARIA, Moves.AQUA_STEP, Moves.FIERY_DANCE ],
[Species.BASCULIN]: [ Moves.LAST_RESPECTS, Moves.CLOSE_COMBAT, Moves.TRIPLE_DIVE, Moves.DRAGON_DANCE ],
[Species.SANDILE]: [ Moves.DIRE_CLAW, Moves.PARTING_SHOT, Moves.FIRE_LASH, Moves.PRECIPICE_BLADES ],
[Species.DARUMAKA]: [ Moves.DRAIN_PUNCH, Moves.THUNDER_PUNCH, Moves.BLAZING_TORQUE, Moves.V_CREATE ],
[Species.MARACTUS]: [ Moves.SCORCHING_SANDS, Moves.QUIVER_DANCE, Moves.FIERY_DANCE, Moves.SEED_FLARE ],
[Species.DWEBBLE]: [ Moves.CRABHAMMER, Moves.STONE_AXE, Moves.LEECH_LIFE, Moves.SHORE_UP ],
[Species.DWEBBLE]: [ Moves.CRABHAMMER, Moves.STONE_AXE, Moves.LEECH_LIFE, Moves.MIGHTY_CLEAVE ],
[Species.SCRAGGY]: [ Moves.SUCKER_PUNCH, Moves.TRIPLE_AXEL, Moves.DRAGON_DANCE, Moves.COLLISION_COURSE ],
[Species.SIGILYPH]: [ Moves.STORED_POWER, Moves.TAKE_HEART, Moves.FREEZING_GLARE, Moves.OBLIVION_WING ],
[Species.YAMASK]: [ Moves.RECOVER, Moves.INFERNAL_PARADE, Moves.AURA_SPHERE, Moves.TOPSY_TURVY ],
[Species.TIRTOUGA]: [ Moves.ICE_SPINNER, Moves.WAVE_CRASH, Moves.SHORE_UP, Moves.MIGHTY_CLEAVE ],
[Species.TIRTOUGA]: [ Moves.ICE_SPINNER, Moves.LIQUIDATION, Moves.SHORE_UP, Moves.MIGHTY_CLEAVE ],
[Species.ARCHEN]: [ Moves.ROOST, Moves.MIGHTY_CLEAVE, Moves.FLOATY_FALL, Moves.SKILL_SWAP ],
[Species.TRUBBISH]: [ Moves.TIDY_UP, Moves.RECOVER, Moves.DIRE_CLAW, Moves.GIGATON_HAMMER ],
[Species.ZORUA]: [ Moves.FLAMETHROWER, Moves.PSYCHIC, Moves.AURA_SPHERE, Moves.BADDY_BAD ],
[Species.ZORUA]: [ Moves.FLAMETHROWER, Moves.MOONBLAST, Moves.AURA_SPHERE, Moves.FIERY_WRATH ],
[Species.MINCCINO]: [ Moves.ICICLE_SPEAR, Moves.TIDY_UP, Moves.KNOCK_OFF, Moves.POPULATION_BOMB ],
[Species.GOTHITA]: [ Moves.MILK_DRINK, Moves.COSMIC_POWER, Moves.AURA_SPHERE, Moves.PSYSTRIKE ],
[Species.GOTHITA]: [ Moves.MILK_DRINK, Moves.MOONBLAST, Moves.AURA_SPHERE, Moves.PSYSTRIKE ],
[Species.SOLOSIS]: [ Moves.COSMIC_POWER, Moves.MOONBLAST, Moves.AURA_SPHERE, Moves.PSYSTRIKE ],
[Species.DUCKLETT]: [ Moves.QUIVER_DANCE, Moves.EARTH_POWER, Moves.FREEZE_DRY, Moves.OBLIVION_WING ],
[Species.VANILLITE]: [ Moves.EARTH_POWER, Moves.AURORA_VEIL, Moves.DECORATE, Moves.MILK_DRINK ],
@ -304,7 +304,7 @@ export const speciesEggMoves = {
[Species.FERROSEED]: [ Moves.STRENGTH_SAP, Moves.BODY_PRESS, Moves.SPIKY_SHIELD, Moves.SAPPY_SEED ],
[Species.KLINK]: [ Moves.FLARE_BLITZ, Moves.HIGH_HORSEPOWER, Moves.FUSION_BOLT, Moves.DOUBLE_IRON_BASH ],
[Species.TYNAMO]: [ Moves.SCALD, Moves.STRENGTH_SAP, Moves.FIRE_LASH, Moves.PLASMA_FISTS ],
[Species.ELGYEM]: [ Moves.MYSTICAL_POWER, Moves.TRICK_ROOM, Moves.STORED_POWER, Moves.LUMINA_CRASH ],
[Species.ELGYEM]: [ Moves.MYSTICAL_POWER, Moves.TRICK_ROOM, Moves.STORED_POWER, Moves.ASTRAL_BARRAGE ],
[Species.LITWICK]: [ Moves.FIERY_DANCE, Moves.EARTH_POWER, Moves.MOONBLAST, Moves.ASTRAL_BARRAGE ],
[Species.AXEW]: [ Moves.STONE_AXE, Moves.DIRE_CLAW, Moves.FIRE_LASH, Moves.GLAIVE_RUSH ],
[Species.CUBCHOO]: [ Moves.TRIPLE_AXEL, Moves.LIQUIDATION, Moves.SWORDS_DANCE, Moves.COLLISION_COURSE ],
@ -312,7 +312,7 @@ export const speciesEggMoves = {
[Species.SHELMET]: [ Moves.SHED_TAIL, Moves.NASTY_PLOT, Moves.BATON_PASS, Moves.HEAT_WAVE ],
[Species.STUNFISK]: [ Moves.SHORE_UP, Moves.BANEFUL_BUNKER, Moves.THUNDER_CAGE, Moves.THUNDERCLAP ],
[Species.MIENFOO]: [ Moves.GUNK_SHOT, Moves.SUPERCELL_SLAM, Moves.KNOCK_OFF, Moves.MOUNTAIN_GALE ],
[Species.DRUDDIGON]: [ Moves.GLARE, Moves.ROOST, Moves.DRAGON_HAMMER, Moves.FIRE_LASH ],
[Species.DRUDDIGON]: [ Moves.FIRE_LASH, Moves.ROOST, Moves.DRAGON_DARTS, Moves.CLANGOROUS_SOUL ],
[Species.GOLETT]: [ Moves.SHIFT_GEAR, Moves.DRAIN_PUNCH, Moves.HEADLONG_RUSH, Moves.RAGE_FIST ],
[Species.PAWNIARD]: [ Moves.SUCKER_PUNCH, Moves.CEASELESS_EDGE, Moves.BITTER_BLADE, Moves.LAST_RESPECTS ],
[Species.BOUFFALANT]: [ Moves.SLACK_OFF, Moves.JUMP_KICK, Moves.HEAD_SMASH, Moves.FLARE_BLITZ ],
@ -330,7 +330,7 @@ export const speciesEggMoves = {
[Species.RESHIRAM]: [ Moves.ROOST, Moves.TAKE_HEART, Moves.ERUPTION, Moves.DRAGON_ENERGY ],
[Species.ZEKROM]: [ Moves.DRAGON_DANCE, Moves.THUNDEROUS_KICK, Moves.DRAGON_HAMMER, Moves.BOLT_BEAK ],
[Species.LANDORUS]: [ Moves.STONE_AXE, Moves.THOUSAND_ARROWS, Moves.ROOST, Moves.FLOATY_FALL ],
[Species.KYUREM]: [ Moves.ICICLE_CRASH, Moves.DRAGON_ENERGY, Moves.NASTY_PLOT, Moves.GLACIAL_LANCE ],
[Species.KYUREM]: [ Moves.DRAGON_DARTS, Moves.DRAGON_ENERGY, Moves.NO_RETREAT, Moves.GLACIAL_LANCE ],
[Species.KELDEO]: [ Moves.BOUNCY_BUBBLE, Moves.THUNDERBOLT, Moves.FREEZE_DRY, Moves.STEAM_ERUPTION ],
[Species.MELOETTA]: [ Moves.TORCH_SONG, Moves.QUIVER_DANCE, Moves.THUNDEROUS_KICK, Moves.BOOMBURST ],
[Species.GENESECT]: [ Moves.EXTREME_SPEED, Moves.U_TURN, Moves.SHIFT_GEAR, Moves.TAIL_GLOW ],
@ -352,7 +352,7 @@ export const speciesEggMoves = {
[Species.INKAY]: [ Moves.POWER_TRIP, Moves.STORED_POWER, Moves.RECOVER, Moves.PSYCHO_BOOST ],
[Species.BINACLE]: [ Moves.TRIPLE_AXEL, Moves.ACCELEROCK, Moves.DIRE_CLAW, Moves.MIGHTY_CLEAVE ],
[Species.SKRELP]: [ Moves.RECOVER, Moves.CORE_ENFORCER, Moves.CALM_MIND, Moves.MALIGNANT_CHAIN ],
[Species.CLAUNCHER]: [ Moves.SHELL_SMASH, Moves.ARMOR_CANNON, Moves.TERRAIN_PULSE, Moves.ORIGIN_PULSE ],
[Species.CLAUNCHER]: [ Moves.SHELL_SMASH, Moves.ARMOR_CANNON, Moves.WATER_SHURIKEN, Moves.ORIGIN_PULSE ],
[Species.HELIOPTILE]: [ Moves.WEATHER_BALL, Moves.BOOMBURST, Moves.EARTH_POWER, Moves.TAIL_GLOW ],
[Species.TYRUNT]: [ Moves.DRAGON_HAMMER, Moves.FLARE_BLITZ, Moves.VOLT_TACKLE, Moves.AXE_KICK ],
[Species.AMAURA]: [ Moves.RECOVER, Moves.AURORA_VEIL, Moves.POWER_GEM, Moves.GEOMANCY ],
@ -369,7 +369,7 @@ export const speciesEggMoves = {
[Species.YVELTAL]: [ Moves.SLUDGE_WAVE, Moves.POWER_TRIP, Moves.FIERY_WRATH, Moves.CLANGOROUS_SOUL ],
[Species.ZYGARDE]: [ Moves.DRAGON_DARTS, Moves.HEAL_ORDER, Moves.VICTORY_DANCE, Moves.DOUBLE_IRON_BASH ],
[Species.DIANCIE]: [ Moves.MAGICAL_TORQUE, Moves.BODY_PRESS, Moves.SHORE_UP, Moves.GEOMANCY ],
[Species.HOOPA]: [ Moves.PHOTON_GEYSER, Moves.EARTH_POWER, Moves.BATON_PASS, Moves.TIDY_UP ],
[Species.HOOPA]: [ Moves.PHOTON_GEYSER, Moves.SECRET_SWORD, Moves.TIDY_UP, Moves.WICKED_BLOW ],
[Species.VOLCANION]: [ Moves.HYDRO_STEAM, Moves.CALM_MIND, Moves.ENERGY_BALL, Moves.SEARING_SHOT ],
[Species.ROWLET]: [ Moves.SNIPE_SHOT, Moves.POLTERGEIST, Moves.FIRST_IMPRESSION, Moves.VICTORY_DANCE ],
[Species.LITTEN]: [ Moves.FAKE_OUT, Moves.PARTING_SHOT, Moves.MORNING_SUN, Moves.SACRED_FIRE ],
@ -386,7 +386,7 @@ export const speciesEggMoves = {
[Species.MUDBRAY]: [ Moves.BODY_PRESS, Moves.YAWN, Moves.SHORE_UP, Moves.THOUSAND_WAVES ],
[Species.DEWPIDER]: [ Moves.AQUA_JET, Moves.SILK_TRAP, Moves.SWORDS_DANCE, Moves.AQUA_STEP ],
[Species.FOMANTIS]: [ Moves.SUPERPOWER, Moves.HEADLONG_RUSH, Moves.ICE_HAMMER, Moves.BITTER_BLADE ],
[Species.MORELULL]: [ Moves.CALM_MIND, Moves.LEECH_SEED, Moves.STRENGTH_SAP, Moves.SPARKLY_SWIRL ],
[Species.MORELULL]: [ Moves.CALM_MIND, Moves.SAPPY_SEED, Moves.SPARKLY_SWIRL, Moves.MATCHA_GOTCHA ],
[Species.SALANDIT]: [ Moves.FAKE_OUT, Moves.FIERY_DANCE, Moves.SCALD, Moves.MALIGNANT_CHAIN ],
[Species.STUFFUL]: [ Moves.DRAIN_PUNCH, Moves.METEOR_MASH, Moves.ICE_HAMMER, Moves.RAGE_FIST ],
[Species.BOUNSWEET]: [ Moves.TRIPLE_AXEL, Moves.AQUA_STEP, Moves.THUNDEROUS_KICK, Moves.SAPPY_SEED ],
@ -394,12 +394,12 @@ export const speciesEggMoves = {
[Species.ORANGURU]: [ Moves.FOUL_PLAY, Moves.YAWN, Moves.FOLLOW_ME, Moves.LUNAR_BLESSING ],
[Species.PASSIMIAN]: [ Moves.FAKE_OUT, Moves.SUCKER_PUNCH, Moves.SWORDS_DANCE, Moves.PYRO_BALL ],
[Species.WIMPOD]: [ Moves.ICE_SPINNER, Moves.OBSTRUCT, Moves.KNOCK_OFF, Moves.SURGING_STRIKES ],
[Species.SANDYGAST]: [ Moves.SCORCHING_SANDS, Moves.PARTING_SHOT, Moves.CURSE, Moves.SALT_CURE ],
[Species.SANDYGAST]: [ Moves.SCORCHING_SANDS, Moves.SPLISHY_SPLASH, Moves.CURSE, Moves.SALT_CURE ],
[Species.PYUKUMUKU]: [ Moves.MIRROR_COAT, Moves.BANEFUL_BUNKER, Moves.TOXIC_SPIKES, Moves.SALT_CURE ],
[Species.TYPE_NULL]: [ Moves.DIRE_CLAW, Moves.RECOVER, Moves.EXTREME_SPEED, Moves.NO_RETREAT ],
[Species.MINIOR]: [ Moves.EARTH_POWER, Moves.FLOATY_FALL, Moves.ZING_ZAP, Moves.DIAMOND_STORM ],
[Species.KOMALA]: [ Moves.SLACK_OFF, Moves.EXTREME_SPEED, Moves.KNOCK_OFF, Moves.CLOSE_COMBAT ],
[Species.TURTONATOR]: [ Moves.SHELL_SMASH, Moves.ARMOR_CANNON, Moves.EARTH_POWER, Moves.CLANGING_SCALES ],
[Species.TURTONATOR]: [ Moves.BURNING_BULWARK, Moves.ARMOR_CANNON, Moves.EARTH_POWER, Moves.CLANGING_SCALES ],
[Species.TOGEDEMARU]: [ Moves.FAKE_OUT, Moves.METAL_BURST, Moves.METEOR_MASH, Moves.BOLT_STRIKE ],
[Species.MIMIKYU]: [ Moves.SPIRIT_BREAK, Moves.TIDY_UP, Moves.SIZZLY_SLIDE, Moves.SPECTRAL_THIEF ],
[Species.BRUXISH]: [ Moves.ICE_FANG, Moves.FIRE_FANG, Moves.FLIP_TURN, Moves.FILLET_AWAY ],
@ -415,7 +415,7 @@ export const speciesEggMoves = {
[Species.BUZZWOLE]: [ Moves.LEECH_LIFE, Moves.BULLET_PUNCH, Moves.DARKEST_LARIAT, Moves.COLLISION_COURSE ],
[Species.PHEROMOSA]: [ Moves.AURA_SPHERE, Moves.MAKE_IT_RAIN, Moves.ATTACK_ORDER, Moves.COLLISION_COURSE ],
[Species.XURKITREE]: [ Moves.OVERHEAT, Moves.GIGA_DRAIN, Moves.TAIL_GLOW, Moves.THUNDERCLAP ],
[Species.CELESTEELA]: [ Moves.ROOST, Moves.BUZZY_BUZZ, Moves.SPIKES, Moves.OBLIVION_WING ],
[Species.CELESTEELA]: [ Moves.RECOVER, Moves.BUZZY_BUZZ, Moves.EARTH_POWER, Moves.OBLIVION_WING ],
[Species.KARTANA]: [ Moves.MIGHTY_CLEAVE, Moves.CEASELESS_EDGE, Moves.BITTER_BLADE, Moves.BEHEMOTH_BLADE ],
[Species.GUZZLORD]: [ Moves.SUCKER_PUNCH, Moves.COMEUPPANCE, Moves.SLACK_OFF, Moves.RUINATION ],
[Species.NECROZMA]: [ Moves.COSMIC_POWER, Moves.SACRED_FIRE, Moves.ASTRAL_BARRAGE, Moves.CLANGOROUS_SOUL ],
@ -426,9 +426,9 @@ export const speciesEggMoves = {
[Species.BLACEPHALON]: [ Moves.NASTY_PLOT, Moves.SEARING_SHOT, Moves.GIGA_DRAIN, Moves.ASTRAL_BARRAGE ],
[Species.ZERAORA]: [ Moves.SWORDS_DANCE, Moves.TRIPLE_AXEL, Moves.BOLT_STRIKE, Moves.PYRO_BALL ],
[Species.MELTAN]: [ Moves.BULLET_PUNCH, Moves.DRAIN_PUNCH, Moves.BULK_UP, Moves.PLASMA_FISTS ],
[Species.GROOKEY]: [ Moves.HEADLONG_RUSH, Moves.CLOSE_COMBAT, Moves.GRASSY_GLIDE, Moves.CLANGOROUS_SOUL ],
[Species.SCORBUNNY]: [ Moves.EXTREME_SPEED, Moves.TROP_KICK, Moves.TRIPLE_AXEL, Moves.THUNDEROUS_KICK ],
[Species.SOBBLE]: [ Moves.AEROBLAST, Moves.FROST_BREATH, Moves.SEARING_SHOT, Moves.SURGING_STRIKES ],
[Species.GROOKEY]: [ Moves.HIGH_HORSEPOWER, Moves.CLANGOROUS_SOUL, Moves.GRASSY_GLIDE, Moves.SAPPY_SEED ],
[Species.SCORBUNNY]: [ Moves.EXTREME_SPEED, Moves.HIGH_JUMP_KICK, Moves.TRIPLE_AXEL, Moves.BOLT_STRIKE ],
[Species.SOBBLE]: [ Moves.ESPER_WING, Moves.FROST_BREATH, Moves.SEARING_SHOT, Moves.STEAM_ERUPTION ],
[Species.SKWOVET]: [ Moves.KNOCK_OFF, Moves.GRAV_APPLE, Moves.BODY_PRESS, Moves.SLACK_OFF ],
[Species.ROOKIDEE]: [ Moves.ROOST, Moves.BODY_PRESS, Moves.IRON_HEAD, Moves.KINGS_SHIELD ],
[Species.BLIPBUG]: [ Moves.HEAL_ORDER, Moves.EXPANDING_FORCE, Moves.SPORE, Moves.TAIL_GLOW ],
@ -452,11 +452,11 @@ export const speciesEggMoves = {
[Species.FALINKS]: [ Moves.COMBAT_TORQUE, Moves.PSYSHIELD_BASH, Moves.HEAL_ORDER, Moves.POPULATION_BOMB ],
[Species.PINCURCHIN]: [ Moves.TRICK_ROOM, Moves.RISING_VOLTAGE, Moves.STRENGTH_SAP, Moves.THUNDERCLAP ],
[Species.SNOM]: [ Moves.MOONBLAST, Moves.SURF, Moves.EARTH_POWER, Moves.FIERY_DANCE ],
[Species.STONJOURNER]: [ Moves.BODY_PRESS, Moves.BULK_UP, Moves.SHORE_UP, Moves.ACCELEROCK ],
[Species.STONJOURNER]: [ Moves.BODY_PRESS, Moves.HELPING_HAND, Moves.ACCELEROCK, Moves.DIAMOND_STORM ],
[Species.EISCUE]: [ Moves.TRIPLE_AXEL, Moves.AQUA_STEP, Moves.SHELL_SMASH, Moves.GLACIAL_LANCE ],
[Species.INDEEDEE]: [ Moves.MATCHA_GOTCHA, Moves.EXPANDING_FORCE, Moves.MOONBLAST, Moves.REVIVAL_BLESSING ],
[Species.MORPEKO]: [ Moves.TRIPLE_AXEL, Moves.OBSTRUCT, Moves.PARTING_SHOT, Moves.SWORDS_DANCE ],
[Species.CUFANT]: [ Moves.LIQUIDATION, Moves.HEAVY_SLAM, Moves.CLOSE_COMBAT, Moves.GIGATON_HAMMER ],
[Species.CUFANT]: [ Moves.LIQUIDATION, Moves.CURSE, Moves.COMBAT_TORQUE, Moves.GIGATON_HAMMER ],
[Species.DRACOZOLT]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.FIRE_LASH, Moves.DRAGON_DANCE ],
[Species.ARCTOZOLT]: [ Moves.TRIPLE_AXEL, Moves.LIQUIDATION, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ],
[Species.DRACOVISH]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.THUNDER_FANG, Moves.DRAGON_DANCE ],
@ -467,8 +467,8 @@ export const speciesEggMoves = {
[Species.ZAMAZENTA]: [ Moves.PSYSHIELD_BASH, Moves.BODY_PRESS, Moves.SLACK_OFF, Moves.VICTORY_DANCE ],
[Species.KUBFU]: [ Moves.METEOR_MASH, Moves.DRAIN_PUNCH, Moves.JET_PUNCH, Moves.DRAGON_DANCE ],
[Species.ZARUDE]: [ Moves.SAPPY_SEED, Moves.PARTING_SHOT, Moves.WICKED_BLOW, Moves.VICTORY_DANCE ],
[Species.REGIELEKI]: [ Moves.NASTY_PLOT, Moves.FROST_BREATH, Moves.PARTING_SHOT, Moves.ELECTRO_DRIFT ],
[Species.REGIDRAGO]: [ Moves.METEOR_MASH, Moves.FLAMETHROWER, Moves.CALM_MIND, Moves.DRAGON_DARTS ],
[Species.REGIELEKI]: [ Moves.NASTY_PLOT, Moves.ICE_BEAM, Moves.EARTH_POWER, Moves.ELECTRO_DRIFT ],
[Species.REGIDRAGO]: [ Moves.METEOR_MASH, Moves.FLAMETHROWER, Moves.TAKE_HEART, Moves.DRAGON_DARTS ],
[Species.GLASTRIER]: [ Moves.TRICK_ROOM, Moves.SLACK_OFF, Moves.HIGH_HORSEPOWER, Moves.GLACIAL_LANCE ],
[Species.SPECTRIER]: [ Moves.EARTH_POWER, Moves.PARTING_SHOT, Moves.AURA_SPHERE, Moves.ASTRAL_BARRAGE ],
[Species.CALYREX]: [ Moves.SAPPY_SEED, Moves.RECOVER, Moves.SECRET_SWORD, Moves.PHOTON_GEYSER ],
@ -478,40 +478,40 @@ export const speciesEggMoves = {
[Species.QUAXLY]: [ Moves.DRAGON_DANCE, Moves.TRIPLE_AXEL, Moves.TROP_KICK, Moves.THUNDEROUS_KICK ],
[Species.LECHONK]: [ Moves.MILK_DRINK, Moves.BLAZING_TORQUE, Moves.FILLET_AWAY, Moves.MULTI_ATTACK ],
[Species.TAROUNTULA]: [ Moves.STONE_AXE, Moves.LEECH_LIFE, Moves.THIEF, Moves.SPORE ],
[Species.NYMBLE]: [ Moves.CEASELESS_EDGE, Moves.FELL_STINGER, Moves.LEECH_LIFE, Moves.WICKED_BLOW ],
[Species.PAWMI]: [ Moves.DRAIN_PUNCH, Moves.WISH, Moves.PARTING_SHOT, Moves.PLASMA_FISTS ],
[Species.TANDEMAUS]: [ Moves.BATON_PASS, Moves.BITE, Moves.SIZZLY_SLIDE, Moves.REVIVAL_BLESSING ],
[Species.FIDOUGH]: [ Moves.WISH, Moves.BODY_PRESS, Moves.PARTING_SHOT, Moves.SIZZLY_SLIDE ],
[Species.NYMBLE]: [ Moves.CEASELESS_EDGE, Moves.FELL_STINGER, Moves.ATTACK_ORDER, Moves.WICKED_BLOW ],
[Species.PAWMI]: [ Moves.DRAIN_PUNCH, Moves.PARTING_SHOT, Moves.MACH_PUNCH, Moves.PLASMA_FISTS ],
[Species.TANDEMAUS]: [ Moves.BATON_PASS, Moves.THIEF, Moves.SIZZLY_SLIDE, Moves.REVIVAL_BLESSING ],
[Species.FIDOUGH]: [ Moves.WISH, Moves.BODY_PRESS, Moves.SIZZLY_SLIDE, Moves.TIDY_UP ],
[Species.SMOLIV]: [ Moves.STRENGTH_SAP, Moves.EARTH_POWER, Moves.CALM_MIND, Moves.BOOMBURST ],
[Species.SQUAWKABILLY]: [ Moves.PARTING_SHOT, Moves.BULK_UP, Moves.FLARE_BLITZ, Moves.HEAD_CHARGE ],
[Species.NACLI]: [ Moves.BODY_PRESS, Moves.SPIKES, Moves.CURSE, Moves.DIAMOND_STORM ],
[Species.SQUAWKABILLY]: [ Moves.PARTING_SHOT, Moves.EARTHQUAKE, Moves.FLARE_BLITZ, Moves.EXTREME_SPEED ],
[Species.NACLI]: [ Moves.BODY_PRESS, Moves.SOAK, Moves.CURSE, Moves.DIAMOND_STORM ],
[Species.CHARCADET]: [ Moves.SACRED_SWORD, Moves.PHOTON_GEYSER, Moves.MOONBLAST, Moves.SPECTRAL_THIEF ],
[Species.TADBULB]: [ Moves.PARABOLIC_CHARGE, Moves.SCALD, Moves.EARTH_POWER, Moves.ELECTRO_SHOT ],
[Species.WATTREL]: [ Moves.NASTY_PLOT, Moves.TAILWIND, Moves.HEAT_WAVE, Moves.AEROBLAST ],
[Species.MASCHIFF]: [ Moves.PARTING_SHOT, Moves.KNOCK_OFF, Moves.NUZZLE, Moves.COLLISION_COURSE ],
[Species.SHROODLE]: [ Moves.FIRE_LASH, Moves.PARTING_SHOT, Moves.TOXIC, Moves.TOPSY_TURVY ],
[Species.MASCHIFF]: [ Moves.PARTING_SHOT, Moves.KNOCK_OFF, Moves.PLAY_ROUGH, Moves.COLLISION_COURSE ],
[Species.SHROODLE]: [ Moves.GASTRO_ACID, Moves.PARTING_SHOT, Moves.TOXIC, Moves.SKETCH ],
[Species.BRAMBLIN]: [ Moves.TAILWIND, Moves.STRENGTH_SAP, Moves.CEASELESS_EDGE, Moves.LAST_RESPECTS ],
[Species.TOEDSCOOL]: [ Moves.STRENGTH_SAP, Moves.TOPSY_TURVY, Moves.PARTING_SHOT, Moves.SAPPY_SEED ],
[Species.KLAWF]: [ Moves.CRABHAMMER, Moves.SHORE_UP, Moves.MIGHTY_CLEAVE, Moves.SHELL_SMASH ],
[Species.CAPSAKID]: [ Moves.STRENGTH_SAP, Moves.APPLE_ACID, Moves.FROST_BREATH, Moves.TORCH_SONG ],
[Species.RELLOR]: [ Moves.TOXIC_SPIKES, Moves.RECOVER, Moves.HEAT_WAVE, Moves.LUMINA_CRASH ],
[Species.FLITTLE]: [ Moves.COSMIC_POWER, Moves.AURA_SPHERE, Moves.ROOST, Moves.SEARING_SHOT ],
[Species.TINKATINK]: [ Moves.NUZZLE, Moves.SHIFT_GEAR, Moves.ICE_HAMMER, Moves.PYRO_BALL ],
[Species.FLITTLE]: [ Moves.COSMIC_POWER, Moves.MOONBLAST, Moves.ROOST, Moves.FIERY_DANCE ],
[Species.TINKATINK]: [ Moves.MAGICAL_TORQUE, Moves.SHIFT_GEAR, Moves.ICE_HAMMER, Moves.PYRO_BALL ],
[Species.WIGLETT]: [ Moves.SHELL_SMASH, Moves.ICICLE_CRASH, Moves.SEED_BOMB, Moves.SURGING_STRIKES ],
[Species.BOMBIRDIER]: [ Moves.U_TURN, Moves.TIDY_UP, Moves.SUCKER_PUNCH, Moves.MIGHTY_CLEAVE ],
[Species.FINIZEN]: [ Moves.TRIPLE_AXEL, Moves.DRAIN_PUNCH, Moves.HEADLONG_RUSH, Moves.SURGING_STRIKES ],
[Species.VAROOM]: [ Moves.COMBAT_TORQUE, Moves.U_TURN, Moves.BLAZING_TORQUE, Moves.NOXIOUS_TORQUE ],
[Species.CYCLIZAR]: [ Moves.BATON_PASS, Moves.BLAZING_TORQUE, Moves.HEAD_CHARGE, Moves.CLANGOROUS_SOUL ],
[Species.ORTHWORM]: [ Moves.GLARE, Moves.COIL, Moves.BODY_PRESS, Moves.SHORE_UP ],
[Species.GLIMMET]: [ Moves.CALM_MIND, Moves.SHORE_UP, Moves.PARTING_SHOT, Moves.FIERY_DANCE ],
[Species.GREAVARD]: [ Moves.TIDY_UP, Moves.YAWN, Moves.SHORE_UP, Moves.COLLISION_COURSE ],
[Species.ORTHWORM]: [ Moves.SIZZLY_SLIDE, Moves.COIL, Moves.BODY_PRESS, Moves.SHORE_UP ],
[Species.GLIMMET]: [ Moves.CALM_MIND, Moves.EARTH_POWER, Moves.FIERY_DANCE, Moves.MALIGNANT_CHAIN ],
[Species.GREAVARD]: [ Moves.SHADOW_BONE, Moves.YAWN, Moves.SHORE_UP, Moves.COLLISION_COURSE ],
[Species.FLAMIGO]: [ Moves.THUNDEROUS_KICK, Moves.TRIPLE_AXEL, Moves.U_TURN, Moves.VICTORY_DANCE ],
[Species.CETODDLE]: [ Moves.ICICLE_CRASH, Moves.HIGH_HORSEPOWER, Moves.RECOVER, Moves.DRAGON_DANCE ],
[Species.CETODDLE]: [ Moves.TRIPLE_AXEL, Moves.HIGH_HORSEPOWER, Moves.RECOVER, Moves.DRAGON_DANCE ],
[Species.VELUZA]: [ Moves.CEASELESS_EDGE, Moves.FLIP_TURN, Moves.ICE_SPINNER, Moves.PSYBLADE ],
[Species.DONDOZO]: [ Moves.SOFT_BOILED, Moves.ICE_SPINNER, Moves.TOXIC, Moves.SALT_CURE ],
[Species.TATSUGIRI]: [ Moves.ICE_BEAM, Moves.BATON_PASS, Moves.SCALD, Moves.FILLET_AWAY ],
[Species.TATSUGIRI]: [ Moves.ICE_BEAM, Moves.FILLET_AWAY, Moves.CORE_ENFORCER, Moves.STEAM_ERUPTION ],
[Species.GREAT_TUSK]: [ Moves.STONE_AXE, Moves.MORNING_SUN, Moves.DRAGON_DANCE, Moves.COLLISION_COURSE ],
[Species.SCREAM_TAIL]: [ Moves.COSMIC_POWER, Moves.LUMINA_CRASH, Moves.MOONLIGHT, Moves.SHED_TAIL ],
[Species.SCREAM_TAIL]: [ Moves.TORCH_SONG, Moves.GLITZY_GLOW, Moves.MOONLIGHT, Moves.SPARKLY_SWIRL ],
[Species.BRUTE_BONNET]: [ Moves.DARKEST_LARIAT, Moves.STRENGTH_SAP, Moves.EARTHQUAKE, Moves.SAPPY_SEED ],
[Species.FLUTTER_MANE]: [ Moves.MOONLIGHT, Moves.FLAMETHROWER, Moves.EARTH_POWER, Moves.ASTRAL_BARRAGE ],
[Species.SLITHER_WING]: [ Moves.KNOCK_OFF, Moves.VICTORY_DANCE, Moves.FIRE_LASH, Moves.THUNDEROUS_KICK ],
@ -521,12 +521,12 @@ export const speciesEggMoves = {
[Species.IRON_HANDS]: [ Moves.DRAIN_PUNCH, Moves.BULK_UP, Moves.PLASMA_FISTS, Moves.ICE_HAMMER ],
[Species.IRON_JUGULIS]: [ Moves.FIERY_WRATH, Moves.ROOST, Moves.NASTY_PLOT, Moves.OBLIVION_WING ],
[Species.IRON_MOTH]: [ Moves.EARTH_POWER, Moves.SEARING_SHOT, Moves.QUIVER_DANCE, Moves.MALIGNANT_CHAIN ],
[Species.IRON_THORNS]: [ Moves.MIGHTY_CLEAVE, Moves.SHORE_UP, Moves.SHIFT_GEAR, Moves.FUSION_BOLT ],
[Species.FRIGIBAX]: [ Moves.DRAGON_DARTS, Moves.BULK_UP, Moves.SHORE_UP, Moves.GLACIAL_LANCE ],
[Species.GIMMIGHOUL]: [ Moves.COSMIC_POWER, Moves.STORED_POWER, Moves.BATON_PASS, Moves.ASTRAL_BARRAGE ],
[Species.WO_CHIEN]: [ Moves.SPORE, Moves.RAGE_POWDER, Moves.SAPPY_SEED, Moves.STRENGTH_SAP ],
[Species.IRON_THORNS]: [ Moves.DIAMOND_STORM, Moves.SHORE_UP, Moves.SHIFT_GEAR, Moves.PLASMA_FISTS ],
[Species.FRIGIBAX]: [ Moves.DRAGON_DARTS, Moves.DRAGON_DANCE, Moves.EARTHQUAKE, Moves.GLACIAL_LANCE ],
[Species.GIMMIGHOUL]: [ Moves.COSMIC_POWER, Moves.STORED_POWER, Moves.EARTH_POWER, Moves.ASTRAL_BARRAGE ],
[Species.WO_CHIEN]: [ Moves.SPORE, Moves.FIERY_WRATH, Moves.SAPPY_SEED, Moves.STRENGTH_SAP ],
[Species.CHIEN_PAO]: [ Moves.KNOCK_OFF, Moves.PARTING_SHOT, Moves.BITTER_BLADE, Moves.GLACIAL_LANCE ],
[Species.TING_LU]: [ Moves.SHORE_UP, Moves.CURSE, Moves.SAPPY_SEED, Moves.THOUSAND_ARROWS ],
[Species.TING_LU]: [ Moves.SHORE_UP, Moves.WICKED_BLOW, Moves.SAPPY_SEED, Moves.THOUSAND_ARROWS ],
[Species.CHI_YU]: [ Moves.FIERY_WRATH, Moves.HYDRO_STEAM, Moves.TORCH_SONG, Moves.ERUPTION ],
[Species.ROARING_MOON]: [ Moves.FIRE_LASH, Moves.DRAGON_HAMMER, Moves.SUCKER_PUNCH, Moves.WICKED_BLOW ],
[Species.IRON_VALIANT]: [ Moves.PLASMA_FISTS, Moves.VICTORY_DANCE, Moves.QUIVER_DANCE, Moves.MAGICAL_TORQUE ],
@ -534,28 +534,28 @@ export const speciesEggMoves = {
[Species.MIRAIDON]: [ Moves.ICE_BEAM, Moves.CLANGOROUS_SOUL, Moves.RISING_VOLTAGE, Moves.DRAGON_ENERGY ],
[Species.WALKING_WAKE]: [ Moves.BOUNCY_BUBBLE, Moves.NASTY_PLOT, Moves.EARTH_POWER, Moves.DRAGON_ENERGY ],
[Species.IRON_LEAVES]: [ Moves.SPORE, Moves.U_TURN, Moves.MIGHTY_CLEAVE, Moves.BITTER_BLADE ],
[Species.POLTCHAGEIST]: [ Moves.COSMIC_POWER, Moves.INFERNAL_PARADE, Moves.LEECH_SEED, Moves.SPARKLY_SWIRL ],
[Species.OKIDOGI]: [ Moves.SLACK_OFF, Moves.OBSTRUCT, Moves.DIRE_CLAW, Moves.COLLISION_COURSE ],
[Species.POLTCHAGEIST]: [ Moves.SHELL_SMASH, Moves.INFERNAL_PARADE, Moves.LEECH_SEED, Moves.SPARKLY_SWIRL ],
[Species.OKIDOGI]: [ Moves.DRAIN_PUNCH, Moves.KNOCK_OFF, Moves.DIRE_CLAW, Moves.VICTORY_DANCE ],
[Species.MUNKIDORI]: [ Moves.PSYSTRIKE, Moves.HEAT_WAVE, Moves.EARTH_POWER, Moves.MALIGNANT_CHAIN ],
[Species.FEZANDIPITI]: [ Moves.BATON_PASS, Moves.COSMIC_POWER, Moves.SIZZLY_SLIDE, Moves.MALIGNANT_CHAIN ],
[Species.FEZANDIPITI]: [ Moves.BARB_BARRAGE, Moves.VICTORY_DANCE, Moves.TRIPLE_AXEL, Moves.MAGICAL_TORQUE ],
[Species.OGERPON]: [ Moves.FLOWER_TRICK, Moves.BONEMERANG, Moves.TRIPLE_AXEL, Moves.GIGATON_HAMMER ],
[Species.GOUGING_FIRE]: [ Moves.SUPERCELL_SLAM, Moves.BULK_UP, Moves.SACRED_FIRE, Moves.GLAIVE_RUSH ],
[Species.RAGING_BOLT]: [ Moves.NASTY_PLOT, Moves.FLAMETHROWER, Moves.RECOVER, Moves.ELECTRO_DRIFT ],
[Species.IRON_BOULDER]: [ Moves.PSYBLADE, Moves.KOWTOW_CLEAVE, Moves.STONE_AXE, Moves.BITTER_BLADE ],
[Species.IRON_CROWN]: [ Moves.NASTY_PLOT, Moves.SECRET_SWORD, Moves.PHOTON_GEYSER, Moves.ELECTRO_DRIFT ],
[Species.TERAPAGOS]: [ Moves.EARTH_POWER, Moves.SHORE_UP, Moves.ICE_BEAM, Moves.SHELL_SMASH ],
[Species.TERAPAGOS]: [ Moves.MOONBLAST, Moves.RECOVER, Moves.ICE_BEAM, Moves.SHELL_SMASH ],
[Species.PECHARUNT]: [ Moves.TOXIC_SPIKES, Moves.BODY_PRESS, Moves.HEX, Moves.BANEFUL_BUNKER ],
[Species.ALOLA_RATTATA]: [ Moves.STORM_THROW, Moves.PLAY_ROUGH, Moves.TIDY_UP, Moves.POPULATION_BOMB ],
[Species.ALOLA_SANDSHREW]: [ Moves.SPIKY_SHIELD, Moves.AQUA_CUTTER, Moves.SHIFT_GEAR, Moves.GLACIAL_LANCE ],
[Species.ALOLA_VULPIX]: [ Moves.MOONBLAST, Moves.AURORA_VEIL, Moves.PARTING_SHOT, Moves.FREEZY_FROST ],
[Species.ALOLA_VULPIX]: [ Moves.MOONBLAST, Moves.AURORA_VEIL, Moves.FLAMETHROWER, Moves.FREEZY_FROST ],
[Species.ALOLA_DIGLETT]: [ Moves.THOUSAND_WAVES, Moves.SWORDS_DANCE, Moves.TRIPLE_DIVE, Moves.MOUNTAIN_GALE ],
[Species.ALOLA_MEOWTH]: [ Moves.MAKE_IT_RAIN, Moves.BUZZY_BUZZ, Moves.PARTING_SHOT, Moves.BADDY_BAD ],
[Species.ALOLA_MEOWTH]: [ Moves.BADDY_BAD, Moves.BUZZY_BUZZ, Moves.PARTING_SHOT, Moves.MAKE_IT_RAIN ],
[Species.ALOLA_GEODUDE]: [ Moves.HIGH_HORSEPOWER, Moves.BULK_UP, Moves.STONE_AXE, Moves.EXTREME_SPEED ],
[Species.ALOLA_GRIMER]: [ Moves.SUCKER_PUNCH, Moves.DIRE_CLAW, Moves.STRENGTH_SAP, Moves.SURGING_STRIKES ],
[Species.ETERNAL_FLOETTE]: [ Moves.FIERY_DANCE, Moves.GIGA_DRAIN, Moves.POLLEN_PUFF, Moves.QUIVER_DANCE ],
[Species.ETERNAL_FLOETTE]: [ Moves.FIERY_DANCE, Moves.CHLOROBLAST, Moves.POLLEN_PUFF, Moves.QUIVER_DANCE ],
[Species.GALAR_MEOWTH]: [ Moves.AQUA_CUTTER, Moves.KNOCK_OFF, Moves.BULLET_PUNCH, Moves.BEHEMOTH_BASH ],
[Species.GALAR_PONYTA]: [ Moves.SPIRIT_BREAK, Moves.EXTREME_SPEED, Moves.FLARE_BLITZ, Moves.PHOTON_GEYSER ],
[Species.GALAR_SLOWPOKE]: [ Moves.TRICK_ROOM, Moves.BADDY_BAD, Moves.MOONBLAST, Moves.LUMINA_CRASH ],
[Species.GALAR_SLOWPOKE]: [ Moves.TRICK_ROOM, Moves.BADDY_BAD, Moves.MOONBLAST, Moves.TORCH_SONG ],
[Species.GALAR_FARFETCHD]: [ Moves.ROOST, Moves.SACRED_SWORD, Moves.KINGS_SHIELD, Moves.BEHEMOTH_BLADE ],
[Species.GALAR_ARTICUNO]: [ Moves.AURA_SPHERE, Moves.OBLIVION_WING, Moves.ICE_BEAM, Moves.PSYSTRIKE ],
[Species.GALAR_ZAPDOS]: [ Moves.TIDY_UP, Moves.FLOATY_FALL, Moves.ROOST, Moves.BOLT_BEAK ],
@ -566,13 +566,13 @@ export const speciesEggMoves = {
[Species.GALAR_YAMASK]: [ Moves.STRENGTH_SAP, Moves.DIRE_CLAW, Moves.THOUSAND_WAVES, Moves.SPECTRAL_THIEF ],
[Species.GALAR_STUNFISK]: [ Moves.SPIKY_SHIELD, Moves.TRICK_ROOM, Moves.SHORE_UP, Moves.SALT_CURE ],
[Species.HISUI_GROWLITHE]: [ Moves.WOOD_HAMMER, Moves.HEAD_SMASH, Moves.VOLT_TACKLE, Moves.MORNING_SUN ],
[Species.HISUI_VOLTORB]: [ Moves.FROST_BREATH, Moves.NASTY_PLOT, Moves.PARABOLIC_CHARGE, Moves.SEED_FLARE ],
[Species.HISUI_VOLTORB]: [ Moves.ICE_BEAM, Moves.NASTY_PLOT, Moves.PARABOLIC_CHARGE, Moves.SEED_FLARE ],
[Species.HISUI_QWILFISH]: [ Moves.CEASELESS_EDGE, Moves.KNOCK_OFF, Moves.STRENGTH_SAP, Moves.FISHIOUS_REND ],
[Species.HISUI_SNEASEL]: [ Moves.THUNDEROUS_KICK, Moves.KNOCK_OFF, Moves.ICE_SPINNER, Moves.VICTORY_DANCE ],
[Species.HISUI_ZORUA]: [ Moves.MOONBLAST, Moves.AURA_SPHERE, Moves.PARTING_SHOT, Moves.BLOOD_MOON ],
[Species.PALDEA_TAUROS]: [ Moves.NO_RETREAT, Moves.BLAZING_TORQUE, Moves.AQUA_STEP, Moves.THUNDEROUS_KICK ],
[Species.PALDEA_WOOPER]: [ Moves.RECOVER, Moves.STONE_AXE, Moves.BANEFUL_BUNKER, Moves.SAPPY_SEED ],
[Species.BLOODMOON_URSALUNA]: [ Moves.GLARE, Moves.TRICK_ROOM, Moves.PARTING_SHOT, Moves.MIND_BLOWN ]
[Species.BLOODMOON_URSALUNA]: [ Moves.NASTY_PLOT, Moves.TRICK_ROOM, Moves.THUNDERBOLT, Moves.BOOMBURST ]
};
function parseEggMoves(content: string): void {

View File

@ -1,6 +1,6 @@
import { Moves } from "./enums/moves";
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
import { BattleEndPhase, MoveEffectPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases";
import { BattleEndPhase, MoveEffectPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase, ToggleDoublePositionPhase } from "../phases";
import { BattleStat, getBattleStatName } from "./battle-stat";
import { EncoreTag } from "./battler-tags";
import { BattlerTagType } from "./enums/battler-tag-type";
@ -12,10 +12,10 @@ import * as Utils from "../utils";
import { WeatherType } from "./weather";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, NoTransformAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr } from "./ability";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, NoTransformAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, PreventBerryUseAbAttr, BlockItemTheftAbAttr } from "./ability";
import { Abilities } from "./enums/abilities";
import { allAbilities } from './ability';
import { PokemonHeldItemModifier } from "../modifier/modifier";
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
import { BattlerIndex } from "../battle";
import { Stat } from "./pokemon-stat";
import { TerrainType } from "./terrain";
@ -25,6 +25,7 @@ import { ModifierPoolType } from "#app/modifier/modifier-type";
import { Command } from "../ui/command-ui-handler";
import { Biome } from "./enums/biome";
import i18next, { Localizable } from '../plugins/i18n';
import { BerryType, BerryEffectFunc, getBerryEffectFunc } from './berry';
export enum MoveCategory {
PHYSICAL,
@ -58,7 +59,8 @@ export enum MoveTarget {
/** {@link https://bulbapedia.bulbagarden.net/wiki/Category:Entry_hazard-creating_moves Entry hazard-creating moves} */
ENEMY_SIDE,
BOTH_SIDES,
PARTY
PARTY,
CURSE
}
export enum MoveFlags {
@ -780,8 +782,8 @@ export class RecoilAttr extends MoveEffectAttr {
if (cancelled.value)
return false;
const recoilDamage = Math.max(Math.floor((!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio),
user.turnData.damageDealt ? 1 : 0);
const recoilDamage = Math.max(Math.floor((!this.useHp ? user.turnData.currDamageDealt : user.getMaxHp()) * this.damageRatio),
user.turnData.currDamageDealt ? 1 : 0);
if (!recoilDamage)
return false;
@ -916,6 +918,7 @@ export enum MultiHitType {
_3,
_3_INCR,
_1_TO_10,
BEAT_UP,
}
/**
@ -1166,6 +1169,42 @@ export class StrengthSapHealAttr extends MoveEffectAttr {
return true;
}
}
/**
* Attribute used for moves that change priority in a turn given a condition,
* e.g. Grassy Glide
* Called when move order is calculated in {@linkcode TurnStartPhase}.
* @extends MoveAttr
* @see {@linkcode apply}
*/
export class IncrementMovePriorityAttr extends MoveAttr {
/** The condition for a move's priority being incremented */
private moveIncrementFunc: (pokemon: Pokemon, target:Pokemon, move: Move) => boolean;
/** The amount to increment priority by, if condition passes. */
private increaseAmount: integer;
constructor(moveIncrementFunc: (pokemon: Pokemon, target:Pokemon, move: Move) => boolean, increaseAmount = 1) {
super();
this.moveIncrementFunc = moveIncrementFunc;
this.increaseAmount = increaseAmount;
}
/**
* Increments move priority by set amount if condition passes
* @param user {@linkcode Pokemon} using this move
* @param target {@linkcode Pokemon} target of this move
* @param move {@linkcode Move} being used
* @param args [0] {@linkcode Utils.IntegerHolder} for move priority.
* @returns true if function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!this.moveIncrementFunc(user, target, move))
return false;
(args[0] as Utils.IntegerHolder).value += this.increaseAmount;
return true;
}
}
export class MultiHitAttr extends MoveAttr {
private multiHitType: MultiHitType;
@ -1233,6 +1272,11 @@ export class MultiHitAttr extends MoveAttr {
hitTimes = 10;
}
break;
case MultiHitType.BEAT_UP:
// No status means the ally pokemon can contribute to Beat Up
hitTimes = user.scene.getParty().reduce((total, pokemon) => {
return total + (pokemon.id === user.id ? 1 : pokemon?.status && pokemon.status.effect !== StatusEffect.NONE ? 0 : 1)
}, 0);
}
(args[0] as Utils.IntegerHolder).value = hitTimes;
return true;
@ -1436,6 +1480,95 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
}
}
/**
* Attribute that causes targets of the move to eat a berry. If chosenBerry is not overriden, a random berry will be picked from the target's inventory.
*/
export class EatBerryAttr extends MoveEffectAttr {
protected chosenBerry: BerryModifier;
constructor() {
super(true, MoveEffectTrigger.HIT);
this.chosenBerry = undefined;
}
/**
* Causes the target to eat a berry.
* @param user {@linkcode Pokemon} Pokemon that used the move
* @param target {@linkcode Pokemon} Pokemon that will eat a berry
* @param move {@linkcode Move} The move being used
* @param args Unused
* @returns {boolean} true if the function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args))
return false;
if(this.chosenBerry === undefined) { // if no berry has been provided, pick a random berry from their inventory
const heldBerries = this.getTargetHeldBerries(target);
if(heldBerries.length <= 0)
return false;
this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)];
}
getBerryEffectFunc(this.chosenBerry.berryType)(target); // target eats the berry
const preserve = new Utils.BooleanHolder(false);
target.scene.applyModifiers(PreserveBerryModifier, target.isPlayer(), target, preserve);
if (!preserve.value){ // remove the eaten berry if not preserved
if (!--this.chosenBerry.stackCount)
target.scene.removeModifier(this.chosenBerry, !target.isPlayer());
target.scene.updateModifiers(target.isPlayer());
}
this.chosenBerry = undefined;
return true;
}
getTargetHeldBerries(target: Pokemon): BerryModifier[] {
return target.scene.findModifiers(m => m instanceof BerryModifier
&& (m as BerryModifier).pokemonId === target.id, target.isPlayer()) as BerryModifier[];
}
}
/**
* Attribute used for moves that steal a random berry from the target. The user then eats the stolen berry.
* Used for Pluck & Bug Bite.
*/
export class StealEatBerryAttr extends EatBerryAttr {
constructor() {
super();
}
/**
* User steals a random berry from the target and then eats it.
* @param {Pokemon} user Pokemon that used the move and will eat the stolen berry
* @param {Pokemon} target Pokemon that will have its berry stolen
* @param {Move} move Move being used
* @param {any[]} args Unused
* @returns {boolean} true if the function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const cancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // check for abilities that block item theft
if(cancelled.value == true)
return false;
const heldBerries = this.getTargetHeldBerries(target).filter(i => i.getTransferrable(false));
if (heldBerries.length) { // if the target has berries, pick a random berry and steal it
this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)];
if (this.chosenBerry.stackCount == 1) // remove modifier if its the last berry
target.scene.removeModifier(this.chosenBerry, !target.isPlayer());
target.scene.updateModifiers(target.isPlayer());
user.scene.queueMessage(getPokemonMessage(user, ` stole and ate\n${target.name}'s ${this.chosenBerry.type.name}!`));
return super.apply(user, user, move, args);
}
return false;
}
}
export class HealStatusEffectAttr extends MoveEffectAttr {
private effects: StatusEffect[];
@ -2034,6 +2167,46 @@ export class VariablePowerAttr extends MoveAttr {
}
}
export class LessPPMorePowerAttr extends VariablePowerAttr {
/**
* Power up moves when less PP user has
* @param user {@linkcode Pokemon} using this move
* @param target {@linkcode Pokemon} target of this move
* @param move {@linkcode Move} being used
* @param args [0] {@linkcode Utils.NumberHolder} of power
* @returns true if the function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const ppMax = move.pp;
let ppUsed = user.moveset.find((m) => m.moveId === move.id).ppUsed;
let ppRemains = ppMax - ppUsed;
/** Reduce to 0 to avoid negative numbers if user has 1PP before attack and target has Ability.PRESSURE */
if(ppRemains < 0) ppRemains = 0;
const power = args[0] as Utils.NumberHolder;
switch (ppRemains) {
case 0:
power.value = 200;
break;
case 1:
power.value = 80;
break;
case 2:
power.value = 60;
break;
case 3:
power.value = 50;
break;
default:
power.value = 40;
break;
}
return true;
}
}
export class MovePowerMultiplierAttr extends VariablePowerAttr {
private powerMultiplierFunc: (user: Pokemon, target: Pokemon, move: Move) => number;
@ -2051,6 +2224,45 @@ export class MovePowerMultiplierAttr extends VariablePowerAttr {
}
}
/**
* Helper function to calculate the the base power of an ally's hit when using Beat Up.
* @param user The Pokemon that used Beat Up.
* @param allyIndex The party position of the ally contributing to Beat Up.
* @returns The base power of the Beat Up hit.
*/
const beatUpFunc = (user: Pokemon, allyIndex: number): number => {
const party = user.scene.getParty();
for (let i = allyIndex; i < party.length; i++) {
const pokemon = party[i];
// The user contributes to Beat Up regardless of status condition.
// Allies can contribute only if they do not have a non-volatile status condition.
if (pokemon.id !== user.id && pokemon?.status && pokemon.status.effect !== StatusEffect.NONE) {
continue;
}
return (pokemon.species.getBaseStat(Stat.ATK) / 10) + 5;
}
}
export class BeatUpAttr extends VariablePowerAttr {
/**
* Gets the next party member to contribute to a Beat Up hit, and calculates the base power for it.
* @param user Pokemon that used the move
* @param _target N/A
* @param _move Move with this attribute
* @param args N/A
* @returns true if the function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const power = args[0] as Utils.NumberHolder;
const allyIndex = user.turnData.hitCount - user.turnData.hitsLeft;
power.value = beatUpFunc(user, allyIndex);
return true;
}
}
const doublePowerChanceMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => {
let message: string = null;
user.scene.executeWithSeedOffset(() => {
@ -2778,6 +2990,47 @@ export class WeatherBallTypeAttr extends VariableMoveTypeAttr {
}
}
/**
* Changes the move's type to match the current terrain.
* Has no effect if the user is not grounded.
* @extends VariableMoveTypeAttr
* @see {@linkcode apply}
*/
export class TerrainPulseTypeAttr extends VariableMoveTypeAttr {
/**
* @param user {@linkcode Pokemon} using this move
* @param target N/A
* @param move N/A
* @param args [0] {@linkcode Utils.IntegerHolder} The move's type to be modified
* @returns true if the function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if(!user.isGrounded)
return false;
const currentTerrain = user.scene.arena.getTerrainType();
const type = (args[0] as Utils.IntegerHolder);
switch (currentTerrain) {
case TerrainType.MISTY:
type.value = Type.FAIRY;
break;
case TerrainType.ELECTRIC:
type.value = Type.ELECTRIC;
break;
case TerrainType.GRASSY:
type.value = Type.GRASS;
break;
case TerrainType.PSYCHIC:
type.value = Type.PSYCHIC;
break;
default:
return false;
}
return true;
}
}
export class HiddenPowerTypeAttr extends VariableMoveTypeAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const type = (args[0] as Utils.IntegerHolder);
@ -3441,6 +3694,67 @@ export class RemoveScreensAttr extends MoveEffectAttr {
}
}
/**
* Attribute used for Revival Blessing.
* @extends MoveEffectAttr
* @see {@linkcode apply}
*/
export class RevivalBlessingAttr extends MoveEffectAttr {
constructor(user?: boolean) {
super(true);
}
/**
*
* @param user {@linkcode Pokemon} using this move
* @param target {@linkcode Pokemon} target of this move
* @param move {@linkcode Move} being used
* @param args N/A
* @returns Promise, true if function succeeds.
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
return new Promise(resolve => {
// If user is player, checks if the user has fainted pokemon
if(user instanceof PlayerPokemon
&& user.scene.getParty().findIndex(p => p.isFainted())>-1) {
(user as PlayerPokemon).revivalBlessing().then(() => {
resolve(true)
});
// If user is enemy, checks that it is a trainer, and it has fainted non-boss pokemon in party
} else if(user instanceof EnemyPokemon
&& user.hasTrainer()
&& user.scene.getEnemyParty().findIndex(p => p.isFainted() && !p.isBoss()) > -1) {
// Selects a random fainted pokemon
const faintedPokemon = user.scene.getEnemyParty().filter(p => p.isFainted() && !p.isBoss());
const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length)];
const slotIndex = user.scene.getEnemyParty().findIndex(p => pokemon.id === p.id);
pokemon.resetStatus();
pokemon.heal(Math.min(Math.max(Math.ceil(Math.floor(0.5 * pokemon.getMaxHp())), 1), pokemon.getMaxHp()));
user.scene.queueMessage(`${pokemon.name} was revived!`,0,true);
if(user.scene.currentBattle.double && user.scene.getEnemyParty().length > 1) {
const allyPokemon = user.getAlly();
if(slotIndex<=1) {
user.scene.unshiftPhase(new SwitchSummonPhase(user.scene, pokemon.getFieldIndex(), slotIndex, false, false, false));
} else if(allyPokemon.isFainted()){
user.scene.unshiftPhase(new SwitchSummonPhase(user.scene, allyPokemon.getFieldIndex(), slotIndex, false, false,false));
}
}
resolve(true);
} else {
user.scene.queueMessage(`But it failed!`);
resolve(false);
}
})
}
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
if(user.hasTrainer() && user.scene.getEnemyParty().findIndex(p => p.isFainted() && !p.isBoss()) > -1)
return 20;
return -20;
}
}
export class ForceSwitchOutAttr extends MoveEffectAttr {
private user: boolean;
@ -4375,7 +4689,7 @@ export function getMoveTargets(user: Pokemon, move: Moves): MoveTargetSet {
switch (moveTarget) {
case MoveTarget.USER:
case MoveTarget.PARTY:
set = [ user];
set = [ user ];
break;
case MoveTarget.NEAR_OTHER:
case MoveTarget.OTHER:
@ -4411,6 +4725,9 @@ export function getMoveTargets(user: Pokemon, move: Moves): MoveTargetSet {
set = [ user, user.getAlly() ].concat(opponents);
multiple = true;
break;
case MoveTarget.CURSE:
set = user.getTypes(true).includes(Type.GHOST) ? (opponents.concat([ user.getAlly() ])) : [ user ];
break;
}
return { targets: set.filter(p => p?.isActive(true)).map(p => p.getBattlerIndex()).filter(t => t !== undefined), multiple };
@ -4897,7 +5214,8 @@ export function initMoves() {
.soundBased(),
new StatusMove(Moves.CURSE, Type.GHOST, -1, 10, -1, 0, 2)
.attr(CurseAttr)
.ignoresProtect(true),
.ignoresProtect(true)
.target(MoveTarget.CURSE),
new AttackMove(Moves.FLAIL, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 15, -1, 0, 2)
.attr(LowHpPowerAttr),
new StatusMove(Moves.CONVERSION_2, Type.NORMAL, -1, 30, -1, 0, 2)
@ -5115,8 +5433,9 @@ export function initMoves() {
.attr(TrapAttr, BattlerTagType.WHIRLPOOL)
.attr(HitsTagAttr, BattlerTagType.UNDERWATER, true),
new AttackMove(Moves.BEAT_UP, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 2)
.makesContact(false)
.unimplemented(),
.attr(MultiHitAttr, MultiHitType.BEAT_UP)
.attr(BeatUpAttr)
.makesContact(false),
new AttackMove(Moves.FAKE_OUT, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 10, 100, 3, 3)
.attr(FlinchAttr)
.condition(new FirstMoveCondition()),
@ -5424,7 +5743,7 @@ export function initMoves() {
.makesContact(false)
.ignoresProtect(),
new AttackMove(Moves.PLUCK, Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 4)
.partial(),
.attr(StealEatBerryAttr),
new StatusMove(Moves.TAILWIND, Type.FLYING, -1, 15, -1, 0, 4)
.windMove()
.attr(AddArenaTagAttr, ArenaTagType.TAILWIND, 4, true)
@ -5460,7 +5779,7 @@ export function initMoves() {
),
new AttackMove(Moves.TRUMP_CARD, Type.NORMAL, MoveCategory.SPECIAL, -1, -1, 5, -1, 0, 4)
.makesContact()
.unimplemented(),
.attr(LessPPMorePowerAttr),
new StatusMove(Moves.HEAL_BLOCK, Type.PSYCHIC, 100, 15, -1, 0, 4)
.target(MoveTarget.ALL_NEAR_ENEMIES)
.unimplemented(),
@ -5661,7 +5980,7 @@ export function initMoves() {
new AttackMove(Moves.JUDGMENT, Type.NORMAL, MoveCategory.SPECIAL, 100, 100, 10, -1, 0, 4)
.partial(),
new AttackMove(Moves.BUG_BITE, Type.BUG, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 4)
.partial(),
.attr(StealEatBerryAttr),
new AttackMove(Moves.CHARGE_BEAM, Type.ELECTRIC, MoveCategory.SPECIAL, 50, 90, 10, 70, 0, 4)
.attr(StatChangeAttr, BattleStat.SPATK, 1, true),
new AttackMove(Moves.WOOD_HAMMER, Type.GRASS, MoveCategory.PHYSICAL, 120, 100, 15, -1, 0, 4)
@ -6523,8 +6842,8 @@ export function initMoves() {
.makesContact(false)
.partial(),
new StatusMove(Moves.TEATIME, Type.NORMAL, -1, 10, -1, 0, 8)
.target(MoveTarget.ALL)
.unimplemented(),
.attr(EatBerryAttr)
.target(MoveTarget.ALL),
new StatusMove(Moves.OCTOLOCK, Type.FIGHTING, 100, 15, -1, 0, 8)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1)
.partial(),
@ -6691,14 +7010,16 @@ export function initMoves() {
.attr(SacrificialAttr)
.target(MoveTarget.ALL_NEAR_OTHERS)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.MISTY && user.isGrounded() ? 1.5 : 1)
.condition(failIfDampCondition),
.condition(failIfDampCondition)
.makesContact(false),
new AttackMove(Moves.GRASSY_GLIDE, Type.GRASS, MoveCategory.PHYSICAL, 55, 100, 20, -1, 0, 8)
.partial(),
.attr(IncrementMovePriorityAttr,(user,target,move) =>user.scene.arena.getTerrainType()===TerrainType.GRASSY&&user.isGrounded()),
new AttackMove(Moves.RISING_VOLTAGE, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 20, -1, 0, 8)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.ELECTRIC && target.isGrounded() ? 2 : 1),
new AttackMove(Moves.TERRAIN_PULSE, Type.NORMAL, MoveCategory.SPECIAL, 50, 100, 10, -1, 0, 8)
.pulseMove()
.partial(),
.attr(TerrainPulseTypeAttr)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() !== TerrainType.NONE && user.isGrounded() ? 2 : 1)
.pulseMove(),
new AttackMove(Moves.SKITTER_SMACK, Type.BUG, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8)
.attr(StatChangeAttr, BattleStat.SPATK, -1),
new AttackMove(Moves.BURNING_JEALOUSY, Type.FIRE, MoveCategory.SPECIAL, 70, 100, 5, 100, 0, 8)
@ -6975,7 +7296,8 @@ export function initMoves() {
.partial(),
new StatusMove(Moves.REVIVAL_BLESSING, Type.NORMAL, -1, 1, -1, 0, 9)
.triageMove()
.unimplemented(),
.attr(RevivalBlessingAttr)
.target(MoveTarget.USER),
new AttackMove(Moves.SALT_CURE, Type.ROCK, MoveCategory.PHYSICAL, 40, 100, 15, -1, 0, 9)
.attr(AddBattlerTagAttr, BattlerTagType.SALT_CURED)
.makesContact(false),
@ -7158,7 +7480,10 @@ export function initMoves() {
new AttackMove(Moves.PSYCHIC_NOISE, Type.PSYCHIC, MoveCategory.SPECIAL, 75, 100, 10, -1, 0, 9)
.soundBased()
.partial(),
new AttackMove(Moves.UPPER_HAND, Type.FIGHTING, MoveCategory.PHYSICAL, 65, 100, 15, -1, 3, 9)
new AttackMove(Moves.UPPER_HAND, Type.FIGHTING, MoveCategory.PHYSICAL, 65, 100, 15, 100, 3, 9)
.attr(FlinchAttr)
.condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].priority > 0 )
//TODO: Should also apply when target move priority increased by ability ex. gale wings
.partial(),
new AttackMove(Moves.MALIGNANT_CHAIN, Type.POISON, MoveCategory.SPECIAL, 100, 100, 5, 50, 0, 9)
.attr(StatusEffectAttr, StatusEffect.TOXIC)

View File

@ -16,6 +16,7 @@ import { GameMode } from '../game-mode';
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities";
import { VariantSet } from './variant';
import i18next, { Localizable } from '../plugins/i18n';
import { Stat } from "./pokemon-stat";
export enum Region {
NORMAL,
@ -192,6 +193,15 @@ export abstract class PokemonSpeciesForm {
return false;
}
/**
* Gets the species' base stat amount for the given stat.
* @param stat The desired stat.
* @returns The species' base stat amount.
*/
getBaseStat(stat: Stat): integer {
return this.baseStats[stat]
}
getBaseExp(): integer {
let ret = this.baseExp;
switch (this.getFormSpriteKey()) {
@ -2624,7 +2634,7 @@ export const speciesStarters = {
[Species.MOLTRES]: 6,
[Species.DRATINI]: 4,
[Species.MEWTWO]: 8,
[Species.MEW]: 7,
[Species.MEW]: 6,
[Species.CHIKORITA]: 3,
[Species.CYNDAQUIL]: 3,
@ -2683,7 +2693,7 @@ export const speciesStarters = {
[Species.LARVITAR]: 4,
[Species.LUGIA]: 8,
[Species.HO_OH]: 8,
[Species.CELEBI]: 7,
[Species.CELEBI]: 6,
[Species.TREECKO]: 3,
[Species.TORCHIC]: 3,
@ -2755,9 +2765,9 @@ export const speciesStarters = {
[Species.REGISTEEL]: 6,
[Species.LATIAS]: 7,
[Species.LATIOS]: 7,
[Species.KYOGRE]: 8,
[Species.GROUDON]: 8,
[Species.RAYQUAZA]: 8,
[Species.KYOGRE]: 9,
[Species.GROUDON]: 9,
[Species.RAYQUAZA]: 9,
[Species.JIRACHI]: 7,
[Species.DEOXYS]: 7,
@ -2799,19 +2809,19 @@ export const speciesStarters = {
[Species.MANTYKE]: 3,
[Species.SNOVER]: 3,
[Species.ROTOM]: 5,
[Species.UXIE]: 7,
[Species.MESPRIT]: 7,
[Species.AZELF]: 7,
[Species.UXIE]: 6,
[Species.MESPRIT]: 6,
[Species.AZELF]: 6,
[Species.DIALGA]: 8,
[Species.PALKIA]: 8,
[Species.HEATRAN]: 7,
[Species.REGIGIGAS]: 8,
[Species.HEATRAN]: 6,
[Species.REGIGIGAS]: 7,
[Species.GIRATINA]: 8,
[Species.CRESSELIA]: 7,
[Species.PHIONE]: 5,
[Species.CRESSELIA]: 6,
[Species.PHIONE]: 4,
[Species.MANAPHY]: 7,
[Species.DARKRAI]: 7,
[Species.SHAYMIN]: 7,
[Species.DARKRAI]: 6,
[Species.SHAYMIN]: 6,
[Species.ARCEUS]: 9,
[Species.VICTINI]: 7,
@ -2893,9 +2903,9 @@ export const speciesStarters = {
[Species.ZEKROM]: 8,
[Species.LANDORUS]: 7,
[Species.KYUREM]: 8,
[Species.KELDEO]: 7,
[Species.MELOETTA]: 7,
[Species.GENESECT]: 7,
[Species.KELDEO]: 6,
[Species.MELOETTA]: 6,
[Species.GENESECT]: 6,
[Species.CHESPIN]: 3,
[Species.FENNEKIN]: 3,
@ -2933,7 +2943,7 @@ export const speciesStarters = {
[Species.ZYGARDE]: 8,
[Species.DIANCIE]: 7,
[Species.HOOPA]: 7,
[Species.VOLCANION]: 7,
[Species.VOLCANION]: 6,
[Species.ETERNAL_FLOETTE]: 5,
[Species.ROWLET]: 3,
@ -2961,7 +2971,7 @@ export const speciesStarters = {
[Species.WIMPOD]: 3,
[Species.SANDYGAST]: 3,
[Species.PYUKUMUKU]: 3,
[Species.TYPE_NULL]: 6,
[Species.TYPE_NULL]: 5,
[Species.MINIOR]: 5,
[Species.KOMALA]: 5,
[Species.TURTONATOR]: 5,
@ -2975,21 +2985,21 @@ export const speciesStarters = {
[Species.TAPU_LELE]: 6,
[Species.TAPU_BULU]: 6,
[Species.TAPU_FINI]: 6,
[Species.COSMOG]: 7,
[Species.NIHILEGO]: 7,
[Species.BUZZWOLE]: 7,
[Species.COSMOG]: 6,
[Species.NIHILEGO]: 6,
[Species.BUZZWOLE]: 6,
[Species.PHEROMOSA]: 7,
[Species.XURKITREE]: 7,
[Species.CELESTEELA]: 7,
[Species.XURKITREE]: 6,
[Species.CELESTEELA]: 6,
[Species.KARTANA]: 7,
[Species.GUZZLORD]: 7,
[Species.GUZZLORD]: 6,
[Species.NECROZMA]: 8,
[Species.MAGEARNA]: 7,
[Species.MARSHADOW]: 7,
[Species.POIPOLE]: 7,
[Species.STAKATAKA]: 7,
[Species.STAKATAKA]: 6,
[Species.BLACEPHALON]: 7,
[Species.ZERAORA]: 7,
[Species.ZERAORA]: 6,
[Species.MELTAN]: 6,
[Species.ALOLA_RATTATA]: 2,
[Species.ALOLA_SANDSHREW]: 4,
@ -3036,14 +3046,14 @@ export const speciesStarters = {
[Species.ARCTOVISH]: 5,
[Species.DURALUDON]: 5,
[Species.DREEPY]: 4,
[Species.ZACIAN]: 8,
[Species.ZACIAN]: 9,
[Species.ZAMAZENTA]: 8,
[Species.ETERNATUS]: 10,
[Species.KUBFU]: 7,
[Species.ZARUDE]: 7,
[Species.KUBFU]: 6,
[Species.ZARUDE]: 6,
[Species.REGIELEKI]: 6,
[Species.REGIDRAGO]: 6,
[Species.GLASTRIER]: 7,
[Species.GLASTRIER]: 6,
[Species.SPECTRIER]: 7,
[Species.CALYREX]: 8,
[Species.GALAR_MEOWTH]: 4,
@ -3117,27 +3127,27 @@ export const speciesStarters = {
[Species.IRON_THORNS]: 6,
[Species.FRIGIBAX]: 4,
[Species.GIMMIGHOUL]: 5,
[Species.WO_CHIEN]: 7,
[Species.WO_CHIEN]: 6,
[Species.CHIEN_PAO]: 7,
[Species.TING_LU]: 7,
[Species.TING_LU]: 6,
[Species.CHI_YU]: 7,
[Species.ROARING_MOON]: 6,
[Species.IRON_VALIANT]: 6,
[Species.KORAIDON]: 8,
[Species.MIRAIDON]: 8,
[Species.WALKING_WAKE]: 7,
[Species.IRON_LEAVES]: 7,
[Species.KORAIDON]: 9,
[Species.MIRAIDON]: 9,
[Species.WALKING_WAKE]: 6,
[Species.IRON_LEAVES]: 6,
[Species.POLTCHAGEIST]: 4,
[Species.OKIDOGI]: 7,
[Species.MUNKIDORI]: 7,
[Species.FEZANDIPITI]: 7,
[Species.OGERPON]: 8,
[Species.OKIDOGI]: 6,
[Species.MUNKIDORI]: 6,
[Species.FEZANDIPITI]: 6,
[Species.OGERPON]: 7,
[Species.GOUGING_FIRE]: 7,
[Species.RAGING_BOLT]: 7,
[Species.RAGING_BOLT]: 6,
[Species.IRON_BOULDER]: 7,
[Species.IRON_CROWN]: 7,
[Species.IRON_CROWN]: 6,
[Species.TERAPAGOS]: 8,
[Species.PECHARUNT]: 7,
[Species.PECHARUNT]: 6,
[Species.PALDEA_TAUROS]: 5,
[Species.PALDEA_WOOPER]: 3,
[Species.BLOODMOON_URSALUNA]: 7,

View File

@ -43762,6 +43762,7 @@ export const tmSpecies: TmSpecies = {
Species.TAUROS,
Species.MEW,
Species.SNUBBULL,
Species.GRANBULL,
Species.SCIZOR,
Species.HERACROSS,
Species.TEDDIURSA,
@ -43785,11 +43786,14 @@ export const tmSpecies: TmSpecies = {
Species.LUCARIO,
Species.TOXICROAK,
Species.GALLADE,
Species.PIGNITE,
Species.EMBOAR,
Species.TIMBURR,
Species.GURDURR,
Species.CONKELDURR,
Species.SAWK,
Species.KROOKODILE,
Species.SCRAGGY,
Species.SCRAFTY,
Species.ESCAVALIER,
Species.EELEKTROSS,
@ -60022,10 +60026,14 @@ export const tmSpecies: TmSpecies = {
Species.ARCANINE,
Species.AERODACTYL,
Species.MEW,
Species.CROCONAW,
Species.FERALIGATR,
Species.ESPEON,
Species.GIRAFARIG,
Species.GLIGAR,
Species.STEELIX,
Species.SNUBBULL,
Species.GRANBULL,
Species.HOUNDOUR,
Species.HOUNDOOM,
Species.POOCHYENA,

View File

@ -235,11 +235,10 @@ export class TrainerConfig {
if (!getIsInitialized()) {
initI18n();
}
// This is only the male name, because the female name is handled in a different function (setHasGenders)
if (name === 'Finn') {
name = i18next.t('trainerNames:rival');
}
}
this.name = name;
return this;
@ -254,6 +253,7 @@ export class TrainerConfig {
// Make the title lowercase and replace spaces with underscores
title = title.toLowerCase().replace(/\s/g, '_');
// Get the title from the i18n file
this.title = i18next.t(`titles:${title}`);
@ -281,21 +281,40 @@ export class TrainerConfig {
return trainerType;
}
/**
* Sets the configuration for trainers with genders, including the female name and encounter background music (BGM).
* @param {string} [nameFemale] - The name of the female trainer. If 'Ivy', a localized name will be assigned.
* @param {TrainerType | string} [femaleEncounterBgm] - The encounter BGM for the female trainer, which can be a TrainerType or a string.
* @returns {TrainerConfig} - The updated TrainerConfig instance.
**/
setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig {
// If the female name is 'Ivy' (the rival), assign a localized name.
if (nameFemale === 'Ivy') {
// Give the rival a localized name
// First check if i18n is initialized
// Check if the internationalization (i18n) system is initialized.
if (!getIsInitialized()) {
// Initialize the i18n system if it is not already initialized.
initI18n();
}
this.nameFemale = i18next.t('trainerNames:rival_female');
} else {
// Set the localized name for the female rival.
this.nameFemale = i18next.t('trainerNames:rival_female');
} else {
// Otherwise, assign the provided female name.
this.nameFemale = nameFemale;
}
// Indicate that this trainer configuration includes genders.
this.hasGenders = true;
if (femaleEncounterBgm)
this.femaleEncounterBgm = typeof femaleEncounterBgm === 'number' ? TrainerType[femaleEncounterBgm].toString().replace(/\_/g, ' ').toLowerCase() : femaleEncounterBgm;
// If a female encounter BGM is provided.
if (femaleEncounterBgm) {
// If the BGM is a TrainerType (number), convert it to a string, replace underscores with spaces, and convert to lowercase.
// Otherwise, assign the provided string as the BGM.
this.femaleEncounterBgm = typeof femaleEncounterBgm === 'number'
? TrainerType[femaleEncounterBgm].toString().replace(/_/g, ' ').toLowerCase()
: femaleEncounterBgm;
}
// Return the updated TrainerConfig instance.
return this;
}
@ -398,29 +417,44 @@ export class TrainerConfig {
return this;
}
/**
* Initializes the trainer configuration for a Gym Leader.
* @param {Species | Species[]} signatureSpecies - The signature species for the Gym Leader.
* @param {Type[]} specialtyTypes - The specialty types for the Gym Leader.
* @returns {TrainerConfig} - The updated TrainerConfig instance.
* **/
initForGymLeader(signatureSpecies: (Species | Species[])[], ...specialtyTypes: Type[]): TrainerConfig {
// Check if the internationalization (i18n) system is initialized.
if (!getIsInitialized()) {
initI18n();
}
// Set the function to generate the Gym Leader's party template.
this.setPartyTemplateFunc(getGymLeaderPartyTemplate);
// Set up party members with their corresponding species.
signatureSpecies.forEach((speciesPool, s) => {
// Ensure speciesPool is an array.
if (!Array.isArray(speciesPool))
speciesPool = [speciesPool];
// Set a function to get a random party member from the species pool.
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
});
// If specialty types are provided, set species filter and specialty types.
if (specialtyTypes.length) {
this.setSpeciesFilter(p => specialtyTypes.find(t => p.isOfType(t)) !== undefined);
this.setSpecialtyTypes(...specialtyTypes);
}
// Handle name by checking this.name - making it lowercase and replacing spaces with underscores and then calling i18next.t with the name
// Localize the trainer's name by converting it to lowercase and replacing spaces with underscores.
const nameForCall = this.name.toLowerCase().replace(/\s/g, '_');
this.name = i18next.t(`trainerNames:${nameForCall}`);
// Set the title to "gym_leader". (this is the key in the i18n file)
this.setTitle('gym_leader');
this.setTitle("gym_leader");
// Configure various properties for the Gym Leader.
this.setMoneyMultiplier(2.5);
this.setBoss();
this.setStaticParty();
@ -430,75 +464,125 @@ export class TrainerConfig {
const waveIndex = party[0].scene.currentBattle.waveIndex;
return getRandomTeraModifiers(party, waveIndex >= 100 ? 1 : 0, specialtyTypes.length ? specialtyTypes : null);
});
return this;
}
/**
* Initializes the trainer configuration for an Elite Four member.
* @param {Species | Species[]} signatureSpecies - The signature species for the Elite Four member.
* @param {Type[]} specialtyTypes - The specialty types for the Elite Four member.
* @returns {TrainerConfig} - The updated TrainerConfig instance.
**/
initForEliteFour(signatureSpecies: (Species | Species[])[], ...specialtyTypes: Type[]): TrainerConfig {
// Check if the internationalization (i18n) system is initialized.
if (!getIsInitialized()) {
initI18n();
}
// Set the party templates for the Elite Four.
this.setPartyTemplates(trainerPartyTemplates.ELITE_FOUR);
// Set up party members with their corresponding species.
signatureSpecies.forEach((speciesPool, s) => {
// Ensure speciesPool is an array.
if (!Array.isArray(speciesPool))
speciesPool = [speciesPool];
// Set a function to get a random party member from the species pool.
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
});
// Set species filter and specialty types if provided, otherwise filter by base total.
if (specialtyTypes.length) {
this.setSpeciesFilter(p => specialtyTypes.find(t => p.isOfType(t)) && p.baseTotal >= 450);
this.setSpecialtyTypes(...specialtyTypes);
} else
} else {
this.setSpeciesFilter(p => p.baseTotal >= 450);
// Handle name by checking this.name - making it lowercase and replacing spaces with underscores and then calling i18next.t with the name
}
// Localize the trainer's name by converting it to lowercase and replacing spaces with underscores.
const nameForCall = this.name.toLowerCase().replace(/\s/g, '_');
this.name = i18next.t(`trainerNames:${nameForCall}`);
this.setTitle("elite_four");
// Set the title to "elite_four". (this is the key in the i18n file)
this.setTitle('elite_four');
// Configure various properties for the Elite Four member.
this.setMoneyMultiplier(3.25);
this.setBoss();
this.setStaticParty();
this.setBattleBgm('battle_elite');
this.setVictoryBgm('victory_gym');
this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 2, specialtyTypes.length ? specialtyTypes : null));
return this;
}
/**
* Initializes the trainer configuration for a Champion.
* @param {Species | Species[]} signatureSpecies - The signature species for the Champion.
* @returns {TrainerConfig} - The updated TrainerConfig instance.
**/
initForChampion(signatureSpecies: (Species | Species[])[]): TrainerConfig {
// Check if the internationalization (i18n) system is initialized.
if (!getIsInitialized()) {
initI18n();
}
// Set the party templates for the Champion.
this.setPartyTemplates(trainerPartyTemplates.CHAMPION);
// Set up party members with their corresponding species.
signatureSpecies.forEach((speciesPool, s) => {
// Ensure speciesPool is an array.
if (!Array.isArray(speciesPool))
speciesPool = [speciesPool];
// Set a function to get a random party member from the species pool.
this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool));
});
// Set species filter to only include species with a base total of 470 or higher.
this.setSpeciesFilter(p => p.baseTotal >= 470);
// Handle name by checking this.name - making it lowercase and replacing spaces with underscores and then calling i18next.t with the name
// Localize the trainer's name by converting it to lowercase and replacing spaces with underscores.
const nameForCall = this.name.toLowerCase().replace(/\s/g, '_');
this.name = i18next.t(`trainerNames:${nameForCall}`);
this.setTitle("champion");
// Set the title to "champion". (this is the key in the i18n file)
this.setTitle('champion');
// Configure various properties for the Champion.
this.setMoneyMultiplier(10);
this.setBoss();
this.setStaticParty();
this.setBattleBgm('battle_champion_alder');
this.setVictoryBgm('victory_champion');
this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 3));
return this;
}
/**
* Retrieves the title for the trainer based on the provided trainer slot and variant.
* @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE.
* @param {TrainerVariant} variant - The variant of the trainer to determine the specific title.
* @returns {string} - The title of the trainer.
**/
getTitle(trainerSlot: TrainerSlot = TrainerSlot.NONE, variant: TrainerVariant): string {
let ret = this.name;
// Check if the variant is double and the name for double exists
if (!trainerSlot && variant === TrainerVariant.DOUBLE && this.nameDouble)
return this.nameDouble;
// Female variant
if (this.hasGenders) {
// If the name is already set
if (this.nameFemale) {
// Check if the variant is either female or this is for the partner in a double battle
if (variant === TrainerVariant.FEMALE || (variant === TrainerVariant.DOUBLE && trainerSlot === TrainerSlot.TRAINER_PARTNER))
return this.nameFemale;
} else
// Check if !variant is true, if so return the name, else return the name with _female appended
if (variant) {
if (!getIsInitialized()) {
@ -603,12 +687,12 @@ function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: T
export const trainerConfigs: TrainerConfigs = {
[TrainerType.UNKNOWN]: new TrainerConfig(0).setHasGenders(),
[TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders().setHasDouble('Ace Duo').setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER)
[TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders('Ace Trainer Female').setHasDouble('Ace Duo').setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER)
.setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.THREE_WEAK_BALANCED, trainerPartyTemplates.FOUR_WEAK_BALANCED, trainerPartyTemplates.FIVE_WEAK_BALANCED, trainerPartyTemplates.SIX_WEAK_BALANCED)),
[TrainerType.ARTIST]: new TrainerConfig(++t).setEncounterBgm(TrainerType.RICH).setPartyTemplates(trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.THREE_AVG)
.setSpeciesPools([ Species.SMEARGLE ]),
[TrainerType.BACKERS]: new TrainerConfig(++t).setHasGenders().setDoubleOnly().setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.BACKPACKER]: new TrainerConfig(++t).setHasGenders().setHasDouble('Backpackers').setSpeciesFilter(s => s.isOfType(Type.FLYING) || s.isOfType(Type.ROCK)).setEncounterBgm(TrainerType.BACKPACKER)
[TrainerType.BACKERS]: new TrainerConfig(++t).setHasGenders("Backers").setDoubleOnly().setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.BACKPACKER]: new TrainerConfig(++t).setHasGenders("Backpacker Female").setHasDouble('Backpackers').setSpeciesFilter(s => s.isOfType(Type.FLYING) || s.isOfType(Type.ROCK)).setEncounterBgm(TrainerType.BACKPACKER)
.setPartyTemplates(trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.ONE_WEAK_ONE_STRONG, trainerPartyTemplates.ONE_AVG_ONE_STRONG)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.RHYHORN, Species.AIPOM, Species.MAKUHITA, Species.MAWILE, Species.NUMEL, Species.LILLIPUP, Species.SANDILE, Species.WOOLOO ],
@ -628,17 +712,17 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [ Species.HITMONTOP, Species.INFERNAPE, Species.GALLADE, Species.HAWLUCHA, Species.HAKAMO_O ],
[TrainerPoolTier.ULTRA_RARE]: [ Species.KUBFU ]
}),
[TrainerType.BREEDER]: new TrainerConfig(++t).setMoneyMultiplier(1.325).setEncounterBgm(TrainerType.POKEFAN).setHasGenders().setHasDouble('Breeders')
[TrainerType.BREEDER]: new TrainerConfig(++t).setMoneyMultiplier(1.325).setEncounterBgm(TrainerType.POKEFAN).setHasGenders("Breeder Female").setHasDouble('Breeders')
.setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.FOUR_WEAKER, trainerPartyTemplates.FIVE_WEAKER, trainerPartyTemplates.SIX_WEAKER))
.setSpeciesFilter(s => s.baseTotal < 450),
[TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders().setHasDouble('Colleagues').setEncounterBgm(TrainerType.CLERK)
[TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders("Clerk Female").setHasDouble('Colleagues').setEncounterBgm(TrainerType.CLERK)
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.THREE_WEAK, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_ONE_AVG)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.MEOWTH, Species.PSYDUCK, Species.BUDEW, Species.PIDOVE, Species.CINCCINO, Species.LITLEO ],
[TrainerPoolTier.UNCOMMON]: [ Species.JIGGLYPUFF, Species.MAGNEMITE, Species.MARILL, Species.COTTONEE, Species.SKIDDO ],
[TrainerPoolTier.RARE]: [ Species.BUIZEL, Species.SNEASEL, Species.KLEFKI, Species.INDEEDEE ]
}),
[TrainerType.CYCLIST]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setHasGenders().setHasDouble('Cyclists').setEncounterBgm(TrainerType.CYCLIST)
[TrainerType.CYCLIST]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setHasGenders("Cyclist Female").setHasDouble('Cyclists').setEncounterBgm(TrainerType.CYCLIST)
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.ONE_AVG)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.PICHU, Species.STARLY, Species.TAILLOW, Species.BOLTUND ],
@ -697,9 +781,9 @@ export const trainerConfigs: TrainerConfigs = {
}),
[TrainerType.PARASOL_LADY]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.PARASOL_LADY).setSpeciesFilter(s => s.isOfType(Type.WATER)),
[TrainerType.PILOT]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1),
[TrainerType.POKEFAN]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName('Poké Fan').setHasGenders().setHasDouble('Poké Fan Family').setEncounterBgm(TrainerType.POKEFAN)
[TrainerType.POKEFAN]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName('PokéFan').setHasGenders("PokéFan Female").setHasDouble('PokéFan Family').setEncounterBgm(TrainerType.POKEFAN)
.setPartyTemplates(trainerPartyTemplates.SIX_WEAKER, trainerPartyTemplates.FOUR_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.FOUR_WEAK_SAME, trainerPartyTemplates.FIVE_WEAK, trainerPartyTemplates.SIX_WEAKER_SAME),
[TrainerType.PRESCHOOLER]: new TrainerConfig(++t).setMoneyMultiplier(0.2).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders(undefined, 'lass').setHasDouble('Preschoolers')
[TrainerType.PRESCHOOLER]: new TrainerConfig(++t).setMoneyMultiplier(0.2).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("Preschooler Female", 'lass').setHasDouble('Preschoolers')
.setPartyTemplates(trainerPartyTemplates.THREE_WEAK, trainerPartyTemplates.FOUR_WEAKER, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.FIVE_WEAKER)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.CATERPIE, Species.PICHU, Species.SANDSHREW, Species.LEDYBA, Species.BUDEW, Species.BURMY, Species.WOOLOO, Species.PAWMI, Species.SMOLIV ],
@ -707,7 +791,7 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.RARE]: [ Species.RALTS, Species.RIOLU, Species.JOLTIK, Species.TANDEMAUS ],
[TrainerPoolTier.SUPER_RARE]: [ Species.DARUMAKA, Species.TINKATINK ],
}),
[TrainerType.PSYCHIC]: new TrainerConfig(++t).setHasGenders().setHasDouble('Psychics').setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.PSYCHIC)
[TrainerType.PSYCHIC]: new TrainerConfig(++t).setHasGenders("Psychic Female").setHasDouble('Psychics').setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.PSYCHIC)
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.TWO_WEAK_SAME_TWO_WEAK_SAME, trainerPartyTemplates.ONE_STRONGER)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.ABRA, Species.DROWZEE, Species.RALTS, Species.SPOINK, Species.GOTHITA, Species.SOLOSIS, Species.BLIPBUG, Species.ESPURR, Species.HATENNA ],
@ -715,7 +799,7 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.RARE]: [ Species.ELGYEM, Species.SIGILYPH, Species.BALTOY, Species.GIRAFARIG, Species.MEOWSTIC ],
[TrainerPoolTier.SUPER_RARE]: [ Species.BELDUM, Species.ESPEON, Species.STANTLER ],
}),
[TrainerType.RANGER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName('Pokémon Ranger').setEncounterBgm(TrainerType.BACKPACKER).setHasGenders().setHasDouble('Pokémon Rangers')
[TrainerType.RANGER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName('Pokémon Ranger').setEncounterBgm(TrainerType.BACKPACKER).setHasGenders("Pokémon Ranger Female").setHasDouble('Pokémon Rangers')
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.PICHU, Species.GROWLITHE, Species.PONYTA, Species.ZIGZAGOON, Species.SEEDOT, Species.BIDOOF, Species.RIOLU, Species.SEWADDLE, Species.SKIDDO, Species.SALANDIT, Species.YAMPER ],
[TrainerPoolTier.UNCOMMON]: [ Species.AZURILL, Species.TAUROS, Species.MAREEP, Species.FARFETCHD, Species.TEDDIURSA, Species.SHROOMISH, Species.ELECTRIKE, Species.BUDEW, Species.BUIZEL, Species.MUDBRAY, Species.STUFFUL ],
@ -725,7 +809,7 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerType.RICH]: new TrainerConfig(++t).setMoneyMultiplier(5).setName('Gentleman').setHasGenders('Madame').setHasDouble('Rich Couple'),
[TrainerType.RICH_KID]: new TrainerConfig(++t).setMoneyMultiplier(3.75).setName('Rich Boy').setHasGenders('Lady').setHasDouble('Rich Kids').setEncounterBgm(TrainerType.RICH),
[TrainerType.ROUGHNECK]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.DARK)),
[TrainerType.SCIENTIST]: new TrainerConfig(++t).setHasGenders().setHasDouble('Scientists').setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.SCIENTIST)
[TrainerType.SCIENTIST]: new TrainerConfig(++t).setHasGenders("Scientist Female").setHasDouble('Scientists').setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.SCIENTIST)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.MAGNEMITE, Species.GRIMER, Species.DROWZEE, Species.VOLTORB, Species.KOFFING ],
[TrainerPoolTier.UNCOMMON]: [ Species.BALTOY, Species.BRONZOR, Species.FERROSEED, Species.KLINK, Species.CHARJABUG, Species.BLIPBUG, Species.HELIOPTILE ],
@ -734,29 +818,29 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.ULTRA_RARE]: [ Species.ROTOM, Species.MELTAN ]
}),
[TrainerType.SMASHER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.SNOW_WORKER]: new TrainerConfig(++t).setName('Worker').setHasGenders().setHasDouble('Workers').setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => s.isOfType(Type.ICE) || s.isOfType(Type.STEEL)),
[TrainerType.SNOW_WORKER]: new TrainerConfig(++t).setName('Worker').setHasGenders("Worker Female").setHasDouble('Workers').setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => s.isOfType(Type.ICE) || s.isOfType(Type.STEEL)),
[TrainerType.STRIKER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.SCHOOL_KID]: new TrainerConfig(++t).setMoneyMultiplier(0.75).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders(undefined, 'lass').setHasDouble('School Kids')
[TrainerType.SCHOOL_KID]: new TrainerConfig(++t).setMoneyMultiplier(0.75).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("School Kid Female", 'lass').setHasDouble('School Kids')
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.ODDISH, Species.EXEGGCUTE, Species.TEDDIURSA, Species.WURMPLE, Species.RALTS, Species.SHROOMISH, Species.FLETCHLING ],
[TrainerPoolTier.UNCOMMON]: [ Species.VOLTORB, Species.WHISMUR, Species.MEDITITE, Species.MIME_JR, Species.NYMBLE ],
[TrainerPoolTier.RARE]: [ Species.TANGELA, Species.EEVEE, Species.YANMA ],
[TrainerPoolTier.SUPER_RARE]: [ Species.TADBULB ]
}),
[TrainerType.SWIMMER]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm(TrainerType.PARASOL_LADY).setHasGenders().setHasDouble('Swimmers').setSpecialtyTypes(Type.WATER).setSpeciesFilter(s => s.isOfType(Type.WATER)),
[TrainerType.SWIMMER]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm(TrainerType.PARASOL_LADY).setHasGenders("Swimmer Female").setHasDouble('Swimmers').setSpecialtyTypes(Type.WATER).setSpeciesFilter(s => s.isOfType(Type.WATER)),
[TrainerType.TWINS]: new TrainerConfig(++t).setDoubleOnly().setMoneyMultiplier(0.65).setUseSameSeedForAllMembers()
.setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_STRONG))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PLUSLE, Species.VOLBEAT, Species.PACHIRISU, Species.SILCOON, Species.METAPOD, Species.IGGLYBUFF, Species.PETILIL, Species.EEVEE ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MINUN, Species.ILLUMISE, Species.EMOLGA, Species.CASCOON, Species.KAKUNA, Species.CLEFFA, Species.COTTONEE, Species.EEVEE ], TrainerSlot.TRAINER_PARTNER))
.setEncounterBgm(TrainerType.TWINS),
[TrainerType.VETERAN]: new TrainerConfig(++t).setHasGenders().setHasDouble('Veteran Duo').setMoneyMultiplier(2.5).setEncounterBgm(TrainerType.ACE_TRAINER).setSpeciesFilter(s => s.isOfType(Type.DRAGON)),
[TrainerType.VETERAN]: new TrainerConfig(++t).setHasGenders("Veteran Female").setHasDouble('Veteran Duo').setMoneyMultiplier(2.5).setEncounterBgm(TrainerType.ACE_TRAINER).setSpeciesFilter(s => s.isOfType(Type.DRAGON)),
[TrainerType.WAITER]: new TrainerConfig(++t).setHasGenders('Waitress').setHasDouble('Restaurant Staff').setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.CLERK)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.CLEFFA, Species.CHATOT, Species.PANSAGE, Species.PANSEAR, Species.PANPOUR, Species.MINCCINO ],
[TrainerPoolTier.UNCOMMON]: [ Species.TROPIUS, Species.PETILIL, Species.BOUNSWEET, Species.INDEEDEE ],
[TrainerPoolTier.RARE]: [ Species.APPLIN, Species.SINISTEA, Species.POLTCHAGEIST ]
}),
[TrainerType.WORKER]: new TrainerConfig(++t).setHasGenders().setHasDouble('Workers').setEncounterBgm(TrainerType.CLERK).setMoneyMultiplier(1.7).setSpeciesFilter(s => s.isOfType(Type.ROCK) || s.isOfType(Type.STEEL)),
[TrainerType.WORKER]: new TrainerConfig(++t).setHasGenders("Worker Female").setHasDouble('Workers').setEncounterBgm(TrainerType.CLERK).setMoneyMultiplier(1.7).setSpeciesFilter(s => s.isOfType(Type.ROCK) || s.isOfType(Type.STEEL)),
[TrainerType.YOUNGSTER]: new TrainerConfig(++t).setMoneyMultiplier(0.5).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders('Lass', 'lass').setHasDouble('Beginners').setPartyTemplates(trainerPartyTemplates.TWO_WEAKER)
.setSpeciesPools(
[ Species.CATERPIE, Species.WEEDLE, Species.RATTATA, Species.SENTRET, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.BIDOOF, Species.PATRAT, Species.LILLIPUP ]

View File

@ -4,7 +4,7 @@ import { Variant, VariantSet, variantColorCache } from '#app/data/variant';
import { variantData } from '#app/data/variant';
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from '../ui/battle-info';
import { Moves } from "../data/enums/moves";
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr } from "../data/move";
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit } from "../data/move";
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from '../data/pokemon-species';
import * as Utils from '../utils';
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from '../data/type';
@ -17,7 +17,7 @@ import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims';
import { Status, StatusEffect, getRandomStatus } from '../data/status-effect';
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from '../data/pokemon-evolutions';
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from '../data/tms';
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase } from '../phases';
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchPhase, SwitchSummonPhase, ToggleDoublePositionPhase } from '../phases';
import { BattleStat } from '../data/battle-stat';
import { BattlerTag, BattlerTagLapseType, EncoreTag, HelpingHandTag, HighestStatBoostTag, TypeBoostTag, getBattlerTag } from '../data/battler-tags';
import { BattlerTagType } from "../data/enums/battler-tag-type";
@ -27,7 +27,7 @@ import { TempBattleStat } from '../data/temp-battle-stat';
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag';
import { ArenaTagType } from "../data/enums/arena-tag-type";
import { Biome } from "../data/enums/biome";
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr } from '../data/ability';
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr } from '../data/ability';
import { Abilities } from "#app/data/enums/abilities";
import PokemonData from '../system/pokemon-data';
import Battle, { BattlerIndex } from '../battle';
@ -329,9 +329,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (variantSet && variantSet[this.variant] === 1) {
if (variantColorCache.hasOwnProperty(key))
return resolve();
this.scene.cachedFetch(`./images/pokemon/variant/${useExpSprite ? 'exp/' : ''}${battleSpritePath}.json`).then(res => res.json()).then(c => {
variantColorCache[key] = c;
resolve();
this.scene.cachedFetch(`./images/pokemon/variant/${useExpSprite ? 'exp/' : ''}${battleSpritePath}.json`).
then(res => {
// Prevent the JSON from processing if it failed to load
if (!res.ok) {
console.error(`Could not load ${res.url}!`);
return;
}
return res.json()
}).then(c => {
variantColorCache[key] = c;
resolve();
});
} else
resolve();
@ -493,9 +501,31 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.shinySparkle = shinySparkle;
}
/**
* Attempts to animate a given {@linkcode Phaser.GameObjects.Sprite}
* @see {@linkcode Phaser.GameObjects.Sprite.play}
* @param sprite {@linkcode Phaser.GameObjects.Sprite} to animate
* @param tintSprite {@linkcode Phaser.GameObjects.Sprite} placed on top of the sprite to add a color tint
* @param animConfig {@linkcode String} to pass to {@linkcode Phaser.GameObjects.Sprite.play}
* @returns true if the sprite was able to be animated
*/
tryPlaySprite(sprite: Phaser.GameObjects.Sprite, tintSprite: Phaser.GameObjects.Sprite, key: string): boolean {
// Catch errors when trying to play an animation that doesn't exist
try {
sprite.play(key);
tintSprite.play(key);
}
catch(error: unknown) {
console.error(`Couldn't play animation for '${key}'!\nIs the image for this Pokemon missing?\n`, error);
return false;
}
return true;
}
playAnim(): void {
this.getSprite().play(this.getBattleSpriteKey());
this.getTintSprite().play(this.getBattleSpriteKey());
this.tryPlaySprite(this.getSprite(), this.getTintSprite(), this.getBattleSpriteKey());
}
getFieldPositionOffset(): [ number, number ] {
@ -1097,7 +1127,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let shinyThreshold = new Utils.IntegerHolder(32);
if (thresholdOverride === undefined) {
if (!this.hasTrainer()) {
if (new Date() < new Date('2024-05-21'))
if (new Date() < new Date(Date.UTC(2024, 4, 22, 0)))
shinyThreshold.value *= 3;
this.scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold);
}
@ -1252,11 +1282,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.isBoss()) // Bosses never get self ko moves
movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(SacrificialAttr).length);
movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(SacrificialAttrOnHit).length);
if (this.hasTrainer()) {
// Trainers never get OHKO moves
movePool = movePool.filter(m => !allMoves[m[0]].getAttrs(OneHitKOAttr).length);
// Half the weight of self KO moves
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].getAttrs(SacrificialAttr).length ? 0.5 : 1)]);
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].getAttrs(SacrificialAttrOnHit).length ? 0.5 : 1)]);
// Trainers get a weight bump to stat buffing moves
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].getAttrs(StatChangeAttr).some(a => (a as StatChangeAttr).levels > 1 && (a as StatChangeAttr).selfTarget) ? 1.25 : 1)]);
// Trainers get a weight decrease to multiturn moves
@ -1493,6 +1525,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const critOnly = new Utils.BooleanHolder(false);
const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT);
applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly);
applyAbAttrs(ConditionalCritAbAttr, source, null, critOnly, this, move);
if (critOnly.value || critAlways)
isCritical = true;
else {
@ -1508,12 +1541,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
critLevel.value += 2;
const critChance = [24, 8, 2, 1][Math.max(0, Math.min(critLevel.value, 3))];
isCritical = !source.getTag(BattlerTagType.NO_CRIT) && (critChance === 1 || !this.scene.randBattleSeedInt(critChance));
if (isCritical) {
const blockCrit = new Utils.BooleanHolder(false);
applyAbAttrs(BlockCritAbAttr, this, null, blockCrit);
if (blockCrit.value)
isCritical = false;
}
}
if (isCritical) {
const blockCrit = new Utils.BooleanHolder(false);
applyAbAttrs(BlockCritAbAttr, this, null, blockCrit);
if (blockCrit.value)
isCritical = false;
}
const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, null, isCritical));
const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical));
@ -1628,6 +1661,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.gameData.gameStats.highestDamage = damage.value;
}
source.turnData.damageDealt += damage.value;
source.turnData.currDamageDealt = damage.value;
this.battleData.hitCount++;
const attackResult = { move: move.id, result: result as DamageResult, damage: damage.value, critical: isCritical, sourceId: source.id };
this.turnData.attacksReceived.unshift(attackResult);
@ -2649,6 +2683,42 @@ export class PlayerPokemon extends Pokemon {
sd.friendship = Math.max((sd.friendship || 0) + starterAmount.value, 0);
}
}
/**
* Handles Revival Blessing when used by player.
* @returns Promise to revive a pokemon.
* @see {@linkcode RevivalBlessingAttr}
*/
revivalBlessing(): Promise<void> {
return new Promise(resolve => {
this.scene.ui.setMode(Mode.PARTY, PartyUiMode.REVIVAL_BLESSING, this.getFieldIndex(), (slotIndex:integer, option: PartyOption) => {
if(slotIndex >= 0 && slotIndex<6) {
const pokemon = this.scene.getParty()[slotIndex];
if(!pokemon || !pokemon.isFainted())
resolve();
pokemon.resetTurnData();
pokemon.resetStatus();
pokemon.heal(Math.min(Math.max(Math.ceil(Math.floor(0.5 * pokemon.getMaxHp())), 1), pokemon.getMaxHp()));
this.scene.queueMessage(`${pokemon.name} was revived!`,0,true);
if(this.scene.currentBattle.double && this.scene.getParty().length > 1) {
const allyPokemon = this.getAlly();
if(slotIndex<=1) {
// Revived ally pokemon
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), slotIndex, false, false, true));
this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true));
} else if(allyPokemon.isFainted()) {
// Revived party pokemon, and ally pokemon is fainted
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, allyPokemon.getFieldIndex(), slotIndex, false, false, true));
this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true));
}
}
}
this.scene.ui.setMode(Mode.MESSAGE).then(() => resolve());
}, PartyUiHandler.FilterFainted)
})
}
getPossibleEvolution(evolution: SpeciesFormEvolution): Promise<Pokemon> {
return new Promise(resolve => {
@ -3350,6 +3420,7 @@ export class PokemonTurnData {
public hitCount: integer;
public hitsLeft: integer;
public damageDealt: integer = 0;
public currDamageDealt: integer = 0;
public damageTaken: integer = 0;
public attacksReceived: AttackMoveResult[] = [];
}

View File

@ -96,30 +96,54 @@ export default class Trainer extends Phaser.GameObjects.Container {
return this.config.getSpriteKey(this.variant === TrainerVariant.FEMALE || forceFemale);
}
/**
* Returns the name of the trainer based on the provided trainer slot and the option to include a title.
* @param {TrainerSlot} trainerSlot - The slot to determine which name to use. Defaults to TrainerSlot.NONE.
* @param {boolean} includeTitle - Whether to include the title in the returned name. Defaults to false.
* @returns {string} - The formatted name of the trainer.
**/
getName(trainerSlot: TrainerSlot = TrainerSlot.NONE, includeTitle: boolean = false): string {
// Get the base title based on the trainer slot and variant.
let name = this.config.getTitle(trainerSlot, this.variant);
// Determine the title to include based on the configuration and includeTitle flag.
let title = includeTitle && this.config.title ? this.config.title : null;
// If the trainer has a name (not null or undefined).
if (this.name) {
if (includeTitle)
// Check if i18n is initialized
// If the title should be included.
if (includeTitle) {
// Check if the internationalization (i18n) system is initialized.
if (!getIsInitialized()) {
initI18n()
// Initialize the i18n system if it is not already initialized.
initI18n();
}
// Get the localized trainer class name from the i18n file and set it as the title.
// This is used for trainer class names, not titles like "Elite Four, Champion, etc."
title = i18next.t(`trainerClasses:${name.toLowerCase().replace(/\s/g, '_')}`);
}
// If no specific trainer slot is set.
if (!trainerSlot) {
// Use the trainer's name.
name = this.name;
if (this.partnerName)
// If there is a partner name, concatenate it with the trainer's name using "&".
if (this.partnerName) {
name = `${name} & ${this.partnerName}`;
} else
}
} else {
// Assign the name based on the trainer slot:
// Use 'this.name' if 'trainerSlot' is TRAINER.
// Otherwise, use 'this.partnerName' if it exists, or 'this.name' if it doesn't.
name = trainerSlot === TrainerSlot.TRAINER ? this.name : this.partnerName || this.name;
}
}
// Return the formatted name, including the title if it is set.
return title ? `${title} ${name}` : name;
}
isDouble(): boolean {
return this.config.doubleOnly || this.variant === TrainerVariant.DOUBLE;
}

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!`,
'badDreams': `{{pokemonName}} ist in einem Alptraum gefangen!`,
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const deConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const deConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Polizist",
"parasol_lady": "Schirmdame",
"pilot": "Pilot",
"pokefan": "Pokéfan",
"pokefan_family": "Pokéfan-Pärchen",
"pokéfan": "Pokéfan",
"pokéfan_female": "Pokéfan",
"pokéfan_family": "Pokéfan-Pärchen",
"preschooler": "Vorschüler",
"preschooler_female": "Vorschülerin",
"preschoolers": "Vorschüler",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Seherin",
"psychics": "Seher",
"pokémon_ranger": "Pokémon-Ranger",
"pokémon_ranger_female": "Pokémon-Ranger",
"pokémon_rangers": "Pokémon-Ranger",
"ranger": "Ranger",
"restaurant_staff": "Restaurant Angestellte",

11
src/locales/de/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`,
'badDreams': `{{pokemonName}} is tormented!`,
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const enConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const enConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Officer",
"parasol_lady": "Parasol Lady",
"pilot": "Pilot",
"pokefan": "Poké Fan",
"pokefan_family": "Poké Fan Family",
"pokéfan": "Poké Fan",
"pokéfan_female": "Poké Fan",
"pokéfan_family": "Poké Fan Family",
"preschooler": "Preschooler",
"preschooler_female": "Preschooler",
"preschoolers": "Preschoolers",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Psychic",
"psychics": "Psychics",
"pokémon_ranger": "Pokémon Ranger",
"pokémon_ranger_female": "Pokémon Ranger",
"pokémon_rangers": "Pokémon Ranger",
"ranger": "Ranger",
"restaurant_staff": "Restaurant Staff",

11
src/locales/en/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`,
} as const;
'badDreams': `{{pokemonName}} Está atormentado!`
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const esConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const esConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Officer",
"parasol_lady": "Parasol Lady",
"pilot": "Pilot",
"pokefan": "Poké Fan",
"pokefan_family": "Poké Fan Family",
"pokéfan": "Poké Fan",
"pokéfan_female": "Poké Fan",
"pokéfan_family": "Poké Fan Family",
"preschooler": "Preschooler",
"preschooler_female": "Preschooler",
"preschoolers": "Preschoolers",

11
src/locales/es/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !`,
'badDreams': `{{pokemonName}} a le sommeil agité !`
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const frConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const frConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -52,16 +52,16 @@ export const modifierType: ModifierTypeTranslationEntries = {
description: "Double les chances de tomber sur un combat double pendant {{battleCount}} combats",
},
"TempBattleStatBoosterModifierType": {
description: "Augmente d1 cran {{tempBattleStatName}} pour toute léquipe pendant 5 combats",
description: "Augmente dun cran {{tempBattleStatName}} pour toute léquipe pendant 5 combats",
},
"AttackTypeBoosterModifierType": {
description: "Augmente de 20% la puissance des capacités de type {{moveType}} dun Pokémon",
},
"PokemonLevelIncrementModifierType": {
description: "Fait monter un Pokémon d1 niveau",
description: "Fait monter un Pokémon dun niveau",
},
"AllPokemonLevelIncrementModifierType": {
description: "Fait monter toute léquipe d1 niveau",
description: "Fait monter toute léquipe dun niveau",
},
"PokemonBaseStatBoosterModifierType": {
description: "Augmente de 10% {{statName}} de base de son porteur. Plus les IV sont hauts, plus il peut en porter.",
@ -214,13 +214,13 @@ export const modifierType: ModifierTypeTranslationEntries = {
"SHINY_CHARM": { name: "Charme Chroma", description: "Augmente énormément les chances de rencontrer un Pokémon sauvage chromatique" },
"ABILITY_CHARM": { name: "Charme Talent", description: "Augmente énormément les chances de rencontrer un Pokémon sauvage avec un Talent Caché" },
"IV_SCANNER": { name: "Scanner dIV", description: "Scanne les IV dun Pokémon sauvage. 2 IV sont révélés par Scanner. Les meilleurs sont montrés en 1er." },
"IV_SCANNER": { name: "Scanner dIV", description: "Révèle la qualité de deux IV dun Pokémon sauvage par scanner possédé. Les meilleurs IV sont révélés en priorité." },
"DNA_SPLICERS": { name: "Pointeau ADN" },
"MINI_BLACK_HOLE": { name: "Mini Trou Noir" },
"GOLDEN_POKEBALL": { name: "Poké Ball Dorée", description: "Ajoute 1 choix dobjet à la fin de chaque combat" },
"GOLDEN_POKEBALL": { name: "Poké Ball Dorée", description: "Ajoute un choix dobjet à la fin de chaque combat" },
"ENEMY_DAMAGE_BOOSTER": { name: "Jeton Dégâts", description: "Augmente les dégâts de 5%" },
"ENEMY_DAMAGE_REDUCTION": { name: "Jeton Protection", description: "Diminue les dégâts reçus de 2,5%" },

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Policier",
"parasol_lady": "Sœur Parasol",
"pilot": "Pilote",
"pokefan": "Poké Fan",
"pokefan_family": "Couple de Pokéfans",
"pokéfan": "Poké Fan",
"pokéfan_female": "Poké Fan",
"pokéfan_family": "Couple de Pokéfans",
"preschooler": "Petit",
"preschooler_female": "Petite",
"preschoolers": "Petits",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Kinésiste",
"psychics": "Kinésistes",
"pokémon_ranger": "Pokémon Ranger",
"pokémon_ranger_female": "Pokémon Ranger",
"pokémon_rangers": "Pokémon Rangers",
"ranger": "Ranger",
"restaurant_staff": "Serveurs",

11
src/locales/fr/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Coupons",
"eggVoucher": "Coupon Œuf",
"eggVoucherPlus": "Coupon Œuf +",
"eggVoucherPremium": "Coupon Œuf Premium",
"eggVoucherGold": "Coupon Œuf Or",
"locked": "Verrouillé",
"defeatTrainer": "Vaincre {{trainerName}}"
} as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{abilityName}} di {{pokemonName}}\nl'ha protetto dal contraccolpo!`,
'badDreams': `{{pokemonName}} è tormentato!`,
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const itConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const itConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Officer",
"parasol_lady": "Parasol Lady",
"pilot": "Pilot",
"pokefan": "Poké Fan",
"pokefan_family": "Poké Fan Family",
"pokéfan": "Poké Fan",
"pokéfan_female": "Poké Fan",
"pokéfan_family": "Poké Fan Family",
"preschooler": "Preschooler",
"preschooler_female": "Preschooler",
"preschoolers": "Preschoolers",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Psychic",
"psychics": "Psychics",
"pokémon_ranger": "Pokémon Ranger",
"pokémon_ranger_female": "Pokémon Ranger",
"pokémon_rangers": "Pokémon Ranger",
"ranger": "Ranger",
"restaurant_staff": "Restaurant Staff",

11
src/locales/it/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -19,6 +19,7 @@ import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const ptBrConfig = {
@ -45,4 +46,5 @@ export const ptBrConfig = {
weather: weather,
modifierType: modifierType,
berry: berry,
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Policial",
"parasol_lady": "Moça de Sombrinha",
"pilot": "Piloto",
"poké_fan": "Pokefã",
"poké_fan_family": "Família Pokefã",
"pokéfan": "Pokefã",
"pokéfan_female": "Pokéfã",
"pokéfan_family": "Família Pokefã",
"preschooler": "Menino do Prezinho",
"preschooler_female": "Menina do Prezinho",
"preschoolers": "Alunos do Prezinho",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Médium",
"psychics": "Médiuns",
"pokémon_ranger": "Guarda Pokémon",
"pokémon_ranger_female": "Guarda Pokémon",
"pokémon_rangers": "Guardas Pokémon",
"ranger": "Guarda",
"restaurant_staff": "Equipe do Restaurante",

View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}} 的 {{abilityName}}\n抵消了反作用力`,
'badDreams': `{{pokemonName}} 被折磨着!`
} as const;

View File

@ -2,7 +2,7 @@ import { ability } from "./ability";
import { abilityTriggers } from "./ability-trigger";
import { battle } from "./battle";
import { commandUiHandler } from "./command-ui-handler";
// import { egg } from "./egg";
import { egg } from "./egg";
import { fightUiHandler } from "./fight-ui-handler";
import { growth } from "./growth";
import { menu } from "./menu";
@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const zhCnConfig = {
@ -27,7 +28,7 @@ export const zhCnConfig = {
abilityTriggers: abilityTriggers,
battle: battle,
commandUiHandler: commandUiHandler,
// egg: egg,
egg: egg,
fightUiHandler: fightUiHandler,
growth: growth,
menu: menu,
@ -47,4 +48,5 @@ export const zhCnConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

21
src/locales/zh_CN/egg.ts Normal file
View File

@ -0,0 +1,21 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const egg: SimpleTranslationEntries = {
"egg": "蛋",
"greatTier": "稀有",
"ultraTier": "史诗",
"masterTier": "传说",
"defaultTier": "普通",
"hatchWavesMessageSoon": "里面传来声音!\n似乎快要孵化了",
"hatchWavesMessageClose": "有时好像会动一下。\n就快孵化了吧",
"hatchWavesMessageNotClose": "会孵化出什么呢?\n看来还需要很长时\n间才能孵化。",
"hatchWavesMessageLongTime": "这个蛋需要很长时间\n才能孵化。",
"gachaTypeLegendary": "传说概率上升",
"gachaTypeMove": "稀有概率上升",
"gachaTypeShiny": "闪光概率上升",
"selectMachine": "选择一个机器。",
"notEnoughVouchers": "你没有足够的兑换券!",
"tooManyEggs": "你的蛋太多啦!",
"pull": "次",
"pulls": "次"
} as const;

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "警察",
"parasol_lady": "阳伞姐姐",
"pilot": "飞行员",
"poké_fan": "发烧友俱乐部",
"poké_fan_family": "同好夫妇",
"pokéfan": "发烧友俱乐部",
"pokéfan_female": "发烧友俱乐部",
"pokéfan_family": "同好夫妇",
"preschooler": "幼儿园小朋友",
"preschooler_female": "幼儿园小朋友",
"preschoolers": "幼儿园小朋友组合",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "超能力者",
"psychics": "超能力者组合",
"pokémon_ranger": "宝可梦巡护员",
"pokémon_ranger_female": "宝可梦巡护员",
"pokémon_rangers": "宝可梦巡护员组合",
"ranger": "巡护员",
"restaurant_staff": "服务生组合",

View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "兑换券",
"eggVoucher": "初级扭蛋券",
"eggVoucherPlus": "中级扭蛋券",
"eggVoucherPremium": "高级扭蛋券",
"eggVoucherGold": "黄金扭蛋券",
"locked": "锁定",
"defeatTrainer": "你打败了{{trainerName}}"
} as const;

View File

@ -1423,7 +1423,7 @@ export class ExpBalanceModifier extends PersistentModifier {
}
getMaxStackCount(scene: BattleScene): integer {
return 5;
return 4;
}
}

View File

@ -2,7 +2,7 @@ import BattleScene, { AnySound, bypassLogin, startingWave } from "./battle-scene
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
import * as Utils from './utils';
import { Moves } from "./data/enums/moves";
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr, VariableTargetAttr, SacrificialAttr } from "./data/move";
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr, VariableTargetAttr, SacrificialAttr, IncrementMovePriorityAttr } from "./data/move";
import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler";
import { Stat } from "./data/pokemon-stat";
@ -366,10 +366,14 @@ export class TitlePhase extends Phase {
this.scene.pushPhase(new SummonPhase(this.scene, 0, true, true));
if (this.scene.currentBattle.double && availablePartyMembers > 1)
this.scene.pushPhase(new SummonPhase(this.scene, 1, true, true));
if (this.scene.currentBattle.waveIndex > 1 && this.scene.currentBattle.battleType !== BattleType.TRAINER) {
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double));
if (this.scene.currentBattle.double && availablePartyMembers > 1)
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double));
if (this.scene.currentBattle.battleType !== BattleType.TRAINER && (this.scene.currentBattle.waveIndex > 1 || !this.scene.gameMode.isDaily)) {
const minPartySize = this.scene.currentBattle.double ? 2 : 1;
if (availablePartyMembers > minPartySize) {
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double));
if (this.scene.currentBattle.double)
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double));
}
}
}
@ -906,7 +910,7 @@ export class EncounterPhase extends BattlePhase {
const showDialogueAndSummon = () => {
let message: string;
this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.waveIndex);
this.scene.ui.showDialogue(message, trainer.getName(), null, () => {
this.scene.ui.showDialogue(message, trainer.getName(TrainerSlot.NONE,true), null, () => {
this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => doSummon()));
});
};
@ -955,10 +959,13 @@ export class EncounterPhase extends BattlePhase {
this.scene.pushPhase(new ToggleDoublePositionPhase(this.scene, false));
}
if (this.scene.currentBattle.waveIndex > startingWave && this.scene.currentBattle.battleType !== BattleType.TRAINER) {
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double));
if (this.scene.currentBattle.double && availablePartyMembers.length > 1)
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double));
if (this.scene.currentBattle.battleType !== BattleType.TRAINER && (this.scene.currentBattle.waveIndex > 1 || !this.scene.gameMode.isDaily)) {
const minPartySize = this.scene.currentBattle.double ? 2 : 1;
if (availablePartyMembers.length > minPartySize) {
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double));
if (this.scene.currentBattle.double)
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double));
}
}
}
@ -1809,7 +1816,7 @@ export class CommandPhase extends FieldPhase {
const trapped = new Utils.BooleanHolder(false);
const batonPass = isSwitch && args[0] as boolean;
if (!batonPass)
enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped));
enemyField.forEach(enemyPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trapped, playerPokemon));
if (batonPass || (!trapTag && !trapped.value)) {
this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch
? { command: Command.POKEMON, cursor: cursor, args: args }
@ -1914,7 +1921,7 @@ export class EnemyCommandPhase extends FieldPhase {
const trapTag = enemyPokemon.findTag(t => t instanceof TrappedTag) as TrappedTag;
const trapped = new Utils.BooleanHolder(false);
opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped));
opponents.forEach(playerPokemon => applyCheckTrappedAbAttrs(CheckTrappedAbAttr, playerPokemon, trapped, enemyPokemon));
if (!trapTag && !trapped.value) {
const partyMemberScores = trainer.getPartyMemberMatchupScores(enemyPokemon.trainerSlot, true);
@ -2012,6 +2019,9 @@ export class TurnStartPhase extends FieldPhase {
const aPriority = new Utils.IntegerHolder(aMove.priority);
const bPriority = new Utils.IntegerHolder(bMove.priority);
applyMoveAttrs(IncrementMovePriorityAttr,this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a),null,aMove,aPriority);
applyMoveAttrs(IncrementMovePriorityAttr,this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b),null,bMove,bPriority);
applyAbAttrs(IncrementMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a), null, aMove, aPriority);
applyAbAttrs(IncrementMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b), null, bMove, bPriority);
@ -3045,7 +3055,8 @@ export class PostTurnStatusEffectPhase extends PokemonPhase {
break;
}
if (damage) {
this.scene.damageNumberHandler.add(this.getPokemon(), pokemon.damage(damage));
// Set preventEndure flag to avoid pokemon surviving thanks to focus band, sturdy, endure ...
this.scene.damageNumberHandler.add(this.getPokemon(), pokemon.damage(damage, false, true));
pokemon.updateInfo();
}
new CommonBattleAnim(CommonAnim.POISON + (pokemon.status.effect - 1), pokemon).play(this.scene, () => this.end());
@ -3840,6 +3851,10 @@ export class SwitchPhase extends BattlePhase {
if (this.isModal && !this.scene.getParty().filter(p => !p.isFainted() && !p.isActive(true)).length)
return super.end();
// Check if there is any space still in field
if (this.isModal && this.scene.getPlayerField().filter(p => !p.isFainted() && p.isActive(true)).length >= this.scene.currentBattle.getBattlerCount())
return super.end();
// Override field index to 0 in case of double battle where 2/3 remaining party members fainted at once
const fieldIndex = this.scene.currentBattle.getBattlerCount() === 1 || this.scene.getParty().filter(p => !p.isFainted()).length > 1 ? this.fieldIndex : 0;
@ -4349,6 +4364,7 @@ export class AttemptCapturePhase extends PokemonPhase {
scale: 1
});
this.scene.currentBattle.lastUsedPokeball = this.pokeballType;
this.removePb();
this.end();
}
@ -4407,6 +4423,7 @@ export class AttemptCapturePhase extends PokemonPhase {
if (this.scene.getParty().length === 6) {
const promptRelease = () => {
this.scene.ui.showText(`Your party is full.\nRelease a Pokémon to make room for ${pokemon.name}?`, null, () => {
this.scene.pokemonInfoContainer.makeRoomForConfirmUi();
this.scene.ui.setMode(Mode.CONFIRM, () => {
this.scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, this.fieldIndex, (slotIndex: integer, _option: PartyOption) => {
this.scene.ui.setMode(Mode.MESSAGE).then(() => {

View File

@ -93,8 +93,9 @@ export function initI18n(): void {
i18next.use(LanguageDetector).init({
lng: lang,
nonExplicitSupportedLngs: true,
fallbackLng: 'en',
supportedLngs: ['en', 'es', 'fr', 'it', 'de', 'zh_CN','pt_BR'],
supportedLngs: ['en', 'es', 'fr', 'it', 'de', 'zh','pt'],
debug: true,
interpolation: {
escapeValue: false,
@ -153,6 +154,7 @@ declare module 'i18next' {
modifierType: ModifierTypeTranslationEntries;
battleMessageUiHandler: SimpleTranslationEntries;
berry: BerryTranslationEntries;
voucher: SimpleTranslationEntries;
};
}
}

View File

@ -867,8 +867,11 @@ export class GameData {
const ret: PersistentModifierData[] = [];
if (v === null)
v = [];
for (let md of v)
for (let md of v) {
if(md?.className === 'ExpBalanceModifier') // Temporarily limit EXP Balance until it gets reworked
md.stackCount = Math.min(md.stackCount, 4);
ret.push(new PersistentModifierData(md, player));
}
return ret;
}

View File

@ -184,11 +184,17 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
scene.ui.revertMode();
(scene.ui.getHandler() as SettingsUiHandler).setOptionCursor(Object.values(Setting).indexOf(Setting.Language), 0, true);
};
const changeLocaleHandler = (locale: string) => {
i18next.changeLanguage(locale);
localStorage.setItem('prLang', locale);
cancelHandler();
scene.reset(true, false, true);
const changeLocaleHandler = (locale: string): boolean => {
try {
i18next.changeLanguage(locale);
localStorage.setItem('prLang', locale);
cancelHandler();
scene.reset(true, false, true);
return true;
} catch (error) {
console.error('Error changing locale:', error);
return false;
}
};
scene.ui.setOverlayMode(Mode.OPTION_SELECT, {
options: [

View File

@ -2,6 +2,7 @@ import BattleScene from "../battle-scene";
import { TrainerType } from "../data/enums/trainer-type";
import { ModifierTier } from "../modifier/modifier-tier";
import { Achv, AchvTier, achvs } from "./achv";
import i18next from '../plugins/i18n';
export enum VoucherType {
REGULAR,
@ -52,13 +53,13 @@ export class Voucher {
export function getVoucherTypeName(voucherType: VoucherType): string {
switch (voucherType) {
case VoucherType.REGULAR:
return 'Egg Voucher';
return i18next.t("voucher:eggVoucher");
case VoucherType.PLUS:
return 'Egg Voucher Plus';
return i18next.t("voucher:eggVoucherPlus");
case VoucherType.PREMIUM:
return 'Egg Voucher Premium';
return i18next.t("voucher:eggVoucherPremium");
case VoucherType.GOLDEN:
return 'Egg Voucher Gold';
return i18next.t("voucher:eggVoucherGold");
}
}
@ -75,9 +76,8 @@ export function getVoucherTypeIcon(voucherType: VoucherType): string {
}
}
export interface Vouchers {
[key: string]: Voucher
[key: string]: Voucher;
}
export const vouchers: Vouchers = {};
@ -87,6 +87,8 @@ const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ];
{
(function() {
import('../data/trainer-config').then(tc => {
const trainerConfigs = tc.trainerConfigs;
for (let achv of voucherAchvs) {
const voucherType = achv.score >= 150
? VoucherType.GOLDEN
@ -98,7 +100,6 @@ const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ];
vouchers[achv.id] = new Voucher(voucherType, achv.description);
}
const trainerConfigs = tc.trainerConfigs;
const bossTrainerTypes = Object.keys(trainerConfigs)
.filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL);
@ -107,12 +108,17 @@ const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ];
? VoucherType.PLUS
: VoucherType.PREMIUM;
const key = TrainerType[trainerType];
vouchers[key] = new Voucher(voucherType, `Defeat ${trainerConfigs[trainerType].name}`);
const trainerName = trainerConfigs[trainerType].name;
vouchers[key] = new Voucher(
voucherType,
i18next.t("voucher:defeatTrainer", { trainerName })
);
}
const voucherKeys = Object.keys(vouchers);
for (let k of voucherKeys)
for (let k of voucherKeys) {
vouchers[k].id = k;
}
});
})();
}
}

View File

@ -0,0 +1,225 @@
import {beforeAll, describe, expect, it} from "vitest";
import _masterlist from '../../public/images/pokemon/variant/_masterlist.json';
import fs from 'fs';
import path from 'path';
import {getAppRootDir} from "#app/test/testUtils";
const deepCopy = (data) => {
return JSON.parse(JSON.stringify(data));
}
describe("check if every variant's sprite are correctly set", () => {
let masterlist;
let expVariant;
let femaleVariant;
let backVariant;
let rootDir;
beforeAll(() => {
rootDir = `${getAppRootDir()}${path.sep}public${path.sep}images${path.sep}pokemon${path.sep}variant${path.sep}`
masterlist = deepCopy(_masterlist);
expVariant = masterlist.exp;
femaleVariant = masterlist.female;
backVariant = masterlist.back;
delete masterlist.exp
delete masterlist.female
delete masterlist.back
});
it('data should not be undefined', () => {
expect(masterlist).not.toBeUndefined();
expect(expVariant).not.toBeUndefined();
expect(femaleVariant).not.toBeUndefined();
expect(backVariant).not.toBeUndefined();
});
function getMissingMasterlist(mlist, dirpath, excludes = []) {
const errors = [];
const trimmedDirpath = `variant${path.sep}${dirpath.split(rootDir)[1]}`;
if (fs.existsSync(dirpath)) {
const files = fs.readdirSync(dirpath);
for (const filename of files) {
const filePath = `${dirpath}${filename}`
const trimmedFilePath = `${trimmedDirpath}${filename}`
const ext = filename.split('.')[1];
const name = filename.split('.')[0];
if (excludes.includes(name)) continue;
if (name.includes('_')) {
const id = name.split('_')[0];
const variant = name.split('_')[1];
if (ext !== 'json') {
if (mlist.hasOwnProperty(id)) {
const urlJsonFile = `${dirpath}${id}.json`;
const trimmedUrlJsonFilepath = `${trimmedDirpath}${id}.json`;
const jsonFileExists = fs.existsSync(urlJsonFile);
if (mlist[id].includes(1)) {
const msg = `[${name}] MISSING JSON ${trimmedUrlJsonFilepath}`;
if (!jsonFileExists && !errors.includes(msg)) errors.push(msg);
}
}
if (!mlist.hasOwnProperty(id)) errors.push(`[${id}] missing key ${id} in masterlist for ${trimmedFilePath}`);
else if (mlist[id][parseInt(variant, 10) - 1] !== 2) {
const urlJsonFile = `${dirpath}${name}.json`;
const trimmedUrlJsonFilepath = `${trimmedDirpath}${name}.json`;
const jsonFileExists = fs.existsSync(urlJsonFile);
if (mlist[id].includes(1)) {
const msg = `[${id}] MISSING JSON ${trimmedUrlJsonFilepath}`;
if (!jsonFileExists && !errors.includes(msg)) errors.push(msg);
}
errors.push(`[${id}] [${mlist[id]}] - the value should be 2 for the index ${parseInt(variant, 10) - 1} - ${trimmedFilePath}`);
}
}
} else if (!mlist.hasOwnProperty(name)) errors.push(`named - missing key ${name} in masterlist for ${trimmedFilePath}`);else {
const raw = fs.readFileSync(filePath, {encoding: 'utf8', flag: 'r'});
const data = JSON.parse(raw);
for (const key of Object.keys(data)) {
if (mlist[name][key] !== 1) errors.push(`[${name}] [${mlist[name]}] - the value should be 1 for the index ${key} - ${trimmedFilePath}`);
}
}
}
}
return errors;
}
function getMissingFiles(keys, dirPath) {
const errors = [];
for (const key of Object.keys(keys)) {
const row = keys[key];
for (const [index, elm] of row.entries()) {
let url;
if (elm === 0) continue
else if (elm === 1) {
url = `${key}.json`
let filePath = `${dirPath}${url}`;
const raw = fs.readFileSync(filePath, {encoding: 'utf8', flag: 'r'});
const data = JSON.parse(raw);
if (!data.hasOwnProperty(index)) {
errors.push(`index: ${index} - ${filePath}`);
}
} else if (elm === 2) {
url = `${key}_${parseInt(index, 10) + 1}.png`;
let filePath = `${dirPath}${url}`;
if (!fs.existsSync(filePath)) {
errors.push(filePath)
}
url = `${key}_${parseInt(index, 10) + 1}.json`;
filePath = `${dirPath}${url}`;
if (!fs.existsSync(filePath)) {
errors.push(filePath)
}
}
}
}
return errors;
}
// chech presence of every files listed in masterlist
it('check root variant files', () => {
const dirPath = rootDir;
const errors = getMissingFiles(masterlist, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check female variant files', () => {
const dirPath = `${rootDir}female${path.sep}`;
const errors = getMissingFiles(femaleVariant, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check back female variant files', () => {
const dirPath = `${rootDir}back${path.sep}female${path.sep}`;
const errors = getMissingFiles(backVariant.female, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check back male back variant files', () => {
const dirPath = `${rootDir}back${path.sep}`;
let backMaleVariant = deepCopy(backVariant);
delete backMaleVariant.female;
const errors = getMissingFiles(backMaleVariant, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check exp back variant files', () => {
const dirPath = `${rootDir}exp${path.sep}back${path.sep}`;
const errors = getMissingFiles(expVariant.back, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check exp female variant files', () => {
const dirPath = `${rootDir}exp${path.sep}female${path.sep}`;
const errors = getMissingFiles(expVariant.female, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
it('check exp male variant files', () => {
const dirPath = `${rootDir}exp${path.sep}`;
let expMaleVariant = deepCopy(expVariant);
delete expMaleVariant.female;
delete expMaleVariant.back;
const errors = getMissingFiles(expMaleVariant, dirPath);
if (errors.length) console.log('errors', errors);
expect(errors.length).toBe(0);
});
// check over every file if it's correctly set in the masterlist
it('look over every file in variant female and check if present in masterlist', () => {
const dirPath = `${rootDir}female${path.sep}`;
const errors = getMissingMasterlist(femaleVariant, dirPath);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant back female and check if present in masterlist', () => {
const dirPath = `${rootDir}back${path.sep}female${path.sep}`;
const errors = getMissingMasterlist(backVariant.female, dirPath);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant back male and check if present in masterlist', () => {
const dirPath = `${rootDir}back${path.sep}`;
let backMaleVariant = deepCopy(backVariant);
const errors = getMissingMasterlist(backMaleVariant, dirPath, ['female']);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant exp back and check if present in masterlist', () => {
const dirPath = `${rootDir}exp${path.sep}back${path.sep}`;
const errors = getMissingMasterlist(expVariant.back, dirPath);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant exp female and check if present in masterlist', () => {
const dirPath = `${rootDir}exp${path.sep}female${path.sep}`;
const errors = getMissingMasterlist(expVariant.female, dirPath);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant exp male and check if present in masterlist', () => {
const dirPath = `${rootDir}exp${path.sep}`;
const errors = getMissingMasterlist(expVariant, dirPath, ['back', 'female']);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
it('look over every file in variant root and check if present in masterlist', () => {
const dirPath = `${rootDir}`;
const errors = getMissingMasterlist(masterlist, dirPath, ['back', 'female', 'exp', 'icons']);
if (errors.length) console.log('errors for ', dirPath, errors);
expect(errors.length).toBe(0);
});
});

10
src/test/testUtils.ts Normal file
View File

@ -0,0 +1,10 @@
const fs = require('fs')
const path = require('path')
export function getAppRootDir () {
let currentDir = __dirname
while(!fs.existsSync(path.join(currentDir, 'package.json'))) {
currentDir = path.join(currentDir, '..')
}
return currentDir
}

View File

@ -5,6 +5,9 @@ import i18next from "i18next";
import {Button} from "../enums/buttons";
export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
public static readonly windowWidth: integer = 48;
private switchCheck: boolean;
private switchCheckCursor: integer;
@ -13,7 +16,7 @@ export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler {
}
getWindowWidth(): integer {
return 48;
return ConfirmUiHandler.windowWidth;
}
show(args: any[]): boolean {

View File

@ -30,13 +30,34 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
private pageCount: integer;
private page: integer;
private category: ScoreboardCategory;
private _isUpdating: boolean;
constructor(scene: BattleScene, x: number, y: number) {
super(scene, x, y);
this._isUpdating = false;
this.setup();
}
/**
* Sets the updating state and updates button states accordingly.
* If value is true (updating), disables the buttons; if false, enables the buttons.
* @param {boolean} value - The new updating state.
*/
set isUpdating(value) {
this._isUpdating = value;
this.setButtonsState(!value);
}
/**
* Gets the current updating state.
* @returns {boolean} - The current updating state.
*/
get isUpdating() {
return this._isUpdating;
}
setup() {
const titleWindow = addWindow(this.scene, 0, 0, 114, 18, false, false, null, null, WindowVariant.THIN);
this.add(titleWindow);
@ -140,7 +161,24 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
});
}
/**
* Updates the scoreboard rankings based on the selected category and page.
*
* If the update process is already ongoing, the method exits early. Otherwise, it begins the update process by clearing
* the current rankings and showing a loading label. If the category changes, the page is reset to 1.
*
* The method fetches the total page count if necessary, followed by fetching the rankings for the specified category
* and page. It updates the UI with the fetched rankings or shows an appropriate message if no rankings are found.
*
* @param {ScoreboardCategory} [category=this.category] - The category to fetch rankings for. Defaults to the current category.
* @param {number} [page=this.page] - The page number to fetch. Defaults to the current page.
*/
update(category: ScoreboardCategory = this.category, page: integer = this.page) {
if (this.isUpdating) {
return;
}
this.isUpdating = true;
this.rankingsContainer.removeAll(true);
this.loadingLabel.setText(i18next.t('menu:loading'));
@ -150,7 +188,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
this.page = page = 1;
Utils.executeIf(category !== this.category || this.pageCount === undefined,
() => Utils.apiFetch(`daily/rankingpagecount?category=${category}`).then(response => response.json()).then(count => this.pageCount = count)
() => Utils.apiFetch(`daily/rankingpagecount?category=${category}`).then(response => response.json()).then(count => this.pageCount = count)
).then(() => {
Utils.apiFetch(`daily/rankings?category=${category}&page=${page}`)
.then(response => response.json())
@ -158,16 +196,40 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
this.page = page;
this.category = category;
this.titleLabel.setText(`${i18next.t(`menu:${ScoreboardCategory[category].toLowerCase()}Rankings`)}`);
this.prevPageButton.setAlpha(page > 1 ? 1 : 0.5);
this.nextPageButton.setAlpha(page < this.pageCount ? 1 : 0.5);
this.pageNumberLabel.setText(page.toString());
if (jsonResponse) {
this.loadingLabel.setVisible(false);
this.updateRankings(jsonResponse);
} else
this.loadingLabel.setText(i18next.t('menu:noRankings'));
}).finally(() => {
this.isUpdating = false;
});
}).catch(err => { console.error("Failed to load daily rankings:\n", err) });
}).catch(err => {
console.error("Failed to load daily rankings:\n", err)
})
}
/**
* Sets the state of the navigation buttons.
* @param {boolean} [enabled=true] - Whether the buttons should be enabled or disabled.
*/
setButtonsState(enabled: boolean = true) {
const buttons = [
{ button: this.prevPageButton, alphaValue: enabled ? (this.page > 1 ? 1 : 0.5) : 0.5 },
{ button: this.nextPageButton, alphaValue: enabled ? (this.page < this.pageCount ? 1 : 0.5) : 0.5 },
{ button: this.nextCategoryButton, alphaValue: enabled ? 1 : 0.5 },
{ button: this.prevCategoryButton, alphaValue: enabled ? 1 : 0.5 }
];
buttons.forEach(({ button, alphaValue }) => {
if (enabled) {
button.setInteractive();
} else {
button.disableInteractive();
}
button.setAlpha(alphaValue);
});
}
}

View File

@ -24,6 +24,7 @@ export enum PartyUiMode {
SWITCH,
FAINT_SWITCH,
POST_BATTLE_SWITCH,
REVIVAL_BLESSING,
MODIFIER,
MOVE_MODIFIER,
TM_MODIFIER,
@ -37,6 +38,7 @@ export enum PartyOption {
CANCEL = -1,
SEND_OUT,
PASS_BATON,
REVIVE,
APPLY,
TEACH,
TRANSFER,
@ -103,6 +105,12 @@ export default class PartyUiHandler extends MessageUiHandler {
return null;
};
public static FilterFainted = (pokemon: PlayerPokemon) => {
if(!pokemon.isFainted())
return `${pokemon.name} still has energy\nto battle!`;
return null;
}
private static FilterAllMoves = (_pokemonMove: PokemonMove) => null;
public static FilterItemMaxStacks = (pokemon: PlayerPokemon, modifier: PokemonHeldItemModifier) => {
@ -361,7 +369,7 @@ export default class PartyUiHandler extends MessageUiHandler {
if (this.cursor < 6) {
this.showOptions();
ui.playSelect();
} else if (this.partyUiMode === PartyUiMode.FAINT_SWITCH)
} else if (this.partyUiMode === PartyUiMode.FAINT_SWITCH || this.partyUiMode === PartyUiMode.REVIVAL_BLESSING)
ui.playError();
else
return this.processInput(Button.CANCEL);
@ -370,7 +378,7 @@ export default class PartyUiHandler extends MessageUiHandler {
if ((this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER || this.partyUiMode === PartyUiMode.SPLICE) && this.transferMode) {
this.clearTransfer();
ui.playSelect();
} else if (this.partyUiMode !== PartyUiMode.FAINT_SWITCH) {
} else if (this.partyUiMode !== PartyUiMode.FAINT_SWITCH && this.partyUiMode !== PartyUiMode.REVIVAL_BLESSING) {
if (this.selectCallback) {
const selectCallback = this.selectCallback;
this.selectCallback = null;
@ -580,6 +588,9 @@ export default class PartyUiHandler extends MessageUiHandler {
this.options.push(PartyOption.FORM_CHANGE_ITEM + i);
}
break;
case PartyUiMode.REVIVAL_BLESSING:
this.options.push(PartyOption.REVIVE);
break;
case PartyUiMode.MODIFIER:
this.options.push(PartyOption.APPLY);
break;

View File

@ -9,8 +9,11 @@ import { getNatureName } from "../data/nature";
import * as Utils from "../utils";
import { Type } from "../data/type";
import { getVariantTint } from "#app/data/variant";
import ConfirmUiHandler from "./confirm-ui-handler";
export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
private readonly infoWindowWidth = 104;
private pokemonGenderLabelText: Phaser.GameObjects.Text;
private pokemonGenderText: Phaser.GameObjects.Text;
private pokemonAbilityLabelText: Phaser.GameObjects.Text;
@ -37,7 +40,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
}
setup(): void {
const infoBg = addWindow(this.scene, 0, 0, 104, 132);
const infoBg = addWindow(this.scene, 0, 0, this.infoWindowWidth, 132);
infoBg.setOrigin(0.5, 0.5);
this.pokemonMovesContainer = this.scene.add.container(6, 14);
@ -172,7 +175,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
targets: this,
duration: Utils.fixedInt(Math.floor(750 / speedMultiplier)),
ease: 'Cubic.easeInOut',
x: this.initialX - 104,
x: this.initialX - this.infoWindowWidth,
onComplete: () => {
resolve();
}
@ -201,6 +204,20 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
});
}
makeRoomForConfirmUi(speedMultiplier: number = 1): Promise<void> {
return new Promise<void>(resolve => {
this.scene.tweens.add({
targets: this,
duration: Utils.fixedInt(Math.floor(150 / speedMultiplier)),
ease: 'Cubic.easeInOut',
x: this.initialX - this.infoWindowWidth - ConfirmUiHandler.windowWidth,
onComplete: () => {
resolve();
}
});
});
}
hide(speedMultiplier: number = 1): Promise<void> {
return new Promise(resolve => {
if (!this.shown)

View File

@ -42,48 +42,65 @@ export interface Starter {
pokerus: boolean;
}
interface LanguageSetting {
starterInfoTextSize: string,
instructionTextSize: string,
starterInfoXPos?: integer,
starterInfoYOffset?: integer
}
const languageSettings: { [key: string]: LanguageSetting } = {
"en":{
starterInfoTextSize: '56px',
instructionTextSize: '42px',
},
"de":{
starterInfoTextSize: '56px',
instructionTextSize: '35px',
},
"es":{
starterInfoTextSize: '56px',
instructionTextSize: '35px',
},
"it":{
starterInfoTextSize: '56px',
instructionTextSize: '38px',
},
"fr":{
starterInfoTextSize: '54px',
instructionTextSize: '42px',
},
"zh":{
starterInfoTextSize: '40px',
instructionTextSize: '42px',
starterInfoYOffset: 2
},
"pt":{
starterInfoTextSize: '47px',
instructionTextSize: '38px',
starterInfoXPos: 32,
},
}
const starterCandyCosts: { passive: integer, costReduction: [integer, integer] }[] = [
{ passive: 50, costReduction: [30, 75] }, // 1
{ passive: 45, costReduction: [25, 60] }, // 2
{ passive: 40, costReduction: [20, 50] }, // 3
{ passive: 30, costReduction: [15, 40] }, // 4
{ passive: 25, costReduction: [12, 35] }, // 5
{ passive: 20, costReduction: [10, 30] }, // 6
{ passive: 15, costReduction: [8, 20] }, // 7
{ passive: 10, costReduction: [5, 15] }, // 8
{ passive: 10, costReduction: [3, 10] }, // 9
{ passive: 10, costReduction: [3, 10] }, // 10
]
function getPassiveCandyCount(baseValue: integer): integer {
switch (baseValue) {
case 1:
return 50;
case 2:
return 45;
case 3:
return 40;
case 4:
return 30;
case 5:
return 25;
case 6:
return 20;
case 7:
return 15;
default:
return 10;
}
return starterCandyCosts[baseValue - 1].passive;
}
function getValueReductionCandyCounts(baseValue: integer): [integer, integer] {
switch (baseValue) {
case 1:
return [ 30, 75];
case 2:
return [ 25, 60 ];
case 3:
return [ 20, 50 ];
case 4:
return [ 15, 40 ];
case 5:
return [ 12, 35 ];
case 6:
return [ 10, 30 ];
case 7:
return [ 8, 20 ];
case 8:
return [ 5, 15 ];
default:
return [ 3, 10 ];
}
return starterCandyCosts[baseValue - 1].costReduction;
}
const gens = [
@ -201,6 +218,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
setup() {
const ui = this.getUi();
const currentLanguage = i18next.language;
const langSettingKey = Object.keys(languageSettings).find(lang => currentLanguage.includes(lang));
const textSettings = languageSettings[langSettingKey];
this.starterSelectContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6);
this.starterSelectContainer.setVisible(false);
@ -257,54 +277,38 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonUncaughtText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonUncaughtText);
let starterInfoXPosition = 31; // Only text
// The position should be set per language
const currentLanguage = i18next.language;
switch (currentLanguage) {
case 'pt_BR':
starterInfoXPosition = 32;
break;
default:
starterInfoXPosition = 31;
break
}
let starterInfoXPos = textSettings?.starterInfoXPos || 31;
let starterInfoYOffset = textSettings?.starterInfoYOffset || 0;
let starterInfoTextSize = '56px'; // Labels and text
// The font size should be set per language
// currentLanguage is already defined
switch (currentLanguage) {
case 'pt_BR':
starterInfoTextSize = '47px';
break;
default:
starterInfoTextSize = '56px';
break
}
let starterInfoTextSize = textSettings?.starterInfoTextSize || 56;
this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 127, i18next.t("starterSelectUiHandler:ability"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 127 + starterInfoYOffset, i18next.t("starterSelectUiHandler:ability"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityLabelText.setOrigin(0, 0);
this.pokemonAbilityLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonAbilityLabelText);
this.pokemonAbilityText = addTextObject(this.scene, starterInfoXPosition, 127, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityText = addTextObject(this.scene, starterInfoXPos, 127 + starterInfoYOffset, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonAbilityText);
this.pokemonPassiveLabelText = addTextObject(this.scene, 6, 136, i18next.t("starterSelectUiHandler:passive"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonPassiveLabelText = addTextObject(this.scene, 6, 136 + starterInfoYOffset, i18next.t("starterSelectUiHandler:passive"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonPassiveLabelText.setOrigin(0, 0);
this.pokemonPassiveLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonPassiveLabelText);
this.pokemonPassiveText = addTextObject(this.scene, starterInfoXPosition, 136, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonPassiveText = addTextObject(this.scene, starterInfoXPos, 136 + starterInfoYOffset, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonPassiveText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonPassiveText);
this.pokemonNatureLabelText = addTextObject(this.scene, 6, 145, i18next.t("starterSelectUiHandler:nature"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonNatureLabelText = addTextObject(this.scene, 6, 145 + starterInfoYOffset, i18next.t("starterSelectUiHandler:nature"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonNatureLabelText.setOrigin(0, 0);
this.pokemonNatureLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonNatureLabelText);
this.pokemonNatureText = addBBCodeTextObject(this.scene, starterInfoXPosition, 145, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonNatureText = addBBCodeTextObject(this.scene, starterInfoXPos, 145 + starterInfoYOffset, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonNatureText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonNatureText);
@ -610,36 +614,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectContainer.add(this.pokemonEggMovesContainer);
let instructionTextSize = '42px';
// The font size should be set per language
// currentLanguage is already defined in the previous code block
switch (currentLanguage) {
case 'de':
instructionTextSize = '35px';
break;
case 'en':
instructionTextSize = '42px';
break;
case 'es':
instructionTextSize = '35px';
break;
case 'fr':
instructionTextSize = '42px';
break;
case 'it':
instructionTextSize = '38px';
break;
case 'pt_BR':
instructionTextSize = '38px';
break;
case 'zh_CN':
instructionTextSize = '42px';
break;
}
let instructionTextSize = textSettings.instructionTextSize;
this.instructionsText = addTextObject(this.scene, 4, 156, '', TextStyle.PARTY, { fontSize: instructionTextSize });
this.starterSelectContainer.add(this.instructionsText);

View File

@ -494,20 +494,16 @@ export default class SummaryUiHandler extends UiHandler {
}
break;
case Button.LEFT:
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE)
break;
if (this.cursor)
success = this.setCursor(this.cursor - 1);
break;
case Button.RIGHT:
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
this.setCursor(Page.MOVES);
this.moveSelect = true;
success = true;
break;
}
if (this.cursor < pages.length - 1)
if (this.cursor < pages.length - 1) {
success = this.setCursor(this.cursor + 1);
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE && this.cursor === Page.MOVES) {
this.moveSelect = true;
}
}
break;
}
}
@ -614,13 +610,7 @@ export default class SummaryUiHandler extends UiHandler {
onComplete: () => {
if (forward){
this.populatePageContainer(this.summaryPageContainer);
if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) {
this.moveCursorObj = null;
this.extraMoveRowContainer.setVisible(true);
this.setCursor(0, true);
this.showMoveEffect();
}
else if (this.cursor===Page.MOVES) {
if (this.cursor===Page.MOVES) {
this.moveCursorObj = null;
this.showMoveSelect();
this.showMoveEffect();

View File

@ -4,6 +4,7 @@ import { ModifierTier } from "../modifier/modifier-tier";
import { EggTier } from "../data/enums/egg-type";
import BattleScene from "../battle-scene";
import { UiTheme } from "../enums/ui-theme";
import i18next from "i18next";
export enum TextStyle {
MESSAGE,
@ -28,12 +29,31 @@ export enum TextStyle {
MOVE_INFO_CONTENT
};
interface LanguageSetting {
summaryFontSize?: string,
battleInfoFontSize?: string,
partyFontSize?: string,
tooltipContentFontSize?: string,
moveInfoFontSize?: string,
textScale?: number
}
const languageSettings: { [key: string]: LanguageSetting } = {
"en":{},
"de":{},
"es":{},
"it":{},
"fr":{},
"zh_CN":{},
"pt_BR":{},
}
export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): Phaser.GameObjects.Text {
const [ styleOptions, shadowColor, shadowSize ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions);
const [ styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions);
const ret = scene.add.text(x, y, content, styleOptions);
ret.setScale(0.1666666667);
ret.setShadow(shadowSize, shadowSize, shadowColor);
ret.setShadow(shadowXpos, shadowYpos, shadowColor);
if (!(styleOptions as Phaser.Types.GameObjects.Text.TextStyle).lineSpacing)
ret.setLineSpacing(5);
@ -41,12 +61,12 @@ export function addTextObject(scene: Phaser.Scene, x: number, y: number, content
}
export function addBBCodeTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): BBCodeText {
const [ styleOptions, shadowColor, shadowSize ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions);
const [ styleOptions, shadowColor, shadowXpos, shadowYpos ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions);
const ret = new BBCodeText(scene, x, y, content, styleOptions as BBCodeText.TextStyle);
scene.add.existing(ret);
ret.setScale(0.1666666667);
ret.setShadow(shadowSize, shadowSize, shadowColor);
ret.setShadow(shadowXpos, shadowYpos, shadowColor);
if (!(styleOptions as BBCodeText.TextStyle).lineSpacing)
ret.setLineSpacing(10);
@ -64,8 +84,10 @@ export function addTextInputObject(scene: Phaser.Scene, x: number, y: number, wi
}
function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): [ Phaser.Types.GameObjects.Text.TextStyle | InputText.IConfig, string, integer ] {
const lang = i18next.language;
let shadowColor: string;
let shadowSize = 6;
let shadowXpos = 4;
let shadowYpos = 5;
let styleOptions: Phaser.Types.GameObjects.Text.TextStyle = {
fontFamily: 'emerald',
@ -90,26 +112,29 @@ function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptio
case TextStyle.MESSAGE:
case TextStyle.SETTINGS_LABEL:
case TextStyle.SETTINGS_SELECTED:
styleOptions.fontSize = '96px';
styleOptions.fontSize = languageSettings[lang]?.summaryFontSize || '96px';
break;
case TextStyle.BATTLE_INFO:
case TextStyle.MONEY:
case TextStyle.TOOLTIP_TITLE:
styleOptions.fontSize = '72px';
shadowSize = 4.5;
styleOptions.fontSize = languageSettings[lang]?.battleInfoFontSize || '72px';
shadowXpos = 3.5;
shadowYpos = 3.5;
break;
case TextStyle.PARTY:
case TextStyle.PARTY_RED:
styleOptions.fontSize = languageSettings[lang]?.partyFontSize || '66px';
styleOptions.fontFamily = 'pkmnems';
styleOptions.fontSize = '66px';
break;
case TextStyle.TOOLTIP_CONTENT:
styleOptions.fontSize = '64px';
shadowSize = 4;
styleOptions.fontSize = languageSettings[lang]?.tooltipContentFontSize || '64px';
shadowXpos = 3;
shadowYpos = 3;
break;
case TextStyle.MOVE_INFO_CONTENT:
styleOptions.fontSize = '56px';
shadowSize = 3;
styleOptions.fontSize = languageSettings[lang]?.moveInfoFontSize || '56px';
shadowXpos = 3;
shadowYpos = 3;
break;
}
@ -118,12 +143,12 @@ function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptio
if (extraStyleOptions) {
if (extraStyleOptions.fontSize) {
const sizeRatio = parseInt(extraStyleOptions.fontSize.toString().slice(0, -2)) / parseInt(styleOptions.fontSize.toString().slice(0, -2));
shadowSize *= sizeRatio;
shadowXpos *= sizeRatio;
}
styleOptions = Object.assign(styleOptions, extraStyleOptions);
}
return [ styleOptions, shadowColor, shadowSize ];
return [ styleOptions, shadowColor, shadowXpos, shadowYpos ];
}
export function getBBCodeFrag(content: string, textStyle: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string {

View File

@ -5,6 +5,7 @@ import { TextStyle, addTextObject } from "./text";
import { Mode } from "./ui";
import { addWindow } from "./ui-theme";
import {Button} from "../enums/buttons";
import i18next from '../plugins/i18n';
const itemRows = 4;
const itemCols = 17;
@ -40,7 +41,7 @@ export default class VouchersUiHandler extends MessageUiHandler {
const headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24);
headerBg.setOrigin(0, 0);
const headerText = addTextObject(this.scene, 0, 0, 'Vouchers', TextStyle.SETTINGS_LABEL);
const headerText = addTextObject(this.scene, 0, 0, i18next.t("voucher:vouchers"), TextStyle.SETTINGS_LABEL);
headerText.setOrigin(0, 0);
headerText.setPositionRelative(headerBg, 8, 4);
@ -127,7 +128,7 @@ export default class VouchersUiHandler extends MessageUiHandler {
this.titleText.setText(getVoucherTypeName(voucher.voucherType));
this.showText(voucher.description);
this.unlockText.setText(unlocked ? new Date(voucherUnlocks[voucher.id]).toLocaleDateString() : 'Locked');
this.unlockText.setText(unlocked ? new Date(voucherUnlocks[voucher.id]).toLocaleDateString() : i18next.t("voucher:locked"));
}
processInput(button: Button): boolean {
@ -246,4 +247,4 @@ export default class VouchersUiHandler extends MessageUiHandler {
this.cursorObj.destroy();
this.cursorObj = null;
}
}
}