Merge branch 'beta' into splash-texts-locales-update

This commit is contained in:
Lugiad 2024-09-26 01:27:20 +02:00 committed by GitHub
commit 9cf3496d7c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 633 additions and 126 deletions

150
package-lock.json generated
View File

@ -1511,224 +1511,208 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz",
"integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==", "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"android" "android"
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz",
"integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==", "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"android" "android"
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz",
"integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==", "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"darwin" "darwin"
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz",
"integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==", "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"darwin" "darwin"
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz",
"integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==", "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz",
"integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==", "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz",
"integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==", "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz",
"integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==", "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz",
"integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==", "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz",
"integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==", "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz",
"integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==", "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz",
"integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==", "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz",
"integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==", "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz",
"integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==", "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz",
"integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==", "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz",
"integrity": "sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==", "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true, "dev": true,
"license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
@ -5446,9 +5430,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.18.1", "version": "4.22.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz",
"integrity": "sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==", "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/estree": "1.0.5" "@types/estree": "1.0.5"
@ -5461,22 +5445,22 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.18.1", "@rollup/rollup-android-arm-eabi": "4.22.4",
"@rollup/rollup-android-arm64": "4.18.1", "@rollup/rollup-android-arm64": "4.22.4",
"@rollup/rollup-darwin-arm64": "4.18.1", "@rollup/rollup-darwin-arm64": "4.22.4",
"@rollup/rollup-darwin-x64": "4.18.1", "@rollup/rollup-darwin-x64": "4.22.4",
"@rollup/rollup-linux-arm-gnueabihf": "4.18.1", "@rollup/rollup-linux-arm-gnueabihf": "4.22.4",
"@rollup/rollup-linux-arm-musleabihf": "4.18.1", "@rollup/rollup-linux-arm-musleabihf": "4.22.4",
"@rollup/rollup-linux-arm64-gnu": "4.18.1", "@rollup/rollup-linux-arm64-gnu": "4.22.4",
"@rollup/rollup-linux-arm64-musl": "4.18.1", "@rollup/rollup-linux-arm64-musl": "4.22.4",
"@rollup/rollup-linux-powerpc64le-gnu": "4.18.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4",
"@rollup/rollup-linux-riscv64-gnu": "4.18.1", "@rollup/rollup-linux-riscv64-gnu": "4.22.4",
"@rollup/rollup-linux-s390x-gnu": "4.18.1", "@rollup/rollup-linux-s390x-gnu": "4.22.4",
"@rollup/rollup-linux-x64-gnu": "4.18.1", "@rollup/rollup-linux-x64-gnu": "4.22.4",
"@rollup/rollup-linux-x64-musl": "4.18.1", "@rollup/rollup-linux-x64-musl": "4.22.4",
"@rollup/rollup-win32-arm64-msvc": "4.18.1", "@rollup/rollup-win32-arm64-msvc": "4.22.4",
"@rollup/rollup-win32-ia32-msvc": "4.18.1", "@rollup/rollup-win32-ia32-msvc": "4.22.4",
"@rollup/rollup-win32-x64-msvc": "4.18.1", "@rollup/rollup-win32-x64-msvc": "4.22.4",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },

View File

