Merge branch 'main' into 1078Fix

This commit is contained in:
Jannik Tappert 2024-05-19 23:15:25 +02:00
commit 74c5203835
24 changed files with 1978 additions and 109 deletions

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

@ -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

@ -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

@ -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;
@ -1822,6 +1823,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 +2277,33 @@ export class PostTurnFormChangeAbAttr extends PostTurnAbAttr {
}
}
/**
* 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 +2396,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 +2696,6 @@ export class SuppressFieldAbilitiesAbAttr extends AbAttr {
}
}
export class AlwaysHitAbAttr extends AbAttr { }
export class UncopiableAbilityAbAttr extends AbAttr {
@ -2859,8 +2940,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 },
@ -3442,7 +3523,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 +3678,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

@ -58,7 +58,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 {
@ -916,6 +917,7 @@ export enum MultiHitType {
_3,
_3_INCR,
_1_TO_10,
BEAT_UP,
}
/**
@ -1233,6 +1235,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;
@ -2034,6 +2041,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 +2098,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 +2864,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);
@ -4411,6 +4538,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 +5027,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 +5246,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()),
@ -5460,7 +5592,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(),
@ -6691,14 +6823,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(),
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)
@ -7158,7 +7292,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()) {

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,

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();
}
// 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

@ -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';
@ -1523,6 +1523,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 {
@ -1538,13 +1539,13 @@ 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;
}
}
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));
const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1);

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

@ -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",

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",

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",

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",

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",

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

@ -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

@ -906,7 +906,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()));
});
};
@ -1809,7 +1809,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 +1914,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);
@ -3045,7 +3045,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());
@ -4349,6 +4350,7 @@ export class AttemptCapturePhase extends PokemonPhase {
scale: 1
});
this.scene.currentBattle.lastUsedPokeball = this.pokeballType;
this.removePb();
this.end();
}

View File

@ -178,11 +178,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) => {
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

@ -271,6 +271,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
// The font size should be set per language
// currentLanguage is already defined
switch (currentLanguage) {
case 'fr':
starterInfoTextSize = '54px';
break;
case 'pt_BR':
starterInfoTextSize = '47px';
break;

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();