mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-20 22:39:31 +02:00
Merge branch 'beta' into trick-room-challenge
This commit is contained in:
commit
1badbe486f
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "pokemon-rogue-battle",
|
"name": "pokemon-rogue-battle",
|
||||||
"version": "1.1.0",
|
"version": "1.1.6",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "pokemon-rogue-battle",
|
"name": "pokemon-rogue-battle",
|
||||||
"version": "1.1.0",
|
"version": "1.1.6",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material/material-color-utilities": "^0.2.7",
|
"@material/material-color-utilities": "^0.2.7",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "pokemon-rogue-battle",
|
"name": "pokemon-rogue-battle",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.1.0",
|
"version": "1.1.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite",
|
"start": "vite",
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "658-ash.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 79,
|
|
||||||
"h": 79
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 79, "h": 74 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 79, "h": 74 },
|
||||||
"w": 79,
|
"sourceSize": { "w": 79, "h": 74 },
|
||||||
"h": 74
|
"duration": 100
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 79,
|
|
||||||
"h": 74
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 79,
|
|
||||||
"h": 74
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-x64",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:936f62fa49ba4d6e402bb2e2eaf2afd0:ed00ba047a44b4bf1309bc147dd000e3:bfbf521a5c7bd80bcd95a96d9789c0dd$"
|
"format": "I8",
|
||||||
|
"size": { "w": 79, "h": 74 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "658.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 75,
|
|
||||||
"h": 75
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 85, "h": 67 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 85, "h": 67 },
|
||||||
"w": 75,
|
"sourceSize": { "w": 85, "h": 67 },
|
||||||
"h": 65
|
"duration": 100
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 75,
|
|
||||||
"h": 65
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 75,
|
|
||||||
"h": 65
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-x64",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:e0b10df331bd4ce6760edab61dee144b:061561c45beff89a92bf0158d065204f:5affcab976148657d36bf4ff3410f92d$"
|
"format": "I8",
|
||||||
|
"size": { "w": 85, "h": 67 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 63 },
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 63 },
|
||||||
"sourceSize": { "w": 64, "h": 63 },
|
"sourceSize": { "w": 64, "h": 63 }
|
||||||
"duration": 100
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
|
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "658-ash.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 73,
|
|
||||||
"h": 73
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 73, "h": 73 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 73, "h": 73 },
|
||||||
"w": 73,
|
"sourceSize": { "w": 73, "h": 73 },
|
||||||
"h": 69
|
"duration": 100
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 73,
|
|
||||||
"h": 69
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 73,
|
|
||||||
"h": 69
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-x64",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:4f38801bb3afeda5faff04bdcf6a666f:0c78ce2715e7510bf55da0a92b42661c:bfbf521a5c7bd80bcd95a96d9789c0dd$"
|
"format": "I8",
|
||||||
|
"size": { "w": 73, "h": 73 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "658.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 77,
|
|
||||||
"h": 77
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 77, "h": 77 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 77, "h": 77 },
|
||||||
"w": 77,
|
"sourceSize": { "w": 77, "h": 77 },
|
||||||
"h": 65
|
"duration": 100
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 77,
|
|
||||||
"h": 65
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 77,
|
|
||||||
"h": 65
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-x64",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:acdb9925f3f23b947504eec7cc28c92d:1a13d9d418f6c107bb9e5d621d9154bb:5affcab976148657d36bf4ff3410f92d$"
|
"format": "I8",
|
||||||
|
"size": { "w": 77, "h": 77 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "688.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 52,
|
|
||||||
"h": 52
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 51, "h": 65 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 51, "h": 65 },
|
||||||
"w": 41,
|
"sourceSize": { "w": 51, "h": 65 }
|
||||||
"h": 52
|
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 41,
|
|
||||||
"h": 52
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 41,
|
|
||||||
"h": 52
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-dev",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:ea462f2b1b46327e3b8fcb7ec5e44f08:2d2598cc03dec73182dbea237ad83b34:176060351d0044923af938ba7932a6ef$"
|
"image": "688.png",
|
||||||
|
"format": "I8",
|
||||||
|
"size": { "w": 51, "h": 65 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "658-ash.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 73,
|
|
||||||
"h": 73
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 73, "h": 73 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 73, "h": 73 },
|
||||||
"w": 73,
|
"sourceSize": { "w": 73, "h": 73 },
|
||||||
"h": 69
|
"duration": 100
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 73,
|
|
||||||
"h": 69
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 73,
|
|
||||||
"h": 69
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-x64",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:d474b821316a87dfe09b397bdc2db5ef:497de0c2ec59ceba163e870b3226c76c:bfbf521a5c7bd80bcd95a96d9789c0dd$"
|
"format": "I8",
|
||||||
|
"size": { "w": 73, "h": 73 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "658.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 77,
|
|
||||||
"h": 77
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 77, "h": 77 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 77, "h": 77 },
|
||||||
"w": 77,
|
"sourceSize": { "w": 77, "h": 77 },
|
||||||
"h": 65
|
"duration": 100
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 77,
|
|
||||||
"h": 65
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 77,
|
|
||||||
"h": 65
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-x64",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:5891f87a78022cde3402e7d9714cc7bf:756360084290e39c139e3fef91c81759:5affcab976148657d36bf4ff3410f92d$"
|
"format": "I8",
|
||||||
|
"size": { "w": 77, "h": 77 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "688.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 52,
|
|
||||||
"h": 52
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 51, "h": 65 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 51, "h": 65 },
|
||||||
"w": 41,
|
"sourceSize": { "w": 51, "h": 65 }
|
||||||
"h": 52
|
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 41,
|
|
||||||
"h": 52
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 41,
|
|
||||||
"h": 52
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-dev",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:0261b6c9242bba728fcfbfc515875b27:de0d9ddceed9311b33ae50ba86e969d1:176060351d0044923af938ba7932a6ef$"
|
"image": "688.png",
|
||||||
|
"format": "I8",
|
||||||
|
"size": { "w": 51, "h": 65 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "658-ash.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 79,
|
|
||||||
"h": 79
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 79, "h": 74 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 79, "h": 74 },
|
||||||
"w": 79,
|
"sourceSize": { "w": 79, "h": 74 },
|
||||||
"h": 74
|
"duration": 100
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 79,
|
|
||||||
"h": 74
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 79,
|
|
||||||
"h": 74
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-x64",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:3dd081ba5490f090a73de8423aac2f6b:f088fafaea755476f2abf488e7340cab:bfbf521a5c7bd80bcd95a96d9789c0dd$"
|
"format": "I8",
|
||||||
|
"size": { "w": 79, "h": 74 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,19 @@
|
|||||||
{
|
{ "frames": [
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "658.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 75,
|
|
||||||
"h": 75
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
{
|
||||||
"filename": "0001.png",
|
"filename": "0001.png",
|
||||||
|
"frame": { "x": 0, "y": 0, "w": 85, "h": 67 },
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"sourceSize": {
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 85, "h": 67 },
|
||||||
"w": 75,
|
"sourceSize": { "w": 85, "h": 67 },
|
||||||
"h": 65
|
"duration": 100
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 75,
|
|
||||||
"h": 65
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 75,
|
|
||||||
"h": 65
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "3.0",
|
"version": "1.3.7-x64",
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:be07c062265a19e890f1e2d2d1b5527d:ad4583a5a0498c496e9a93574c55ee03:5affcab976148657d36bf4ff3410f92d$"
|
"format": "I8",
|
||||||
|
"size": { "w": 85, "h": 67 },
|
||||||
|
"scale": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
"rotated": false,
|
"rotated": false,
|
||||||
"trimmed": false,
|
"trimmed": false,
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 63 },
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 63 },
|
||||||
"sourceSize": { "w": 64, "h": 63 },
|
"sourceSize": { "w": 64, "h": 63 }
|
||||||
"duration": 100
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "statuses_es.png",
|
"image": "statuses_es-ES.png",
|
||||||
"format": "RGBA8888",
|
"format": "RGBA8888",
|
||||||
"size": {
|
"size": {
|
||||||
"w": 22,
|
"w": 22,
|
Before Width: | Height: | Size: 441 B After Width: | Height: | Size: 441 B |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "types_es.png",
|
"image": "types_es-ES.png",
|
||||||
"format": "RGBA8888",
|
"format": "RGBA8888",
|
||||||
"size": {
|
"size": {
|
||||||
"w": 32,
|
"w": 32,
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
@ -1 +1 @@
|
|||||||
Subproject commit 71390cba88f4103d0d2273d59a6dd8340a4fa54f
|
Subproject commit 3cf6d553541d79ba165387bc73fb06544d00f1f9
|
@ -323,6 +323,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.conditionalQueue = [];
|
this.conditionalQueue = [];
|
||||||
this.phaseQueuePrependSpliceIndex = -1;
|
this.phaseQueuePrependSpliceIndex = -1;
|
||||||
this.nextCommandPhaseQueue = [];
|
this.nextCommandPhaseQueue = [];
|
||||||
|
this.eventManager = new TimedEventManager();
|
||||||
this.updateGameInfo();
|
this.updateGameInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,7 +379,6 @@ export default class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
this.fieldSpritePipeline = new FieldSpritePipeline(this.game);
|
this.fieldSpritePipeline = new FieldSpritePipeline(this.game);
|
||||||
(this.renderer as Phaser.Renderer.WebGL.WebGLRenderer).pipelines.add("FieldSprite", this.fieldSpritePipeline);
|
(this.renderer as Phaser.Renderer.WebGL.WebGLRenderer).pipelines.add("FieldSprite", this.fieldSpritePipeline);
|
||||||
this.eventManager = new TimedEventManager();
|
|
||||||
|
|
||||||
this.launchBattle();
|
this.launchBattle();
|
||||||
}
|
}
|
||||||
|
@ -330,6 +330,30 @@ export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces the damage dealt to an allied Pokemon. Used by Friend Guard.
|
||||||
|
* @see {@linkcode applyPreDefend}
|
||||||
|
*/
|
||||||
|
export class AlliedFieldDamageReductionAbAttr extends PreDefendAbAttr {
|
||||||
|
private damageMultiplier: number;
|
||||||
|
|
||||||
|
constructor(damageMultiplier: number) {
|
||||||
|
super();
|
||||||
|
this.damageMultiplier = damageMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the damage reduction
|
||||||
|
* @param args
|
||||||
|
* - `[0]` {@linkcode Utils.NumberHolder} - The damage being dealt
|
||||||
|
*/
|
||||||
|
override applyPreDefend(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _attacker: Pokemon, _move: Move, _cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
|
const damage = args[0] as Utils.NumberHolder;
|
||||||
|
damage.value = Utils.toDmgValue(damage.value * this.damageMultiplier);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
||||||
constructor(moveType: Type, damageMultiplier: number) {
|
constructor(moveType: Type, damageMultiplier: number) {
|
||||||
super((target, user, move) => user.getMoveType(move) === moveType, damageMultiplier);
|
super((target, user, move) => user.getMoveType(move) === moveType, damageMultiplier);
|
||||||
@ -3590,22 +3614,19 @@ export class MoodyAbAttr extends PostTurnAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostTurnStatStageChangeAbAttr extends PostTurnAbAttr {
|
export class SpeedBoostAbAttr extends PostTurnAbAttr {
|
||||||
private stats: BattleStat[];
|
|
||||||
private stages: number;
|
|
||||||
|
|
||||||
constructor(stats: BattleStat[], stages: number) {
|
constructor() {
|
||||||
super(true);
|
super(true);
|
||||||
|
|
||||||
this.stats = Array.isArray(stats)
|
|
||||||
? stats
|
|
||||||
: [ stats ];
|
|
||||||
this.stages = stages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
|
applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.stages));
|
if (!pokemon.turnData.switchedInThisTurn && !pokemon.turnData.failedRunAway) {
|
||||||
|
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.SPD ], 1));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -4679,6 +4700,84 @@ export class PreventBypassSpeedChanceAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This applies a terrain-based type change to the Pokemon.
|
||||||
|
* Used by Mimicry.
|
||||||
|
*/
|
||||||
|
export class TerrainEventTypeChangeAbAttr extends PostSummonAbAttr {
|
||||||
|
constructor() {
|
||||||
|
super(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: Utils.BooleanHolder, _args: any[]): boolean {
|
||||||
|
if (pokemon.isTerastallized()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const currentTerrain = pokemon.scene.arena.getTerrainType();
|
||||||
|
const typeChange: Type[] = this.determineTypeChange(pokemon, currentTerrain);
|
||||||
|
if (typeChange.length !== 0) {
|
||||||
|
if (pokemon.summonData.addedType && typeChange.includes(pokemon.summonData.addedType)) {
|
||||||
|
pokemon.summonData.addedType = null;
|
||||||
|
}
|
||||||
|
pokemon.summonData.types = typeChange;
|
||||||
|
pokemon.updateInfo();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the type(s) the Pokemon should change to in response to a terrain
|
||||||
|
* @param pokemon
|
||||||
|
* @param currentTerrain {@linkcode TerrainType}
|
||||||
|
* @returns a list of type(s)
|
||||||
|
*/
|
||||||
|
private determineTypeChange(pokemon: Pokemon, currentTerrain: TerrainType): Type[] {
|
||||||
|
const typeChange: Type[] = [];
|
||||||
|
switch (currentTerrain) {
|
||||||
|
case TerrainType.ELECTRIC:
|
||||||
|
typeChange.push(Type.ELECTRIC);
|
||||||
|
break;
|
||||||
|
case TerrainType.MISTY:
|
||||||
|
typeChange.push(Type.FAIRY);
|
||||||
|
break;
|
||||||
|
case TerrainType.GRASSY:
|
||||||
|
typeChange.push(Type.GRASS);
|
||||||
|
break;
|
||||||
|
case TerrainType.PSYCHIC:
|
||||||
|
typeChange.push(Type.PSYCHIC);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pokemon.getTypes(false, false, true).forEach(t => {
|
||||||
|
typeChange.push(t);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return typeChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the Pokemon should change types if summoned into an active terrain
|
||||||
|
* @returns `true` if there is an active terrain requiring a type change | `false` if not
|
||||||
|
*/
|
||||||
|
override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise<boolean> {
|
||||||
|
if (pokemon.scene.arena.getTerrainType() !== TerrainType.NONE) {
|
||||||
|
return this.apply(pokemon, passive, simulated, new Utils.BooleanHolder(false), []);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
override getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) {
|
||||||
|
const currentTerrain = pokemon.scene.arena.getTerrainType();
|
||||||
|
const pokemonNameWithAffix = getPokemonNameWithAffix(pokemon);
|
||||||
|
if (currentTerrain === TerrainType.NONE) {
|
||||||
|
return i18next.t("abilityTriggers:pokemonTypeChangeRevert", { pokemonNameWithAffix });
|
||||||
|
} else {
|
||||||
|
const moveType = i18next.t(`pokemonInfo:Type.${Type[this.determineTypeChange(pokemon, currentTerrain)[0]]}`);
|
||||||
|
return i18next.t("abilityTriggers:pokemonTypeChange", { pokemonNameWithAffix, moveType });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function applyAbAttrsInternal<TAttr extends AbAttr>(
|
async function applyAbAttrsInternal<TAttr extends AbAttr>(
|
||||||
attrType: Constructor<TAttr>,
|
attrType: Constructor<TAttr>,
|
||||||
pokemon: Pokemon | null,
|
pokemon: Pokemon | null,
|
||||||
@ -4909,7 +5008,7 @@ export function initAbilities() {
|
|||||||
.attr(PostSummonWeatherChangeAbAttr, WeatherType.RAIN)
|
.attr(PostSummonWeatherChangeAbAttr, WeatherType.RAIN)
|
||||||
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.RAIN),
|
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.RAIN),
|
||||||
new Ability(Abilities.SPEED_BOOST, 3)
|
new Ability(Abilities.SPEED_BOOST, 3)
|
||||||
.attr(PostTurnStatStageChangeAbAttr, [ Stat.SPD ], 1),
|
.attr(SpeedBoostAbAttr),
|
||||||
new Ability(Abilities.BATTLE_ARMOR, 3)
|
new Ability(Abilities.BATTLE_ARMOR, 3)
|
||||||
.attr(BlockCritAbAttr)
|
.attr(BlockCritAbAttr)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
@ -5310,8 +5409,8 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.HEALER, 5)
|
new Ability(Abilities.HEALER, 5)
|
||||||
.conditionalAttr(pokemon => pokemon.getAlly() && Utils.randSeedInt(10) < 3, PostTurnResetStatusAbAttr, true),
|
.conditionalAttr(pokemon => pokemon.getAlly() && Utils.randSeedInt(10) < 3, PostTurnResetStatusAbAttr, true),
|
||||||
new Ability(Abilities.FRIEND_GUARD, 5)
|
new Ability(Abilities.FRIEND_GUARD, 5)
|
||||||
.ignorable()
|
.attr(AlliedFieldDamageReductionAbAttr, 0.75)
|
||||||
.unimplemented(),
|
.ignorable(),
|
||||||
new Ability(Abilities.WEAK_ARMOR, 5)
|
new Ability(Abilities.WEAK_ARMOR, 5)
|
||||||
.attr(PostDefendStatStageChangeAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, Stat.DEF, -1)
|
.attr(PostDefendStatStageChangeAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, Stat.DEF, -1)
|
||||||
.attr(PostDefendStatStageChangeAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, Stat.SPD, 2),
|
.attr(PostDefendStatStageChangeAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL, Stat.SPD, 2),
|
||||||
@ -5743,7 +5842,7 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.POWER_SPOT, 8)
|
new Ability(Abilities.POWER_SPOT, 8)
|
||||||
.attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL, MoveCategory.PHYSICAL ], 1.3),
|
.attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL, MoveCategory.PHYSICAL ], 1.3),
|
||||||
new Ability(Abilities.MIMICRY, 8)
|
new Ability(Abilities.MIMICRY, 8)
|
||||||
.unimplemented(),
|
.attr(TerrainEventTypeChangeAbAttr),
|
||||||
new Ability(Abilities.SCREEN_CLEANER, 8)
|
new Ability(Abilities.SCREEN_CLEANER, 8)
|
||||||
.attr(PostSummonRemoveArenaTagAbAttr, [ ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT ]),
|
.attr(PostSummonRemoveArenaTagAbAttr, [ ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT ]),
|
||||||
new Ability(Abilities.STEELY_SPIRIT, 8)
|
new Ability(Abilities.STEELY_SPIRIT, 8)
|
||||||
@ -5900,7 +5999,7 @@ export function initAbilities() {
|
|||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.SLICING_MOVE), 1.5),
|
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.SLICING_MOVE), 1.5),
|
||||||
new Ability(Abilities.SUPREME_OVERLORD, 9)
|
new Ability(Abilities.SUPREME_OVERLORD, 9)
|
||||||
.attr(VariableMovePowerBoostAbAttr, (user, target, move) => 1 + 0.1 * Math.min(user.isPlayer() ? user.scene.currentBattle.playerFaints : user.scene.currentBattle.enemyFaints, 5))
|
.attr(VariableMovePowerBoostAbAttr, (user, target, move) => 1 + 0.1 * Math.min(user.isPlayer() ? user.scene.currentBattle.playerFaints : user.scene.currentBattle.enemyFaints, 5))
|
||||||
.partial(), // Counter resets every wave
|
.partial(), // Counter resets every wave instead of on arena reset
|
||||||
new Ability(Abilities.COSTAR, 9)
|
new Ability(Abilities.COSTAR, 9)
|
||||||
.attr(PostSummonCopyAllyStatsAbAttr),
|
.attr(PostSummonCopyAllyStatsAbAttr),
|
||||||
new Ability(Abilities.TOXIC_DEBRIS, 9)
|
new Ability(Abilities.TOXIC_DEBRIS, 9)
|
||||||
|
@ -126,6 +126,7 @@ export class MistTag extends ArenaTag {
|
|||||||
* Cancels the lowering of stats
|
* Cancels the lowering of stats
|
||||||
* @param arena the {@linkcode Arena} containing this effect
|
* @param arena the {@linkcode Arena} containing this effect
|
||||||
* @param simulated `true` if the effect should be applied quietly
|
* @param simulated `true` if the effect should be applied quietly
|
||||||
|
* @param attacker the {@linkcode Pokemon} using a move into this effect.
|
||||||
* @param cancelled a {@linkcode BooleanHolder} whose value is set to `true`
|
* @param cancelled a {@linkcode BooleanHolder} whose value is set to `true`
|
||||||
* to flag the stat reduction as cancelled
|
* to flag the stat reduction as cancelled
|
||||||
* @returns `true` if a stat reduction was cancelled; `false` otherwise
|
* @returns `true` if a stat reduction was cancelled; `false` otherwise
|
||||||
|
@ -1443,7 +1443,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
],
|
],
|
||||||
[Species.ROCKRUFF]: [
|
[Species.ROCKRUFF]: [
|
||||||
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0))),
|
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0))),
|
||||||
new SpeciesFormEvolution(Species.LYCANROC, "", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1)),
|
new SpeciesFormEvolution(Species.LYCANROC, "own-tempo", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1)),
|
||||||
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)))
|
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)))
|
||||||
],
|
],
|
||||||
[Species.STEENEE]: [
|
[Species.STEENEE]: [
|
||||||
|
@ -497,7 +497,7 @@ export const speciesEggTiers = {
|
|||||||
[Species.DREEPY]: EggTier.RARE,
|
[Species.DREEPY]: EggTier.RARE,
|
||||||
[Species.ZACIAN]: EggTier.LEGENDARY,
|
[Species.ZACIAN]: EggTier.LEGENDARY,
|
||||||
[Species.ZAMAZENTA]: EggTier.LEGENDARY,
|
[Species.ZAMAZENTA]: EggTier.LEGENDARY,
|
||||||
[Species.ETERNATUS]: EggTier.COMMON,
|
[Species.ETERNATUS]: EggTier.LEGENDARY,
|
||||||
[Species.KUBFU]: EggTier.EPIC,
|
[Species.KUBFU]: EggTier.EPIC,
|
||||||
[Species.ZARUDE]: EggTier.EPIC,
|
[Species.ZARUDE]: EggTier.EPIC,
|
||||||
[Species.REGIELEKI]: EggTier.EPIC,
|
[Species.REGIELEKI]: EggTier.EPIC,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -544,11 +544,15 @@ export class Egg {
|
|||||||
////
|
////
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: number): Species {
|
export function getValidLegendaryGachaSpecies() : Species[] {
|
||||||
const legendarySpecies = Object.entries(speciesEggTiers)
|
return Object.entries(speciesEggTiers)
|
||||||
.filter(s => s[1] === EggTier.LEGENDARY)
|
.filter(s => s[1] === EggTier.LEGENDARY)
|
||||||
.map(s => parseInt(s[0]))
|
.map(s => parseInt(s[0]))
|
||||||
.filter(s => getPokemonSpecies(s).isObtainable());
|
.filter(s => getPokemonSpecies(s).isObtainable() && s !== Species.ETERNATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: number): Species {
|
||||||
|
const legendarySpecies = getValidLegendaryGachaSpecies();
|
||||||
|
|
||||||
let ret: Species;
|
let ret: Species;
|
||||||
|
|
||||||
|
@ -1420,6 +1420,11 @@ export class RecoilAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Chloroblast and Struggle should not deal recoil damage if the move was not successful
|
||||||
|
if (this.useHp && [ MoveResult.FAIL, MoveResult.MISS ].includes(user.getLastXMoves(1)[0]?.result)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const damageValue = (!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio;
|
const damageValue = (!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio;
|
||||||
const minValue = user.turnData.damageDealt ? 1 : 0;
|
const minValue = user.turnData.damageDealt ? 1 : 0;
|
||||||
const recoilDamage = Utils.toDmgValue(damageValue, minValue);
|
const recoilDamage = Utils.toDmgValue(damageValue, minValue);
|
||||||
@ -2177,7 +2182,10 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, false);
|
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, false);
|
||||||
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(moveChance * -0.1) : 0;
|
const score = (moveChance < 0) ? -10 : Math.floor(moveChance * -0.1);
|
||||||
|
const pokemon = this.selfTarget ? user : target;
|
||||||
|
|
||||||
|
return !pokemon.status && pokemon.canSetStatus(this.effect, true, false, user) ? score : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2197,7 +2205,10 @@ export class MultiStatusEffectAttr extends StatusEffectAttr {
|
|||||||
|
|
||||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, false);
|
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, false);
|
||||||
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(moveChance * -0.1) : 0;
|
const score = (moveChance < 0) ? -10 : Math.floor(moveChance * -0.1);
|
||||||
|
const pokemon = this.selfTarget ? user : target;
|
||||||
|
|
||||||
|
return !pokemon.status && pokemon.canSetStatus(this.effect, true, false, user) ? score : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2228,7 +2239,7 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||||
return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(user.status?.effect, true, false, user) ? Math.floor(move.chance * -0.1) : 0;
|
return !target.status && target.canSetStatus(user.status?.effect, true, false, user) ? -10 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -5739,6 +5750,11 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't allow wild mons to flee with U-turn et al
|
||||||
|
if (this.selfSwitch && !user.isPlayer() && move.category !== MoveCategory.STATUS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (switchOutTarget.hp > 0) {
|
if (switchOutTarget.hp > 0) {
|
||||||
switchOutTarget.leaveField(false);
|
switchOutTarget.leaveField(false);
|
||||||
user.scene.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500);
|
user.scene.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500);
|
||||||
@ -5858,6 +5874,9 @@ export class RemoveTypeAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
const userTypes = user.getTypes(true);
|
const userTypes = user.getTypes(true);
|
||||||
const modifiedTypes = userTypes.filter(type => type !== this.removedType);
|
const modifiedTypes = userTypes.filter(type => type !== this.removedType);
|
||||||
|
if (modifiedTypes.length === 0) {
|
||||||
|
modifiedTypes.push(Type.UNKNOWN);
|
||||||
|
}
|
||||||
user.summonData.types = modifiedTypes;
|
user.summonData.types = modifiedTypes;
|
||||||
user.updateInfo();
|
user.updateInfo();
|
||||||
|
|
||||||
@ -5880,7 +5899,11 @@ export class CopyTypeAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.summonData.types = target.getTypes(true);
|
const targetTypes = target.getTypes(true);
|
||||||
|
if (targetTypes.includes(Type.UNKNOWN) && targetTypes.indexOf(Type.UNKNOWN) > -1) {
|
||||||
|
targetTypes[targetTypes.indexOf(Type.UNKNOWN)] = Type.NORMAL;
|
||||||
|
}
|
||||||
|
user.summonData.types = targetTypes;
|
||||||
user.updateInfo();
|
user.updateInfo();
|
||||||
|
|
||||||
user.scene.queueMessage(i18next.t("moveTriggers:copyType", { pokemonName: getPokemonNameWithAffix(user), targetPokemonName: getPokemonNameWithAffix(target) }));
|
user.scene.queueMessage(i18next.t("moveTriggers:copyType", { pokemonName: getPokemonNameWithAffix(user), targetPokemonName: getPokemonNameWithAffix(target) }));
|
||||||
@ -5889,7 +5912,7 @@ export class CopyTypeAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCondition(): MoveConditionFunc {
|
getCondition(): MoveConditionFunc {
|
||||||
return (user, target, move) => target.getTypes()[0] !== Type.UNKNOWN;
|
return (user, target, move) => target.getTypes()[0] !== Type.UNKNOWN || target.summonData.addedType !== null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5947,11 +5970,7 @@ export class AddTypeAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const types = target.getTypes().slice(0, 2).filter(t => t !== Type.UNKNOWN); // TODO: Figure out some way to actually check if another version of this effect is already applied
|
target.summonData.addedType = this.type;
|
||||||
if (this.type !== Type.UNKNOWN) {
|
|
||||||
types.push(this.type);
|
|
||||||
}
|
|
||||||
target.summonData.types = types;
|
|
||||||
target.updateInfo();
|
target.updateInfo();
|
||||||
|
|
||||||
user.scene.queueMessage(i18next.t("moveTriggers:addType", { typeName: i18next.t(`pokemonInfo:Type.${Type[this.type]}`), pokemonName: getPokemonNameWithAffix(target) }));
|
user.scene.queueMessage(i18next.t("moveTriggers:addType", { typeName: i18next.t(`pokemonInfo:Type.${Type[this.type]}`), pokemonName: getPokemonNameWithAffix(target) }));
|
||||||
@ -8983,8 +9002,7 @@ export function initMoves() {
|
|||||||
.ignoresProtect()
|
.ignoresProtect()
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
new StatusMove(Moves.TRICK_OR_TREAT, Type.GHOST, 100, 20, -1, 0, 6)
|
new StatusMove(Moves.TRICK_OR_TREAT, Type.GHOST, 100, 20, -1, 0, 6)
|
||||||
.attr(AddTypeAttr, Type.GHOST)
|
.attr(AddTypeAttr, Type.GHOST),
|
||||||
.edgeCase(), // Weird interaction with Forest's Curse, reflect type, burn up
|
|
||||||
new StatusMove(Moves.NOBLE_ROAR, Type.NORMAL, 100, 30, -1, 0, 6)
|
new StatusMove(Moves.NOBLE_ROAR, Type.NORMAL, 100, 30, -1, 0, 6)
|
||||||
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1)
|
.attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1)
|
||||||
.soundBased(),
|
.soundBased(),
|
||||||
@ -8996,8 +9014,7 @@ export function initMoves() {
|
|||||||
.target(MoveTarget.ALL_NEAR_OTHERS)
|
.target(MoveTarget.ALL_NEAR_OTHERS)
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new StatusMove(Moves.FORESTS_CURSE, Type.GRASS, 100, 20, -1, 0, 6)
|
new StatusMove(Moves.FORESTS_CURSE, Type.GRASS, 100, 20, -1, 0, 6)
|
||||||
.attr(AddTypeAttr, Type.GRASS)
|
.attr(AddTypeAttr, Type.GRASS),
|
||||||
.edgeCase(), // Weird interaction with Trick or Treat, reflect type, burn up
|
|
||||||
new AttackMove(Moves.PETAL_BLIZZARD, Type.GRASS, MoveCategory.PHYSICAL, 90, 100, 15, -1, 0, 6)
|
new AttackMove(Moves.PETAL_BLIZZARD, Type.GRASS, MoveCategory.PHYSICAL, 90, 100, 15, -1, 0, 6)
|
||||||
.windMove()
|
.windMove()
|
||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
@ -9501,7 +9518,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.PIKA_PAPOW, Type.ELECTRIC, MoveCategory.SPECIAL, -1, -1, 20, -1, 0, 7)
|
new AttackMove(Moves.PIKA_PAPOW, Type.ELECTRIC, MoveCategory.SPECIAL, -1, -1, 20, -1, 0, 7)
|
||||||
.attr(FriendshipPowerAttr),
|
.attr(FriendshipPowerAttr),
|
||||||
new AttackMove(Moves.BOUNCY_BUBBLE, Type.WATER, MoveCategory.SPECIAL, 60, 100, 20, -1, 0, 7)
|
new AttackMove(Moves.BOUNCY_BUBBLE, Type.WATER, MoveCategory.SPECIAL, 60, 100, 20, -1, 0, 7)
|
||||||
.attr(HitHealAttr, 1.0)
|
.attr(HitHealAttr) // Custom
|
||||||
.triageMove()
|
.triageMove()
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.BUZZY_BUZZ, Type.ELECTRIC, MoveCategory.SPECIAL, 60, 100, 20, 100, 0, 7)
|
new AttackMove(Moves.BUZZY_BUZZ, Type.ELECTRIC, MoveCategory.SPECIAL, 60, 100, 20, 100, 0, 7)
|
||||||
@ -10005,6 +10022,7 @@ export function initMoves() {
|
|||||||
.attr(ConfuseAttr)
|
.attr(ConfuseAttr)
|
||||||
.recklessMove(),
|
.recklessMove(),
|
||||||
new AttackMove(Moves.LAST_RESPECTS, Type.GHOST, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 9)
|
new AttackMove(Moves.LAST_RESPECTS, Type.GHOST, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 9)
|
||||||
|
.partial() // Counter resets every wave instead of on arena reset
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => 1 + Math.min(user.isPlayer() ? user.scene.currentBattle.playerFaints : user.scene.currentBattle.enemyFaints, 100))
|
.attr(MovePowerMultiplierAttr, (user, target, move) => 1 + Math.min(user.isPlayer() ? user.scene.currentBattle.playerFaints : user.scene.currentBattle.enemyFaints, 100))
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.LUMINA_CRASH, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, 100, 0, 9)
|
new AttackMove(Moves.LUMINA_CRASH, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, 100, 0, 9)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import { EnemyPartyConfig, generateModifierType, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, loadCustomMovesForEncounter, selectPokemonForOption, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { trainerConfigs, TrainerPartyCompoundTemplate, TrainerPartyTemplate, } from "#app/data/trainer-config";
|
import { trainerConfigs, TrainerPartyCompoundTemplate, TrainerPartyTemplate, } from "#app/data/trainer-config";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
import { ModifierPoolType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
@ -280,7 +280,7 @@ export const ClowningAroundEncounter: MysteryEncounter =
|
|||||||
let numRogue = 0;
|
let numRogue = 0;
|
||||||
items.filter(m => m.isTransferable && !(m instanceof BerryModifier))
|
items.filter(m => m.isTransferable && !(m instanceof BerryModifier))
|
||||||
.forEach(m => {
|
.forEach(m => {
|
||||||
const type = m.type.withTierFromPool();
|
const type = m.type.withTierFromPool(ModifierPoolType.PLAYER, party);
|
||||||
const tier = type.tier ?? ModifierTier.ULTRA;
|
const tier = type.tier ?? ModifierTier.ULTRA;
|
||||||
if (type.id === "GOLDEN_EGG" || tier === ModifierTier.ROGUE) {
|
if (type.id === "GOLDEN_EGG" || tier === ModifierTier.ROGUE) {
|
||||||
numRogue += m.stackCount;
|
numRogue += m.stackCount;
|
||||||
|
@ -418,7 +418,7 @@ export function generateModifierType(scene: BattleScene, modifier: () => Modifie
|
|||||||
// Populates item id and tier (order matters)
|
// Populates item id and tier (order matters)
|
||||||
result = result
|
result = result
|
||||||
.withIdFromFunc(modifierTypes[modifierId])
|
.withIdFromFunc(modifierTypes[modifierId])
|
||||||
.withTierFromPool();
|
.withTierFromPool(ModifierPoolType.PLAYER, scene.getParty());
|
||||||
|
|
||||||
return result instanceof ModifierTypeGenerator ? result.generateType(scene.getParty(), pregenArgs) : result;
|
return result instanceof ModifierTypeGenerator ? result.generateType(scene.getParty(), pregenArgs) : result;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
* or {@linkcode SwitchSummonPhase} will carry out.
|
* or {@linkcode SwitchSummonPhase} will carry out.
|
||||||
*/
|
*/
|
||||||
export enum SwitchType {
|
export enum SwitchType {
|
||||||
|
/** Switchout specifically for when combat starts and the player is prompted if they will switch Pokemon */
|
||||||
|
INITIAL_SWITCH,
|
||||||
/** Basic switchout where the Pokemon to switch in is selected */
|
/** Basic switchout where the Pokemon to switch in is selected */
|
||||||
SWITCH,
|
SWITCH,
|
||||||
/** Transfers stat stages and other effects from the returning Pokemon to the switched in Pokemon */
|
/** Transfers stat stages and other effects from the returning Pokemon to the switched in Pokemon */
|
||||||
|
@ -10,7 +10,14 @@ import Move from "#app/data/move";
|
|||||||
import { ArenaTag, ArenaTagSide, ArenaTrapTag, getArenaTag } from "#app/data/arena-tag";
|
import { ArenaTag, ArenaTagSide, ArenaTrapTag, getArenaTag } from "#app/data/arena-tag";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import { Terrain, TerrainType } from "#app/data/terrain";
|
import { Terrain, TerrainType } from "#app/data/terrain";
|
||||||
import { applyPostTerrainChangeAbAttrs, applyPostWeatherChangeAbAttrs, PostTerrainChangeAbAttr, PostWeatherChangeAbAttr } from "#app/data/ability";
|
import {
|
||||||
|
applyAbAttrs,
|
||||||
|
applyPostTerrainChangeAbAttrs,
|
||||||
|
applyPostWeatherChangeAbAttrs,
|
||||||
|
PostTerrainChangeAbAttr,
|
||||||
|
PostWeatherChangeAbAttr,
|
||||||
|
TerrainEventTypeChangeAbAttr
|
||||||
|
} from "#app/data/ability";
|
||||||
import Pokemon from "#app/field/pokemon";
|
import Pokemon from "#app/field/pokemon";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { TagAddedEvent, TagRemovedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena";
|
import { TagAddedEvent, TagRemovedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena";
|
||||||
@ -387,6 +394,7 @@ export class Arena {
|
|||||||
this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => {
|
this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => {
|
||||||
pokemon.findAndRemoveTags(t => "terrainTypes" in t && !(t.terrainTypes as TerrainType[]).find(t => t === terrain));
|
pokemon.findAndRemoveTags(t => "terrainTypes" in t && !(t.terrainTypes as TerrainType[]).find(t => t === terrain));
|
||||||
applyPostTerrainChangeAbAttrs(PostTerrainChangeAbAttr, pokemon, terrain);
|
applyPostTerrainChangeAbAttrs(PostTerrainChangeAbAttr, pokemon, terrain);
|
||||||
|
applyAbAttrs(TerrainEventTypeChangeAbAttr, pokemon, null, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -786,7 +794,7 @@ export class Arena {
|
|||||||
case Biome.VOLCANO:
|
case Biome.VOLCANO:
|
||||||
return 17.637;
|
return 17.637;
|
||||||
case Biome.GRAVEYARD:
|
case Biome.GRAVEYARD:
|
||||||
return 3.232;
|
return 13.711;
|
||||||
case Biome.DOJO:
|
case Biome.DOJO:
|
||||||
return 6.205;
|
return 6.205;
|
||||||
case Biome.FACTORY:
|
case Biome.FACTORY:
|
||||||
|
@ -22,7 +22,7 @@ import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "#app/data/balance/
|
|||||||
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, SubstituteTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag, TarShotTag, AutotomizedTag, PowerTrickTag } from "../data/battler-tags";
|
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, SubstituteTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag, TarShotTag, AutotomizedTag, PowerTrickTag } from "../data/battler-tags";
|
||||||
import { WeatherType } from "#app/data/weather";
|
import { WeatherType } from "#app/data/weather";
|
||||||
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag";
|
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag";
|
||||||
import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr } from "#app/data/ability";
|
import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr } from "#app/data/ability";
|
||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui";
|
||||||
@ -1258,6 +1258,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the type added to Pokemon from moves like Forest's Curse or Trick Or Treat
|
||||||
|
if (!ignoreOverride && this.summonData && this.summonData.addedType && !types.includes(this.summonData.addedType)) {
|
||||||
|
types.push(this.summonData.addedType);
|
||||||
|
}
|
||||||
|
|
||||||
// If both types are the same (can happen in weird custom typing scenarios), reduce to single type
|
// If both types are the same (can happen in weird custom typing scenarios), reduce to single type
|
||||||
if (types.length > 1 && types[0] === types[1]) {
|
if (types.length > 1 && types[0] === types[1]) {
|
||||||
types.splice(0, 1);
|
types.splice(0, 1);
|
||||||
@ -2667,9 +2672,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.scene.applyModifiers(EnemyDamageReducerModifier, false, damage);
|
this.scene.applyModifiers(EnemyDamageReducerModifier, false, damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Apply this Pokemon's post-calc defensive modifiers (e.g. Fur Coat) */
|
/** Apply this Pokemon's post-calc defensive modifiers (e.g. Fur Coat) */
|
||||||
if (!ignoreAbility) {
|
if (!ignoreAbility) {
|
||||||
applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, simulated, damage);
|
applyPreDefendAbAttrs(ReceivedMoveDamageMultiplierAbAttr, this, source, move, cancelled, simulated, damage);
|
||||||
|
|
||||||
|
/** Additionally apply friend guard damage reduction if ally has it. */
|
||||||
|
if (this.scene.currentBattle.double && this.getAlly()?.isActive(true)) {
|
||||||
|
applyPreDefendAbAttrs(AlliedFieldDamageReductionAbAttr, this.getAlly(), source, move, cancelled, simulated, damage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This attribute may modify damage arbitrarily, so be careful about changing its order of application.
|
// This attribute may modify damage arbitrarily, so be careful about changing its order of application.
|
||||||
@ -5094,6 +5105,7 @@ export class PokemonSummonData {
|
|||||||
public moveset: (PokemonMove | null)[];
|
public moveset: (PokemonMove | null)[];
|
||||||
// If not initialized this value will not be populated from save data.
|
// If not initialized this value will not be populated from save data.
|
||||||
public types: Type[] = [];
|
public types: Type[] = [];
|
||||||
|
public addedType: Type | null = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PokemonBattleData {
|
export class PokemonBattleData {
|
||||||
@ -5131,6 +5143,8 @@ export class PokemonTurnData {
|
|||||||
public statStagesDecreased: boolean = false;
|
public statStagesDecreased: boolean = false;
|
||||||
public moveEffectiveness: TypeDamageMultiplier | null = null;
|
public moveEffectiveness: TypeDamageMultiplier | null = null;
|
||||||
public combiningPledge?: Moves;
|
public combiningPledge?: Moves;
|
||||||
|
public switchedInThisTurn: boolean = false;
|
||||||
|
public failedRunAway: boolean = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AiType {
|
export enum AiType {
|
||||||
|
@ -244,7 +244,7 @@ export class LoadingScene extends SceneBase {
|
|||||||
this.loadAtlas("statuses", "");
|
this.loadAtlas("statuses", "");
|
||||||
this.loadAtlas("types", "");
|
this.loadAtlas("types", "");
|
||||||
}
|
}
|
||||||
const availableLangs = [ "en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN" ];
|
const availableLangs = [ "en", "de", "it", "fr", "ja", "ko", "es-ES", "pt-BR", "zh-CN" ];
|
||||||
if (lang && availableLangs.includes(lang)) {
|
if (lang && availableLangs.includes(lang)) {
|
||||||
this.loadImage("halloween2024-event-" + lang, "events");
|
this.loadImage("halloween2024-event-" + lang, "events");
|
||||||
} else {
|
} else {
|
||||||
|
@ -44,7 +44,7 @@ document.fonts.load("16px emerald").then(() => document.fonts.load("10px pkmnems
|
|||||||
|
|
||||||
let game;
|
let game;
|
||||||
|
|
||||||
const startGame = async () => {
|
const startGame = async (manifest?: any) => {
|
||||||
await initI18n();
|
await initI18n();
|
||||||
const LoadingScene = (await import("./loading-scene")).LoadingScene;
|
const LoadingScene = (await import("./loading-scene")).LoadingScene;
|
||||||
const BattleScene = (await import("./battle-scene")).default;
|
const BattleScene = (await import("./battle-scene")).default;
|
||||||
@ -94,13 +94,15 @@ const startGame = async () => {
|
|||||||
version: version
|
version: version
|
||||||
});
|
});
|
||||||
game.sound.pauseOnBlur = false;
|
game.sound.pauseOnBlur = false;
|
||||||
|
if (manifest) {
|
||||||
|
game["manifest"] = manifest;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetch("/manifest.json")
|
fetch("/manifest.json")
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(jsonResponse => {
|
.then(jsonResponse => {
|
||||||
startGame();
|
startGame(jsonResponse.manifest);
|
||||||
game["manifest"] = jsonResponse.manifest;
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
// Manifest not found (likely local build)
|
// Manifest not found (likely local build)
|
||||||
startGame();
|
startGame();
|
||||||
|
@ -19,7 +19,7 @@ import { Unlockables } from "#app/system/unlockables";
|
|||||||
import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#app/system/voucher";
|
import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#app/system/voucher";
|
||||||
import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler";
|
import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler";
|
||||||
import { getModifierTierTextTint } from "#app/ui/text";
|
import { getModifierTierTextTint } from "#app/ui/text";
|
||||||
import { formatMoney, getEnumKeys, getEnumValues, IntegerHolder, NumberHolder, padInt, randSeedInt, randSeedItem } from "#app/utils";
|
import { formatMoney, getEnumKeys, getEnumValues, IntegerHolder, isNullOrUndefined, NumberHolder, padInt, randSeedInt, randSeedItem } from "#app/utils";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { BerryType } from "#enums/berry-type";
|
import { BerryType } from "#enums/berry-type";
|
||||||
@ -121,17 +121,40 @@ export class ModifierType {
|
|||||||
* Populates item tier for ModifierType instance
|
* Populates item tier for ModifierType instance
|
||||||
* Tier is a necessary field for items that appear in player shop (determines the Pokeball visual they use)
|
* Tier is a necessary field for items that appear in player shop (determines the Pokeball visual they use)
|
||||||
* To find the tier, this function performs a reverse lookup of the item type in modifier pools
|
* To find the tier, this function performs a reverse lookup of the item type in modifier pools
|
||||||
|
* It checks the weight of the item and will use the first tier for which the weight is greater than 0
|
||||||
|
* This is to allow items to be in multiple item pools depending on the conditions, for example for events
|
||||||
|
* If all tiers have a weight of 0 for the item, the first tier where the item was found is used
|
||||||
* @param poolType Default 'ModifierPoolType.PLAYER'. Which pool to lookup item tier from
|
* @param poolType Default 'ModifierPoolType.PLAYER'. Which pool to lookup item tier from
|
||||||
|
* @param party optional. Needed to check the weight of modifiers with conditional weight (see {@linkcode WeightedModifierTypeWeightFunc})
|
||||||
|
* if not provided or empty, the weight check will be ignored
|
||||||
|
* @param rerollCount Default `0`. Used to check the weight of modifiers with conditional weight (see {@linkcode WeightedModifierTypeWeightFunc})
|
||||||
*/
|
*/
|
||||||
withTierFromPool(poolType: ModifierPoolType = ModifierPoolType.PLAYER): ModifierType {
|
withTierFromPool(poolType: ModifierPoolType = ModifierPoolType.PLAYER, party?: PlayerPokemon[], rerollCount: number = 0): ModifierType {
|
||||||
|
let defaultTier: undefined | ModifierTier;
|
||||||
for (const tier of Object.values(getModifierPoolForType(poolType))) {
|
for (const tier of Object.values(getModifierPoolForType(poolType))) {
|
||||||
for (const modifier of tier) {
|
for (const modifier of tier) {
|
||||||
if (this.id === modifier.modifierType.id) {
|
if (this.id === modifier.modifierType.id) {
|
||||||
|
let weight: number;
|
||||||
|
if (modifier.weight instanceof Function) {
|
||||||
|
weight = party ? modifier.weight(party, rerollCount) : 0;
|
||||||
|
} else {
|
||||||
|
weight = modifier.weight;
|
||||||
|
}
|
||||||
|
if (weight > 0) {
|
||||||
this.tier = modifier.modifierType.tier;
|
this.tier = modifier.modifierType.tier;
|
||||||
return this;
|
return this;
|
||||||
|
} else if (isNullOrUndefined(defaultTier)) {
|
||||||
|
// If weight is 0, keep track of the first tier where the item was found
|
||||||
|
defaultTier = modifier.modifierType.tier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Didn't find a pool with weight > 0, fallback to first tier where the item was found, if any
|
||||||
|
if (defaultTier) {
|
||||||
|
this.tier = defaultTier;
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -502,45 +525,25 @@ export class BerryModifierType extends PokemonHeldItemModifierType implements Ge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAttackTypeBoosterItemName(type: Type) {
|
enum AttackTypeBoosterItem {
|
||||||
switch (type) {
|
SILK_SCARF,
|
||||||
case Type.NORMAL:
|
BLACK_BELT,
|
||||||
return "Silk Scarf";
|
SHARP_BEAK,
|
||||||
case Type.FIGHTING:
|
POISON_BARB,
|
||||||
return "Black Belt";
|
SOFT_SAND,
|
||||||
case Type.FLYING:
|
HARD_STONE,
|
||||||
return "Sharp Beak";
|
SILVER_POWDER,
|
||||||
case Type.POISON:
|
SPELL_TAG,
|
||||||
return "Poison Barb";
|
METAL_COAT,
|
||||||
case Type.GROUND:
|
CHARCOAL,
|
||||||
return "Soft Sand";
|
MYSTIC_WATER,
|
||||||
case Type.ROCK:
|
MIRACLE_SEED,
|
||||||
return "Hard Stone";
|
MAGNET,
|
||||||
case Type.BUG:
|
TWISTED_SPOON,
|
||||||
return "Silver Powder";
|
NEVER_MELT_ICE,
|
||||||
case Type.GHOST:
|
DRAGON_FANG,
|
||||||
return "Spell Tag";
|
BLACK_GLASSES,
|
||||||
case Type.STEEL:
|
FAIRY_FEATHER
|
||||||
return "Metal Coat";
|
|
||||||
case Type.FIRE:
|
|
||||||
return "Charcoal";
|
|
||||||
case Type.WATER:
|
|
||||||
return "Mystic Water";
|
|
||||||
case Type.GRASS:
|
|
||||||
return "Miracle Seed";
|
|
||||||
case Type.ELECTRIC:
|
|
||||||
return "Magnet";
|
|
||||||
case Type.PSYCHIC:
|
|
||||||
return "Twisted Spoon";
|
|
||||||
case Type.ICE:
|
|
||||||
return "Never-Melt Ice";
|
|
||||||
case Type.DRAGON:
|
|
||||||
return "Dragon Fang";
|
|
||||||
case Type.DARK:
|
|
||||||
return "Black Glasses";
|
|
||||||
case Type.FAIRY:
|
|
||||||
return "Fairy Feather";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType {
|
export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType {
|
||||||
@ -548,7 +551,7 @@ export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType i
|
|||||||
public boostPercent: integer;
|
public boostPercent: integer;
|
||||||
|
|
||||||
constructor(moveType: Type, boostPercent: integer) {
|
constructor(moveType: Type, boostPercent: integer) {
|
||||||
super("", `${getAttackTypeBoosterItemName(moveType)?.replace(/[ \-]/g, "_").toLowerCase()}`,
|
super("", `${AttackTypeBoosterItem[moveType]?.toLowerCase()}`,
|
||||||
(_type, args) => new AttackTypeBoosterModifier(this, (args[0] as Pokemon).id, moveType, boostPercent));
|
(_type, args) => new AttackTypeBoosterModifier(this, (args[0] as Pokemon).id, moveType, boostPercent));
|
||||||
|
|
||||||
this.moveType = moveType;
|
this.moveType = moveType;
|
||||||
@ -556,7 +559,7 @@ export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType i
|
|||||||
}
|
}
|
||||||
|
|
||||||
get name(): string {
|
get name(): string {
|
||||||
return i18next.t(`modifierType:AttackTypeBoosterItem.${getAttackTypeBoosterItemName(this.moveType)?.replace(/[ \-]/g, "_").toLowerCase()}`);
|
return i18next.t(`modifierType:AttackTypeBoosterItem.${AttackTypeBoosterItem[this.moveType]?.toLowerCase()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescription(scene: BattleScene): string {
|
getDescription(scene: BattleScene): string {
|
||||||
@ -2137,7 +2140,7 @@ export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemo
|
|||||||
// Populates item id and tier
|
// Populates item id and tier
|
||||||
guaranteedMod = guaranteedMod
|
guaranteedMod = guaranteedMod
|
||||||
.withIdFromFunc(modifierTypes[modifierId])
|
.withIdFromFunc(modifierTypes[modifierId])
|
||||||
.withTierFromPool();
|
.withTierFromPool(ModifierPoolType.PLAYER, party);
|
||||||
|
|
||||||
const modType = guaranteedMod instanceof ModifierTypeGenerator ? guaranteedMod.generateType(party) : guaranteedMod;
|
const modType = guaranteedMod instanceof ModifierTypeGenerator ? guaranteedMod.generateType(party) : guaranteedMod;
|
||||||
if (modType) {
|
if (modType) {
|
||||||
@ -2206,7 +2209,7 @@ export function overridePlayerModifierTypeOptions(options: ModifierTypeOption[],
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (modifierType) {
|
if (modifierType) {
|
||||||
options[i].type = modifierType.withIdFromFunc(modifierFunc).withTierFromPool();
|
options[i].type = modifierType.withIdFromFunc(modifierFunc).withTierFromPool(ModifierPoolType.PLAYER, party);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,10 @@ import { NewBattlePhase } from "./new-battle-phase";
|
|||||||
import { PokemonPhase } from "./pokemon-phase";
|
import { PokemonPhase } from "./pokemon-phase";
|
||||||
|
|
||||||
export class AttemptRunPhase extends PokemonPhase {
|
export class AttemptRunPhase extends PokemonPhase {
|
||||||
|
|
||||||
|
/** For testing purposes: this is to force the pokemon to fail and escape */
|
||||||
|
public forceFailEscape = false;
|
||||||
|
|
||||||
constructor(scene: BattleScene, fieldIndex: number) {
|
constructor(scene: BattleScene, fieldIndex: number) {
|
||||||
super(scene, fieldIndex);
|
super(scene, fieldIndex);
|
||||||
}
|
}
|
||||||
@ -28,7 +32,7 @@ export class AttemptRunPhase extends PokemonPhase {
|
|||||||
|
|
||||||
applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance);
|
applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance);
|
||||||
|
|
||||||
if (playerPokemon.randSeedInt(100) < escapeChance.value) {
|
if (playerPokemon.randSeedInt(100) < escapeChance.value && !this.forceFailEscape) {
|
||||||
this.scene.playSound("se/flee");
|
this.scene.playSound("se/flee");
|
||||||
this.scene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500);
|
this.scene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500);
|
||||||
|
|
||||||
@ -51,6 +55,7 @@ export class AttemptRunPhase extends PokemonPhase {
|
|||||||
this.scene.pushPhase(new BattleEndPhase(this.scene));
|
this.scene.pushPhase(new BattleEndPhase(this.scene));
|
||||||
this.scene.pushPhase(new NewBattlePhase(this.scene));
|
this.scene.pushPhase(new NewBattlePhase(this.scene));
|
||||||
} else {
|
} else {
|
||||||
|
playerPokemon.turnData.failedRunAway = true;
|
||||||
this.scene.queueMessage(i18next.t("battle:runAwayCannotEscape"), null, true, 500);
|
this.scene.queueMessage(i18next.t("battle:runAwayCannotEscape"), null, true, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ export class CheckSwitchPhase extends BattlePhase {
|
|||||||
this.scene.ui.setMode(Mode.CONFIRM, () => {
|
this.scene.ui.setMode(Mode.CONFIRM, () => {
|
||||||
this.scene.ui.setMode(Mode.MESSAGE);
|
this.scene.ui.setMode(Mode.MESSAGE);
|
||||||
this.scene.tryRemovePhase(p => p instanceof PostSummonPhase && p.player && p.fieldIndex === this.fieldIndex);
|
this.scene.tryRemovePhase(p => p instanceof PostSummonPhase && p.player && p.fieldIndex === this.fieldIndex);
|
||||||
this.scene.unshiftPhase(new SwitchPhase(this.scene, SwitchType.SWITCH, this.fieldIndex, false, true));
|
this.scene.unshiftPhase(new SwitchPhase(this.scene, SwitchType.INITIAL_SWITCH, this.fieldIndex, false, true));
|
||||||
this.end();
|
this.end();
|
||||||
}, () => {
|
}, () => {
|
||||||
this.scene.ui.setMode(Mode.MESSAGE);
|
this.scene.ui.setMode(Mode.MESSAGE);
|
||||||
|
@ -65,6 +65,15 @@ export class FaintPhase extends PokemonPhase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** In case the current pokemon was just switched in, make sure it is counted as participating in the combat */
|
||||||
|
this.scene.getPlayerField().forEach((pokemon, i) => {
|
||||||
|
if (pokemon?.isActive(true)) {
|
||||||
|
if (pokemon.isPlayer()) {
|
||||||
|
this.scene.currentBattle.addParticipant(pokemon as PlayerPokemon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!this.tryOverrideForBattleSpec()) {
|
if (!this.tryOverrideForBattleSpec()) {
|
||||||
this.doFaint();
|
this.doFaint();
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import BattleScene from "#app/battle-scene";
|
|||||||
import { applyAbAttrs, applyPostMoveUsedAbAttrs, applyPreAttackAbAttrs, BlockRedirectAbAttr, IncreasePpAbAttr, PokemonTypeChangeAbAttr, PostMoveUsedAbAttr, RedirectMoveAbAttr, ReduceStatusEffectDurationAbAttr } from "#app/data/ability";
|
import { applyAbAttrs, applyPostMoveUsedAbAttrs, applyPreAttackAbAttrs, BlockRedirectAbAttr, IncreasePpAbAttr, PokemonTypeChangeAbAttr, PostMoveUsedAbAttr, RedirectMoveAbAttr, ReduceStatusEffectDurationAbAttr } from "#app/data/ability";
|
||||||
import { CommonAnim } from "#app/data/battle-anims";
|
import { CommonAnim } from "#app/data/battle-anims";
|
||||||
import { BattlerTagLapseType, CenterOfAttentionTag } from "#app/data/battler-tags";
|
import { BattlerTagLapseType, CenterOfAttentionTag } from "#app/data/battler-tags";
|
||||||
import { allMoves, applyMoveAttrs, BypassRedirectAttr, BypassSleepAttr, CopyMoveAttr, HealStatusEffectAttr, MoveFlags, PreMoveMessageAttr } from "#app/data/move";
|
import { allMoves, applyMoveAttrs, BypassRedirectAttr, BypassSleepAttr, CopyMoveAttr, frenzyMissFunc, HealStatusEffectAttr, MoveFlags, PreMoveMessageAttr } from "#app/data/move";
|
||||||
import { SpeciesFormChangePreMoveTrigger } from "#app/data/pokemon-forms";
|
import { SpeciesFormChangePreMoveTrigger } from "#app/data/pokemon-forms";
|
||||||
import { getStatusEffectActivationText, getStatusEffectHealText } from "#app/data/status-effect";
|
import { getStatusEffectActivationText, getStatusEffectHealText } from "#app/data/status-effect";
|
||||||
import { Type } from "#app/data/type";
|
import { Type } from "#app/data/type";
|
||||||
@ -470,6 +470,10 @@ export class MovePhase extends BattlePhase {
|
|||||||
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), ppUsed));
|
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), ppUsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.cancelled && this.pokemon.summonData?.tags?.find(t => t.tagType === BattlerTagType.FRENZY)) {
|
||||||
|
frenzyMissFunc(this.pokemon, this.move.getMove());
|
||||||
|
}
|
||||||
|
|
||||||
this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL });
|
this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL });
|
||||||
|
|
||||||
this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT);
|
this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT);
|
||||||
|
@ -65,7 +65,7 @@ export class StatStageChangePhase extends PokemonPhase {
|
|||||||
|
|
||||||
if (!this.selfTarget && stages.value < 0) {
|
if (!this.selfTarget && stages.value < 0) {
|
||||||
// TODO: add a reference to the source of the stat change to fix Infiltrator interaction
|
// TODO: add a reference to the source of the stat change to fix Infiltrator interaction
|
||||||
this.scene.arena.applyTagsForSide(MistTag, pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, false, null, false, cancelled);
|
this.scene.arena.applyTagsForSide(MistTag, pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, false, null, cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cancelled.value && !this.selfTarget && stages.value < 0) {
|
if (!cancelled.value && !this.selfTarget && stages.value < 0) {
|
||||||
|
@ -64,10 +64,8 @@ export class SwitchSummonPhase extends SummonPhase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pokemon = this.getPokemon();
|
const pokemon = this.getPokemon();
|
||||||
|
|
||||||
(this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id));
|
(this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id));
|
||||||
|
if (this.switchType === SwitchType.SWITCH || this.switchType === SwitchType.INITIAL_SWITCH) {
|
||||||
if (this.switchType === SwitchType.SWITCH) {
|
|
||||||
const substitute = pokemon.getTag(SubstituteTag);
|
const substitute = pokemon.getTag(SubstituteTag);
|
||||||
if (substitute) {
|
if (substitute) {
|
||||||
this.scene.tweens.add({
|
this.scene.tweens.add({
|
||||||
@ -186,6 +184,11 @@ export class SwitchSummonPhase extends SummonPhase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.switchType !== SwitchType.INITIAL_SWITCH) {
|
||||||
|
pokemon.resetTurnData();
|
||||||
|
pokemon.turnData.switchedInThisTurn = true;
|
||||||
|
}
|
||||||
|
|
||||||
this.lastPokemon?.resetSummonData();
|
this.lastPokemon?.resetSummonData();
|
||||||
|
|
||||||
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
||||||
|
@ -205,11 +205,11 @@ export class TurnStartPhase extends FieldPhase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.scene.pushPhase(new WeatherEffectPhase(this.scene));
|
this.scene.pushPhase(new WeatherEffectPhase(this.scene));
|
||||||
|
this.scene.pushPhase(new BerryPhase(this.scene));
|
||||||
|
|
||||||
/** Add a new phase to check who should be taking status damage */
|
/** Add a new phase to check who should be taking status damage */
|
||||||
this.scene.pushPhase(new CheckStatusEffectPhase(this.scene, moveOrder));
|
this.scene.pushPhase(new CheckStatusEffectPhase(this.scene, moveOrder));
|
||||||
|
|
||||||
this.scene.pushPhase(new BerryPhase(this.scene));
|
|
||||||
this.scene.pushPhase(new TurnEndPhase(this.scene));
|
this.scene.pushPhase(new TurnEndPhase(this.scene));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,7 +153,7 @@ export async function initI18n(): Promise<void> {
|
|||||||
i18next.use(new KoreanPostpositionProcessor());
|
i18next.use(new KoreanPostpositionProcessor());
|
||||||
await i18next.init({
|
await i18next.init({
|
||||||
fallbackLng: "en",
|
fallbackLng: "en",
|
||||||
supportedLngs: [ "en", "es", "fr", "it", "de", "zh-CN", "zh-TW", "pt-BR", "ko", "ja", "ca-ES" ],
|
supportedLngs: [ "en", "es-ES", "fr", "it", "de", "zh-CN", "zh-TW", "pt-BR", "ko", "ja", "ca-ES" ],
|
||||||
backend: {
|
backend: {
|
||||||
loadPath(lng: string, [ ns ]: string[]) {
|
loadPath(lng: string, [ ns ]: string[]) {
|
||||||
let fileName: string;
|
let fileName: string;
|
||||||
@ -164,7 +164,7 @@ export async function initI18n(): Promise<void> {
|
|||||||
} else {
|
} else {
|
||||||
fileName = camelCaseToKebabCase(ns);
|
fileName = camelCaseToKebabCase(ns);
|
||||||
}
|
}
|
||||||
return `/locales/${lng}/${fileName}.json?v=${pkg.version}`;
|
return `./locales/${lng}/${fileName}.json?v=${pkg.version}`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultNS: "menu",
|
defaultNS: "menu",
|
||||||
|
@ -866,8 +866,8 @@ export function setSetting(scene: BattleScene, setting: string, value: integer):
|
|||||||
handler: () => changeLocaleHandler("en")
|
handler: () => changeLocaleHandler("en")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Español",
|
label: "Español (ES)",
|
||||||
handler: () => changeLocaleHandler("es")
|
handler: () => changeLocaleHandler("es-ES")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Italiano",
|
label: "Italiano",
|
||||||
|
120
src/test/abilities/friend_guard.test.ts
Normal file
120
src/test/abilities/friend_guard.test.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { allAbilities } from "#app/data/ability";
|
||||||
|
import { allMoves, MoveCategory } from "#app/data/move";
|
||||||
|
|
||||||
|
describe("Moves - Friend Guard", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.battleType("double")
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset([ Moves.TACKLE, Moves.SPLASH, Moves.DRAGON_RAGE ])
|
||||||
|
.enemySpecies(Species.SHUCKLE)
|
||||||
|
.moveset([ Moves.SPLASH ])
|
||||||
|
.startingLevel(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should reduce damage that other allied Pokémon receive from attacks (from any Pokémon) by 25%", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.BULBASAUR, Species.CHARMANDER ]);
|
||||||
|
const [ player1, player2 ] = game.scene.getPlayerField();
|
||||||
|
const spy = vi.spyOn(player1, "getAttackDamage");
|
||||||
|
|
||||||
|
const enemy1 = game.scene.getEnemyField()[0];
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
// Get the last return value from `getAttackDamage`
|
||||||
|
const turn1Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
|
||||||
|
// Making sure the test is controlled; turn 1 damage is equal to base damage (after rounding)
|
||||||
|
expect(turn1Damage).toBe(Math.floor(player1.getBaseDamage(enemy1, allMoves[Moves.TACKLE], MoveCategory.PHYSICAL)));
|
||||||
|
|
||||||
|
vi.spyOn(player2, "getAbility").mockReturnValue(allAbilities[Abilities.FRIEND_GUARD]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
// Get the last return value from `getAttackDamage`
|
||||||
|
const turn2Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
|
||||||
|
// With the ally's Friend Guard, damage should have been reduced from base damage by 25%
|
||||||
|
expect(turn2Damage).toBe(Math.floor(player1.getBaseDamage(enemy1, allMoves[Moves.TACKLE], MoveCategory.PHYSICAL) * 0.75));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should NOT reduce damage to pokemon with friend guard", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.BULBASAUR, Species.CHARMANDER ]);
|
||||||
|
|
||||||
|
const player2 = game.scene.getPlayerField()[1];
|
||||||
|
const spy = vi.spyOn(player2, "getAttackDamage");
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
const turn1Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
|
||||||
|
|
||||||
|
vi.spyOn(player2, "getAbility").mockReturnValue(allAbilities[Abilities.FRIEND_GUARD]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
const turn2Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
|
||||||
|
expect(turn2Damage).toBe(turn1Damage);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should NOT reduce damage from fixed damage attacks", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.BULBASAUR, Species.CHARMANDER ]);
|
||||||
|
|
||||||
|
const [ player1, player2 ] = game.scene.getPlayerField();
|
||||||
|
const spy = vi.spyOn(player1, "getAttackDamage");
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.forceEnemyMove(Moves.DRAGON_RAGE, BattlerIndex.PLAYER);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
const turn1Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
|
||||||
|
expect(turn1Damage).toBe(40);
|
||||||
|
|
||||||
|
vi.spyOn(player2, "getAbility").mockReturnValue(allAbilities[Abilities.FRIEND_GUARD]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.forceEnemyMove(Moves.DRAGON_RAGE, BattlerIndex.PLAYER);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
const turn2Damage = spy.mock.results[spy.mock.results.length - 1].value.damage;
|
||||||
|
expect(turn2Damage).toBe(40);
|
||||||
|
});
|
||||||
|
});
|
91
src/test/abilities/mimicry.test.ts
Normal file
91
src/test/abilities/mimicry.test.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Abilities - Mimicry", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.SPLASH ])
|
||||||
|
.ability(Abilities.MIMICRY)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Mimicry activates after the Pokémon with Mimicry is switched in while terrain is present, or whenever there is a change in terrain", async () => {
|
||||||
|
game.override.enemyAbility(Abilities.MISTY_SURGE);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS, Species.ABRA ]);
|
||||||
|
|
||||||
|
const [ playerPokemon1, playerPokemon2 ] = game.scene.getParty();
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(playerPokemon1.getTypes().includes(Type.FAIRY)).toBe(true);
|
||||||
|
|
||||||
|
game.doSwitchPokemon(1);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(playerPokemon2.getTypes().includes(Type.FAIRY)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Pokemon should revert back to its original, root type once terrain ends", async () => {
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.SPLASH, Moves.TRANSFORM ])
|
||||||
|
.enemyAbility(Abilities.MIMICRY)
|
||||||
|
.enemyMoveset([ Moves.SPLASH, Moves.PSYCHIC_TERRAIN ]);
|
||||||
|
await game.classicMode.startBattle([ Species.REGIELEKI ]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon();
|
||||||
|
game.move.select(Moves.TRANSFORM);
|
||||||
|
await game.forceEnemyMove(Moves.PSYCHIC_TERRAIN);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(playerPokemon?.getTypes().includes(Type.PSYCHIC)).toBe(true);
|
||||||
|
|
||||||
|
if (game.scene.arena.terrain) {
|
||||||
|
game.scene.arena.terrain.turnsLeft = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(playerPokemon?.getTypes().includes(Type.ELECTRIC)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("If the Pokemon is under the effect of a type-adding move and an equivalent terrain activates, the move's effect disappears", async () => {
|
||||||
|
game.override
|
||||||
|
.enemyMoveset([ Moves.FORESTS_CURSE, Moves.GRASSY_TERRAIN ]);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon();
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.forceEnemyMove(Moves.FORESTS_CURSE);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(playerPokemon?.summonData.addedType).toBe(Type.GRASS);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.forceEnemyMove(Moves.GRASSY_TERRAIN);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(playerPokemon?.summonData.addedType).toBeNull();
|
||||||
|
expect(playerPokemon?.getTypes().includes(Type.GRASS)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
125
src/test/abilities/speed_boost.test.ts
Normal file
125
src/test/abilities/speed_boost.test.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
import { CommandPhase } from "#app/phases/command-phase";
|
||||||
|
import { Command } from "#app/ui/command-ui-handler";
|
||||||
|
import { AttemptRunPhase } from "#app/phases/attempt-run-phase";
|
||||||
|
|
||||||
|
describe("Abilities - Speed Boost", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.enemySpecies(Species.DRAGAPULT)
|
||||||
|
.ability(Abilities.SPEED_BOOST)
|
||||||
|
.enemyMoveset(Moves.SPLASH)
|
||||||
|
.moveset([ Moves.SPLASH, Moves.U_TURN ]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should increase speed by 1 stage at end of turn",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not trigger this turn if pokemon was switched into combat via attack, but the turn after",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([
|
||||||
|
Species.SHUCKLE,
|
||||||
|
Species.NINJASK
|
||||||
|
]);
|
||||||
|
|
||||||
|
game.move.select(Moves.U_TURN);
|
||||||
|
game.doSelectPartyPokemon(1);
|
||||||
|
await game.toNextTurn();
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("checking back to back swtiches",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([
|
||||||
|
Species.SHUCKLE,
|
||||||
|
Species.NINJASK
|
||||||
|
]);
|
||||||
|
|
||||||
|
game.move.select(Moves.U_TURN);
|
||||||
|
game.doSelectPartyPokemon(1);
|
||||||
|
await game.toNextTurn();
|
||||||
|
let playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||||
|
|
||||||
|
game.move.select(Moves.U_TURN);
|
||||||
|
game.doSelectPartyPokemon(1);
|
||||||
|
await game.toNextTurn();
|
||||||
|
playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not trigger this turn if pokemon was switched into combat via normal switch, but the turn after",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([
|
||||||
|
Species.SHUCKLE,
|
||||||
|
Species.NINJASK
|
||||||
|
]);
|
||||||
|
|
||||||
|
game.doSwitchPokemon(1);
|
||||||
|
await game.toNextTurn();
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not trigger if pokemon fails to escape",
|
||||||
|
async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.SHUCKLE ]);
|
||||||
|
|
||||||
|
const commandPhase = game.scene.getCurrentPhase() as CommandPhase;
|
||||||
|
commandPhase.handleCommand(Command.RUN, 0);
|
||||||
|
const runPhase = game.scene.getCurrentPhase() as AttemptRunPhase;
|
||||||
|
runPhase.forceFailEscape = true;
|
||||||
|
await game.phaseInterceptor.to(AttemptRunPhase);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
@ -1,4 +1,7 @@
|
|||||||
import { Egg, getLegendaryGachaSpeciesForTimestamp } from "#app/data/egg";
|
import { speciesEggTiers } from "#app/data/balance/species-egg-tiers";
|
||||||
|
import { speciesStarterCosts } from "#app/data/balance/starters";
|
||||||
|
import { Egg, getLegendaryGachaSpeciesForTimestamp, getValidLegendaryGachaSpecies } from "#app/data/egg";
|
||||||
|
import { allSpecies } from "#app/data/pokemon-species";
|
||||||
import { EggSourceType } from "#app/enums/egg-source-types";
|
import { EggSourceType } from "#app/enums/egg-source-types";
|
||||||
import { EggTier } from "#app/enums/egg-type";
|
import { EggTier } from "#app/enums/egg-type";
|
||||||
import { VariantTier } from "#app/enums/variant-tier";
|
import { VariantTier } from "#app/enums/variant-tier";
|
||||||
@ -64,6 +67,12 @@ describe("Egg Generation Tests", () => {
|
|||||||
expect(gachaSpeciesCount).toBeGreaterThan(0.4 * EGG_HATCH_COUNT);
|
expect(gachaSpeciesCount).toBeGreaterThan(0.4 * EGG_HATCH_COUNT);
|
||||||
expect(gachaSpeciesCount).toBeLessThan(0.6 * EGG_HATCH_COUNT);
|
expect(gachaSpeciesCount).toBeLessThan(0.6 * EGG_HATCH_COUNT);
|
||||||
});
|
});
|
||||||
|
it("should never be allowed to generate Eternatus via the legendary gacha", () => {
|
||||||
|
const validLegendaryGachaSpecies = getValidLegendaryGachaSpecies();
|
||||||
|
expect(validLegendaryGachaSpecies.every(s => speciesEggTiers[s] === EggTier.LEGENDARY)).toBe(true);
|
||||||
|
expect(validLegendaryGachaSpecies.every(s => allSpecies[s].isObtainable())).toBe(true);
|
||||||
|
expect(validLegendaryGachaSpecies.includes(Species.ETERNATUS)).toBe(false);
|
||||||
|
});
|
||||||
it("should hatch an Arceus. Set from species", () => {
|
it("should hatch an Arceus. Set from species", () => {
|
||||||
const scene = game.scene;
|
const scene = game.scene;
|
||||||
const expectedSpecies = Species.ARCEUS;
|
const expectedSpecies = Species.ARCEUS;
|
||||||
@ -376,4 +385,23 @@ describe("Egg Generation Tests", () => {
|
|||||||
expect(diffShiny).toBe(true);
|
expect(diffShiny).toBe(true);
|
||||||
expect(diffAbility).toBe(true);
|
expect(diffAbility).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// For now, we are using this test to detect oversights in egg tiers.
|
||||||
|
// Delete this test if the balance team rebalances species costs independently of egg tiers.
|
||||||
|
it("should have correct egg tiers based on species costs", () => {
|
||||||
|
const getExpectedEggTier = (starterCost) =>
|
||||||
|
starterCost <= 3 ? EggTier.COMMON
|
||||||
|
: starterCost <= 5 ? EggTier.RARE
|
||||||
|
: starterCost <= 7 ? EggTier.EPIC
|
||||||
|
: EggTier.LEGENDARY;
|
||||||
|
|
||||||
|
allSpecies.forEach(pokemonSpecies => {
|
||||||
|
const rootSpecies = pokemonSpecies.getRootSpeciesId();
|
||||||
|
const speciesCost = speciesStarterCosts[rootSpecies];
|
||||||
|
const expectedEggTier = getExpectedEggTier(speciesCost);
|
||||||
|
const actualEggTier = speciesEggTiers[rootSpecies];
|
||||||
|
|
||||||
|
expect(actualEggTier).toBe(expectedEggTier);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
42
src/test/moves/chloroblast.test.ts
Normal file
42
src/test/moves/chloroblast.test.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Chloroblast", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.CHLOROBLAST ])
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.PROTECT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not deal recoil damage if the opponent uses protect", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.CHLOROBLAST);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()!.isFullHp()).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
47
src/test/moves/forests_curse.test.ts
Normal file
47
src/test/moves/forests_curse.test.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Forest's Curse", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.FORESTS_CURSE, Moves.TRICK_OR_TREAT ])
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("will replace the added type from Trick Or Treat", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||||
|
game.move.select(Moves.TRICK_OR_TREAT);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
expect(enemyPokemon!.summonData.addedType).toBe(Type.GHOST);
|
||||||
|
|
||||||
|
game.move.select(Moves.FORESTS_CURSE);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
expect(enemyPokemon?.summonData.addedType).toBe(Type.GRASS);
|
||||||
|
});
|
||||||
|
});
|
49
src/test/moves/mist.test.ts
Normal file
49
src/test/moves/mist.test.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Mist", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.MIST, Moves.SPLASH ])
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.battleType("double")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.SNORLAX)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.GROWL);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should prevent the user's side from having stats lowered", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.MAGIKARP, Species.FEEBAS ]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerField();
|
||||||
|
|
||||||
|
game.move.select(Moves.MIST, 0);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
playerPokemon.forEach(p => expect(p.getStatStage(Stat.ATK)).toBe(0));
|
||||||
|
});
|
||||||
|
|
||||||
|
it.todo("should be ignored by opponents with Infiltrator");
|
||||||
|
});
|
59
src/test/moves/reflect_type.test.ts
Normal file
59
src/test/moves/reflect_type.test.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Reflect Type", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("will make the user Normal/Grass if targetting a typeless Pokemon affected by Forest's Curse", async () => {
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.FORESTS_CURSE, Moves.REFLECT_TYPE ])
|
||||||
|
.startingLevel(60)
|
||||||
|
.enemySpecies(Species.CHARMANDER)
|
||||||
|
.enemyMoveset([ Moves.BURN_UP, Moves.SPLASH ]);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon();
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.forceEnemyMove(Moves.BURN_UP);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
game.move.select(Moves.FORESTS_CURSE);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(enemyPokemon?.getTypes().includes(Type.UNKNOWN)).toBe(true);
|
||||||
|
expect(enemyPokemon?.getTypes().includes(Type.GRASS)).toBe(true);
|
||||||
|
|
||||||
|
game.move.select(Moves.REFLECT_TYPE);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
expect(playerPokemon?.getTypes()[0]).toBe(Type.NORMAL);
|
||||||
|
expect(playerPokemon?.getTypes().includes(Type.GRASS)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
47
src/test/moves/trick_or_treat.test.ts
Normal file
47
src/test/moves/trick_or_treat.test.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Trick Or Treat", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.FORESTS_CURSE, Moves.TRICK_OR_TREAT ])
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("will replace added type from Forest's Curse", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||||
|
game.move.select(Moves.FORESTS_CURSE);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
expect(enemyPokemon!.summonData.addedType).toBe(Type.GRASS);
|
||||||
|
|
||||||
|
game.move.select(Moves.TRICK_OR_TREAT);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
expect(enemyPokemon?.summonData.addedType).toBe(Type.GHOST);
|
||||||
|
});
|
||||||
|
});
|
72
src/test/phases/frenzy-move-reset.test.ts
Normal file
72
src/test/phases/frenzy-move-reset.test.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, it, expect } from "vitest";
|
||||||
|
|
||||||
|
describe("Frenzy Move Reset", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.starterSpecies(Species.MAGIKARP)
|
||||||
|
.moveset(Moves.THRASH)
|
||||||
|
.statusEffect(StatusEffect.PARALYSIS)
|
||||||
|
.enemyMoveset(Moves.SPLASH)
|
||||||
|
.enemyLevel(100)
|
||||||
|
.enemySpecies(Species.SHUCKLE)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Thrash (or frenzy moves in general) should not continue to run if attack fails due to paralysis
|
||||||
|
*
|
||||||
|
* This is a 3-turn Thrash test:
|
||||||
|
* 1. Thrash is selected and succeeds to hit the enemy -> Enemy Faints
|
||||||
|
*
|
||||||
|
* 2. Thrash is automatically selected but misses due to paralysis
|
||||||
|
* Note: After missing the Pokemon should stop automatically attacking
|
||||||
|
*
|
||||||
|
* 3. At the start of the 3rd turn the Player should be able to select a move/switch Pokemon/etc.
|
||||||
|
* Note: This means that BattlerTag.FRENZY is not anymore in pokemon.summonData.tags and pokemon.summonData.moveQueue is empty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
it("should cancel frenzy move if move fails turn 2", async () => {
|
||||||
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
game.move.select(Moves.THRASH);
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||||
|
await game.move.forceStatusActivation(false);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(playerPokemon.summonData.moveQueue.length).toBe(2);
|
||||||
|
expect(playerPokemon.summonData.tags.some(tag => tag.tagType === BattlerTagType.FRENZY)).toBe(true);
|
||||||
|
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||||
|
await game.move.forceStatusActivation(true);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(playerPokemon.summonData.moveQueue.length).toBe(0);
|
||||||
|
expect(playerPokemon.summonData.tags.some(tag => tag.tagType === BattlerTagType.FRENZY)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
@ -24,6 +24,7 @@ import GamepadPlugin = Phaser.Input.Gamepad.GamepadPlugin;
|
|||||||
import EventEmitter = Phaser.Events.EventEmitter;
|
import EventEmitter = Phaser.Events.EventEmitter;
|
||||||
import UpdateList = Phaser.GameObjects.UpdateList;
|
import UpdateList = Phaser.GameObjects.UpdateList;
|
||||||
import { version } from "../../../package.json";
|
import { version } from "../../../package.json";
|
||||||
|
import { MockTimedEventManager } from "./mocks/mockTimedEventManager";
|
||||||
|
|
||||||
Object.defineProperty(window, "localStorage", {
|
Object.defineProperty(window, "localStorage", {
|
||||||
value: mockLocalStorage(),
|
value: mockLocalStorage(),
|
||||||
@ -232,6 +233,7 @@ export default class GameWrapper {
|
|||||||
this.scene.make = new MockGameObjectCreator(mockTextureManager);
|
this.scene.make = new MockGameObjectCreator(mockTextureManager);
|
||||||
this.scene.time = new MockClock(this.scene);
|
this.scene.time = new MockClock(this.scene);
|
||||||
this.scene.remove = vi.fn(); // TODO: this should be stubbed differently
|
this.scene.remove = vi.fn(); // TODO: this should be stubbed differently
|
||||||
|
this.scene.eventManager = new MockTimedEventManager(); // Disable Timed Events
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
src/test/utils/mocks/mockTimedEventManager.ts
Normal file
17
src/test/utils/mocks/mockTimedEventManager.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { TimedEventManager } from "#app/timed-event-manager";
|
||||||
|
|
||||||
|
/** Mock TimedEventManager so that ongoing events don't impact tests */
|
||||||
|
export class MockTimedEventManager extends TimedEventManager {
|
||||||
|
override activeEvent() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
override isEventActive(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
override getFriendshipMultiplier(): number {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
override getShinyMultiplier(): number {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,7 @@ const timedEvents: TimedEvent[] = [
|
|||||||
endDate: new Date(Date.UTC(2024, 10, 4, 0)),
|
endDate: new Date(Date.UTC(2024, 10, 4, 0)),
|
||||||
bannerKey: "halloween2024-event-",
|
bannerKey: "halloween2024-event-",
|
||||||
scale: 0.21,
|
scale: 0.21,
|
||||||
availableLangs: [ "en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN" ]
|
availableLangs: [ "en", "de", "it", "fr", "ja", "ko", "es-ES", "pt-BR", "zh-CN" ]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
|||||||
let pokemonIconX = -20;
|
let pokemonIconX = -20;
|
||||||
let pokemonIconY = 6;
|
let pokemonIconY = 6;
|
||||||
|
|
||||||
if ([ "de", "es", "fr", "ko", "pt-BR" ].includes(currentLanguage)) {
|
if ([ "de", "es-ES", "fr", "ko", "pt-BR" ].includes(currentLanguage)) {
|
||||||
gachaTextStyle = TextStyle.SMALLER_WINDOW_ALT;
|
gachaTextStyle = TextStyle.SMALLER_WINDOW_ALT;
|
||||||
gachaX = 2;
|
gachaX = 2;
|
||||||
gachaY = 2;
|
gachaY = 2;
|
||||||
@ -115,7 +115,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
let legendaryLabelX = gachaX;
|
let legendaryLabelX = gachaX;
|
||||||
let legendaryLabelY = gachaY;
|
let legendaryLabelY = gachaY;
|
||||||
if ([ "de", "es" ].includes(currentLanguage)) {
|
if ([ "de", "es-ES" ].includes(currentLanguage)) {
|
||||||
pokemonIconX = -25;
|
pokemonIconX = -25;
|
||||||
pokemonIconY = 10;
|
pokemonIconY = 10;
|
||||||
legendaryLabelX = -6;
|
legendaryLabelX = -6;
|
||||||
@ -128,7 +128,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
switch (gachaType as GachaType) {
|
switch (gachaType as GachaType) {
|
||||||
case GachaType.LEGENDARY:
|
case GachaType.LEGENDARY:
|
||||||
if ([ "de", "es" ].includes(currentLanguage)) {
|
if ([ "de", "es-ES" ].includes(currentLanguage)) {
|
||||||
gachaUpLabel.setAlign("center");
|
gachaUpLabel.setAlign("center");
|
||||||
gachaUpLabel.setY(0);
|
gachaUpLabel.setY(0);
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ export default class EggGachaUiHandler extends MessageUiHandler {
|
|||||||
gachaInfoContainer.add(pokemonIcon);
|
gachaInfoContainer.add(pokemonIcon);
|
||||||
break;
|
break;
|
||||||
case GachaType.MOVE:
|
case GachaType.MOVE:
|
||||||
if ([ "de", "es", "fr", "pt-BR" ].includes(currentLanguage)) {
|
if ([ "de", "es-ES", "fr", "pt-BR" ].includes(currentLanguage)) {
|
||||||
gachaUpLabel.setAlign("center");
|
gachaUpLabel.setAlign("center");
|
||||||
gachaUpLabel.setY(0);
|
gachaUpLabel.setY(0);
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ let wikiUrl = "https://wiki.pokerogue.net/start";
|
|||||||
const discordUrl = "https://discord.gg/uWpTfdKG49";
|
const discordUrl = "https://discord.gg/uWpTfdKG49";
|
||||||
const githubUrl = "https://github.com/pagefaultgames/pokerogue";
|
const githubUrl = "https://github.com/pagefaultgames/pokerogue";
|
||||||
const redditUrl = "https://www.reddit.com/r/pokerogue";
|
const redditUrl = "https://www.reddit.com/r/pokerogue";
|
||||||
const donateUrl = "https://github.com/sponsors/patapancakes";
|
const donateUrl = "https://github.com/sponsors/pagefaultgames";
|
||||||
|
|
||||||
export default class MenuUiHandler extends MessageUiHandler {
|
export default class MenuUiHandler extends MessageUiHandler {
|
||||||
private readonly textPadding = 8;
|
private readonly textPadding = 8;
|
||||||
|
@ -21,24 +21,6 @@ interface LanguageSetting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const languageSettings: { [key: string]: LanguageSetting } = {
|
const languageSettings: { [key: string]: LanguageSetting } = {
|
||||||
"en": {
|
|
||||||
infoContainerTextSize: "64px"
|
|
||||||
},
|
|
||||||
"de": {
|
|
||||||
infoContainerTextSize: "64px",
|
|
||||||
},
|
|
||||||
"es": {
|
|
||||||
infoContainerTextSize: "64px"
|
|
||||||
},
|
|
||||||
"fr": {
|
|
||||||
infoContainerTextSize: "64px"
|
|
||||||
},
|
|
||||||
"it": {
|
|
||||||
infoContainerTextSize: "64px"
|
|
||||||
},
|
|
||||||
"zh": {
|
|
||||||
infoContainerTextSize: "64px"
|
|
||||||
},
|
|
||||||
"pt": {
|
"pt": {
|
||||||
infoContainerTextSize: "60px",
|
infoContainerTextSize: "60px",
|
||||||
infoContainerLabelXPos: -15,
|
infoContainerLabelXPos: -15,
|
||||||
@ -237,14 +219,20 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
const formKey = (pokemon.species?.forms?.[pokemon.formIndex!]?.formKey);
|
const formKey = (pokemon.species?.forms?.[pokemon.formIndex!]?.formKey);
|
||||||
const formText = Utils.capitalizeString(formKey, "-", false, false) || "";
|
const formText = Utils.capitalizeString(formKey, "-", false, false) || "";
|
||||||
const speciesName = Utils.capitalizeString(Species[pokemon.species.getRootSpeciesId()], "_", true, false);
|
const speciesName = Utils.capitalizeString(Species[pokemon.species.speciesId], "_", true, false);
|
||||||
|
|
||||||
let formName = "";
|
let formName = "";
|
||||||
if (pokemon.species.speciesId === Species.ARCEUS) {
|
if (pokemon.species.speciesId === Species.ARCEUS) {
|
||||||
formName = i18next.t(`pokemonInfo:Type.${formText?.toUpperCase()}`);
|
formName = i18next.t(`pokemonInfo:Type.${formText?.toUpperCase()}`);
|
||||||
} else {
|
} else {
|
||||||
const i18key = `pokemonForm:${speciesName}${formText}`;
|
const i18key = `pokemonForm:${speciesName}${formText}`;
|
||||||
formName = i18next.exists(i18key) ? i18next.t(i18key) : formText;
|
if (i18next.exists(i18key)) {
|
||||||
|
formName = i18next.t(i18key);
|
||||||
|
} else {
|
||||||
|
const rootSpeciesName = Utils.capitalizeString(Species[pokemon.species.getRootSpeciesId()], "_", true, false);
|
||||||
|
const i18RootKey = `pokemonForm:${rootSpeciesName}${formText}`;
|
||||||
|
formName = i18next.exists(i18RootKey) ? i18next.t(i18RootKey) : formText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formName) {
|
if (formName) {
|
||||||
|
@ -13,7 +13,7 @@ interface LanguageSetting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const languageSettings: { [key: string]: LanguageSetting } = {
|
const languageSettings: { [key: string]: LanguageSetting } = {
|
||||||
"es":{
|
"es-ES": {
|
||||||
inputFieldFontSize: "50px",
|
inputFieldFontSize: "50px",
|
||||||
errorMessageFontSize: "40px",
|
errorMessageFontSize: "40px",
|
||||||
}
|
}
|
||||||
|
@ -677,7 +677,7 @@ export default class RunInfoUiHandler extends UiHandler {
|
|||||||
const def = i18next.t("pokemonInfo:Stat.DEFshortened") + ": " + pStats[2];
|
const def = i18next.t("pokemonInfo:Stat.DEFshortened") + ": " + pStats[2];
|
||||||
const spatk = i18next.t("pokemonInfo:Stat.SPATKshortened") + ": " + pStats[3];
|
const spatk = i18next.t("pokemonInfo:Stat.SPATKshortened") + ": " + pStats[3];
|
||||||
const spdef = i18next.t("pokemonInfo:Stat.SPDEFshortened") + ": " + pStats[4];
|
const spdef = i18next.t("pokemonInfo:Stat.SPDEFshortened") + ": " + pStats[4];
|
||||||
const speedLabel = (currentLanguage === "es" || currentLanguage === "pt_BR") ? i18next.t("runHistory:SPDshortened") : i18next.t("pokemonInfo:Stat.SPDshortened");
|
const speedLabel = (currentLanguage === "es-ES" || currentLanguage === "pt_BR") ? i18next.t("runHistory:SPDshortened") : i18next.t("pokemonInfo:Stat.SPDshortened");
|
||||||
const speed = speedLabel + ": " + pStats[5];
|
const speed = speedLabel + ": " + pStats[5];
|
||||||
// Column 1: HP Atk Def
|
// Column 1: HP Atk Def
|
||||||
const pokeStatText1 = addBBCodeTextObject(this.scene, -5, 0, hp, TextStyle.SUMMARY, { fontSize: textContainerFontSize, lineSpacing: lineSpacing });
|
const pokeStatText1 = addBBCodeTextObject(this.scene, -5, 0, hp, TextStyle.SUMMARY, { fontSize: textContainerFontSize, lineSpacing: lineSpacing });
|
||||||
|
@ -29,10 +29,10 @@ export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler
|
|||||||
label: "English",
|
label: "English",
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "es":
|
case "es-ES":
|
||||||
this.settings[languageIndex].options[0] = {
|
this.settings[languageIndex].options[0] = {
|
||||||
value: "Español",
|
value: "Español (ES)",
|
||||||
label: "Español",
|
label: "Español (ES)",
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "it":
|
case "it":
|
||||||
|
@ -81,7 +81,7 @@ const languageSettings: { [key: string]: LanguageSetting } = {
|
|||||||
instructionTextSize: "35px",
|
instructionTextSize: "35px",
|
||||||
starterInfoXPos: 33,
|
starterInfoXPos: 33,
|
||||||
},
|
},
|
||||||
"es":{
|
"es-ES":{
|
||||||
starterInfoTextSize: "56px",
|
starterInfoTextSize: "56px",
|
||||||
instructionTextSize: "35px",
|
instructionTextSize: "35px",
|
||||||
},
|
},
|
||||||
|
@ -184,6 +184,7 @@ export default class TargetSelectUiHandler extends UiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
|
this.cursor = -1;
|
||||||
super.clear();
|
super.clear();
|
||||||
this.eraseCursor();
|
this.eraseCursor();
|
||||||
}
|
}
|
||||||
|
@ -487,7 +487,7 @@ export function verifyLang(lang?: string): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (lang) {
|
switch (lang) {
|
||||||
case "es":
|
case "es-ES":
|
||||||
case "fr":
|
case "fr":
|
||||||
case "de":
|
case "de":
|
||||||
case "it":
|
case "it":
|
||||||
|
Loading…
Reference in New Issue
Block a user