@ -2026,6 +2026,7 @@ export class PostSummonAbAttr extends AbAttr {
return false; return false;
} }
} }
/** /**
* Removes specified arena tags when a Pokemon is summoned. * Removes specified arena tags when a Pokemon is summoned.
*/ */
@ -2852,17 +2853,17 @@ export class PreApplyBattlerTagAbAttr extends AbAttr {
* Provides immunity to BattlerTags {@linkcode BattlerTag} to specified targets. * Provides immunity to BattlerTags {@linkcode BattlerTag} to specified targets.
*/ */
export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr { export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
private immuneTagType: BattlerTagType; private immuneTagTypes: BattlerTagType[];
private battlerTag: BattlerTag; private battlerTag: BattlerTag;
constructor(immuneTagType: BattlerTagType) { constructor(immuneTagTypes: BattlerTagType | BattlerTagType[]) {
super(); super();
this.immuneTagType = immuneTagType; this.immuneTagTypes = Array.isArray(immuneTagTypes) ? immuneTagTypes : [immuneTagTypes];
} }
applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean { applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (tag.tagType === this.immuneTagType) { if (this.immuneTagTypes.includes(tag.tagType)) {
cancelled.value = true; cancelled.value = true;
if (!simulated) { if (!simulated) {
this.battlerTag = tag; this.battlerTag = tag;
@ -4916,7 +4917,7 @@ export function initAbilities() {
.attr(TypeImmunityHealAbAttr, Type.WATER) .attr(TypeImmunityHealAbAttr, Type.WATER)
.ignorable(), .ignorable(),
new Ability(Abilities.OBLIVIOUS, 3) new Ability(Abilities.OBLIVIOUS, 3)
.attr(BattlerTagImmunityAbAttr, BattlerTagType.INFATUATED) .attr(BattlerTagImmunityAbAttr, [BattlerTagType.INFATUATED, BattlerTagType.TAUNT])
.attr(IntimidateImmunityAbAttr) .attr(IntimidateImmunityAbAttr)
.ignorable(), .ignorable(),
new Ability(Abilities.CLOUD_NINE, 3) new Ability(Abilities.CLOUD_NINE, 3)
@ -5402,8 +5403,7 @@ export function initAbilities() {
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonTeravolt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })) .attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonTeravolt", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
.attr(MoveAbilityBypassAbAttr), .attr(MoveAbilityBypassAbAttr),
new Ability(Abilities.AROMA_VEIL, 6) new Ability(Abilities.AROMA_VEIL, 6)
.ignorable() .attr(UserFieldBattlerTagImmunityAbAttr, [BattlerTagType.INFATUATED, BattlerTagType.TAUNT, BattlerTagType.DISABLED, BattlerTagType.TORMENT, BattlerTagType.HEAL_BLOCK]),
.unimplemented(),
new Ability(Abilities.FLOWER_VEIL, 6) new Ability(Abilities.FLOWER_VEIL, 6)
.ignorable() .ignorable()
.unimplemented(), .unimplemented(),
@ -5885,7 +5885,6 @@ export function initAbilities() {
.ignorable(), .ignorable(),
new Ability(Abilities.EARTH_EATER, 9) new Ability(Abilities.EARTH_EATER, 9)
.attr(TypeImmunityHealAbAttr, Type.GROUND) .attr(TypeImmunityHealAbAttr, Type.GROUND)
.partial() // Healing not blocked by Heal Block
.ignorable(), .ignorable(),
new Ability(Abilities.MYCELIUM_MIGHT, 9) new Ability(Abilities.MYCELIUM_MIGHT, 9)
.attr(ChangeMovePriorityAbAttr, (pokemon, move) => move.category === MoveCategory.STATUS, -0.2) .attr(ChangeMovePriorityAbAttr, (pokemon, move) => move.category === MoveCategory.STATUS, -0.2)
@ -5900,8 +5899,7 @@ export function initAbilities() {
.attr(PostSummonStatStageChangeAbAttr, [ Stat.EVA ], -1) .attr(PostSummonStatStageChangeAbAttr, [ Stat.EVA ], -1)
.condition(getOncePerBattleCondition(Abilities.SUPERSWEET_SYRUP)), .condition(getOncePerBattleCondition(Abilities.SUPERSWEET_SYRUP)),
new Ability(Abilities.HOSPITALITY, 9) new Ability(Abilities.HOSPITALITY, 9)
.attr(PostSummonAllyHealAbAttr, 4, true) .attr(PostSummonAllyHealAbAttr, 4, true),
.partial(), // Healing not blocked by Heal Block
new Ability(Abilities.TOXIC_CHAIN, 9) new Ability(Abilities.TOXIC_CHAIN, 9)
.attr(PostAttackApplyStatusEffectAbAttr, false, 30, StatusEffect.TOXIC), .attr(PostAttackApplyStatusEffectAbAttr, false, 30, StatusEffect.TOXIC),
new Ability(Abilities.EMBODY_ASPECT_TEAL, 9) new Ability(Abilities.EMBODY_ASPECT_TEAL, 9)

View File

@ -1,14 +1,15 @@
import { Arena } from "../field/arena"; import { Arena } from "#app/field/arena";
import { Type } from "./type"; import BattleScene from "#app/battle-scene";
import * as Utils from "../utils"; import { Type } from "#app/data/type";
import { MoveCategory, allMoves, MoveTarget, IncrementMovePriorityAttr, applyMoveAttrs } from "./move"; import * as Utils from "#app/utils";
import { getPokemonNameWithAffix } from "../messages"; import { MoveCategory, allMoves, MoveTarget, IncrementMovePriorityAttr, applyMoveAttrs } from "#app/data/move";
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages";
import { StatusEffect } from "./status-effect"; import Pokemon, { HitResult, PlayerPokemon, PokemonMove, EnemyPokemon } from "#app/field/pokemon";
import { BattlerIndex } from "../battle"; import { StatusEffect } from "#app/data/status-effect";
import { BlockNonDirectDamageAbAttr, ChangeMovePriorityAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability"; import { BattlerIndex } from "#app/battle";
import { BlockNonDirectDamageAbAttr, ChangeMovePriorityAbAttr, ProtectStatAbAttr, applyAbAttrs } from "#app/data/ability";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CommonAnim, CommonBattleAnim } from "./battle-anims"; import { CommonAnim, CommonBattleAnim } from "#app/data/battle-anims";
import i18next from "i18next"; import i18next from "i18next";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagType } from "#enums/arena-tag-type";
@ -919,6 +920,77 @@ class SafeguardTag extends ArenaTag {
} }
} }
/**
* This arena tag facilitates the application of the move Imprison
* Imprison remains in effect as long as the source Pokemon is active and present on the field.
* Imprison will apply to any opposing Pokemon that switch onto the field as well.
*/
class ImprisonTag extends ArenaTrapTag {
private source: Pokemon;
constructor(sourceId: number, side: ArenaTagSide) {
super(ArenaTagType.IMPRISON, Moves.IMPRISON, sourceId, side, 1);
}
/**
* Helper function that retrieves the Pokemon effected
* @param {BattleScene} scene medium to retrieve the involved Pokemon
* @returns list of PlayerPokemon or EnemyPokemon on the field
*/
private retrieveField(scene: BattleScene): PlayerPokemon[] | EnemyPokemon[] {
if (!this.source.isPlayer()) {
return scene.getPlayerField() ?? [];
}
return scene.getEnemyField() ?? [];
}
/**
* This function applies the effects of Imprison to the opposing Pokemon already present on the field.
* @param arena
*/
override onAdd({ scene }: Arena) {
this.source = scene.getPokemonById(this.sourceId!)!;
if (this.source) {
const party = this.retrieveField(scene);
party?.forEach((p: PlayerPokemon | EnemyPokemon ) => {
p.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
});
scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", {pokemonNameWithAffix: getPokemonNameWithAffix(this.source)}));
}
}
/**
* Checks if the source Pokemon is still active on the field
* @param _arena
* @returns `true` if the source of the tag is still active on the field | `false` if not
*/
override lapse(_arena: Arena): boolean {
return this.source.isActive(true);
}
/**
* This applies the effects of Imprison to any opposing Pokemon that switch into the field while the source Pokemon is still active
* @param {Pokemon} pokemon the Pokemon Imprison is applied to
* @returns `true`
*/
override activateTrap(pokemon: Pokemon): boolean {
if (this.source.isActive(true)) {
pokemon.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId);
}
return true;
}
/**
* When the arena tag is removed, it also attempts to remove any related Battler Tags if they haven't already been removed from the affected Pokemon
* @param arena
*/
override onRemove({ scene }: Arena): void {
const party = this.retrieveField(scene);
party?.forEach((p: PlayerPokemon | EnemyPokemon) => {
p.removeTag(BattlerTagType.IMPRISON);
});
}
}
export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null { export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null {
switch (tagType) { switch (tagType) {
@ -967,6 +1039,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
return new HappyHourTag(turnCount, sourceId, side); return new HappyHourTag(turnCount, sourceId, side);
case ArenaTagType.SAFEGUARD: case ArenaTagType.SAFEGUARD:
return new SafeguardTag(turnCount, sourceId, side); return new SafeguardTag(turnCount, sourceId, side);
case ArenaTagType.IMPRISON:
return new ImprisonTag(sourceId, side);
default: default:
return null; return null;
} }

View File

@ -3,7 +3,7 @@ import { getPokemonNameWithAffix } from "../messages";
import Pokemon, { MoveResult, HitResult } from "../field/pokemon"; import Pokemon, { MoveResult, HitResult } from "../field/pokemon";
import { StatusEffect } from "./status-effect"; import { StatusEffect } from "./status-effect";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { ChargeAttr, MoveFlags, allMoves, MoveCategory, applyMoveAttrs, StatusCategoryOnAllyAttr, HealOnAllyAttr } from "./move"; import { ChargeAttr, MoveFlags, allMoves, MoveCategory, applyMoveAttrs, StatusCategoryOnAllyAttr, HealOnAllyAttr, ConsecutiveUseDoublePowerAttr } from "./move";
import { Type } from "./type"; import { Type } from "./type";
import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs, ProtectStatAbAttr } from "./ability"; import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs, ProtectStatAbAttr } from "./ability";
import { TerrainType } from "./terrain"; import { TerrainType } from "./terrain";
@ -2437,6 +2437,150 @@ export class MysteryEncounterPostSummonTag extends BattlerTag {
} }
} }
/**
* Battle Tag that applies the move Torment to the target Pokemon
* Torment restricts the use of moves twice in a row.
* The tag is only removed if the target leaves the battle.
* Torment does not interrupt the move if the move is performed consecutively in the same turn and right after Torment is applied
*/
export class TormentTag extends MoveRestrictionBattlerTag {
private target: Pokemon;
constructor(sourceId: number) {
super(BattlerTagType.TORMENT, BattlerTagLapseType.AFTER_MOVE, 1, Moves.TORMENT, sourceId);
}
/**
* Adds the battler tag to the target Pokemon and defines the private class variable 'target'
* 'Target' is used to track the Pokemon's current status
* @param {Pokemon} pokemon the Pokemon tormented
*/
override onAdd(pokemon: Pokemon) {
super.onAdd(pokemon);
this.target = pokemon;
pokemon.scene.queueMessage(i18next.t("battlerTags:tormentOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), 1500);
}
/**
* Torment only ends when the affected Pokemon leaves the battle field
* @param {Pokemon} pokemon the Pokemon under the effects of Torment
* @param _tagType
* @returns `true` if still present | `false` if not
*/
override lapse(pokemon: Pokemon, _tagType: BattlerTagLapseType): boolean {
return !pokemon.isActive(true);
}
/**
* This checks if the current move used is identical to the last used move with a {@linkcode MoveResult} of `SUCCESS`/`MISS`
* @param {Moves} move the move under investigation
* @returns `true` if there is valid consecutive usage | `false` if the moves are different from each other
*/
override isMoveRestricted(move: Moves): boolean {
const lastMove = this.target.getLastXMoves(1)[0];
if ( !lastMove ) {
return false;
}
// This checks for locking / momentum moves like Rollout and Hydro Cannon + if the user is under the influence of BattlerTagType.FRENZY
// Because Uproar's unique behavior is not implemented, it does not check for Uproar. Torment has been marked as partial in moves.ts
const moveObj = allMoves[lastMove.move];
const isUnaffected = moveObj.hasAttr(ConsecutiveUseDoublePowerAttr) || this.target.getTag(BattlerTagType.FRENZY) || moveObj.hasAttr(ChargeAttr);
const validLastMoveResult = (lastMove.result === MoveResult.SUCCESS) || (lastMove.result === MoveResult.MISS);
if (lastMove.move === move && validLastMoveResult && lastMove.move !== Moves.STRUGGLE && !isUnaffected) {
return true;
}
return false;
}
override selectionDeniedText(_pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name });
}
}
/**
* BattlerTag that applies the effects of Taunt to the target Pokemon
* Taunt restricts the use of status moves.
* The tag is removed after 4 turns.
*/
export class TauntTag extends MoveRestrictionBattlerTag {
constructor() {
super(BattlerTagType.TAUNT, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE], 4, Moves.TAUNT);
}
override onAdd(pokemon: Pokemon) {
super.onAdd(pokemon);
pokemon.scene.queueMessage(i18next.t("battlerTags:tauntOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), 1500);
}
/**
* Checks if a move is a status move and determines its restriction status on that basis
* @param {Moves} move the move under investigation
* @returns `true` if the move is a status move
*/
override isMoveRestricted(move: Moves): boolean {
return allMoves[move].category === MoveCategory.STATUS;
}
override selectionDeniedText(_pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name });
}
override interruptedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
}
}
/**
* BattlerTag that applies the effects of Imprison to the target Pokemon
* Imprison restricts the opposing side's usage of moves shared by the source-user of Imprison.
* The tag is only removed when the source-user is removed from the field.
*/
export class ImprisonTag extends MoveRestrictionBattlerTag {
private source: Pokemon | null;
constructor(sourceId: number) {
super(BattlerTagType.IMPRISON, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE], 1, Moves.IMPRISON, sourceId);
}
override onAdd(pokemon: Pokemon) {
if (this.sourceId) {
this.source = pokemon.scene.getPokemonById(this.sourceId);
}
}
/**
* Checks if the source of Imprison is still active
* @param _pokemon
* @param _lapseType
* @returns `true` if the source is still active
*/
override lapse(_pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean {
return this.source?.isActive(true) ?? false;
}
/**
* Checks if the source of the tag has the parameter move in its moveset and that the source is still active
* @param {Moves} move the move under investigation
* @returns `false` if either condition is not met
*/
override isMoveRestricted(move: Moves): boolean {
if (this.source) {
const sourceMoveset = this.source.getMoveset().map(m => m!.moveId);
return sourceMoveset?.includes(move) && this.source.isActive(true);
}
return false;
}
override selectionDeniedText(_pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name });
}
override interruptedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
}
}
/** /**
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID. * Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
* *
@ -2604,6 +2748,12 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
return new MysteryEncounterPostSummonTag(); return new MysteryEncounterPostSummonTag();
case BattlerTagType.HEAL_BLOCK: case BattlerTagType.HEAL_BLOCK:
return new HealBlockTag(turnCount, sourceMove); return new HealBlockTag(turnCount, sourceMove);
case BattlerTagType.TORMENT:
return new TormentTag(sourceId);
case BattlerTagType.TAUNT:
return new TauntTag();
case BattlerTagType.IMPRISON:
return new ImprisonTag(sourceId);
case BattlerTagType.NONE: case BattlerTagType.NONE:
default: default:
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);

View File

@ -7507,7 +7507,8 @@ export function initMoves() {
.target(MoveTarget.BOTH_SIDES), .target(MoveTarget.BOTH_SIDES),
new StatusMove(Moves.TORMENT, Type.DARK, 100, 15, -1, 0, 3) new StatusMove(Moves.TORMENT, Type.DARK, 100, 15, -1, 0, 3)
.ignoresSubstitute() .ignoresSubstitute()
.unimplemented(), .partial() // Incomplete implementation because of Uproar's partial implementation
.attr(AddBattlerTagAttr, BattlerTagType.TORMENT, false, true, 1),
new StatusMove(Moves.FLATTER, Type.DARK, 100, 15, -1, 0, 3) new StatusMove(Moves.FLATTER, Type.DARK, 100, 15, -1, 0, 3)
.attr(StatStageChangeAttr, [ Stat.SPATK ], 1) .attr(StatStageChangeAttr, [ Stat.SPATK ], 1)
.attr(ConfuseAttr), .attr(ConfuseAttr),
@ -7538,7 +7539,7 @@ export function initMoves() {
.attr(AddBattlerTagAttr, BattlerTagType.CHARGED, true, false), .attr(AddBattlerTagAttr, BattlerTagType.CHARGED, true, false),
new StatusMove(Moves.TAUNT, Type.DARK, 100, 20, -1, 0, 3) new StatusMove(Moves.TAUNT, Type.DARK, 100, 20, -1, 0, 3)
.ignoresSubstitute() .ignoresSubstitute()
.unimplemented(), .attr(AddBattlerTagAttr, BattlerTagType.TAUNT, false, true, 4),
new StatusMove(Moves.HELPING_HAND, Type.NORMAL, -1, 20, -1, 5, 3) new StatusMove(Moves.HELPING_HAND, Type.NORMAL, -1, 20, -1, 5, 3)
.attr(AddBattlerTagAttr, BattlerTagType.HELPING_HAND) .attr(AddBattlerTagAttr, BattlerTagType.HELPING_HAND)
.ignoresSubstitute() .ignoresSubstitute()
@ -7581,9 +7582,9 @@ export function initMoves() {
new StatusMove(Moves.SKILL_SWAP, Type.PSYCHIC, -1, 10, -1, 0, 3) new StatusMove(Moves.SKILL_SWAP, Type.PSYCHIC, -1, 10, -1, 0, 3)
.ignoresSubstitute() .ignoresSubstitute()
.attr(SwitchAbilitiesAttr), .attr(SwitchAbilitiesAttr),
new SelfStatusMove(Moves.IMPRISON, Type.PSYCHIC, -1, 10, -1, 0, 3) new StatusMove(Moves.IMPRISON, Type.PSYCHIC, 100, 10, -1, 0, 3)
.ignoresSubstitute() .ignoresSubstitute()
.unimplemented(), .attr(AddArenaTagAttr, ArenaTagType.IMPRISON, 1, true, false),
new SelfStatusMove(Moves.REFRESH, Type.NORMAL, -1, 20, -1, 0, 3) new SelfStatusMove(Moves.REFRESH, Type.NORMAL, -1, 20, -1, 0, 3)
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN) .attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN)
.condition((user, target, move) => !!user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)), .condition((user, target, move) => !!user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)),

View File

@ -23,5 +23,6 @@ export enum ArenaTagType {
TAILWIND = "TAILWIND", TAILWIND = "TAILWIND",
HAPPY_HOUR = "HAPPY_HOUR", HAPPY_HOUR = "HAPPY_HOUR",
SAFEGUARD = "SAFEGUARD", SAFEGUARD = "SAFEGUARD",
NO_CRIT = "NO_CRIT" NO_CRIT = "NO_CRIT",
IMPRISON = "IMPRISON",
} }

View File

@ -82,4 +82,7 @@ export enum BattlerTagType {
AUTOTOMIZED = "AUTOTOMIZED", AUTOTOMIZED = "AUTOTOMIZED",
MYSTERY_ENCOUNTER_POST_SUMMON = "MYSTERY_ENCOUNTER_POST_SUMMON", MYSTERY_ENCOUNTER_POST_SUMMON = "MYSTERY_ENCOUNTER_POST_SUMMON",
HEAL_BLOCK = "HEAL_BLOCK", HEAL_BLOCK = "HEAL_BLOCK",
TORMENT = "TORMENT",
TAUNT = "TAUNT",
IMPRISON = "IMPRISON",
} }

View File

@ -74,5 +74,8 @@
"substituteOnAdd": "{{pokemonNameWithAffix}} put in a substitute!", "substituteOnAdd": "{{pokemonNameWithAffix}} put in a substitute!",
"substituteOnHit": "The substitute took damage for {{pokemonNameWithAffix}}!", "substituteOnHit": "The substitute took damage for {{pokemonNameWithAffix}}!",
"substituteOnRemove": "{{pokemonNameWithAffix}}'s substitute faded!", "substituteOnRemove": "{{pokemonNameWithAffix}}'s substitute faded!",
"tormentOnAdd": "{{pokemonNameWithAffix}} was subjected to torment!",
"tauntOnAdd": "{{pokemonNameWithAffix}} fell for the taunt!",
"imprisonOnAdd": "{{pokemonNameWithAffix}} sealed the opponents move(s)!",
"autotomizeOnAdd": "{{pokemonNameWithAffix}} became nimble!" "autotomizeOnAdd": "{{pokemonNameWithAffix}} became nimble!"
} }

View File

@ -69,7 +69,7 @@
"turnEndHpRestore": "{{pokemonName}}의\n체력이 회복되었다!", "turnEndHpRestore": "{{pokemonName}}의\n체력이 회복되었다!",
"hpIsFull": "그러나 {{pokemonName}}의\n체력이 가득 찬 상태다!", "hpIsFull": "그러나 {{pokemonName}}의\n체력이 가득 찬 상태다!",
"skipItemQuestion": "아이템을 받지 않고 넘어가시겠습니까?", "skipItemQuestion": "아이템을 받지 않고 넘어가시겠습니까?",
"itemStackFull": "{{fullItemName}}의 소지 한도에 도달했습니다.\n{{itemname}}[[를]] 대신 받습니다.", "itemStackFull": "{{fullItemName}}의 소지 한도에 도달했습니다.\n{{itemName}}[[를]] 대신 받습니다.",
"eggHatching": "어라…?", "eggHatching": "어라…?",
"eggSkipPrompt": "알 부화 요약 화면으로 바로 넘어가시겠습니까?", "eggSkipPrompt": "알 부화 요약 화면으로 바로 넘어가시겠습니까?",
"ivScannerUseQuestion": "{{pokemonName}}에게 개체값탐지기를 사용하시겠습니까?", "ivScannerUseQuestion": "{{pokemonName}}에게 개체값탐지기를 사용하시겠습니까?",

View File

@ -50,9 +50,9 @@
"description": "{{battleCount}}번의 배틀 동안 더블 배틀이 등장할 확률이 4배가 된다." "description": "{{battleCount}}번의 배틀 동안 더블 배틀이 등장할 확률이 4배가 된다."
}, },
"TempStatStageBoosterModifierType": { "TempStatStageBoosterModifierType": {
"description": "자신의 모든 포켓몬이 5번의 배틀 동안 {{stat}}[[가]] {{amount}}단계 증가한다.", "description": "자신의 모든 포켓몬이 5번의 배틀 동안 {{stat}}[[가]] {{amount}} 증가한다.",
"extra": { "extra": {
"stage": "1 스테이지", "stage": "1단계",
"percentage": "30%" "percentage": "30%"
} }
}, },

View File

@ -22,6 +22,8 @@ export function applySessionDataPatches(data: SessionSaveData) {
} else if (m.className === "PokemonResetNegativeStatStageModifier") { } else if (m.className === "PokemonResetNegativeStatStageModifier") {
m.className = "ResetNegativeStatStageModifier"; m.className = "ResetNegativeStatStageModifier";
} else if (m.className === "TempBattleStatBoosterModifier") { } else if (m.className === "TempBattleStatBoosterModifier") {
// Dire Hit no longer a part of the TempBattleStatBoosterModifierTypeGenerator
if (m.typeId !== "DIRE_HIT") {
m.className = "TempStatStageBoosterModifier"; m.className = "TempStatStageBoosterModifier";
m.typeId = "TEMP_STAT_STAGE_BOOSTER"; m.typeId = "TEMP_STAT_STAGE_BOOSTER";
@ -31,6 +33,14 @@ export function applySessionDataPatches(data: SessionSaveData) {
// From [ stat, battlesLeft ] to [ stat, maxBattles, battleCount ] // From [ stat, battlesLeft ] to [ stat, maxBattles, battleCount ]
m.args = [ newStat, 5, m.args[1] ]; m.args = [ newStat, 5, m.args[1] ];
} else {
m.className = "TempCritBoosterModifier";
m.typePregenArgs = [];
// From [ stat, battlesLeft ] to [ maxBattles, battleCount ]
m.args = [ 5, m.args[1] ];
}
} else if (m.className === "DoubleBattleChanceBoosterModifier" && m.args.length === 1) { } else if (m.className === "DoubleBattleChanceBoosterModifier" && m.args.length === 1) {
let maxBattles: number; let maxBattles: number;
switch (m.typeId) { switch (m.typeId) {
@ -73,7 +83,7 @@ export function applySystemDataPatches(data: SystemSaveData) {
case "1.0.3": case "1.0.3":
case "1.0.4": case "1.0.4":
// --- LEGACY PATCHES --- // --- LEGACY PATCHES ---
if (data.starterData) { if (data.starterData && data.dexData) {
// Migrate ability starter data if empty for caught species // Migrate ability starter data if empty for caught species
Object.keys(data.starterData).forEach(sd => { Object.keys(data.starterData).forEach(sd => {
if (data.dexData[sd]?.caughtAttr && (data.starterData[sd] && !data.starterData[sd].abilityAttr)) { if (data.dexData[sd]?.caughtAttr && (data.starterData[sd] && !data.starterData[sd].abilityAttr)) {
@ -104,6 +114,7 @@ export function applySystemDataPatches(data: SystemSaveData) {
// --- PATCHES --- // --- PATCHES ---
// Fix Starter Data // Fix Starter Data
if (data.starterData && data.dexData) {
for (const starterId of defaultStarterSpecies) { for (const starterId of defaultStarterSpecies) {
if (data.starterData[starterId]?.abilityAttr) { if (data.starterData[starterId]?.abilityAttr) {
data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1; data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1;
@ -113,6 +124,7 @@ export function applySystemDataPatches(data: SystemSaveData) {
} }
} }
} }
}
data.gameVersion = LATEST_VERSION; data.gameVersion = LATEST_VERSION;
} }

View File

@ -0,0 +1,65 @@
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 } from "vitest";
import { BattlerTagType } from "#enums/battler-tag-type";
import { ArenaTagType } from "#enums/arena-tag-type";
import { BattlerIndex } from "#app/battle";
import { PlayerPokemon } from "#app/field/pokemon";
describe("Moves - Aroma Veil", () => {
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.HEAL_BLOCK, Moves.IMPRISON, Moves.SPLASH])
.enemySpecies(Species.SHUCKLE)
.ability(Abilities.AROMA_VEIL)
.moveset([Moves.GROWL]);
});
it("Aroma Veil protects the Pokemon's side against most Move Restriction Battler Tags", async () => {
await game.classicMode.startBattle([Species.REGIELEKI, Species.BULBASAUR]);
const party = game.scene.getParty()! as PlayerPokemon[];
game.move.select(Moves.GROWL);
game.move.select(Moves.GROWL);
await game.forceEnemyMove(Moves.HEAL_BLOCK);
await game.toNextTurn();
party.forEach(p => {
expect(p.getTag(BattlerTagType.HEAL_BLOCK)).toBeUndefined();
});
});
it("Aroma Veil does not protect against Imprison", async () => {
await game.classicMode.startBattle([Species.REGIELEKI, Species.BULBASAUR]);
const party = game.scene.getParty()! as PlayerPokemon[];
game.move.select(Moves.GROWL);
game.move.select(Moves.GROWL, 1);
await game.forceEnemyMove(Moves.IMPRISON, BattlerIndex.PLAYER);
await game.forceEnemyMove(Moves.SPLASH);
await game.toNextTurn();
expect(game.scene.arena.getTag(ArenaTagType.IMPRISON)).toBeDefined();
party.forEach(p => {
expect(p.getTag(BattlerTagType.IMPRISON)).toBeDefined();
});
});
});

View File

@ -0,0 +1,98 @@
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 } from "vitest";
import { BattlerTagType } from "#enums/battler-tag-type";
import { ArenaTagType } from "#enums/arena-tag-type";
describe("Moves - Imprison", () => {
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")
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset([Moves.IMPRISON, Moves.SPLASH, Moves.GROWL])
.enemySpecies(Species.SHUCKLE)
.moveset([Moves.TRANSFORM, Moves.SPLASH]);
});
it("Pokemon under Imprison cannot use shared moves", async () => {
await game.classicMode.startBattle([Species.REGIELEKI]);
const playerPokemon = game.scene.getPlayerPokemon()!;
game.move.select(Moves.TRANSFORM);
await game.forceEnemyMove(Moves.IMPRISON);
await game.toNextTurn();
const playerMoveset = playerPokemon.getMoveset().map(x => x?.moveId);
const enemyMoveset = game.scene.getEnemyPokemon()!.getMoveset().map(x => x?.moveId);
expect(enemyMoveset.includes(playerMoveset[0])).toBeTruthy();
const imprisonArenaTag = game.scene.arena.getTag(ArenaTagType.IMPRISON);
const imprisonBattlerTag = playerPokemon.getTag(BattlerTagType.IMPRISON);
expect(imprisonArenaTag).toBeDefined();
expect(imprisonBattlerTag).toBeDefined();
// Second turn, Imprison forces Struggle to occur
game.move.select(Moves.SPLASH);
await game.forceEnemyMove(Moves.SPLASH);
await game.toNextTurn();
const move1 = playerPokemon.getLastXMoves(1)[0]!;
expect(move1.move).toBe(Moves.STRUGGLE);
});
it("Imprison applies to Pokemon switched into Battle", async () => {
await game.classicMode.startBattle([Species.REGIELEKI, Species.BULBASAUR]);
const playerPokemon1 = game.scene.getPlayerPokemon()!;
game.move.select(Moves.SPLASH);
await game.forceEnemyMove(Moves.IMPRISON);
await game.toNextTurn();
const imprisonArenaTag = game.scene.arena.getTag(ArenaTagType.IMPRISON);
const imprisonBattlerTag1 = playerPokemon1.getTag(BattlerTagType.IMPRISON);
expect(imprisonArenaTag).toBeDefined();
expect(imprisonBattlerTag1).toBeDefined();
// Second turn, Imprison forces Struggle to occur
game.doSwitchPokemon(1);
await game.forceEnemyMove(Moves.SPLASH);
await game.toNextTurn();
const playerPokemon2 = game.scene.getPlayerPokemon()!;
const imprisonBattlerTag2 = playerPokemon2.getTag(BattlerTagType.IMPRISON);
expect(playerPokemon1).not.toEqual(playerPokemon2);
expect(imprisonBattlerTag2).toBeDefined();
});
it("The effects of Imprison only end when the source is no longer active", async () => {
game.override.moveset([Moves.SPLASH, Moves.IMPRISON]);
await game.classicMode.startBattle([Species.REGIELEKI, Species.BULBASAUR]);
const playerPokemon = game.scene.getPlayerPokemon()!;
const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.select(Moves.IMPRISON);
await game.forceEnemyMove(Moves.GROWL);
await game.toNextTurn();
expect(game.scene.arena.getTag(ArenaTagType.IMPRISON)).toBeDefined();
expect(enemyPokemon.getTag(BattlerTagType.IMPRISON)).toBeDefined();
game.doSwitchPokemon(1);
await game.forceEnemyMove(Moves.SPLASH);
await game.toNextTurn();
expect(playerPokemon.isActive(true)).toBeFalsy();
expect(game.scene.arena.getTag(ArenaTagType.IMPRISON)).toBeUndefined();
expect(enemyPokemon.getTag(BattlerTagType.IMPRISON)).toBeUndefined();
});
});

View File

@ -0,0 +1,54 @@
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 } from "vitest";
import { MoveResult } from "#app/field/pokemon";
import { BattlerTagType } from "#enums/battler-tag-type";
describe("Moves - Taunt", () => {
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")
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset([Moves.TAUNT, Moves.SPLASH])
.enemySpecies(Species.SHUCKLE)
.moveset([Moves.GROWL]);
});
it("Pokemon should not be able to use Status Moves", async () => {
await game.classicMode.startBattle([Species.REGIELEKI]);
const playerPokemon = game.scene.getPlayerPokemon()!;
// First turn, Player Pokemon succeeds using Growl without Taunt
game.move.select(Moves.GROWL);
await game.forceEnemyMove(Moves.TAUNT);
await game.toNextTurn();
const move1 = playerPokemon.getLastXMoves(1)[0]!;
expect(move1.move).toBe(Moves.GROWL);
expect(move1.result).toBe(MoveResult.SUCCESS);
expect(playerPokemon?.getTag(BattlerTagType.TAUNT)).toBeDefined();
// Second turn, Taunt forces Struggle to occur
game.move.select(Moves.GROWL);
await game.forceEnemyMove(Moves.SPLASH);
await game.toNextTurn();
const move2 = playerPokemon.getLastXMoves(1)[0]!;
expect(move2.move).toBe(Moves.STRUGGLE);
});
});

View File

@ -0,0 +1,64 @@
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 } from "vitest";
import { MoveResult } from "#app/field/pokemon";
import { BattlerTagType } from "#enums/battler-tag-type";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
describe("Moves - Torment", () => {
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")
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset([Moves.TORMENT, Moves.SPLASH])
.enemySpecies(Species.SHUCKLE)
.enemyLevel(30)
.moveset([Moves.TACKLE])
.ability(Abilities.BALL_FETCH);
});
it("Pokemon should not be able to use the same move consecutively", async () => {
await game.classicMode.startBattle([Species.CHANSEY]);
const playerPokemon = game.scene.getPlayerPokemon()!;
// First turn, Player Pokemon uses Tackle successfully
game.move.select(Moves.TACKLE);
await game.forceEnemyMove(Moves.TORMENT);
await game.toNextTurn();
const move1 = playerPokemon.getLastXMoves(1)[0]!;
expect(move1.move).toBe(Moves.TACKLE);
expect(move1.result).toBe(MoveResult.SUCCESS);
expect(playerPokemon?.getTag(BattlerTagType.TORMENT)).toBeDefined();
// Second turn, Torment forces Struggle to occur
game.move.select(Moves.TACKLE);
await game.forceEnemyMove(Moves.SPLASH);
await game.toNextTurn();
const move2 = playerPokemon.getLastXMoves(1)[0]!;
expect(move2.move).toBe(Moves.STRUGGLE);
// Third turn, Tackle can be used.
game.move.select(Moves.TACKLE);
await game.forceEnemyMove(Moves.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase);
const move3 = playerPokemon.getLastXMoves(1)[0]!;
expect(move3.move).toBe(Moves.TACKLE);
});
});